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