2f52314b9e1695c08dc902c105bf403e770fd90a
[gem5.git] / base / statistics.cc
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
47 float
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
61 static int total_stats = 0;
62 #endif
63
64 using namespace std;
65
66 // This is a hack to get this parameter from the old stats package.
67 namespace Statistics {
68 bool PrintDescriptions = true;
69
70 namespace Detail {
71 /**
72 * Struct to contain a name and description of statistic subfield.
73 */
74 struct 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 */
85 struct 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
114 StatData::StatData()
115 : init(false), print(false), subdata(NULL), precision(-1), flags(none),
116 prereq(NULL)
117 {
118 }
119
120 StatData::~StatData()
121 {
122 if (subdata)
123 delete subdata;
124 }
125
126 class 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
152 Database::Database()
153 {}
154
155 Database::~Database()
156 {}
157
158 void
159 Database::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
172 StatData *
173 Database::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
183 void
184 Database::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
212 void
213 Database::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
224 void
225 Database::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
238 bool
239 Stat::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
264 StatData *
265 Database::print(Stat *stat)
266 {
267 StatData *data = find(stat);
268 assert(data);
269
270 data->print = true;
271
272 return data;
273 }
274
275 Database &
276 StatDB()
277 {
278 static Database db;
279 return db;
280 }
281
282 Stat::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
297 void
298 Stat::setInit()
299 { mydata()->init = true; }
300
301 StatData *
302 Stat::mydata()
303 {
304 StatData *data = StatDB().find(this);
305 assert(data);
306
307 return data;
308 }
309
310 const StatData *
311 Stat::mydata() const
312 {
313 StatData *data = StatDB().find(this);
314 assert(data);
315
316 return data;
317 }
318
319 const SubData *
320 Stat::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
333 SubData *
334 Stat::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
356 string
357 Stat::myname() const
358 { return mydata()->name; }
359
360 string
361 Stat::mysubname(int index) const
362 {
363 const SubData *sd = mysubdata(index);
364 return sd ? sd->name : "";
365 }
366
367 string
368 Stat::mydesc() const
369 { return mydata()->desc; }
370
371 string
372 Stat::mysubdesc(int index) const
373 {
374 const SubData *sd = mysubdata(index);
375 return sd ? sd->desc : "";
376 }
377
378 int
379 Stat::myprecision() const
380 { return mydata()->precision; }
381
382 FormatFlags
383 Stat::myflags() const
384 { return mydata()->flags; }
385
386 bool
387 Stat::dodisplay() const
388 { return !mydata()->prereq || !mydata()->prereq->zero(); }
389
390 StatData *
391 Stat::print()
392 {
393 StatData *data = StatDB().print(this);
394 assert(data && data->init);
395
396 return data;
397 }
398
399 Stat &
400 Stat::name(const string &name)
401 {
402 print()->name = name;
403 return *this;
404 }
405
406 Stat &
407 Stat::desc(const string &desc)
408 {
409 print()->desc = desc;
410 return *this;
411 }
412
413 Stat &
414 Stat::precision(int precision)
415 {
416 print()->precision = precision;
417 return *this;
418 }
419
420 Stat &
421 Stat::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
430 Stat &
431 Stat::prereq(const Stat &prereq)
432 {
433 print()->prereq = &prereq;
434 return *this;
435 }
436
437 Stat &
438 Stat::subname(int index, const string &name)
439 {
440 print();
441 mysubdata_create(index)->name = name;
442 return *this;
443 }
444 Stat &
445 Stat::subdesc(int index, const string &desc)
446 {
447 print();
448 mysubdata_create(index)->desc = desc;
449 return *this;
450 }
451
452 bool
453 ScalarStat::zero() const
454 {
455 return val() == 0.0;
456 }
457
458 bool
459 VectorStat::zero() const
460 {
461 return val()[0] == 0.0;
462 }
463
464 string
465 ValueToString(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
489 void
490 PrintOne(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
525 void
526 ScalarStat::display(ostream &stream) const
527 {
528 PrintOne(stream, val(), myname(), mydesc(), myprecision(), myflags());
529 }
530
531 void
532 VectorStat::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
568 void
569 VectorDisplay(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
617 void
618 VectorDisplay(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
709 void
710 DistDisplay(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
756 void
757 DistDisplay(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
813 void
814 FancyDisplay(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
823 BinBase::BinBase(size_t size)
824 : memsize(CeilPow2(size)), mem(NULL)
825 {
826 }
827
828 BinBase::~BinBase()
829 {
830 if (mem)
831 delete [] mem;
832 }
833
834 char *
835 BinBase::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
847 void
848 check()
849 {
850 Detail::StatDB().check();
851 }
852
853 void
854 dump(ostream &stream)
855 {
856 Detail::StatDB().dump(stream);
857 }
858
859 CallbackQueue resetQueue;
860
861 void
862 regReset(Callback *cb)
863 {
864 resetQueue.add(cb);
865 }
866
867 void
868 reset()
869 {
870 Detail::StatDB().reset();
871 resetQueue.process();
872 }
873
874 } // namespace Statistics