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