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