statistics.cc revision 14266
1/* 2 * Copyright (c) 2019 Arm Limited 3 * All rights reserved. 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2003-2005 The Regents of The University of Michigan 15 * All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions are 19 * met: redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer; 21 * redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution; 24 * neither the name of the copyright holders nor the names of its 25 * contributors may be used to endorse or promote products derived from 26 * this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Nathan Binkert 41 */ 42 43#include "base/statistics.hh" 44 45#include <fstream> 46#include <iomanip> 47#include <list> 48#include <map> 49#include <string> 50 51#include "base/callback.hh" 52#include "base/cprintf.hh" 53#include "base/debug.hh" 54#include "base/hostinfo.hh" 55#include "base/logging.hh" 56#include "base/str.hh" 57#include "base/time.hh" 58#include "base/trace.hh" 59 60using namespace std; 61 62namespace Stats { 63 64std::string Info::separatorString = "::"; 65 66// We wrap these in a function to make sure they're built in time. 67list<Info *> & 68statsList() 69{ 70 static list<Info *> the_list; 71 return the_list; 72} 73 74MapType & 75statsMap() 76{ 77 static MapType the_map; 78 return the_map; 79} 80 81void 82InfoAccess::setInfo(Group *parent, Info *info) 83{ 84 panic_if(statsMap().find(this) != statsMap().end() || 85 _info != nullptr, 86 "shouldn't register stat twice!"); 87 88 // New-style stats are reachable through the hierarchy and 89 // shouldn't be added to the global lists. 90 if (parent) { 91 _info = info; 92 return; 93 } 94 95 statsList().push_back(info); 96 97#ifndef NDEBUG 98 pair<MapType::iterator, bool> result = 99#endif 100 statsMap().insert(make_pair(this, info)); 101 assert(result.second && "this should never fail"); 102 assert(statsMap().find(this) != statsMap().end()); 103} 104 105void 106InfoAccess::setParams(const StorageParams *params) 107{ 108 info()->storageParams = params; 109} 110 111void 112InfoAccess::setInit() 113{ 114 info()->flags.set(init); 115} 116 117Info * 118InfoAccess::info() 119{ 120 if (_info) { 121 // New-style stats 122 return _info; 123 } else { 124 // Legacy stats 125 MapType::const_iterator i = statsMap().find(this); 126 assert(i != statsMap().end()); 127 return (*i).second; 128 } 129} 130 131const Info * 132InfoAccess::info() const 133{ 134 if (_info) { 135 // New-style stats 136 return _info; 137 } else { 138 // Legacy stats 139 MapType::const_iterator i = statsMap().find(this); 140 assert(i != statsMap().end()); 141 return (*i).second; 142 } 143} 144 145StorageParams::~StorageParams() 146{ 147} 148 149NameMapType & 150nameMap() 151{ 152 static NameMapType the_map; 153 return the_map; 154} 155 156int Info::id_count = 0; 157 158int debug_break_id = -1; 159 160Info::Info() 161 : flags(none), precision(-1), prereq(0), storageParams(NULL) 162{ 163 id = id_count++; 164 if (debug_break_id >= 0 and debug_break_id == id) 165 Debug::breakpoint(); 166} 167 168Info::~Info() 169{ 170} 171 172bool 173validateStatName(const string &name) 174{ 175 if (name.empty()) 176 return false; 177 178 vector<string> vec; 179 tokenize(vec, name, '.'); 180 vector<string>::const_iterator item = vec.begin(); 181 while (item != vec.end()) { 182 if (item->empty()) 183 return false; 184 185 string::const_iterator c = item->begin(); 186 187 // The first character is different 188 if (!isalpha(*c) && *c != '_') 189 return false; 190 191 // The rest of the characters have different rules. 192 while (++c != item->end()) { 193 if (!isalnum(*c) && *c != '_') 194 return false; 195 } 196 197 ++item; 198 } 199 200 return true; 201} 202 203void 204Info::setName(const string &name) 205{ 206 setName(nullptr, name); 207} 208 209void 210Info::setName(const Group *parent, const string &name) 211{ 212 if (!validateStatName(name)) 213 panic("invalid stat name '%s'", name); 214 215 // We only register the stat with the nameMap() if we are using 216 // old-style stats without a parent group. New-style stats should 217 // be unique since their names should correspond to a member 218 // variable. 219 if (!parent) { 220 auto p = nameMap().insert(make_pair(name, this)); 221 222 if (!p.second) 223 panic("same statistic name used twice! name=%s\n", 224 name); 225 } 226 227 this->name = name; 228} 229 230bool 231Info::less(Info *stat1, Info *stat2) 232{ 233 const string &name1 = stat1->name; 234 const string &name2 = stat2->name; 235 236 vector<string> v1; 237 vector<string> v2; 238 239 tokenize(v1, name1, '.'); 240 tokenize(v2, name2, '.'); 241 242 size_type last = min(v1.size(), v2.size()) - 1; 243 for (off_type i = 0; i < last; ++i) 244 if (v1[i] != v2[i]) 245 return v1[i] < v2[i]; 246 247 // Special compare for last element. 248 if (v1[last] == v2[last]) 249 return v1.size() < v2.size(); 250 else 251 return v1[last] < v2[last]; 252 253 return false; 254} 255 256bool 257Info::baseCheck() const 258{ 259 if (!(flags & Stats::init)) { 260#ifdef DEBUG 261 cprintf("this is stat number %d\n", id); 262#endif 263 panic("Not all stats have been initialized.\n" 264 "You may need to add <ParentClass>::regStats() to a" 265 " new SimObject's regStats() function. Name: %s", 266 name); 267 return false; 268 } 269 270 if ((flags & display) && name.empty()) { 271 panic("all printable stats must be named"); 272 return false; 273 } 274 275 return true; 276} 277 278void 279Info::enable() 280{ 281} 282 283void 284VectorInfo::enable() 285{ 286 size_type s = size(); 287 if (subnames.size() < s) 288 subnames.resize(s); 289 if (subdescs.size() < s) 290 subdescs.resize(s); 291} 292 293void 294VectorDistInfo::enable() 295{ 296 size_type s = size(); 297 if (subnames.size() < s) 298 subnames.resize(s); 299 if (subdescs.size() < s) 300 subdescs.resize(s); 301} 302 303void 304Vector2dInfo::enable() 305{ 306 if (subnames.size() < x) 307 subnames.resize(x); 308 if (subdescs.size() < x) 309 subdescs.resize(x); 310 if (y_subnames.size() < y) 311 y_subnames.resize(y); 312} 313 314void 315HistStor::grow_out() 316{ 317 int size = cvec.size(); 318 int zero = size / 2; // round down! 319 int top_half = zero + (size - zero + 1) / 2; // round up! 320 int bottom_half = (size - zero) / 2; // round down! 321 322 // grow down 323 int low_pair = zero - 1; 324 for (int i = zero - 1; i >= bottom_half; i--) { 325 cvec[i] = cvec[low_pair]; 326 if (low_pair - 1 >= 0) 327 cvec[i] += cvec[low_pair - 1]; 328 low_pair -= 2; 329 } 330 assert(low_pair == 0 || low_pair == -1 || low_pair == -2); 331 332 for (int i = bottom_half - 1; i >= 0; i--) 333 cvec[i] = Counter(); 334 335 // grow up 336 int high_pair = zero; 337 for (int i = zero; i < top_half; i++) { 338 cvec[i] = cvec[high_pair]; 339 if (high_pair + 1 < size) 340 cvec[i] += cvec[high_pair + 1]; 341 high_pair += 2; 342 } 343 assert(high_pair == size || high_pair == size + 1); 344 345 for (int i = top_half; i < size; i++) 346 cvec[i] = Counter(); 347 348 max_bucket *= 2; 349 min_bucket *= 2; 350 bucket_size *= 2; 351} 352 353void 354HistStor::grow_convert() 355{ 356 int size = cvec.size(); 357 int half = (size + 1) / 2; // round up! 358 //bool even = (size & 1) == 0; 359 360 int pair = size - 1; 361 for (int i = size - 1; i >= half; --i) { 362 cvec[i] = cvec[pair]; 363 if (pair - 1 >= 0) 364 cvec[i] += cvec[pair - 1]; 365 pair -= 2; 366 } 367 368 for (int i = half - 1; i >= 0; i--) 369 cvec[i] = Counter(); 370 371 min_bucket = -max_bucket;// - (even ? bucket_size : 0); 372 bucket_size *= 2; 373} 374 375void 376HistStor::grow_up() 377{ 378 int size = cvec.size(); 379 int half = (size + 1) / 2; // round up! 380 381 int pair = 0; 382 for (int i = 0; i < half; i++) { 383 cvec[i] = cvec[pair]; 384 if (pair + 1 < size) 385 cvec[i] += cvec[pair + 1]; 386 pair += 2; 387 } 388 assert(pair == size || pair == size + 1); 389 390 for (int i = half; i < size; i++) 391 cvec[i] = Counter(); 392 393 max_bucket *= 2; 394 bucket_size *= 2; 395} 396 397void 398HistStor::add(HistStor *hs) 399{ 400 int b_size = hs->size(); 401 assert(size() == b_size); 402 assert(min_bucket == hs->min_bucket); 403 404 sum += hs->sum; 405 logs += hs->logs; 406 squares += hs->squares; 407 samples += hs->samples; 408 409 while (bucket_size > hs->bucket_size) 410 hs->grow_up(); 411 while (bucket_size < hs->bucket_size) 412 grow_up(); 413 414 for (uint32_t i = 0; i < b_size; i++) 415 cvec[i] += hs->cvec[i]; 416} 417 418Formula::Formula(Group *parent, const char *name, const char *desc) 419 : DataWrapVec<Formula, FormulaInfoProxy>(parent, name, desc) 420 421{ 422} 423 424 425 426Formula::Formula(Group *parent, const char *name, const char *desc, 427 const Temp &r) 428 : DataWrapVec<Formula, FormulaInfoProxy>(parent, name, desc) 429{ 430 *this = r; 431} 432 433const Formula & 434Formula::operator=(const Temp &r) 435{ 436 assert(!root && "Can't change formulas"); 437 root = r.getNodePtr(); 438 setInit(); 439 assert(size()); 440 return *this; 441} 442 443const Formula & 444Formula::operator+=(Temp r) 445{ 446 if (root) 447 root = NodePtr(new BinaryNode<std::plus<Result> >(root, r)); 448 else { 449 root = r.getNodePtr(); 450 setInit(); 451 } 452 453 assert(size()); 454 return *this; 455} 456 457const Formula & 458Formula::operator/=(Temp r) 459{ 460 assert (root); 461 root = NodePtr(new BinaryNode<std::divides<Result> >(root, r)); 462 463 assert(size()); 464 return *this; 465} 466 467 468void 469Formula::result(VResult &vec) const 470{ 471 if (root) 472 vec = root->result(); 473} 474 475Result 476Formula::total() const 477{ 478 return root ? root->total() : 0.0; 479} 480 481size_type 482Formula::size() const 483{ 484 if (!root) 485 return 0; 486 else 487 return root->size(); 488} 489 490void 491Formula::reset() 492{ 493} 494 495bool 496Formula::zero() const 497{ 498 VResult vec; 499 result(vec); 500 for (VResult::size_type i = 0; i < vec.size(); ++i) 501 if (vec[i] != 0.0) 502 return false; 503 return true; 504} 505 506string 507Formula::str() const 508{ 509 return root ? root->str() : ""; 510} 511 512Handler resetHandler = NULL; 513Handler dumpHandler = NULL; 514 515void 516registerHandlers(Handler reset_handler, Handler dump_handler) 517{ 518 resetHandler = reset_handler; 519 dumpHandler = dump_handler; 520} 521 522CallbackQueue dumpQueue; 523CallbackQueue resetQueue; 524 525void 526processResetQueue() 527{ 528 resetQueue.process(); 529} 530 531void 532processDumpQueue() 533{ 534 dumpQueue.process(); 535} 536 537void 538registerResetCallback(Callback *cb) 539{ 540 resetQueue.add(cb); 541} 542 543bool _enabled = false; 544 545bool 546enabled() 547{ 548 return _enabled; 549} 550 551void 552enable() 553{ 554 if (_enabled) 555 fatal("Stats are already enabled"); 556 557 _enabled = true; 558} 559 560void 561dump() 562{ 563 if (dumpHandler) 564 dumpHandler(); 565 else 566 fatal("No registered Stats::dump handler"); 567} 568 569void 570reset() 571{ 572 if (resetHandler) 573 resetHandler(); 574 else 575 fatal("No registered Stats::reset handler"); 576} 577 578void 579registerDumpCallback(Callback *cb) 580{ 581 dumpQueue.add(cb); 582} 583 584} // namespace Stats 585 586void 587debugDumpStats() 588{ 589 Stats::dump(); 590} 591