statistics.cc revision 142
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 <math.h>
37
38#include "base/cprintf.hh"
39#include "base/intmath.hh"
40#include "base/misc.hh"
41#include "base/statistics.hh"
42#include "base/str.hh"
43#include "sim/universe.hh"
44
45#ifdef __M5_NAN
46float
47__nan()
48{
49    union {
50        uint32_t ui;
51        float f;
52    } nan;
53
54    nan.ui = 0x7fc00000;
55    return nan.f;
56}
57#endif
58
59#ifdef STAT_DEBUG
60static int total_stats = 0;
61#endif
62
63using namespace std;
64
65// This is a hack to get this parameter from the old stats package.
66namespace Statistics {
67bool PrintDescriptions = true;
68
69namespace Detail {
70/**
71 * Struct to contain a name and description of statistic subfield.
72 */
73struct SubData
74{
75    /** Subfield name. */
76    string name;
77    /** Subfield desc. */
78    string desc;
79};
80
81/**
82 * Struct to contain print data of a Stat.
83 */
84struct StatData
85{
86    /**
87     * Create this struct.
88     */
89    StatData();
90    /**
91     * Destructor.
92     */
93    ~StatData();
94
95    /** True if the stat has been initialized. */
96    bool init;
97    /** True if the stat should be printed. */
98    bool print;
99    /** The name of the stat. */
100    string name;
101    /** Names and descriptions of subfields. */
102    vector<SubData> *subdata;
103    /** The description of the stat. */
104    string desc;
105    /** The display precision. */
106    int precision;
107    /** The formatting flags. */
108    FormatFlags flags;
109    /** A pointer to a prerequisite Stat. */
110    const Stat *prereq;
111};
112
113StatData::StatData()
114    : init(false), print(false), subdata(NULL), precision(-1), flags(none),
115      prereq(NULL)
116{
117}
118
119StatData::~StatData()
120{
121    if (subdata)
122        delete subdata;
123}
124
125class Database
126{
127  private:
128    Database(const Database &) {}
129
130  private:
131    typedef list<Stat *> list_t;
132    typedef map<const Stat *, StatData *> map_t;
133
134    list<BinBase *> bins;
135    map<const BinBase *, std::string > bin_names;
136    list_t binnedStats;
137
138    list_t allStats;
139    list_t printStats;
140    map_t map;
141
142  public:
143    Database();
144    ~Database();
145
146    void dump(ostream &stream);
147
148    StatData *find(const Stat *stat);
149    void check();
150    void regStat(Stat *stat);
151    StatData *print(Stat *stat);
152    void regBin(BinBase *bin, std::string name);
153};
154
155Database::Database()
156{}
157
158Database::~Database()
159{}
160
161void
162Database::dump(ostream &stream)
163{
164
165    list_t::iterator i = printStats.begin();
166    list_t::iterator end = printStats.end();
167    while (i != end) {
168        Stat *stat = *i;
169        if (stat->binned())
170            binnedStats.push_back(stat);
171        ++i;
172    }
173
174    list<BinBase *>::iterator j = bins.begin();
175    list<BinBase *>::iterator bins_end=bins.end();
176
177    if (!bins.empty()) {
178        ccprintf(stream, "PRINTING BINNED STATS\n");
179        while (j != bins_end) {
180            (*j)->activate();
181           ::map<const BinBase  *, std::string>::const_iterator iter;
182            iter = bin_names.find(*j);
183            if (iter == bin_names.end())
184                panic("a binned stat not found in names map!");
185            ccprintf(stream,"---%s Bin------------\n", (*iter).second);
186
187           list_t::iterator i = binnedStats.begin();
188           list_t::iterator end = binnedStats.end();
189           while (i != end) {
190               Stat *stat = *i;
191               if (stat->dodisplay())
192                   stat->display(stream);
193               ++i;
194           }
195           ++j;
196           ccprintf(stream, "---------------------------------\n");
197        }
198    }
199
200    list_t::iterator k = printStats.begin();
201    list_t::iterator endprint = printStats.end();
202    ccprintf(stream, "*****ALL STATS*****\n");
203    while (k != endprint) {
204        Stat *stat = *k;
205        if (stat->dodisplay() && !stat->binned())
206            stat->display(stream);
207        ++k;
208    }
209}
210
211StatData *
212Database::find(const Stat *stat)
213{
214    map_t::const_iterator i = map.find(stat);
215
216    if (i == map.end())
217        return NULL;
218
219    return (*i).second;
220}
221
222void
223Database::check()
224{
225    list_t::iterator i = allStats.begin();
226    list_t::iterator end = allStats.end();
227
228    while (i != end) {
229        Stat *stat = *i;
230        StatData *data = find(stat);
231        if (!data || !data->init) {
232#ifdef STAT_DEBUG
233            cprintf("this is stat number %d\n",(*i)->number);
234#endif
235            panic("Not all stats have been initialized");
236        }
237
238        if (data->print) {
239            if (data->name.empty())
240                panic("all printable stats must be named");
241
242            list_t::iterator j = printStats.insert(printStats.end(), *i);
243            inplace_merge(printStats.begin(), j,
244                          printStats.end(), Stat::less);
245        }
246
247        ++i;
248    }
249}
250
251void
252Database::regStat(Stat *stat)
253{
254    if (map.find(stat) != map.end())
255        panic("shouldn't register stat twice!");
256
257    allStats.push_back(stat);
258
259    StatData *data = new StatData;
260    bool success = (map.insert(make_pair(stat, data))).second;
261    assert(map.find(stat) != map.end());
262    assert(success && "this should never fail");
263}
264
265void
266Database::regBin(BinBase *bin, std::string name)
267{
268    if (bin_names.find(bin) != bin_names.end())
269        panic("shouldn't register bin twice");
270
271    bins.push_back(bin);
272
273    bool success = (bin_names.insert(make_pair(bin,name))).second;
274    assert(bin_names.find(bin) != bin_names.end());
275    assert(success && "this should not fail");
276
277    cprintf("registering %s\n", name);
278}
279
280bool
281Stat::less(Stat *stat1, Stat *stat2)
282{
283    const string &name1 = stat1->myname();
284    const string &name2 = stat2->myname();
285
286    vector<string> v1;
287    vector<string> v2;
288
289    tokenize(v1, name1, '.');
290    tokenize(v2, name2, '.');
291
292    int last = min(v1.size(), v2.size()) - 1;
293    for (int i = 0; i < last; ++i)
294        if (v1[i] != v2[i])
295            return v1[i] < v2[i];
296
297    // Special compare for last element.
298    if (v1[last] == v2[last])
299        return v1.size() < v2.size();
300    else
301        return v1[last] < v2[last];
302
303    return false;
304}
305
306StatData *
307Database::print(Stat *stat)
308{
309    StatData *data = find(stat);
310    assert(data);
311
312    data->print = true;
313
314    return data;
315}
316
317Database &
318StatDB()
319{
320    static Database db;
321    return db;
322}
323
324Stat::Stat(bool reg)
325{
326#if 0
327    // This assert can help you find that pesky stat.
328    assert(this != (void *)0xbffff5c0);
329#endif
330
331    if (reg)
332        StatDB().regStat(this);
333
334#ifdef STAT_DEBUG
335    number = ++total_stats;
336    cprintf("I'm stat number %d\n",number);
337#endif
338}
339
340void
341Stat::setInit()
342{ mydata()->init = true; }
343
344StatData *
345Stat::mydata()
346{
347    StatData *data = StatDB().find(this);
348    assert(data);
349
350    return data;
351}
352
353const StatData *
354Stat::mydata() const
355{
356    StatData *data = StatDB().find(this);
357    assert(data);
358
359    return data;
360}
361
362const SubData *
363Stat::mysubdata(int index) const
364{
365    assert(index >= 0);
366    if (index >= size())
367        return NULL;
368
369    const StatData *data = this->mydata();
370    if (!data->subdata || data->subdata->size() <= index)
371        return NULL;
372
373    return &(*data->subdata)[index];
374}
375
376SubData *
377Stat::mysubdata_create(int index)
378{
379    int size = this->size();
380    assert(index >= 0 && (size == 0 || size > 0 && index < size));
381
382    StatData *data = this->mydata();
383    if (!data->subdata) {
384        if (!data->subdata) {
385            if (size == 0)
386                size = index + 1;
387
388            data->subdata = new vector<SubData>(size);
389        }
390    } else if (data->subdata->size() <= index)
391            data->subdata->resize(index + 1);
392
393    SubData *sd = &(*data->subdata)[index];
394    assert(sd);
395
396    return sd;
397}
398
399string
400Stat::myname() const
401{ return mydata()->name; }
402
403string
404Stat::mysubname(int index) const
405{
406    const SubData *sd = mysubdata(index);
407    return sd ? sd->name : "";
408}
409
410string
411Stat::mydesc() const
412{ return mydata()->desc; }
413
414string
415Stat::mysubdesc(int index) const
416{
417    const SubData *sd = mysubdata(index);
418    return sd ? sd->desc : "";
419}
420
421int
422Stat::myprecision() const
423{ return mydata()->precision; }
424
425FormatFlags
426Stat::myflags() const
427{ return mydata()->flags; }
428
429bool
430Stat::dodisplay() const
431{ return !mydata()->prereq || !mydata()->prereq->zero(); }
432
433StatData *
434Stat::print()
435{
436    StatData *data = StatDB().print(this);
437    assert(data && data->init);
438
439    return data;
440}
441
442Stat &
443Stat::name(const string &name)
444{
445    print()->name = name;
446    return *this;
447}
448
449Stat &
450Stat::desc(const string &desc)
451{
452    print()->desc = desc;
453    return *this;
454}
455
456Stat &
457Stat::precision(int precision)
458{
459    print()->precision = precision;
460    return *this;
461}
462
463Stat &
464Stat::flags(FormatFlags flags)
465{
466    if (flags & __reserved)
467        panic("Cannot set reserved flags!\n");
468
469    print()->flags |= flags;
470    return *this;
471}
472
473Stat &
474Stat::prereq(const Stat &prereq)
475{
476    print()->prereq = &prereq;
477    return *this;
478}
479
480Stat &
481Stat::subname(int index, const string &name)
482{
483    print();
484    mysubdata_create(index)->name = name;
485    return *this;
486}
487Stat &
488Stat::subdesc(int index, const string &desc)
489{
490    print();
491    mysubdata_create(index)->desc = desc;
492    return *this;
493}
494
495bool
496ScalarStat::zero() const
497{
498    return val() == 0.0;
499}
500
501bool
502VectorStat::zero() const
503{
504    return val()[0] == 0.0;
505}
506
507string
508ValueToString(result_t value, int precision)
509{
510    stringstream val;
511
512    if (!isnan(value)) {
513        if (precision != -1)
514            val.precision(precision);
515        else if (value == rint(value))
516            val.precision(0);
517
518        val.unsetf(ios::showpoint);
519        val.setf(ios::fixed);
520        val << value;
521    } else {
522#ifndef STAT_DISPLAY_COMPAT
523        val << "no value";
524#else
525        val << "<err: div-0>";
526#endif
527    }
528
529    return val.str();
530}
531
532void
533PrintOne(ostream &stream, result_t value,
534         const string &name, const string &desc, int precision,
535         FormatFlags flags, result_t pdf = NAN, result_t cdf = NAN)
536{
537    if (flags & nozero && value == 0.0 ||
538        flags & nonan && isnan(value))
539        return;
540
541    stringstream pdfstr, cdfstr;
542
543    if (!isnan(pdf))
544        ccprintf(pdfstr, "%.2f%%", pdf * 100.0);
545
546    if (!isnan(cdf))
547        ccprintf(cdfstr, "%.2f%%", cdf * 100.0);
548
549#ifdef STAT_DISPLAY_COMPAT
550    if (flags & __substat) {
551        ccprintf(stream, "%32s%12s%10s%10s", name,
552                 ValueToString(value, precision),
553                 pdfstr, cdfstr);
554    } else
555#endif
556    {
557        ccprintf(stream, "%-40s%12s%10s%10s", name,
558                 ValueToString(value, precision), pdfstr, cdfstr);
559    }
560
561    if (PrintDescriptions) {
562        if (!desc.empty())
563            ccprintf(stream, " # %s", desc);
564    }
565    stream << endl;
566}
567
568void
569ScalarStat::display(ostream &stream) const
570{
571    PrintOne(stream, val(), myname(), mydesc(), myprecision(), myflags());
572}
573
574void
575VectorStat::display(ostream &stream) const
576{
577    bool have_subname = false;
578    bool have_subdesc = false;
579    int size = this->size();
580    for (int i = 0; i < size; ++i) {
581        if (!mysubname(i).empty())
582            have_subname = true;
583        if (!mysubdesc(i).empty())
584            have_subdesc = true;
585    }
586
587    vector<string> *subnames = 0;
588    vector<string> *subdescs = 0;
589    if (have_subname) {
590        subnames = new vector<string>(size);
591        for (int i = 0; i < size; ++i)
592            (*subnames)[i] = mysubname(i);
593    }
594    if (have_subdesc) {
595        subdescs = new vector<string>(size);
596        for (int i = 0; i < size; ++i)
597            (*subdescs)[i] = mysubdesc(i);
598    }
599
600    VectorDisplay(stream, myname(), subnames, mydesc(), subdescs,
601                  myprecision(), myflags(), val(), total());
602}
603
604#ifndef STAT_DISPLAY_COMPAT
605#define NAMESEP "::"
606#else
607#define NAMESEP "_"
608#endif
609
610#ifndef STAT_DISPLAY_COMPAT
611void
612VectorDisplay(std::ostream &stream,
613              const std::string &myname,
614              const std::vector<std::string> *mysubnames,
615              const std::string &mydesc,
616              const std::vector<std::string> *mysubdescs,
617              int myprecision, FormatFlags myflags,
618              const rvec_t &vec, result_t mytotal)
619{
620    int _size = vec.size();
621    result_t _total = 0.0;
622    result_t _pdf, _cdf = 0.0;
623
624    if (myflags & (pdf | cdf)) {
625        for (int i = 0; i < _size; ++i) {
626            _total += vec[i];
627        }
628    }
629
630    if (_size == 1) {
631        PrintOne(stream, vec[0], myname, mydesc, myprecision, myflags);
632    } else {
633        for (int i = 0; i < _size; ++i) {
634            string subname;
635            if (mysubnames) {
636                subname = (*mysubnames)[i];
637                if (subname.empty())
638                    continue;
639            } else {
640                subname = to_string(i);
641            }
642
643            string name = myname + NAMESEP + subname;
644            if (!(myflags & pdf))
645                PrintOne(stream, vec[i], name, mydesc, myprecision, myflags);
646            else {
647                _pdf = vec[i] / _total;
648                _cdf += _pdf;
649                PrintOne(stream, vec[i], name, mydesc, myprecision, myflags,
650                         _pdf, _cdf);
651            }
652        }
653
654        if (myflags & total)
655            PrintOne(stream, mytotal, myname + NAMESEP + "total",
656                     mydesc, myprecision, myflags);
657    }
658}
659#else
660void
661VectorDisplay(std::ostream &stream,
662              const std::string &myname,
663              const std::vector<std::string> *mysubnames,
664              const std::string &mydesc,
665              const std::vector<std::string> *mysubdescs,
666              int myprecision, FormatFlags myflags,
667              const rvec_t &vec, result_t mytotal)
668{
669    int _size = vec.size();
670    result_t _total = 0.0;
671    result_t _pdf, _cdf = 0.0;
672
673    if (myflags & (pdf | cdf)) {
674        for (int i = 0; i < _size; ++i) {
675            _total += vec[i];
676        }
677    }
678
679    if (_size == 1) {
680        PrintOne(stream, vec[0], myname, mydesc, myprecision, myflags);
681    } else {
682        if (myflags & total)
683            PrintOne(stream, mytotal, myname, mydesc, myprecision, myflags);
684
685        if (myflags & dist) {
686            ccprintf(stream, "%s.start_dist\n", myname);
687            for (int i = 0; i < _size; ++i) {
688                string subname, subdesc;
689                subname = to_string(i);
690                if (mysubnames) {
691                    if (!subname.empty()) {
692                        subname = (*mysubnames)[i];
693                    }
694                }
695                if (mysubdescs) {
696                    subdesc = (*mysubdescs)[i];
697                }
698                if (!(myflags & (pdf | cdf))) {
699                    PrintOne(stream, vec[i], subname, subdesc, myprecision,
700                             myflags | __substat);
701                } else {
702                    if (_total) {
703                        _pdf = vec[i] / _total;
704                        _cdf += _pdf;
705                    } else {
706                        _pdf = _cdf = 0.0;
707                    }
708                    if (!(myflags & cdf)) {
709                        PrintOne(stream, vec[i], subname, subdesc, myprecision,
710                                 myflags | __substat, _pdf);
711                    } else {
712                        PrintOne(stream, vec[i], subname, subdesc, myprecision,
713                                 myflags | __substat, _pdf, _cdf);
714                    }
715                }
716            }
717            ccprintf(stream, "%s.end_dist\n", myname);
718        } else {
719            for (int i = 0; i < _size; ++i) {
720                string subname;
721                if (mysubnames) {
722                    subname = (*mysubnames)[i];
723                    if (subname.empty())
724                        continue;
725                } else {
726                    subname = to_string(i);
727                }
728
729                string name = myname + NAMESEP + subname;
730                if (!(myflags & pdf)) {
731                    PrintOne(stream, vec[i], name, mydesc, myprecision,
732                             myflags);
733                } else {
734                    if (_total) {
735                        _pdf = vec[i] / _total;
736                        _cdf += _pdf;
737                    } else {
738                        _pdf = _cdf = 0.0;
739                    }
740                    _pdf = vec[i] / _total;
741                    _cdf += _pdf;
742                    PrintOne(stream, vec[i], name, mydesc, myprecision,
743                             myflags, _pdf, _cdf);
744                }
745            }
746        }
747    }
748}
749#endif
750
751#ifndef STAT_DISPLAY_COMPAT
752void
753DistDisplay(ostream &stream, const string &name, const string &desc,
754            int precision, FormatFlags flags,
755            result_t min_val, result_t max_val,
756            result_t underflow, result_t overflow,
757            const rvec_t &vec, int min, int max, int bucket_size, int size);
758{
759    assert(size == vec.size());
760
761    result_t total = 0.0;
762    result_t pdf, cdf = 0.0;
763
764    total += underflow;
765    for (int i = 0; i < size; ++i)
766        total += vec[i];
767    total += overflow;
768
769    pdf = underflow / total;
770    cdf += pdf;
771
772    PrintOne(stream, underflow, name + NAMESEP + "underflow", desc,
773             precision, myflags, pdf, cdf);
774
775    for (int i = 0; i < size; ++i) {
776        stringstream namestr;
777        namestr << name;
778
779        int low = i * bucket_size + min;
780        int high = ::std::min((i + 1) * bucket_size + min - 1, max);
781        namestr << low;
782        if (low < high)
783            namestr << "-" << high;
784
785        pdf = vec[i] / total;
786        cdf += pdf;
787        PrintOne(stream, vec[i], namestr.str(), desc, precision, myflags,
788                 pdf, cdf);
789    }
790
791    pdf = overflow / total;
792    cdf += pdf;
793    PrintOne(stream, overflow, name + NAMESEP + "overflow", desc,
794             precision, myflags, pdf, cdf);
795    PrintOne(stream, total, name + NAMESEP + "total", desc,
796             precision, myflags);
797}
798#else
799void
800DistDisplay(ostream &stream, const string &name, const string &desc,
801            int precision, FormatFlags flags,
802            result_t min_val, result_t max_val,
803            result_t underflow, result_t overflow,
804            const rvec_t &vec, int min, int max, int bucket_size, int size)
805{
806    assert(size == vec.size());
807    string blank;
808
809    result_t total = 0.0;
810
811    total += underflow;
812    for (int i = 0; i < size; ++i)
813        total += vec[i];
814    total += overflow;
815
816    ccprintf(stream, "%-42s", name + ".start_dist");
817    if (PrintDescriptions && !desc.empty())
818        ccprintf(stream, "                     # %s", desc);
819    stream << endl;
820
821    PrintOne(stream, total, name + ".samples", blank, precision, flags);
822    PrintOne(stream, min_val, name + ".min_value", blank, precision, flags);
823
824    if (underflow > 0)
825        PrintOne(stream, min_val, name + ".underflows", blank, precision,
826                 flags);
827
828    int _min;
829    result_t _pdf, _cdf, mypdf, mycdf;
830
831    _cdf = 0.0;
832    for (int i = 0; i < size; ++i) {
833        if (flags & nozero && vec[i] == 0.0 ||
834            flags & nonan && isnan(vec[i]))
835            return;
836
837        _min = i * bucket_size + min;
838        _pdf = vec[i] / total * 100.0;
839        _cdf += _pdf;
840
841        mypdf = (flags & pdf) ? _pdf : NAN;
842        mycdf = (flags & cdf) ? _cdf : NAN;
843
844        PrintOne(stream, vec[i], ValueToString(_min, 0), blank, precision,
845                 flags | __substat, mypdf, mycdf);
846    }
847
848    if (overflow > 0)
849        PrintOne(stream, overflow, name + ".overflows", blank, precision,
850                 flags);
851    PrintOne(stream, max_val, name + ".max_value", blank, precision, flags);
852    ccprintf(stream, "%s.end_dist\n\n", name);
853}
854#endif
855
856void
857FancyDisplay(ostream &stream, const string &name, const string &desc,
858             int precision, FormatFlags flags, result_t mean,
859             result_t variance)
860{
861    result_t stdev = isnan(variance) ? NAN : sqrt(variance);
862    PrintOne(stream, mean, name + NAMESEP + "mean", desc, precision, flags);
863    PrintOne(stream, stdev, name + NAMESEP + "stdev", desc, precision, flags);
864}
865
866BinBase::BinBase(size_t size)
867    : memsize(CeilPow2(size)), mem(NULL)
868{
869}
870
871BinBase::~BinBase()
872{
873    if (mem)
874        delete [] mem;
875}
876
877char *
878BinBase::memory()
879{
880    if (!mem) {
881        mem = new char[memsize];
882        memset(mem, 0, memsize);
883    }
884
885    return mem;
886}
887
888void
889BinBase::regBin(BinBase *bin, std::string name)
890{
891    StatDB().regBin(bin, name);
892}
893
894} // namespace Detail
895
896void
897check()
898{
899    Detail::StatDB().check();
900}
901
902void
903dump(ostream &stream)
904{
905    Detail::StatDB().dump(stream);
906}
907
908} // namespace Statistics
909