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