statistics.cc revision 11681:074694750c5d
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 * Authors: Nathan Binkert 29 */ 30 31#include <fstream> 32#include <iomanip> 33#include <list> 34#include <map> 35#include <string> 36 37#include "base/callback.hh" 38#include "base/cprintf.hh" 39#include "base/debug.hh" 40#include "base/hostinfo.hh" 41#include "base/misc.hh" 42#include "base/statistics.hh" 43#include "base/str.hh" 44#include "base/time.hh" 45#include "base/trace.hh" 46 47using namespace std; 48 49namespace Stats { 50 51std::string Info::separatorString = "::"; 52 53// We wrap these in a function to make sure they're built in time. 54list<Info *> & 55statsList() 56{ 57 static list<Info *> the_list; 58 return the_list; 59} 60 61MapType & 62statsMap() 63{ 64 static MapType the_map; 65 return the_map; 66} 67 68void 69InfoAccess::setInfo(Info *info) 70{ 71 if (statsMap().find(this) != statsMap().end()) 72 panic("shouldn't register stat twice!"); 73 74 statsList().push_back(info); 75 76#ifndef NDEBUG 77 pair<MapType::iterator, bool> result = 78#endif 79 statsMap().insert(make_pair(this, info)); 80 assert(result.second && "this should never fail"); 81 assert(statsMap().find(this) != statsMap().end()); 82} 83 84void 85InfoAccess::setParams(const StorageParams *params) 86{ 87 info()->storageParams = params; 88} 89 90void 91InfoAccess::setInit() 92{ 93 info()->flags.set(init); 94} 95 96Info * 97InfoAccess::info() 98{ 99 MapType::const_iterator i = statsMap().find(this); 100 assert(i != statsMap().end()); 101 return (*i).second; 102} 103 104const Info * 105InfoAccess::info() const 106{ 107 MapType::const_iterator i = statsMap().find(this); 108 assert(i != statsMap().end()); 109 return (*i).second; 110} 111 112StorageParams::~StorageParams() 113{ 114} 115 116NameMapType & 117nameMap() 118{ 119 static NameMapType the_map; 120 return the_map; 121} 122 123int Info::id_count = 0; 124 125int debug_break_id = -1; 126 127Info::Info() 128 : flags(none), precision(-1), prereq(0), storageParams(NULL) 129{ 130 id = id_count++; 131 if (debug_break_id >= 0 and debug_break_id == id) 132 Debug::breakpoint(); 133} 134 135Info::~Info() 136{ 137} 138 139bool 140validateStatName(const string &name) 141{ 142 if (name.empty()) 143 return false; 144 145 vector<string> vec; 146 tokenize(vec, name, '.'); 147 vector<string>::const_iterator item = vec.begin(); 148 while (item != vec.end()) { 149 if (item->empty()) 150 return false; 151 152 string::const_iterator c = item->begin(); 153 154 // The first character is different 155 if (!isalpha(*c) && *c != '_') 156 return false; 157 158 // The rest of the characters have different rules. 159 while (++c != item->end()) { 160 if (!isalnum(*c) && *c != '_') 161 return false; 162 } 163 164 ++item; 165 } 166 167 return true; 168} 169 170void 171Info::setName(const string &name) 172{ 173 if (!validateStatName(name)) 174 panic("invalid stat name '%s'", name); 175 176 pair<NameMapType::iterator, bool> p = 177 nameMap().insert(make_pair(name, this)); 178 179 Info *other = p.first->second; 180 bool result = p.second; 181 182 if (!result) { 183 // using other->name instead of just name to avoid a compiler 184 // warning. They should be the same. 185 panic("same statistic name used twice! name=%s\n", other->name); 186 } 187 188 this->name = name; 189} 190 191bool 192Info::less(Info *stat1, Info *stat2) 193{ 194 const string &name1 = stat1->name; 195 const string &name2 = stat2->name; 196 197 vector<string> v1; 198 vector<string> v2; 199 200 tokenize(v1, name1, '.'); 201 tokenize(v2, name2, '.'); 202 203 size_type last = min(v1.size(), v2.size()) - 1; 204 for (off_type i = 0; i < last; ++i) 205 if (v1[i] != v2[i]) 206 return v1[i] < v2[i]; 207 208 // Special compare for last element. 209 if (v1[last] == v2[last]) 210 return v1.size() < v2.size(); 211 else 212 return v1[last] < v2[last]; 213 214 return false; 215} 216 217bool 218Info::baseCheck() const 219{ 220 if (!(flags & Stats::init)) { 221#ifdef DEBUG 222 cprintf("this is stat number %d\n", id); 223#endif 224 panic("Not all stats have been initialized.\n" 225 "You may need to add <ParentClass>::regStats() to a" 226 " new SimObject's regStats() function."); 227 return false; 228 } 229 230 if ((flags & display) && name.empty()) { 231 panic("all printable stats must be named"); 232 return false; 233 } 234 235 return true; 236} 237 238void 239Info::enable() 240{ 241} 242 243void 244VectorInfo::enable() 245{ 246 size_type s = size(); 247 if (subnames.size() < s) 248 subnames.resize(s); 249 if (subdescs.size() < s) 250 subdescs.resize(s); 251} 252 253void 254VectorDistInfo::enable() 255{ 256 size_type s = size(); 257 if (subnames.size() < s) 258 subnames.resize(s); 259 if (subdescs.size() < s) 260 subdescs.resize(s); 261} 262 263void 264Vector2dInfo::enable() 265{ 266 if (subnames.size() < x) 267 subnames.resize(x); 268 if (subdescs.size() < x) 269 subdescs.resize(x); 270 if (y_subnames.size() < y) 271 y_subnames.resize(y); 272} 273 274void 275HistStor::grow_out() 276{ 277 int size = cvec.size(); 278 int zero = size / 2; // round down! 279 int top_half = zero + (size - zero + 1) / 2; // round up! 280 int bottom_half = (size - zero) / 2; // round down! 281 282 // grow down 283 int low_pair = zero - 1; 284 for (int i = zero - 1; i >= bottom_half; i--) { 285 cvec[i] = cvec[low_pair]; 286 if (low_pair - 1 >= 0) 287 cvec[i] += cvec[low_pair - 1]; 288 low_pair -= 2; 289 } 290 assert(low_pair == 0 || low_pair == -1 || low_pair == -2); 291 292 for (int i = bottom_half - 1; i >= 0; i--) 293 cvec[i] = Counter(); 294 295 // grow up 296 int high_pair = zero; 297 for (int i = zero; i < top_half; i++) { 298 cvec[i] = cvec[high_pair]; 299 if (high_pair + 1 < size) 300 cvec[i] += cvec[high_pair + 1]; 301 high_pair += 2; 302 } 303 assert(high_pair == size || high_pair == size + 1); 304 305 for (int i = top_half; i < size; i++) 306 cvec[i] = Counter(); 307 308 max_bucket *= 2; 309 min_bucket *= 2; 310 bucket_size *= 2; 311} 312 313void 314HistStor::grow_convert() 315{ 316 int size = cvec.size(); 317 int half = (size + 1) / 2; // round up! 318 //bool even = (size & 1) == 0; 319 320 int pair = size - 1; 321 for (int i = size - 1; i >= half; --i) { 322 cvec[i] = cvec[pair]; 323 if (pair - 1 >= 0) 324 cvec[i] += cvec[pair - 1]; 325 pair -= 2; 326 } 327 328 for (int i = half - 1; i >= 0; i--) 329 cvec[i] = Counter(); 330 331 min_bucket = -max_bucket;// - (even ? bucket_size : 0); 332 bucket_size *= 2; 333} 334 335void 336HistStor::grow_up() 337{ 338 int size = cvec.size(); 339 int half = (size + 1) / 2; // round up! 340 341 int pair = 0; 342 for (int i = 0; i < half; i++) { 343 cvec[i] = cvec[pair]; 344 if (pair + 1 < size) 345 cvec[i] += cvec[pair + 1]; 346 pair += 2; 347 } 348 assert(pair == size || pair == size + 1); 349 350 for (int i = half; i < size; i++) 351 cvec[i] = Counter(); 352 353 max_bucket *= 2; 354 bucket_size *= 2; 355} 356 357void 358HistStor::add(HistStor *hs) 359{ 360 int b_size = hs->size(); 361 assert(size() == b_size); 362 assert(min_bucket == hs->min_bucket); 363 364 sum += hs->sum; 365 logs += hs->logs; 366 squares += hs->squares; 367 samples += hs->samples; 368 369 while (bucket_size > hs->bucket_size) 370 hs->grow_up(); 371 while (bucket_size < hs->bucket_size) 372 grow_up(); 373 374 for (uint32_t i = 0; i < b_size; i++) 375 cvec[i] += hs->cvec[i]; 376} 377 378Formula::Formula() 379{ 380} 381 382Formula::Formula(Temp r) 383{ 384 root = r.getNodePtr(); 385 setInit(); 386 assert(size()); 387} 388 389const Formula & 390Formula::operator=(Temp r) 391{ 392 assert(!root && "Can't change formulas"); 393 root = r.getNodePtr(); 394 setInit(); 395 assert(size()); 396 return *this; 397} 398 399const Formula & 400Formula::operator+=(Temp r) 401{ 402 if (root) 403 root = NodePtr(new BinaryNode<std::plus<Result> >(root, r)); 404 else { 405 root = r.getNodePtr(); 406 setInit(); 407 } 408 409 assert(size()); 410 return *this; 411} 412 413const Formula & 414Formula::operator/=(Temp r) 415{ 416 assert (root); 417 root = NodePtr(new BinaryNode<std::divides<Result> >(root, r)); 418 419 assert(size()); 420 return *this; 421} 422 423void 424Formula::result(VResult &vec) const 425{ 426 if (root) 427 vec = root->result(); 428} 429 430Result 431Formula::total() const 432{ 433 return root ? root->total() : 0.0; 434} 435 436size_type 437Formula::size() const 438{ 439 if (!root) 440 return 0; 441 else 442 return root->size(); 443} 444 445void 446Formula::reset() 447{ 448} 449 450bool 451Formula::zero() const 452{ 453 VResult vec; 454 result(vec); 455 for (VResult::size_type i = 0; i < vec.size(); ++i) 456 if (vec[i] != 0.0) 457 return false; 458 return true; 459} 460 461string 462Formula::str() const 463{ 464 return root ? root->str() : ""; 465} 466 467Handler resetHandler = NULL; 468Handler dumpHandler = NULL; 469 470void 471registerHandlers(Handler reset_handler, Handler dump_handler) 472{ 473 resetHandler = reset_handler; 474 dumpHandler = dump_handler; 475} 476 477CallbackQueue dumpQueue; 478CallbackQueue resetQueue; 479 480void 481processResetQueue() 482{ 483 resetQueue.process(); 484} 485 486void 487processDumpQueue() 488{ 489 dumpQueue.process(); 490} 491 492void 493registerResetCallback(Callback *cb) 494{ 495 resetQueue.add(cb); 496} 497 498bool _enabled = false; 499 500bool 501enabled() 502{ 503 return _enabled; 504} 505 506void 507enable() 508{ 509 if (_enabled) 510 fatal("Stats are already enabled"); 511 512 _enabled = true; 513} 514 515void 516dump() 517{ 518 if (dumpHandler) 519 dumpHandler(); 520 else 521 fatal("No registered Stats::dump handler"); 522} 523 524void 525reset() 526{ 527 if (resetHandler) 528 resetHandler(); 529 else 530 fatal("No registered Stats::reset handler"); 531} 532 533void 534registerDumpCallback(Callback *cb) 535{ 536 dumpQueue.add(cb); 537} 538 539} // namespace Stats 540 541void 542debugDumpStats() 543{ 544 Stats::dump(); 545} 546