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