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