statistics.cc revision 14205:197360deaa20
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 if (!validateStatName(name)) 207 panic("invalid stat name '%s'", name); 208 209 pair<NameMapType::iterator, bool> p = 210 nameMap().insert(make_pair(name, this)); 211 212 Info *other = p.first->second; 213 bool result = p.second; 214 215 if (!result) { 216 // using other->name instead of just name to avoid a compiler 217 // warning. They should be the same. 218 panic("same statistic name used twice! name=%s\n", other->name); 219 } 220 221 this->name = name; 222} 223 224bool 225Info::less(Info *stat1, Info *stat2) 226{ 227 const string &name1 = stat1->name; 228 const string &name2 = stat2->name; 229 230 vector<string> v1; 231 vector<string> v2; 232 233 tokenize(v1, name1, '.'); 234 tokenize(v2, name2, '.'); 235 236 size_type last = min(v1.size(), v2.size()) - 1; 237 for (off_type i = 0; i < last; ++i) 238 if (v1[i] != v2[i]) 239 return v1[i] < v2[i]; 240 241 // Special compare for last element. 242 if (v1[last] == v2[last]) 243 return v1.size() < v2.size(); 244 else 245 return v1[last] < v2[last]; 246 247 return false; 248} 249 250bool 251Info::baseCheck() const 252{ 253 if (!(flags & Stats::init)) { 254#ifdef DEBUG 255 cprintf("this is stat number %d\n", id); 256#endif 257 panic("Not all stats have been initialized.\n" 258 "You may need to add <ParentClass>::regStats() to a" 259 " new SimObject's regStats() function. Name: %s", 260 name); 261 return false; 262 } 263 264 if ((flags & display) && name.empty()) { 265 panic("all printable stats must be named"); 266 return false; 267 } 268 269 return true; 270} 271 272void 273Info::enable() 274{ 275} 276 277void 278VectorInfo::enable() 279{ 280 size_type s = size(); 281 if (subnames.size() < s) 282 subnames.resize(s); 283 if (subdescs.size() < s) 284 subdescs.resize(s); 285} 286 287void 288VectorDistInfo::enable() 289{ 290 size_type s = size(); 291 if (subnames.size() < s) 292 subnames.resize(s); 293 if (subdescs.size() < s) 294 subdescs.resize(s); 295} 296 297void 298Vector2dInfo::enable() 299{ 300 if (subnames.size() < x) 301 subnames.resize(x); 302 if (subdescs.size() < x) 303 subdescs.resize(x); 304 if (y_subnames.size() < y) 305 y_subnames.resize(y); 306} 307 308void 309HistStor::grow_out() 310{ 311 int size = cvec.size(); 312 int zero = size / 2; // round down! 313 int top_half = zero + (size - zero + 1) / 2; // round up! 314 int bottom_half = (size - zero) / 2; // round down! 315 316 // grow down 317 int low_pair = zero - 1; 318 for (int i = zero - 1; i >= bottom_half; i--) { 319 cvec[i] = cvec[low_pair]; 320 if (low_pair - 1 >= 0) 321 cvec[i] += cvec[low_pair - 1]; 322 low_pair -= 2; 323 } 324 assert(low_pair == 0 || low_pair == -1 || low_pair == -2); 325 326 for (int i = bottom_half - 1; i >= 0; i--) 327 cvec[i] = Counter(); 328 329 // grow up 330 int high_pair = zero; 331 for (int i = zero; i < top_half; i++) { 332 cvec[i] = cvec[high_pair]; 333 if (high_pair + 1 < size) 334 cvec[i] += cvec[high_pair + 1]; 335 high_pair += 2; 336 } 337 assert(high_pair == size || high_pair == size + 1); 338 339 for (int i = top_half; i < size; i++) 340 cvec[i] = Counter(); 341 342 max_bucket *= 2; 343 min_bucket *= 2; 344 bucket_size *= 2; 345} 346 347void 348HistStor::grow_convert() 349{ 350 int size = cvec.size(); 351 int half = (size + 1) / 2; // round up! 352 //bool even = (size & 1) == 0; 353 354 int pair = size - 1; 355 for (int i = size - 1; i >= half; --i) { 356 cvec[i] = cvec[pair]; 357 if (pair - 1 >= 0) 358 cvec[i] += cvec[pair - 1]; 359 pair -= 2; 360 } 361 362 for (int i = half - 1; i >= 0; i--) 363 cvec[i] = Counter(); 364 365 min_bucket = -max_bucket;// - (even ? bucket_size : 0); 366 bucket_size *= 2; 367} 368 369void 370HistStor::grow_up() 371{ 372 int size = cvec.size(); 373 int half = (size + 1) / 2; // round up! 374 375 int pair = 0; 376 for (int i = 0; i < half; i++) { 377 cvec[i] = cvec[pair]; 378 if (pair + 1 < size) 379 cvec[i] += cvec[pair + 1]; 380 pair += 2; 381 } 382 assert(pair == size || pair == size + 1); 383 384 for (int i = half; i < size; i++) 385 cvec[i] = Counter(); 386 387 max_bucket *= 2; 388 bucket_size *= 2; 389} 390 391void 392HistStor::add(HistStor *hs) 393{ 394 int b_size = hs->size(); 395 assert(size() == b_size); 396 assert(min_bucket == hs->min_bucket); 397 398 sum += hs->sum; 399 logs += hs->logs; 400 squares += hs->squares; 401 samples += hs->samples; 402 403 while (bucket_size > hs->bucket_size) 404 hs->grow_up(); 405 while (bucket_size < hs->bucket_size) 406 grow_up(); 407 408 for (uint32_t i = 0; i < b_size; i++) 409 cvec[i] += hs->cvec[i]; 410} 411 412Formula::Formula(Group *parent, const char *name, const char *desc) 413 : DataWrapVec<Formula, FormulaInfoProxy>(parent, name, desc) 414 415{ 416} 417 418 419 420Formula::Formula(Group *parent, const char *name, const char *desc, 421 const Temp &r) 422 : DataWrapVec<Formula, FormulaInfoProxy>(parent, name, desc) 423{ 424 *this = r; 425} 426 427const Formula & 428Formula::operator=(const Temp &r) 429{ 430 assert(!root && "Can't change formulas"); 431 root = r.getNodePtr(); 432 setInit(); 433 assert(size()); 434 return *this; 435} 436 437const Formula & 438Formula::operator+=(Temp r) 439{ 440 if (root) 441 root = NodePtr(new BinaryNode<std::plus<Result> >(root, r)); 442 else { 443 root = r.getNodePtr(); 444 setInit(); 445 } 446 447 assert(size()); 448 return *this; 449} 450 451const Formula & 452Formula::operator/=(Temp r) 453{ 454 assert (root); 455 root = NodePtr(new BinaryNode<std::divides<Result> >(root, r)); 456 457 assert(size()); 458 return *this; 459} 460 461 462void 463Formula::result(VResult &vec) const 464{ 465 if (root) 466 vec = root->result(); 467} 468 469Result 470Formula::total() const 471{ 472 return root ? root->total() : 0.0; 473} 474 475size_type 476Formula::size() const 477{ 478 if (!root) 479 return 0; 480 else 481 return root->size(); 482} 483 484void 485Formula::reset() 486{ 487} 488 489bool 490Formula::zero() const 491{ 492 VResult vec; 493 result(vec); 494 for (VResult::size_type i = 0; i < vec.size(); ++i) 495 if (vec[i] != 0.0) 496 return false; 497 return true; 498} 499 500string 501Formula::str() const 502{ 503 return root ? root->str() : ""; 504} 505 506Handler resetHandler = NULL; 507Handler dumpHandler = NULL; 508 509void 510registerHandlers(Handler reset_handler, Handler dump_handler) 511{ 512 resetHandler = reset_handler; 513 dumpHandler = dump_handler; 514} 515 516CallbackQueue dumpQueue; 517CallbackQueue resetQueue; 518 519void 520processResetQueue() 521{ 522 resetQueue.process(); 523} 524 525void 526processDumpQueue() 527{ 528 dumpQueue.process(); 529} 530 531void 532registerResetCallback(Callback *cb) 533{ 534 resetQueue.add(cb); 535} 536 537bool _enabled = false; 538 539bool 540enabled() 541{ 542 return _enabled; 543} 544 545void 546enable() 547{ 548 if (_enabled) 549 fatal("Stats are already enabled"); 550 551 _enabled = true; 552} 553 554void 555dump() 556{ 557 if (dumpHandler) 558 dumpHandler(); 559 else 560 fatal("No registered Stats::dump handler"); 561} 562 563void 564reset() 565{ 566 if (resetHandler) 567 resetHandler(); 568 else 569 fatal("No registered Stats::reset handler"); 570} 571 572void 573registerDumpCallback(Callback *cb) 574{ 575 dumpQueue.add(cb); 576} 577 578} // namespace Stats 579 580void 581debugDumpStats() 582{ 583 Stats::dump(); 584} 585