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