statistics.cc revision 456
15647SN/A/*
25647SN/A * Copyright (c) 2003 The Regents of The University of Michigan
35647SN/A * All rights reserved.
45647SN/A *
55647SN/A * Redistribution and use in source and binary forms, with or without
65647SN/A * modification, are permitted provided that the following conditions are
75647SN/A * met: redistributions of source code must retain the above copyright
85647SN/A * notice, this list of conditions and the following disclaimer;
95647SN/A * redistributions in binary form must reproduce the above copyright
105647SN/A * notice, this list of conditions and the following disclaimer in the
115647SN/A * documentation and/or other materials provided with the distribution;
125647SN/A * neither the name of the copyright holders nor the names of its
135647SN/A * contributors may be used to endorse or promote products derived from
145647SN/A * this software without specific prior written permission.
155647SN/A *
165647SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
175647SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
185647SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
195647SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
205647SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
215647SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
225647SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235647SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245647SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255647SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265647SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275647SN/A */
285647SN/A
295647SN/A#include <iomanip>
305647SN/A#include <fstream>
315647SN/A#include <list>
325647SN/A#include <map>
335647SN/A#include <string>
346046SN/A#include <sstream>
356046SN/A
365647SN/A#include "base/callback.hh"
375647SN/A#include "base/cprintf.hh"
385647SN/A#include "base/hostinfo.hh"
395647SN/A#include "base/misc.hh"
405647SN/A#include "base/python.hh"
415647SN/A#include "base/statistics.hh"
425647SN/A#include "base/str.hh"
435647SN/A#include "base/time.hh"
445647SN/A#include "base/trace.hh"
455647SN/A
465647SN/A#ifdef __M5_NAN
475647SN/Afloat
485647SN/A__nan()
495647SN/A{
505647SN/A    union {
515647SN/A        uint32_t ui;
525647SN/A        float f;
535647SN/A    } nan;
545647SN/A
555647SN/A    nan.ui = 0x7fc00000;
565647SN/A    return nan.f;
575647SN/A}
585647SN/A#endif
595647SN/A
605647SN/A#ifdef STAT_DEBUG
615647SN/Astatic int total_stats = 0;
625647SN/A#endif
635647SN/A
645647SN/Ausing namespace std;
655647SN/A
665647SN/A// This is a hack to get this parameter from the old stats package.
675647SN/Anamespace Statistics {
685647SN/Abool PrintDescriptions = true;
695647SN/ADisplayMode DefaultMode = mode_simplescalar;
705647SN/A
715647SN/Anamespace Database
725647SN/A{
735647SN/A    class Data
745647SN/A    {
755647SN/A      private:
765647SN/A        typedef list<StatData *> list_t;
775647SN/A        typedef map<void *, StatData *> map_t;
785647SN/A
795647SN/A        list<MainBin *> bins;
805647SN/A
815647SN/A        list_t allStats;
825647SN/A        list_t printStats;
835647SN/A        map_t statMap;
845647SN/A
855647SN/A        ofstream *stream;
865647SN/A        Python *py;
875647SN/A
885647SN/A      public:
895647SN/A        Data();
905647SN/A        ~Data();
916046SN/A
926046SN/A        void dump(ostream &stream, DisplayMode mode);
936046SN/A        void display(ostream &stream, DisplayMode mode);
946046SN/A        void python_start(const string &file);
956046SN/A        void python_dump(const string &name, const string &subname);
966046SN/A        void python(const string &name, const string &subname,
976046SN/A                    const string &bin);
986046SN/A
996046SN/A        StatData *find(void *stat);
1006046SN/A        void mapStat(void *stat, StatData *data);
1016046SN/A
1026046SN/A        void check();
1036046SN/A        void reset();
1046046SN/A        void regBin(MainBin *bin, string name);
1055647SN/A        void regPrint(void *stat);
1065647SN/A
1075647SN/A        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, "if __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    py->next();
213}
214
215void
216Data::python(const string &name, const string &subname, const string &bin)
217{
218    py->start("collections.append");
219    py->start("Collection");
220    py->qarg(name);
221    py->qarg(subname);
222    py->qarg(bin);
223    py->qarg(hostname());
224    py->qarg(Time::start.date());
225    py->startList();
226    list_t::iterator i = allStats.begin();
227    list_t::iterator end = allStats.end();
228    while (i != end) {
229        StatData *stat = *i;
230        stat->python(*py);
231        ++i;
232    }
233    py->endList();
234    py->end();
235    py->end();
236}
237
238StatData *
239Data::find(void *stat)
240{
241    map_t::const_iterator i = statMap.find(stat);
242
243    if (i == statMap.end())
244        return NULL;
245
246    return (*i).second;
247}
248
249void
250Data::check()
251{
252    list_t::iterator i = allStats.begin();
253    list_t::iterator end = allStats.end();
254
255    while (i != end) {
256        StatData *data = *i;
257        assert(data);
258        data->check();
259        ++i;
260    }
261
262    i = allStats.begin();
263    int j = 0;
264    while (i != end) {
265        StatData *data = *i;
266        if (!(data->flags & print))
267            data->name = "__Stat" + to_string(j++);
268        ++i;
269    }
270}
271
272void
273Data::reset()
274{
275    // reset non-binned stats
276    list_t::iterator i = allStats.begin();
277    list_t::iterator end = allStats.end();
278    while (i != end) {
279        StatData *data = *i;
280        if (!data->binned())
281            data->reset();
282        ++i;
283    }
284
285    // save the bin so we can go back to where we were
286    MainBin *orig = MainBin::curBin();
287
288    // reset binned stats
289    list<MainBin *>::iterator bi = bins.begin();
290    list<MainBin *>::iterator be = bins.end();
291    while (bi != be) {
292        MainBin *bin = *bi;
293        bin->activate();
294
295        i = allStats.begin();
296        while (i != end) {
297            StatData *data = *i;
298            if (data->binned())
299                data->reset();
300            ++i;
301        }
302        ++bi;
303    }
304
305    // restore bin
306    MainBin::curBin() = orig;
307}
308
309void
310Data::mapStat(void *stat, StatData *data)
311{
312    if (statMap.find(stat) != statMap.end())
313        panic("shouldn't register stat twice!");
314
315    allStats.push_back(data);
316
317#ifndef NDEBUG
318    bool success =
319#endif
320        (statMap.insert(make_pair(stat, data))).second;
321    assert(statMap.find(stat) != statMap.end());
322    assert(success && "this should never fail");
323}
324
325void
326Data::regBin(MainBin *bin, string _name)
327{
328    bins.push_back(bin);
329    DPRINTF(Stats, "registering %s\n", _name);
330}
331
332void
333Data::regPrint(void *stat)
334{
335    StatData *data = find(stat);
336
337    if (data->flags & print)
338        return;
339
340    data->flags |= print;
341
342    list_t::iterator j = printStats.insert(printStats.end(), data);
343    inplace_merge(printStats.begin(), j, printStats.end(), StatData::less);
344}
345
346Data &
347StatDB()
348{
349    static Data db;
350    return db;
351}
352
353}
354
355StatData *
356DataAccess::find() const
357{
358    return Database::StatDB().find(const_cast<void *>((const void *)this));
359}
360
361const StatData *
362getStatData(const void *stat)
363{
364    return Database::StatDB().find(const_cast<void *>(stat));
365}
366
367void
368DataAccess::map(StatData *data)
369{
370    Database::StatDB().mapStat(this, data);
371}
372
373StatData *
374DataAccess::statData()
375{
376    StatData *ptr = find();
377    assert(ptr);
378    return ptr;
379}
380
381const StatData *
382DataAccess::statData() const
383{
384    const StatData *ptr = find();
385    assert(ptr);
386    return ptr;
387}
388
389void
390DataAccess::setInit()
391{
392    statData()->flags |= init;
393}
394
395void
396DataAccess::setPrint()
397{
398    Database::StatDB().regPrint(this);
399}
400
401StatData::~StatData()
402{
403}
404
405bool
406StatData::less(StatData *stat1, StatData *stat2)
407{
408    const string &name1 = stat1->name;
409    const string &name2 = stat2->name;
410
411    vector<string> v1;
412    vector<string> v2;
413
414    tokenize(v1, name1, '.');
415    tokenize(v2, name2, '.');
416
417    int last = min(v1.size(), v2.size()) - 1;
418    for (int i = 0; i < last; ++i)
419        if (v1[i] != v2[i])
420            return v1[i] < v2[i];
421
422    // Special compare for last element.
423    if (v1[last] == v2[last])
424        return v1.size() < v2.size();
425    else
426        return v1[last] < v2[last];
427
428    return false;
429}
430
431bool
432StatData::baseCheck() const
433{
434    if (!(flags & init)) {
435#ifdef STAT_DEBUG
436        cprintf("this is stat number %d\n",(*i)->number);
437#endif
438        panic("Not all stats have been initialized");
439        return false;
440    }
441
442    if ((flags & print) && name.empty()) {
443        panic("all printable stats must be named");
444        return false;
445    }
446
447    return true;
448}
449
450string
451ValueToString(result_t value, DisplayMode mode, int precision)
452{
453    stringstream val;
454
455    if (!isnan(value)) {
456        if (precision != -1)
457            val.precision(precision);
458        else if (value == rint(value))
459            val.precision(0);
460
461        val.unsetf(ios::showpoint);
462        val.setf(ios::fixed);
463        val << value;
464    } else {
465        val << (mode == mode_m5 ? "no value" : "<err: div-0>");
466    }
467
468    return val.str();
469}
470
471struct ScalarPrint
472{
473    result_t value;
474    string name;
475    string desc;
476    StatFlags flags;
477    DisplayMode mode;
478    int precision;
479    result_t pdf;
480    result_t cdf;
481
482    ScalarPrint()
483        : value(0.0), flags(0), mode(DefaultMode), precision(0),
484          pdf(NAN), cdf(NAN)
485    {}
486
487    void operator()(ostream &stream) const;
488};
489
490void
491ScalarPrint::operator()(ostream &stream) const
492{
493    if (flags & nozero && value == 0.0 ||
494        flags & nonan && isnan(value))
495        return;
496
497    stringstream pdfstr, cdfstr;
498
499    if (!isnan(pdf))
500        ccprintf(pdfstr, "%.2f%%", pdf * 100.0);
501
502    if (!isnan(cdf))
503        ccprintf(cdfstr, "%.2f%%", cdf * 100.0);
504
505    if (mode == mode_simplescalar && flags & __substat) {
506        ccprintf(stream, "%32s %12s %10s %10s", name,
507                 ValueToString(value, mode, precision), pdfstr, cdfstr);
508    } else {
509        ccprintf(stream, "%-40s %12s %10s %10s", name,
510                 ValueToString(value, mode, precision), pdfstr, cdfstr);
511    }
512
513    if (PrintDescriptions) {
514        if (!desc.empty())
515            ccprintf(stream, " # %s", desc);
516    }
517    stream << endl;
518}
519
520struct VectorPrint
521{
522    string name;
523    string desc;
524    vector<string> subnames;
525    vector<string> subdescs;
526    StatFlags flags;
527    DisplayMode mode;
528    int precision;
529    rvec_t vec;
530    result_t total;
531
532    VectorPrint()
533        : subnames(0), subdescs(0), flags(0), mode(DefaultMode),
534          precision(-1), total(NAN)
535    {}
536
537    void operator()(ostream &stream) const;
538};
539
540void
541VectorPrint::operator()(std::ostream &stream) const
542{
543    int _size = vec.size();
544    result_t _total = 0.0;
545
546    if (flags & (pdf | cdf)) {
547        for (int i = 0; i < _size; ++i) {
548            _total += vec[i];
549        }
550    }
551
552    string base = name + ((mode == mode_simplescalar) ? "_" : "::");
553
554    ScalarPrint print;
555    print.name = name;
556    print.desc = desc;
557    print.precision = precision;
558    print.flags = flags;
559
560    bool havesub = !subnames.empty();
561
562    if (_size == 1) {
563        print.value = vec[0];
564        print(stream);
565    } else if (mode == mode_m5) {
566        for (int i = 0; i < _size; ++i) {
567            if (havesub && (i >= subnames.size() || subnames[i].empty()))
568                continue;
569
570            print.name = base + (havesub ? subnames[i] : to_string(i));
571            print.desc = subdescs.empty() ? desc : subdescs[i];
572            print.value = vec[i];
573
574            if (_total && (flags & pdf)) {
575                print.pdf = vec[i] / _total;
576                print.cdf += print.pdf;
577            }
578
579            print(stream);
580        }
581
582        if (flags & ::Statistics::total) {
583            print.name = base + "total";
584            print.desc = desc;
585            print.value = total;
586            print(stream);
587        }
588    } else {
589        if (flags & ::Statistics::total) {
590            print.value = total;
591            print(stream);
592        }
593
594        result_t _pdf = 0.0;
595        result_t _cdf = 0.0;
596        if (flags & dist) {
597            ccprintf(stream, "%s.start_dist\n", name);
598            for (int i = 0; i < _size; ++i) {
599                print.name = havesub ? subnames[i] : to_string(i);
600                print.desc = subdescs.empty() ? desc : subdescs[i];
601                print.flags |= __substat;
602                print.value = vec[i];
603
604                if (_total) {
605                    _pdf = vec[i] / _total;
606                    _cdf += _pdf;
607                }
608
609                if (flags & pdf)
610                    print.pdf = _pdf;
611                if (flags & cdf)
612                    print.cdf = _cdf;
613
614                print(stream);
615            }
616            ccprintf(stream, "%s.end_dist\n", name);
617        } else {
618            for (int i = 0; i < _size; ++i) {
619                if (havesub && subnames[i].empty())
620                    continue;
621
622                print.name = base;
623                print.name += havesub ? subnames[i] : to_string(i);
624                print.desc = subdescs.empty() ? desc : subdescs[i];
625                print.value = vec[i];
626
627                if (_total) {
628                    _pdf = vec[i] / _total;
629                    _cdf += _pdf;
630                } else {
631                    _pdf = _cdf = NAN;
632                }
633
634                if (flags & pdf) {
635                    print.pdf = _pdf;
636                    print.cdf = _cdf;
637                }
638
639                print(stream);
640            }
641        }
642    }
643}
644
645struct DistPrint
646{
647    string name;
648    string desc;
649    StatFlags flags;
650    DisplayMode mode;
651    int precision;
652
653    result_t min_val;
654    result_t max_val;
655    result_t underflow;
656    result_t overflow;
657    rvec_t vec;
658    result_t sum;
659    result_t squares;
660    result_t samples;
661
662    int min;
663    int max;
664    int bucket_size;
665    int size;
666    bool fancy;
667
668    void operator()(ostream &stream) const;
669};
670
671void
672DistPrint::operator()(ostream &stream) const
673{
674    if (fancy) {
675        ScalarPrint print;
676        string base = name + ((mode == mode_m5) ? "::" : "_");
677
678        print.precision = precision;
679        print.flags = flags;
680        print.mode = mode;
681        print.desc = desc;
682
683        print.name = base + "mean";
684        print.value = samples ? sum / samples : NAN;
685        print(stream);
686
687        print.name = base + "stdev";
688        print.value = samples ? sqrt((samples * squares - sum * sum) /
689                                     (samples * (samples - 1.0))) : NAN;
690        print(stream);
691
692        print.name = "**Ignore: " + base + "TOT";
693        print.value = samples;
694        print(stream);
695        return;
696    }
697
698    assert(size == vec.size());
699
700    result_t total = 0.0;
701
702    total += underflow;
703    for (int i = 0; i < size; ++i)
704        total += vec[i];
705    total += overflow;
706
707    string base = name + (mode == mode_m5 ? "::" : ".");
708
709    ScalarPrint print;
710    print.desc = (mode == mode_m5) ? desc : "";
711    print.flags = flags;
712    print.mode = mode;
713    print.precision = precision;
714
715    if (mode == mode_simplescalar) {
716        ccprintf(stream, "%-42s", base + "start_dist");
717        if (PrintDescriptions && !desc.empty())
718            ccprintf(stream, "                     # %s", desc);
719        stream << endl;
720    }
721
722    print.name = base + "samples";
723    print.value = samples;
724    print(stream);
725
726    print.name = base + "min_value";
727    print.value = min_val;
728    print(stream);
729
730    if (mode == mode_m5 || underflow > 0.0) {
731        print.name = base + "underflows";
732        print.value = underflow;
733        if (mode == mode_m5 && total) {
734            print.pdf = underflow / total;
735            print.cdf += print.pdf;
736        }
737        print(stream);
738    }
739
740
741    if (mode == mode_m5) {
742        for (int i = 0; i < size; ++i) {
743            stringstream namestr;
744            namestr << name;
745
746            int low = i * bucket_size + min;
747            int high = ::min((i + 1) * bucket_size + min - 1, max);
748            namestr << low;
749            if (low < high)
750                namestr << "-" << high;
751
752            print.name = namestr.str();
753            print.value = vec[i];
754            if (total) {
755                print.pdf = vec[i] / total;
756                print.cdf += print.pdf;
757            }
758            print(stream);
759        }
760
761    } else {
762        int _min;
763        result_t _pdf;
764        result_t _cdf = 0.0;
765
766        print.flags = flags | __substat;
767
768        for (int i = 0; i < size; ++i) {
769            if (flags & nozero && vec[i] == 0.0 ||
770                flags & nonan && isnan(vec[i]))
771                continue;
772
773            _min = i * bucket_size + min;
774            _pdf = vec[i] / total * 100.0;
775            _cdf += _pdf;
776
777
778            print.name = ValueToString(_min, mode, 0);
779            print.value = vec[i];
780            print.pdf = (flags & pdf) ? _pdf : NAN;
781            print.cdf = (flags & cdf) ? _cdf : NAN;
782            print(stream);
783        }
784
785        print.flags = flags;
786    }
787
788    if (mode == mode_m5 || overflow > 0.0) {
789        print.name = base + "overflows";
790        print.value = overflow;
791        if (mode == mode_m5 && total) {
792            print.pdf = overflow / total;
793            print.cdf += print.pdf;
794        } else {
795            print.pdf = NAN;
796            print.cdf = NAN;
797        }
798        print(stream);
799    }
800
801    print.pdf = NAN;
802    print.cdf = NAN;
803
804    if (mode != mode_simplescalar) {
805        print.name = base + "total";
806        print.value = total;
807        print(stream);
808    }
809
810    print.name = base + "max_value";
811    print.value = max_val;
812    print(stream);
813
814    if (mode != mode_simplescalar && samples != 0) {
815        print.name = base + "mean";
816        print.value = sum / samples;
817        print(stream);
818
819        print.name = base + "stdev";
820        print.value = sqrt((samples * squares - sum * sum) /
821                           (samples * (samples - 1.0)));
822        print(stream);
823    }
824
825    if (mode == mode_simplescalar)
826        ccprintf(stream, "%send_dist\n\n", base);
827}
828
829void
830ScalarDataBase::display(ostream &stream, DisplayMode mode) const
831{
832    ScalarPrint print;
833    print.value = val();
834    print.name = name;
835    print.desc = desc;
836    print.flags = flags;
837    print.mode = mode;
838    print.precision = precision;
839
840    print(stream);
841}
842
843void
844VectorDataBase::display(ostream &stream, DisplayMode mode) const
845{
846    int size = this->size();
847    const_cast<VectorDataBase *>(this)->update();
848
849    VectorPrint print;
850
851    print.name = name;
852    print.desc = desc;
853    print.flags = flags;
854    print.mode = mode;
855    print.precision = precision;
856    print.vec = val();
857    print.total = total();
858
859    if (!subnames.empty()) {
860        for (int i = 0; i < size; ++i) {
861            if (!subnames[i].empty()) {
862                print.subnames = subnames;
863                print.subnames.resize(size);
864                for (int i = 0; i < size; ++i) {
865                    if (!subnames[i].empty() && !subdescs[i].empty()) {
866                        print.subdescs = subdescs;
867                        print.subdescs.resize(size);
868                        break;
869                    }
870                }
871                break;
872            }
873        }
874    }
875
876    print(stream);
877}
878
879void
880Vector2dDataBase::display(ostream &stream, DisplayMode mode) const
881{
882    const_cast<Vector2dDataBase *>(this)->update();
883
884    bool havesub = false;
885    VectorPrint print;
886
887    print.subnames = y_subnames;
888    print.flags = flags;
889    print.mode = mode;
890    print.precision = precision;
891
892    if (!subnames.empty()) {
893        for (int i = 0; i < x; ++i)
894            if (!subnames[i].empty())
895                havesub = true;
896    }
897
898    rvec_t tot_vec(y);
899    result_t super_total = 0.0;
900    for (int i = 0; i < x; ++i) {
901        if (havesub && (i >= subnames.size() || subnames[i].empty()))
902            continue;
903
904        int iy = i * y;
905        rvec_t yvec(y);
906
907        result_t total = 0.0;
908        for (int j = 0; j < y; ++j) {
909            yvec[j] = vec[iy + j];
910            tot_vec[j] += yvec[j];
911            total += yvec[j];
912            super_total += yvec[j];
913        }
914
915        print.name = name + "_" + (havesub ? subnames[i] : to_string(i));
916        print.desc = desc;
917        print.vec = yvec;
918        print.total = total;
919        print(stream);
920    }
921
922    if ((flags & ::Statistics::total) && (x > 1)) {
923        print.name = name;
924        print.desc = desc;
925        print.vec = tot_vec;
926        print.total = super_total;
927        print(stream);
928    }
929}
930
931void
932DistDataBase::display(ostream &stream, DisplayMode mode) const
933{
934    const_cast<DistDataBase *>(this)->update();
935
936    DistPrint print;
937
938    print.name = name;
939    print.desc = desc;
940    print.flags = flags;
941    print.mode = mode;
942    print.precision = precision;
943
944    print.min_val = data.min_val;
945    print.max_val = data.max_val;
946    print.underflow = data.underflow;
947    print.overflow = data.overflow;
948    print.vec = data.vec;
949    print.sum = data.sum;
950    print.squares = data.squares;
951    print.samples = data.samples;
952
953    print.min = data.min;
954    print.max = data.max;
955    print.bucket_size = data.bucket_size;
956    print.size = data.size;
957    print.fancy = data.fancy;
958
959    print(stream);
960}
961
962void
963VectorDistDataBase::display(ostream &stream, DisplayMode mode) const
964{
965    const_cast<VectorDistDataBase *>(this)->update();
966
967    for (int i = 0; i < size(); ++i) {
968        DistPrint print;
969
970        print.name = name +
971            (subnames[i].empty() ? ("_" + to_string(i)) : subnames[i]);
972        print.desc = subdescs[i].empty() ? desc : subdescs[i];
973        print.flags = flags;
974        print.mode = mode;
975        print.precision = precision;
976
977        print.min_val = data[i].min_val;
978        print.max_val = data[i].max_val;
979        print.underflow = data[i].underflow;
980        print.overflow = data[i].overflow;
981        print.vec = data[i].vec;
982        print.sum = data[i].sum;
983        print.squares = data[i].squares;
984        print.samples = data[i].samples;
985
986        print.min = data[i].min;
987        print.max = data[i].max;
988        print.bucket_size = data[i].bucket_size;
989        print.size = data[i].size;
990        print.fancy = data[i].fancy;
991
992        print(stream);
993    }
994}
995
996void
997ScalarDataBase::python(Python &py) const
998{
999    py.start("Scalar");
1000    py.qarg(name);
1001    py.qqqarg(desc);
1002    py.kwarg("binned", binned());
1003    py.kwarg("precision", precision);
1004    py.kwarg("flags", flags);
1005    if (prereq)
1006        py.qkwarg("prereq", prereq->name);
1007    py.kwarg("value", val());
1008    py.end();
1009}
1010
1011void
1012VectorDataBase::python(Python &py) const
1013{
1014    const_cast<VectorDataBase *>(this)->update();
1015
1016    py.start("Vector");
1017    py.qarg(name);
1018    py.qqqarg(desc);
1019    py.kwarg("binned", binned());
1020    py.kwarg("precision", precision);
1021    py.kwarg("flags", flags);
1022    if (prereq)
1023        py.qkwarg("prereq", prereq->name);
1024    py.kwarg("value", val());
1025    if (!subnames.empty())
1026        py.qkwarg("subnames", subnames);
1027    if (!subdescs.empty())
1028        py.qkwarg("subdescs", subdescs);
1029    py.end();
1030}
1031
1032void
1033DistDataData::python(Python &py, const string &name) const
1034{
1035    string s = name.empty() ? "" : name + "=";
1036
1037    if (samples == 0 || fancy)
1038        s += "SimpleDist";
1039    else
1040        s += "FullDist";
1041
1042    py.start(s);
1043    py.arg(sum);
1044    py.arg(squares);
1045    py.arg(samples);
1046    if (samples && !fancy) {
1047        py.arg(min_val);
1048        py.arg(min_val);
1049        py.arg(underflow);
1050        py.arg(vec);
1051        py.arg(overflow);
1052        py.arg(min);
1053        py.arg(max);
1054        py.arg(bucket_size);
1055        py.arg(size);
1056    }
1057    py.end();
1058}
1059
1060void
1061FormulaDataBase::python(Python &py) const
1062{
1063    const_cast<FormulaDataBase *>(this)->update();
1064
1065    py.start("Formula");
1066    py.qarg(name);
1067    py.qqqarg(desc);
1068    py.kwarg("binned", binned());
1069    py.kwarg("precision", precision);
1070    py.kwarg("flags", flags);
1071    if (prereq)
1072        py.qkwarg("prereq", prereq->name);
1073    py.qkwarg("formula", str());
1074    if (!subnames.empty())
1075        py.qkwarg("subnames", subnames);
1076    if (!subdescs.empty())
1077        py.qkwarg("subdescs", subdescs);
1078    py.end();
1079}
1080
1081void
1082DistDataBase::python(Python &py) const
1083{
1084    const_cast<DistDataBase *>(this)->update();
1085
1086    py.start("Dist");
1087    py.qarg(name);
1088    py.qqqarg(desc);
1089    py.kwarg("binned", binned());
1090    py.kwarg("precision", precision);
1091    py.kwarg("flags", flags);
1092    if (prereq)
1093        py.qkwarg("prereq", prereq->name);
1094    data.python(py, "dist");
1095    py.end();
1096}
1097
1098void
1099VectorDistDataBase::python(Python &py) const
1100{
1101    const_cast<VectorDistDataBase *>(this)->update();
1102
1103    py.start("VectorDist");
1104    py.qarg(name);
1105    py.qqqarg(desc);
1106    py.kwarg("binned", binned());
1107    py.kwarg("precision", precision);
1108    py.kwarg("flags", flags);
1109    if (prereq)
1110        py.qkwarg("prereq", prereq->name);
1111    if (!subnames.empty())
1112        py.qkwarg("subnames", subnames);
1113    if (!subdescs.empty())
1114        py.qkwarg("subdescs", subdescs);
1115
1116    py.tuple("dist");
1117    typedef std::vector<DistDataData>::const_iterator iter;
1118    iter i = data.begin();
1119    iter end = data.end();
1120    while (i != end) {
1121        i->python(py, "");
1122        ++i;
1123    }
1124    py.endTuple();
1125    py.end();
1126}
1127
1128void
1129Vector2dDataBase::python(Python &py) const
1130{
1131    const_cast<Vector2dDataBase *>(this)->update();
1132
1133    py.start("Vector2d");
1134    py.qarg(name);
1135    py.qqqarg(desc);
1136    py.kwarg("binned", binned());
1137    py.kwarg("precision", precision);
1138    py.kwarg("flags", flags);
1139    if (prereq)
1140        py.qkwarg("prereq", prereq->name);
1141
1142    py.kwarg("value", vec);
1143    if (!subnames.empty())
1144        py.qkwarg("subnames", subnames);
1145    if (!subdescs.empty())
1146        py.qkwarg("subdescs", subdescs);
1147    if (!y_subnames.empty())
1148        py.qkwarg("ysubnames", y_subnames);
1149
1150    py.kwarg("x", x);
1151    py.kwarg("y", y);
1152    py.end();
1153}
1154
1155void
1156FormulaBase::val(rvec_t &vec) const
1157{
1158    if (root)
1159        vec = root->val();
1160}
1161
1162result_t
1163FormulaBase::total() const
1164{
1165    return root ? root->total() : 0.0;
1166}
1167
1168size_t
1169FormulaBase::size() const
1170{
1171    if (!root)
1172        return 0;
1173    else
1174        return root->size();
1175}
1176
1177bool
1178FormulaBase::binned() const
1179{
1180    return root && root->binned();
1181}
1182
1183void
1184FormulaBase::reset()
1185{
1186}
1187
1188bool
1189FormulaBase::zero() const
1190{
1191    rvec_t vec;
1192    val(vec);
1193    for (int i = 0; i < vec.size(); ++i)
1194        if (vec[i] != 0.0)
1195            return false;
1196    return true;
1197}
1198
1199void
1200FormulaBase::update(StatData *)
1201{
1202}
1203
1204string
1205FormulaBase::str() const
1206{
1207    return root ? root->str() : "";
1208}
1209
1210Formula::Formula()
1211{
1212    setInit();
1213}
1214
1215Formula::Formula(Temp r)
1216{
1217    root = r;
1218    assert(size());
1219}
1220
1221const Formula &
1222Formula::operator=(Temp r)
1223{
1224    assert(!root && "Can't change formulas");
1225    root = r;
1226    assert(size());
1227    return *this;
1228}
1229
1230const Formula &
1231Formula::operator+=(Temp r)
1232{
1233    if (root)
1234        root = NodePtr(new BinaryNode<std::plus<result_t> >(root, r));
1235    else
1236        root = r;
1237    assert(size());
1238    return *this;
1239}
1240
1241MainBin::MainBin(const string &name)
1242    : _name(name), mem(NULL), memsize(-1)
1243{
1244    Database::StatDB().regBin(this, name);
1245}
1246
1247MainBin::~MainBin()
1248{
1249    if (mem)
1250        delete [] mem;
1251}
1252
1253char *
1254MainBin::memory(off_t off)
1255{
1256    if (memsize == -1)
1257        memsize = CeilPow2((size_t) offset());
1258
1259    if (!mem) {
1260        mem = new char[memsize];
1261        memset(mem, 0, memsize);
1262    }
1263
1264    assert(offset() <= size());
1265    return mem + off;
1266}
1267
1268void
1269check()
1270{
1271    Database::StatDB().check();
1272}
1273
1274void
1275dump(ostream &stream, DisplayMode mode)
1276{
1277    Database::StatDB().dump(stream, mode);
1278}
1279
1280void
1281python_start(const string &file)
1282{
1283    Database::StatDB().python_start(file);
1284}
1285
1286void
1287python_dump(const string &name, const string &subname)
1288{
1289    Database::StatDB().python_dump(name, subname);
1290}
1291
1292
1293CallbackQueue resetQueue;
1294
1295void
1296registerResetCallback(Callback *cb)
1297{
1298    resetQueue.add(cb);
1299}
1300
1301void
1302reset()
1303{
1304    Database::StatDB().reset();
1305    resetQueue.process();
1306}
1307
1308} // namespace Statistics
1309