statistics.cc revision 148
1/* 2 * Copyright (c) 2003 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 <iostream> 31#include <list> 32#include <map> 33#include <string> 34#include <sstream> 35 36#include <math.h> 37 38#include "base/callback.hh" 39#include "base/cprintf.hh" 40#include "base/intmath.hh" 41#include "base/misc.hh" 42#include "base/statistics.hh" 43#include "base/str.hh" 44#include "sim/universe.hh" 45 46#ifdef __M5_NAN 47float 48__nan() 49{ 50 union { 51 uint32_t ui; 52 float f; 53 } nan; 54 55 nan.ui = 0x7fc00000; 56 return nan.f; 57} 58#endif 59 60#ifdef STAT_DEBUG 61static int total_stats = 0; 62#endif 63 64using namespace std; 65 66// This is a hack to get this parameter from the old stats package. 67namespace Statistics { 68bool PrintDescriptions = true; 69 70namespace Detail { 71/** 72 * Struct to contain a name and description of statistic subfield. 73 */ 74struct SubData 75{ 76 /** Subfield name. */ 77 string name; 78 /** Subfield desc. */ 79 string desc; 80}; 81 82/** 83 * Struct to contain print data of a Stat. 84 */ 85struct StatData 86{ 87 /** 88 * Create this struct. 89 */ 90 StatData(); 91 /** 92 * Destructor. 93 */ 94 ~StatData(); 95 96 /** True if the stat has been initialized. */ 97 bool init; 98 /** True if the stat should be printed. */ 99 bool print; 100 /** The name of the stat. */ 101 string name; 102 /** Names and descriptions of subfields. */ 103 vector<SubData> *subdata; 104 /** The description of the stat. */ 105 string desc; 106 /** The display precision. */ 107 int precision; 108 /** The formatting flags. */ 109 FormatFlags flags; 110 /** A pointer to a prerequisite Stat. */ 111 const Stat *prereq; 112}; 113 114StatData::StatData() 115 : init(false), print(false), subdata(NULL), precision(-1), flags(none), 116 prereq(NULL) 117{ 118} 119 120StatData::~StatData() 121{ 122 if (subdata) 123 delete subdata; 124} 125 126class Database 127{ 128 private: 129 Database(const Database &) {} 130 131 private: 132 typedef list<Stat *> list_t; 133 typedef map<const Stat *, StatData *> map_t; 134 135 list_t allStats; 136 list_t printStats; 137 map_t map; 138 139 public: 140 Database(); 141 ~Database(); 142 143 void dump(ostream &stream); 144 145 StatData *find(const Stat *stat); 146 void check(); 147 void reset(); 148 void regStat(Stat *stat); 149 StatData *print(Stat *stat); 150}; 151 152Database::Database() 153{} 154 155Database::~Database() 156{} 157 158void 159Database::dump(ostream &stream) 160{ 161 list_t::iterator i = printStats.begin(); 162 list_t::iterator end = printStats.end(); 163 164 while (i != end) { 165 Stat *stat = *i; 166 if (stat->dodisplay()) 167 stat->display(stream); 168 ++i; 169 } 170} 171 172StatData * 173Database::find(const Stat *stat) 174{ 175 map_t::const_iterator i = map.find(stat); 176 177 if (i == map.end()) 178 return NULL; 179 180 return (*i).second; 181} 182 183void 184Database::check() 185{ 186 list_t::iterator i = allStats.begin(); 187 list_t::iterator end = allStats.end(); 188 189 while (i != end) { 190 Stat *stat = *i; 191 StatData *data = find(stat); 192 if (!data || !data->init) { 193#ifdef STAT_DEBUG 194 cprintf("this is stat number %d\n",(*i)->number); 195#endif 196 panic("Not all stats have been initialized"); 197 } 198 199 if (data->print) { 200 if (data->name.empty()) 201 panic("all printable stats must be named"); 202 203 list_t::iterator j = printStats.insert(printStats.end(), *i); 204 inplace_merge(printStats.begin(), j, 205 printStats.end(), Stat::less); 206 } 207 208 ++i; 209 } 210} 211 212void 213Database::reset() 214{ 215 list_t::iterator i = allStats.begin(); 216 list_t::iterator end = allStats.end(); 217 218 while (i != end) { 219 (*i)->reset(); 220 ++i; 221 } 222} 223 224void 225Database::regStat(Stat *stat) 226{ 227 if (map.find(stat) != map.end()) 228 panic("shouldn't register stat twice!"); 229 230 allStats.push_back(stat); 231 232 StatData *data = new StatData; 233 bool success = (map.insert(make_pair(stat, data))).second; 234 assert(map.find(stat) != map.end()); 235 assert(success && "this should never fail"); 236} 237 238bool 239Stat::less(Stat *stat1, Stat *stat2) 240{ 241 const string &name1 = stat1->myname(); 242 const string &name2 = stat2->myname(); 243 244 vector<string> v1; 245 vector<string> v2; 246 247 tokenize(v1, name1, '.'); 248 tokenize(v2, name2, '.'); 249 250 int last = min(v1.size(), v2.size()) - 1; 251 for (int i = 0; i < last; ++i) 252 if (v1[i] != v2[i]) 253 return v1[i] < v2[i]; 254 255 // Special compare for last element. 256 if (v1[last] == v2[last]) 257 return v1.size() < v2.size(); 258 else 259 return v1[last] < v2[last]; 260 261 return false; 262} 263 264StatData * 265Database::print(Stat *stat) 266{ 267 StatData *data = find(stat); 268 assert(data); 269 270 data->print = true; 271 272 return data; 273} 274 275Database & 276StatDB() 277{ 278 static Database db; 279 return db; 280} 281 282Stat::Stat(bool reg) 283{ 284#if 0 285 // This assert can help you find that pesky stat. 286 assert(this != (void *)0xbffff5c0); 287#endif 288 289 if (reg) 290 StatDB().regStat(this); 291#ifdef STAT_DEBUG 292 number = ++total_stats; 293 cprintf("I'm stat number %d\n",number); 294#endif 295} 296 297void 298Stat::setInit() 299{ mydata()->init = true; } 300 301StatData * 302Stat::mydata() 303{ 304 StatData *data = StatDB().find(this); 305 assert(data); 306 307 return data; 308} 309 310const StatData * 311Stat::mydata() const 312{ 313 StatData *data = StatDB().find(this); 314 assert(data); 315 316 return data; 317} 318 319const SubData * 320Stat::mysubdata(int index) const 321{ 322 assert(index >= 0); 323 if (index >= size()) 324 return NULL; 325 326 const StatData *data = this->mydata(); 327 if (!data->subdata || data->subdata->size() <= index) 328 return NULL; 329 330 return &(*data->subdata)[index]; 331} 332 333SubData * 334Stat::mysubdata_create(int index) 335{ 336 int size = this->size(); 337 assert(index >= 0 && (size == 0 || size > 0 && index < size)); 338 339 StatData *data = this->mydata(); 340 if (!data->subdata) { 341 if (!data->subdata) { 342 if (size == 0) 343 size = index + 1; 344 345 data->subdata = new vector<SubData>(size); 346 } 347 } else if (data->subdata->size() <= index) 348 data->subdata->resize(index + 1); 349 350 SubData *sd = &(*data->subdata)[index]; 351 assert(sd); 352 353 return sd; 354} 355 356string 357Stat::myname() const 358{ return mydata()->name; } 359 360string 361Stat::mysubname(int index) const 362{ 363 const SubData *sd = mysubdata(index); 364 return sd ? sd->name : ""; 365} 366 367string 368Stat::mydesc() const 369{ return mydata()->desc; } 370 371string 372Stat::mysubdesc(int index) const 373{ 374 const SubData *sd = mysubdata(index); 375 return sd ? sd->desc : ""; 376} 377 378int 379Stat::myprecision() const 380{ return mydata()->precision; } 381 382FormatFlags 383Stat::myflags() const 384{ return mydata()->flags; } 385 386bool 387Stat::dodisplay() const 388{ return !mydata()->prereq || !mydata()->prereq->zero(); } 389 390StatData * 391Stat::print() 392{ 393 StatData *data = StatDB().print(this); 394 assert(data && data->init); 395 396 return data; 397} 398 399Stat & 400Stat::name(const string &name) 401{ 402 print()->name = name; 403 return *this; 404} 405 406Stat & 407Stat::desc(const string &desc) 408{ 409 print()->desc = desc; 410 return *this; 411} 412 413Stat & 414Stat::precision(int precision) 415{ 416 print()->precision = precision; 417 return *this; 418} 419 420Stat & 421Stat::flags(FormatFlags flags) 422{ 423 if (flags & __reserved) 424 panic("Cannot set reserved flags!\n"); 425 426 print()->flags |= flags; 427 return *this; 428} 429 430Stat & 431Stat::prereq(const Stat &prereq) 432{ 433 print()->prereq = &prereq; 434 return *this; 435} 436 437Stat & 438Stat::subname(int index, const string &name) 439{ 440 print(); 441 mysubdata_create(index)->name = name; 442 return *this; 443} 444Stat & 445Stat::subdesc(int index, const string &desc) 446{ 447 print(); 448 mysubdata_create(index)->desc = desc; 449 return *this; 450} 451 452bool 453ScalarStat::zero() const 454{ 455 return val() == 0.0; 456} 457 458bool 459VectorStat::zero() const 460{ 461 return val()[0] == 0.0; 462} 463 464string 465ValueToString(result_t value, int precision) 466{ 467 stringstream val; 468 469 if (!isnan(value)) { 470 if (precision != -1) 471 val.precision(precision); 472 else if (value == rint(value)) 473 val.precision(0); 474 475 val.unsetf(ios::showpoint); 476 val.setf(ios::fixed); 477 val << value; 478 } else { 479#ifndef STAT_DISPLAY_COMPAT 480 val << "no value"; 481#else 482 val << "<err: div-0>"; 483#endif 484 } 485 486 return val.str(); 487} 488 489void 490PrintOne(ostream &stream, result_t value, 491 const string &name, const string &desc, int precision, 492 FormatFlags flags, result_t pdf = NAN, result_t cdf = NAN) 493{ 494 if (flags & nozero && value == 0.0 || 495 flags & nonan && isnan(value)) 496 return; 497 498 stringstream pdfstr, cdfstr; 499 500 if (!isnan(pdf)) 501 ccprintf(pdfstr, "%.2f%%", pdf * 100.0); 502 503 if (!isnan(cdf)) 504 ccprintf(cdfstr, "%.2f%%", cdf * 100.0); 505 506#ifdef STAT_DISPLAY_COMPAT 507 if (flags & __substat) { 508 ccprintf(stream, "%32s%12s%10s%10s", name, 509 ValueToString(value, precision), 510 pdfstr, cdfstr); 511 } else 512#endif 513 { 514 ccprintf(stream, "%-40s%12s%10s%10s", name, 515 ValueToString(value, precision), pdfstr, cdfstr); 516 } 517 518 if (PrintDescriptions) { 519 if (!desc.empty()) 520 ccprintf(stream, " # %s", desc); 521 } 522 stream << endl; 523} 524 525void 526ScalarStat::display(ostream &stream) const 527{ 528 PrintOne(stream, val(), myname(), mydesc(), myprecision(), myflags()); 529} 530 531void 532VectorStat::display(ostream &stream) const 533{ 534 bool have_subname = false; 535 bool have_subdesc = false; 536 int size = this->size(); 537 for (int i = 0; i < size; ++i) { 538 if (!mysubname(i).empty()) 539 have_subname = true; 540 if (!mysubdesc(i).empty()) 541 have_subdesc = true; 542 } 543 544 vector<string> *subnames = 0; 545 vector<string> *subdescs = 0; 546 if (have_subname) { 547 subnames = new vector<string>(size); 548 for (int i = 0; i < size; ++i) 549 (*subnames)[i] = mysubname(i); 550 } 551 if (have_subdesc) { 552 subdescs = new vector<string>(size); 553 for (int i = 0; i < size; ++i) 554 (*subdescs)[i] = mysubdesc(i); 555 } 556 557 VectorDisplay(stream, myname(), subnames, mydesc(), subdescs, 558 myprecision(), myflags(), val(), total()); 559} 560 561#ifndef STAT_DISPLAY_COMPAT 562#define NAMESEP "::" 563#else 564#define NAMESEP "_" 565#endif 566 567#ifndef STAT_DISPLAY_COMPAT 568void 569VectorDisplay(std::ostream &stream, 570 const std::string &myname, 571 const std::vector<std::string> *mysubnames, 572 const std::string &mydesc, 573 const std::vector<std::string> *mysubdescs, 574 int myprecision, FormatFlags myflags, 575 const rvec_t &vec, result_t mytotal) 576{ 577 int _size = vec.size(); 578 result_t _total = 0.0; 579 result_t _pdf, _cdf = 0.0; 580 581 if (myflags & (pdf | cdf)) { 582 for (int i = 0; i < _size; ++i) { 583 _total += vec[i]; 584 } 585 } 586 587 if (_size == 1) { 588 PrintOne(stream, vec[0], myname, mydesc, myprecision, myflags); 589 } else { 590 for (int i = 0; i < _size; ++i) { 591 string subname; 592 if (mysubnames) { 593 subname = (*mysubnames)[i]; 594 if (subname.empty()) 595 continue; 596 } else { 597 subname = to_string(i); 598 } 599 600 string name = myname + NAMESEP + subname; 601 if (!(myflags & pdf)) 602 PrintOne(stream, vec[i], name, mydesc, myprecision, myflags); 603 else { 604 _pdf = vec[i] / _total; 605 _cdf += _pdf; 606 PrintOne(stream, vec[i], name, mydesc, myprecision, myflags, 607 _pdf, _cdf); 608 } 609 } 610 611 if (myflags & total) 612 PrintOne(stream, mytotal, myname + NAMESEP + "total", 613 mydesc, myprecision, myflags); 614 } 615} 616#else 617void 618VectorDisplay(std::ostream &stream, 619 const std::string &myname, 620 const std::vector<std::string> *mysubnames, 621 const std::string &mydesc, 622 const std::vector<std::string> *mysubdescs, 623 int myprecision, FormatFlags myflags, 624 const rvec_t &vec, result_t mytotal) 625{ 626 int _size = vec.size(); 627 result_t _total = 0.0; 628 result_t _pdf, _cdf = 0.0; 629 630 if (myflags & (pdf | cdf)) { 631 for (int i = 0; i < _size; ++i) { 632 _total += vec[i]; 633 } 634 } 635 636 if (_size == 1) { 637 PrintOne(stream, vec[0], myname, mydesc, myprecision, myflags); 638 } else { 639 if (myflags & total) 640 PrintOne(stream, mytotal, myname, mydesc, myprecision, myflags); 641 642 if (myflags & dist) { 643 ccprintf(stream, "%s.start_dist\n", myname); 644 for (int i = 0; i < _size; ++i) { 645 string subname, subdesc; 646 subname = to_string(i); 647 if (mysubnames) { 648 if (!subname.empty()) { 649 subname = (*mysubnames)[i]; 650 } 651 } 652 if (mysubdescs) { 653 subdesc = (*mysubdescs)[i]; 654 } 655 if (!(myflags & (pdf | cdf))) { 656 PrintOne(stream, vec[i], subname, subdesc, myprecision, 657 myflags | __substat); 658 } else { 659 if (_total) { 660 _pdf = vec[i] / _total; 661 _cdf += _pdf; 662 } else { 663 _pdf = _cdf = 0.0; 664 } 665 if (!(myflags & cdf)) { 666 PrintOne(stream, vec[i], subname, subdesc, myprecision, 667 myflags | __substat, _pdf); 668 } else { 669 PrintOne(stream, vec[i], subname, subdesc, myprecision, 670 myflags | __substat, _pdf, _cdf); 671 } 672 } 673 } 674 ccprintf(stream, "%s.end_dist\n", myname); 675 } else { 676 for (int i = 0; i < _size; ++i) { 677 string subname; 678 if (mysubnames) { 679 subname = (*mysubnames)[i]; 680 if (subname.empty()) 681 continue; 682 } else { 683 subname = to_string(i); 684 } 685 686 string name = myname + NAMESEP + subname; 687 if (!(myflags & pdf)) { 688 PrintOne(stream, vec[i], name, mydesc, myprecision, 689 myflags); 690 } else { 691 if (_total) { 692 _pdf = vec[i] / _total; 693 _cdf += _pdf; 694 } else { 695 _pdf = _cdf = 0.0; 696 } 697 _pdf = vec[i] / _total; 698 _cdf += _pdf; 699 PrintOne(stream, vec[i], name, mydesc, myprecision, 700 myflags, _pdf, _cdf); 701 } 702 } 703 } 704 } 705} 706#endif 707 708#ifndef STAT_DISPLAY_COMPAT 709void 710DistDisplay(ostream &stream, const string &name, const string &desc, 711 int precision, FormatFlags flags, 712 result_t min_val, result_t max_val, 713 result_t underflow, result_t overflow, 714 const rvec_t &vec, int min, int max, int bucket_size, int size); 715{ 716 assert(size == vec.size()); 717 718 result_t total = 0.0; 719 result_t pdf, cdf = 0.0; 720 721 total += underflow; 722 for (int i = 0; i < size; ++i) 723 total += vec[i]; 724 total += overflow; 725 726 pdf = underflow / total; 727 cdf += pdf; 728 729 PrintOne(stream, underflow, name + NAMESEP + "underflow", desc, 730 precision, myflags, pdf, cdf); 731 732 for (int i = 0; i < size; ++i) { 733 stringstream namestr; 734 namestr << name; 735 736 int low = i * bucket_size + min; 737 int high = ::std::min((i + 1) * bucket_size + min - 1, max); 738 namestr << low; 739 if (low < high) 740 namestr << "-" << high; 741 742 pdf = vec[i] / total; 743 cdf += pdf; 744 PrintOne(stream, vec[i], namestr.str(), desc, precision, myflags, 745 pdf, cdf); 746 } 747 748 pdf = overflow / total; 749 cdf += pdf; 750 PrintOne(stream, overflow, name + NAMESEP + "overflow", desc, 751 precision, myflags, pdf, cdf); 752 PrintOne(stream, total, name + NAMESEP + "total", desc, 753 precision, myflags); 754} 755#else 756void 757DistDisplay(ostream &stream, const string &name, const string &desc, 758 int precision, FormatFlags flags, 759 result_t min_val, result_t max_val, 760 result_t underflow, result_t overflow, 761 const rvec_t &vec, int min, int max, int bucket_size, int size) 762{ 763 assert(size == vec.size()); 764 string blank; 765 766 result_t total = 0.0; 767 768 total += underflow; 769 for (int i = 0; i < size; ++i) 770 total += vec[i]; 771 total += overflow; 772 773 ccprintf(stream, "%-42s", name + ".start_dist"); 774 if (PrintDescriptions && !desc.empty()) 775 ccprintf(stream, " # %s", desc); 776 stream << endl; 777 778 PrintOne(stream, total, name + ".samples", blank, precision, flags); 779 PrintOne(stream, min_val, name + ".min_value", blank, precision, flags); 780 781 if (underflow > 0) 782 PrintOne(stream, min_val, name + ".underflows", blank, precision, 783 flags); 784 785 int _min; 786 result_t _pdf, _cdf, mypdf, mycdf; 787 788 _cdf = 0.0; 789 for (int i = 0; i < size; ++i) { 790 if (flags & nozero && vec[i] == 0.0 || 791 flags & nonan && isnan(vec[i])) 792 return; 793 794 _min = i * bucket_size + min; 795 _pdf = vec[i] / total * 100.0; 796 _cdf += _pdf; 797 798 mypdf = (flags & pdf) ? _pdf : NAN; 799 mycdf = (flags & cdf) ? _cdf : NAN; 800 801 PrintOne(stream, vec[i], ValueToString(_min, 0), blank, precision, 802 flags | __substat, mypdf, mycdf); 803 } 804 805 if (overflow > 0) 806 PrintOne(stream, overflow, name + ".overflows", blank, precision, 807 flags); 808 PrintOne(stream, max_val, name + ".max_value", blank, precision, flags); 809 ccprintf(stream, "%s.end_dist\n\n", name); 810} 811#endif 812 813void 814FancyDisplay(ostream &stream, const string &name, const string &desc, 815 int precision, FormatFlags flags, result_t mean, 816 result_t variance) 817{ 818 result_t stdev = isnan(variance) ? NAN : sqrt(variance); 819 PrintOne(stream, mean, name + NAMESEP + "mean", desc, precision, flags); 820 PrintOne(stream, stdev, name + NAMESEP + "stdev", desc, precision, flags); 821} 822 823BinBase::BinBase(size_t size) 824 : memsize(CeilPow2(size)), mem(NULL) 825{ 826} 827 828BinBase::~BinBase() 829{ 830 if (mem) 831 delete [] mem; 832} 833 834char * 835BinBase::memory() 836{ 837 if (!mem) { 838 mem = new char[memsize]; 839 memset(mem, 0, memsize); 840 } 841 842 return mem; 843} 844 845} // namespace Detail 846 847void 848check() 849{ 850 Detail::StatDB().check(); 851} 852 853void 854dump(ostream &stream) 855{ 856 Detail::StatDB().dump(stream); 857} 858 859CallbackQueue resetQueue; 860 861void 862regReset(Callback *cb) 863{ 864 resetQueue.add(cb); 865} 866 867void 868reset() 869{ 870 Detail::StatDB().reset(); 871 resetQueue.process(); 872} 873 874} // namespace Statistics 875