statistics.cc revision 2632:1bb2f91485ea
1/* 2 * Copyright (c) 2003-2005 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 35#include "base/callback.hh" 36#include "base/cprintf.hh" 37#include "base/hostinfo.hh" 38#include "base/misc.hh" 39#include "base/statistics.hh" 40#include "base/str.hh" 41#include "base/time.hh" 42#include "base/trace.hh" 43#include "base/stats/statdb.hh" 44#include "config/stats_binning.hh" 45 46using namespace std; 47 48namespace Stats { 49 50StatData * 51DataAccess::find() const 52{ 53 return Database::find(const_cast<void *>((const void *)this)); 54} 55 56const StatData * 57getStatData(const void *stat) 58{ 59 return Database::find(const_cast<void *>(stat)); 60} 61 62void 63DataAccess::map(StatData *data) 64{ 65 Database::regStat(this, data); 66} 67 68StatData * 69DataAccess::statData() 70{ 71 StatData *ptr = find(); 72 assert(ptr); 73 return ptr; 74} 75 76const StatData * 77DataAccess::statData() const 78{ 79 const StatData *ptr = find(); 80 assert(ptr); 81 return ptr; 82} 83 84void 85DataAccess::setInit() 86{ 87 statData()->flags |= init; 88} 89 90void 91DataAccess::setPrint() 92{ 93 Database::regPrint(this); 94} 95 96StatData::StatData() 97 : flags(none), precision(-1), prereq(0) 98{ 99 static int count = 0; 100 id = count++; 101} 102 103StatData::~StatData() 104{ 105} 106 107bool 108StatData::less(StatData *stat1, StatData *stat2) 109{ 110 const string &name1 = stat1->name; 111 const string &name2 = stat2->name; 112 113 vector<string> v1; 114 vector<string> v2; 115 116 tokenize(v1, name1, '.'); 117 tokenize(v2, name2, '.'); 118 119 int last = min(v1.size(), v2.size()) - 1; 120 for (int i = 0; i < last; ++i) 121 if (v1[i] != v2[i]) 122 return v1[i] < v2[i]; 123 124 // Special compare for last element. 125 if (v1[last] == v2[last]) 126 return v1.size() < v2.size(); 127 else 128 return v1[last] < v2[last]; 129 130 return false; 131} 132 133bool 134StatData::baseCheck() const 135{ 136 if (!(flags & init)) { 137#ifdef DEBUG 138 cprintf("this is stat number %d\n", id); 139#endif 140 panic("Not all stats have been initialized"); 141 return false; 142 } 143 144 if ((flags & print) && name.empty()) { 145 panic("all printable stats must be named"); 146 return false; 147 } 148 149 return true; 150} 151 152 153void 154FormulaBase::result(VResult &vec) const 155{ 156 if (root) 157 vec = root->result(); 158} 159 160Result 161FormulaBase::total() const 162{ 163 return root ? root->total() : 0.0; 164} 165 166size_t 167FormulaBase::size() const 168{ 169 if (!root) 170 return 0; 171 else 172 return root->size(); 173} 174 175bool 176FormulaBase::binned() const 177{ 178 return root && root->binned(); 179} 180 181void 182FormulaBase::reset() 183{ 184} 185 186bool 187FormulaBase::zero() const 188{ 189 VResult vec; 190 result(vec); 191 for (int i = 0; i < vec.size(); ++i) 192 if (vec[i] != 0.0) 193 return false; 194 return true; 195} 196 197void 198FormulaBase::update(StatData *) 199{ 200} 201 202string 203FormulaBase::str() const 204{ 205 return root ? root->str() : ""; 206} 207 208Formula::Formula() 209{ 210 setInit(); 211} 212 213Formula::Formula(Temp r) 214{ 215 root = r; 216 assert(size()); 217} 218 219const Formula & 220Formula::operator=(Temp r) 221{ 222 assert(!root && "Can't change formulas"); 223 root = r; 224 assert(size()); 225 return *this; 226} 227 228const Formula & 229Formula::operator+=(Temp r) 230{ 231 if (root) 232 root = NodePtr(new BinaryNode<std::plus<Result> >(root, r)); 233 else 234 root = r; 235 assert(size()); 236 return *this; 237} 238 239MainBin::MainBin(const string &name) 240 : _name(name), mem(NULL), memsize(-1) 241{ 242 Database::regBin(this, name); 243} 244 245MainBin::~MainBin() 246{ 247 if (mem) 248 delete [] mem; 249} 250 251char * 252MainBin::memory(off_t off) 253{ 254 if (memsize == -1) 255 memsize = ceilPow2((size_t) offset()); 256 257 if (!mem) { 258 mem = new char[memsize]; 259 memset(mem, 0, memsize); 260 } 261 262 assert(offset() <= size()); 263 return mem + off; 264} 265 266void 267check() 268{ 269 typedef Database::stat_list_t::iterator iter_t; 270 271 iter_t i, end = Database::stats().end(); 272 for (i = Database::stats().begin(); i != end; ++i) { 273 StatData *data = *i; 274 assert(data); 275 if (!data->check() || !data->baseCheck()) 276 panic("stat check failed for %s\n", data->name); 277 } 278 279 int j = 0; 280 for (i = Database::stats().begin(); i != end; ++i) { 281 StatData *data = *i; 282 if (!(data->flags & print)) 283 data->name = "__Stat" + to_string(j++); 284 } 285 286 Database::stats().sort(StatData::less); 287 288#if STATS_BINNING 289 if (MainBin::curBin() == NULL) { 290 static MainBin mainBin("main bin"); 291 mainBin.activate(); 292 } 293#endif 294 295 if (i == end) 296 return; 297 298 iter_t last = i; 299 ++i; 300 301 for (i = Database::stats().begin(); i != end; ++i) { 302 if ((*i)->name == (*last)->name) 303 panic("same name used twice! name=%s\n", (*i)->name); 304 305 last = i; 306 } 307} 308 309CallbackQueue resetQueue; 310 311void 312reset() 313{ 314 // reset non-binned stats 315 Database::stat_list_t::iterator i = Database::stats().begin(); 316 Database::stat_list_t::iterator end = Database::stats().end(); 317 while (i != end) { 318 StatData *data = *i; 319 if (!data->binned()) 320 data->reset(); 321 ++i; 322 } 323 324 // save the bin so we can go back to where we were 325 MainBin *orig = MainBin::curBin(); 326 327 // reset binned stats 328 Database::bin_list_t::iterator bi = Database::bins().begin(); 329 Database::bin_list_t::iterator be = Database::bins().end(); 330 while (bi != be) { 331 MainBin *bin = *bi; 332 bin->activate(); 333 334 i = Database::stats().begin(); 335 while (i != end) { 336 StatData *data = *i; 337 if (data->binned()) 338 data->reset(); 339 ++i; 340 } 341 ++bi; 342 } 343 344 // restore bin 345 MainBin::curBin() = orig; 346 347 resetQueue.process(); 348} 349 350void 351registerResetCallback(Callback *cb) 352{ 353 resetQueue.add(cb); 354} 355 356/* namespace Stats */ } 357