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