statistics.cc revision 1395
1/* 2 * Copyright (c) 2003-2004 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <iomanip> 30#include <fstream> 31#include <list> 32#include <map> 33#include <string> 34#include <sstream> 35 36#include "base/callback.hh" 37#include "base/cprintf.hh" 38#include "base/hostinfo.hh" 39#include "base/misc.hh" 40#include "base/python.hh" 41#include "base/statistics.hh" 42#include "base/str.hh" 43#include "base/time.hh" 44#include "base/trace.hh" 45#include "base/stats/statdb.hh" 46 47using namespace std; 48 49namespace Stats { 50 51StatData * 52DataAccess::find() const 53{ 54 return Database::find(const_cast<void *>((const void *)this)); 55} 56 57const StatData * 58getStatData(const void *stat) 59{ 60 return Database::find(const_cast<void *>(stat)); 61} 62 63void 64DataAccess::map(StatData *data) 65{ 66 Database::regStat(this, data); 67} 68 69StatData * 70DataAccess::statData() 71{ 72 StatData *ptr = find(); 73 assert(ptr); 74 return ptr; 75} 76 77const StatData * 78DataAccess::statData() const 79{ 80 const StatData *ptr = find(); 81 assert(ptr); 82 return ptr; 83} 84 85void 86DataAccess::setInit() 87{ 88 statData()->flags |= init; 89} 90 91void 92DataAccess::setPrint() 93{ 94 Database::regPrint(this); 95} 96 97StatData::StatData() 98 : flags(none), precision(-1), prereq(0) 99{ 100 static int count = 0; 101 id = count++; 102} 103 104StatData::~StatData() 105{ 106} 107 108bool 109StatData::less(StatData *stat1, StatData *stat2) 110{ 111 const string &name1 = stat1->name; 112 const string &name2 = stat2->name; 113 114 vector<string> v1; 115 vector<string> v2; 116 117 tokenize(v1, name1, '.'); 118 tokenize(v2, name2, '.'); 119 120 int last = min(v1.size(), v2.size()) - 1; 121 for (int i = 0; i < last; ++i) 122 if (v1[i] != v2[i]) 123 return v1[i] < v2[i]; 124 125 // Special compare for last element. 126 if (v1[last] == v2[last]) 127 return v1.size() < v2.size(); 128 else 129 return v1[last] < v2[last]; 130 131 return false; 132} 133 134bool 135StatData::baseCheck() const 136{ 137 if (!(flags & init)) { 138#ifdef DEBUG 139 cprintf("this is stat number %d\n", id); 140#endif 141 panic("Not all stats have been initialized"); 142 return false; 143 } 144 145 if ((flags & print) && name.empty()) { 146 panic("all printable stats must be named"); 147 return false; 148 } 149 150 return true; 151} 152 153 154void 155FormulaBase::result(VResult &vec) const 156{ 157 if (root) 158 vec = root->result(); 159} 160 161Result 162FormulaBase::total() const 163{ 164 return root ? root->total() : 0.0; 165} 166 167size_t 168FormulaBase::size() const 169{ 170 if (!root) 171 return 0; 172 else 173 return root->size(); 174} 175 176bool 177FormulaBase::binned() const 178{ 179 return root && root->binned(); 180} 181 182void 183FormulaBase::reset() 184{ 185} 186 187bool 188FormulaBase::zero() const 189{ 190 VResult vec; 191 result(vec); 192 for (int i = 0; i < vec.size(); ++i) 193 if (vec[i] != 0.0) 194 return false; 195 return true; 196} 197 198void 199FormulaBase::update(StatData *) 200{ 201} 202 203string 204FormulaBase::str() const 205{ 206 return root ? root->str() : ""; 207} 208 209Formula::Formula() 210{ 211 setInit(); 212} 213 214Formula::Formula(Temp r) 215{ 216 root = r; 217 assert(size()); 218} 219 220const Formula & 221Formula::operator=(Temp r) 222{ 223 assert(!root && "Can't change formulas"); 224 root = r; 225 assert(size()); 226 return *this; 227} 228 229const Formula & 230Formula::operator+=(Temp r) 231{ 232 if (root) 233 root = NodePtr(new BinaryNode<std::plus<Result> >(root, r)); 234 else 235 root = r; 236 assert(size()); 237 return *this; 238} 239 240MainBin::MainBin(const string &name) 241 : _name(name), mem(NULL), memsize(-1) 242{ 243 Database::regBin(this, name); 244} 245 246MainBin::~MainBin() 247{ 248 if (mem) 249 delete [] mem; 250} 251 252char * 253MainBin::memory(off_t off) 254{ 255 if (memsize == -1) 256 memsize = CeilPow2((size_t) offset()); 257 258 if (!mem) { 259 mem = new char[memsize]; 260 memset(mem, 0, memsize); 261 } 262 263 assert(offset() <= size()); 264 return mem + off; 265} 266 267void 268check() 269{ 270 typedef Database::stat_list_t::iterator iter_t; 271 272 iter_t i, end = Database::stats().end(); 273 for (i = Database::stats().begin(); i != end; ++i) { 274 StatData *data = *i; 275 assert(data); 276 if (!data->check() || !data->baseCheck()) 277 panic("stat check failed for %s\n", data->name); 278 } 279 280 int j = 0; 281 for (i = Database::stats().begin(); i != end; ++i) { 282 StatData *data = *i; 283 if (!(data->flags & print)) 284 data->name = "__Stat" + to_string(j++); 285 } 286 287 Database::stats().sort(StatData::less); 288 289#if defined(STATS_BINNING) 290 if (MainBin::curBin() == NULL) { 291 static MainBin mainBin("main bin"); 292 mainBin.activate(); 293 } 294#endif 295 296 if (i == end) 297 return; 298 299 iter_t last = i; 300 ++i; 301 302 for (i = Database::stats().begin(); i != end; ++i) { 303 if ((*i)->name == (*last)->name) 304 panic("same name used twice! name=%s\n", (*i)->name); 305 306 last = i; 307 } 308} 309 310CallbackQueue resetQueue; 311 312void 313reset() 314{ 315 // reset non-binned stats 316 Database::stat_list_t::iterator i = Database::stats().begin(); 317 Database::stat_list_t::iterator end = Database::stats().end(); 318 while (i != end) { 319 StatData *data = *i; 320 if (!data->binned()) 321 data->reset(); 322 ++i; 323 } 324 325 // save the bin so we can go back to where we were 326 MainBin *orig = MainBin::curBin(); 327 328 // reset binned stats 329 Database::bin_list_t::iterator bi = Database::bins().begin(); 330 Database::bin_list_t::iterator be = Database::bins().end(); 331 while (bi != be) { 332 MainBin *bin = *bi; 333 bin->activate(); 334 335 i = Database::stats().begin(); 336 while (i != end) { 337 StatData *data = *i; 338 if (data->binned()) 339 data->reset(); 340 ++i; 341 } 342 ++bi; 343 } 344 345 // restore bin 346 MainBin::curBin() = orig; 347 348 resetQueue.process(); 349} 350 351void 352registerResetCallback(Callback *cb) 353{ 354 resetQueue.add(cb); 355} 356 357/* namespace Stats */ } 358