statistics.cc revision 434
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 DefaultMode = 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, mode);
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, mode);
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->flags & print)
239        return;
240
241    data->flags |= print;
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()->flags |= init;
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 (!(flags & 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 ((flags & 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    StatFlags flags;
372    DisplayMode mode;
373    int precision;
374    result_t pdf;
375    result_t cdf;
376
377    ScalarPrint()
378        : value(0.0), flags(0), mode(DefaultMode), precision(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), pdfstr, cdfstr);
403    } else {
404        ccprintf(stream, "%-40s %12s %10s %10s", name,
405                 ValueToString(value, mode, precision), pdfstr, cdfstr);
406    }
407
408    if (PrintDescriptions) {
409        if (!desc.empty())
410            ccprintf(stream, " # %s", desc);
411    }
412    stream << endl;
413}
414
415struct VectorPrint
416{
417    string name;
418    string desc;
419    vector<string> subnames;
420    vector<string> subdescs;
421    StatFlags flags;
422    DisplayMode mode;
423    int precision;
424    rvec_t vec;
425    result_t total;
426
427    VectorPrint()
428        : subnames(0), subdescs(0), flags(0), mode(DefaultMode),
429          precision(-1), total(NAN)
430    {}
431
432    void operator()(ostream &stream) const;
433};
434
435void
436VectorPrint::operator()(std::ostream &stream) const
437{
438    int _size = vec.size();
439    result_t _total = 0.0;
440
441    if (flags & (pdf | cdf)) {
442        for (int i = 0; i < _size; ++i) {
443            _total += vec[i];
444        }
445    }
446
447    string base = name + ((mode == mode_simplescalar) ? "_" : "::");
448
449    ScalarPrint print;
450    print.name = name;
451    print.desc = desc;
452    print.precision = precision;
453    print.flags = flags;
454
455    bool havesub = !subnames.empty();
456
457    if (_size == 1) {
458        print.value = vec[0];
459        print(stream);
460    } else if (mode == mode_m5) {
461        for (int i = 0; i < _size; ++i) {
462            if (havesub && (i >= subnames.size() || subnames[i].empty()))
463                continue;
464
465            print.name = base + (havesub ? subnames[i] : to_string(i));
466            print.desc = subdescs.empty() ? desc : subdescs[i];
467            print.value = vec[i];
468
469            if (_total && (flags & pdf)) {
470                print.pdf = vec[i] / _total;
471                print.cdf += print.pdf;
472            }
473
474            print(stream);
475        }
476
477        if (flags & ::Statistics::total) {
478            print.name = base + "total";
479            print.desc = desc;
480            print.value = total;
481            print(stream);
482        }
483    } else {
484        if (flags & ::Statistics::total) {
485            print.value = total;
486            print(stream);
487        }
488
489        result_t _pdf = 0.0;
490        result_t _cdf = 0.0;
491        if (flags & dist) {
492            ccprintf(stream, "%s.start_dist\n", name);
493            for (int i = 0; i < _size; ++i) {
494                print.name = havesub ? subnames[i] : to_string(i);
495                print.desc = subdescs.empty() ? desc : subdescs[i];
496                print.flags |= __substat;
497                print.value = vec[i];
498
499                if (_total) {
500                    _pdf = vec[i] / _total;
501                    _cdf += _pdf;
502                }
503
504                if (flags & pdf)
505                    print.pdf = _pdf;
506                if (flags & cdf)
507                    print.cdf = _cdf;
508
509                print(stream);
510            }
511            ccprintf(stream, "%s.end_dist\n", name);
512        } else {
513            for (int i = 0; i < _size; ++i) {
514                if (havesub && subnames[i].empty())
515                    continue;
516
517                print.name = base;
518                print.name += havesub ? subnames[i] : to_string(i);
519                print.desc = subdescs.empty() ? desc : subdescs[i];
520                print.value = vec[i];
521
522                if (_total) {
523                    _pdf = vec[i] / _total;
524                    _cdf += _pdf;
525                } else {
526                    _pdf = _cdf = NAN;
527                }
528
529                if (flags & pdf) {
530                    print.pdf = _pdf;
531                    print.cdf = _cdf;
532                }
533
534                print(stream);
535            }
536        }
537    }
538}
539
540struct DistPrint
541{
542    string name;
543    string desc;
544    StatFlags flags;
545    DisplayMode mode;
546    int precision;
547
548    result_t min_val;
549    result_t max_val;
550    result_t underflow;
551    result_t overflow;
552    rvec_t vec;
553    result_t sum;
554    result_t squares;
555    result_t samples;
556
557    int min;
558    int max;
559    int bucket_size;
560    int size;
561    bool fancy;
562
563    void operator()(ostream &stream) const;
564};
565
566void
567DistPrint::operator()(ostream &stream) const
568{
569    if (fancy) {
570        ScalarPrint print;
571        string base = name + ((mode == mode_m5) ? "::" : "_");
572
573        print.precision = precision;
574        print.flags = flags;
575        print.mode = mode;
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.flags = flags;
607    print.mode = mode;
608    print.precision = precision;
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 (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, DisplayMode mode) const
727{
728    ScalarPrint print;
729    print.value = val();
730    print.name = name;
731    print.desc = desc;
732    print.flags = flags;
733    print.mode = mode;
734    print.precision = precision;
735
736    print(stream);
737}
738
739void
740VectorDataBase::display(ostream &stream, DisplayMode mode) const
741{
742    int size = this->size();
743    const_cast<VectorDataBase *>(this)->update();
744
745    VectorPrint print;
746
747    print.name = name;
748    print.desc = desc;
749    print.flags = flags;
750    print.mode = mode;
751    print.precision = precision;
752    print.vec = val();
753    print.total = total();
754
755    for (int i = 0; i < size; ++i) {
756        if (!subnames[i].empty()) {
757            print.subnames = subnames;
758            print.subnames.resize(size);
759            for (int i = 0; i < size; ++i) {
760                if (!subnames[i].empty() && !subdescs[i].empty()) {
761                    print.subdescs = subdescs;
762                    print.subdescs.resize(size);
763                    break;
764                }
765            }
766            break;
767        }
768    }
769
770
771    print(stream);
772}
773
774void
775Vector2dDataBase::display(ostream &stream, DisplayMode mode) const
776{
777    const_cast<Vector2dDataBase *>(this)->update();
778
779    bool havesub = false;
780    VectorPrint print;
781
782    print.subnames = y_subnames;
783    print.flags = flags;
784    print.mode = mode;
785    print.precision = precision;
786
787    if (!subnames.empty()) {
788        for (int i = 0; i < x; ++i)
789            if (!subnames[i].empty())
790                havesub = true;
791    }
792
793    rvec_t tot_vec(y);
794    result_t super_total = 0.0;
795    for (int i = 0; i < x; ++i) {
796        if (havesub && (i >= subnames.size() || subnames[i].empty()))
797            continue;
798
799        int iy = i * y;
800        rvec_t yvec(y);
801
802        result_t total = 0.0;
803        for (int j = 0; j < y; ++j) {
804            yvec[j] = vec[iy + j];
805            tot_vec[j] += yvec[j];
806            total += yvec[j];
807            super_total += yvec[j];
808        }
809
810        print.name = name + "_" + (havesub ? subnames[i] : to_string(i));
811        print.desc = desc;
812        print.vec = yvec;
813        print.total = total;
814        print(stream);
815    }
816
817    if ((flags & ::Statistics::total) && (x > 1)) {
818        print.name = name;
819        print.desc = desc;
820        print.vec = tot_vec;
821        print.total = super_total;
822        print(stream);
823    }
824}
825
826void
827DistDataBase::display(ostream &stream, DisplayMode mode) const
828{
829    const_cast<DistDataBase *>(this)->update();
830
831    DistPrint print;
832
833    print.name = name;
834    print.desc = desc;
835    print.flags = flags;
836    print.mode = mode;
837    print.precision = precision;
838
839    print.min_val = data.min_val;
840    print.max_val = data.max_val;
841    print.underflow = data.underflow;
842    print.overflow = data.overflow;
843    print.vec = data.vec;
844    print.sum = data.sum;
845    print.squares = data.squares;
846    print.samples = data.samples;
847
848    print.min = data.min;
849    print.max = data.max;
850    print.bucket_size = data.bucket_size;
851    print.size = data.size;
852    print.fancy = data.fancy;
853
854    print(stream);
855}
856
857void
858VectorDistDataBase::display(ostream &stream, DisplayMode mode) const
859{
860    const_cast<VectorDistDataBase *>(this)->update();
861
862    for (int i = 0; i < size(); ++i) {
863        DistPrint print;
864
865        print.name = name +
866            (subnames[i].empty() ? ("_" + to_string(i)) : subnames[i]);
867        print.desc = subdescs[i].empty() ? desc : subdescs[i];
868        print.flags = flags;
869        print.mode = mode;
870        print.precision = precision;
871
872        print.min_val = data[i].min_val;
873        print.max_val = data[i].max_val;
874        print.underflow = data[i].underflow;
875        print.overflow = data[i].overflow;
876        print.vec = data[i].vec;
877        print.sum = data[i].sum;
878        print.squares = data[i].squares;
879        print.samples = data[i].samples;
880
881        print.min = data[i].min;
882        print.max = data[i].max;
883        print.bucket_size = data[i].bucket_size;
884        print.size = data[i].size;
885        print.fancy = data[i].fancy;
886
887        print(stream);
888    }
889}
890
891void
892FormulaBase::val(rvec_t &vec) const
893{
894    vec = root->val();
895}
896
897result_t
898FormulaBase::total() const
899{
900    return root->total();
901}
902
903size_t
904FormulaBase::size() const
905{
906    if (!root)
907        return 0;
908    else
909        return root->size();
910}
911
912bool
913FormulaBase::binned() const
914{
915    return root->binned();
916}
917
918void
919FormulaBase::reset()
920{
921}
922
923bool
924FormulaBase::zero() const
925{
926    rvec_t vec;
927    val(vec);
928    for (int i = 0; i < vec.size(); ++i)
929        if (vec[i] != 0.0)
930            return false;
931    return true;
932}
933
934void
935FormulaBase::update(StatData *)
936{
937}
938
939Formula::Formula()
940{
941    setInit();
942}
943
944Formula::Formula(Temp r)
945{
946    root = r;
947    assert(size());
948}
949
950const Formula &
951Formula::operator=(Temp r)
952{
953    assert(!root && "Can't change formulas");
954    root = r;
955    assert(size());
956    return *this;
957}
958
959const Formula &
960Formula::operator+=(Temp r)
961{
962    if (root)
963        root = NodePtr(new BinaryNode<std::plus<result_t> >(root, r));
964    else
965        root = r;
966    assert(size());
967    return *this;
968}
969
970MainBin::MainBin(const string &name)
971    : _name(name), mem(NULL), memsize(-1)
972{
973    Database::StatDB().regBin(this, name);
974}
975
976MainBin::~MainBin()
977{
978    if (mem)
979        delete [] mem;
980}
981
982char *
983MainBin::memory(off_t off)
984{
985    if (memsize == -1)
986        memsize = CeilPow2((size_t) offset());
987
988    if (!mem) {
989        mem = new char[memsize];
990        memset(mem, 0, memsize);
991    }
992
993    assert(offset() <= size());
994    return mem + off;
995}
996
997void
998check()
999{
1000    Database::StatDB().check();
1001}
1002
1003void
1004dump(ostream &stream, DisplayMode mode)
1005{
1006    Database::StatDB().dump(stream, mode);
1007}
1008
1009CallbackQueue resetQueue;
1010
1011void
1012registerResetCallback(Callback *cb)
1013{
1014    resetQueue.add(cb);
1015}
1016
1017void
1018reset()
1019{
1020    Database::StatDB().reset();
1021    resetQueue.process();
1022}
1023
1024} // namespace Statistics
1025