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