2 * Copyright (c) 2003 The Regents of The University of Michigan
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.
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.
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"
61 static int total_stats
= 0;
66 // This is a hack to get this parameter from the old stats package.
67 namespace Statistics
{
68 bool PrintDescriptions
= true;
72 * Struct to contain a name and description of statistic subfield.
83 * Struct to contain print data of a Stat.
96 /** True if the stat has been initialized. */
98 /** True if the stat should be printed. */
100 /** The name of the stat. */
102 /** Names and descriptions of subfields. */
103 vector
<SubData
> *subdata
;
104 /** The description of the stat. */
106 /** The display precision. */
108 /** The formatting flags. */
110 /** A pointer to a prerequisite Stat. */
115 : init(false), print(false), subdata(NULL
), precision(-1), flags(none
),
120 StatData::~StatData()
129 Database(const Database
&) {}
132 typedef list
<Stat
*> list_t
;
133 typedef map
<const Stat
*, StatData
*> map_t
;
135 list
<BinBase
*> bins
;
136 map
<const BinBase
*, std::string
> bin_names
;
147 void dump(ostream
&stream
);
149 StatData
*find(const Stat
*stat
);
152 void regStat(Stat
*stat
);
153 StatData
*print(Stat
*stat
);
154 void regBin(BinBase
*bin
, std::string name
);
160 Database::~Database()
164 Database::dump(ostream
&stream
)
167 list_t::iterator i
= printStats
.begin();
168 list_t::iterator end
= printStats
.end();
172 binnedStats
.push_back(stat
);
176 list
<BinBase
*>::iterator j
= bins
.begin();
177 list
<BinBase
*>::iterator bins_end
=bins
.end();
180 ccprintf(stream
, "PRINTING BINNED STATS\n");
181 while (j
!= bins_end
) {
183 ::map
<const BinBase
*, std::string
>::const_iterator iter
;
184 iter
= bin_names
.find(*j
);
185 if (iter
== bin_names
.end())
186 panic("a binned stat not found in names map!");
187 ccprintf(stream
,"---%s Bin------------\n", (*iter
).second
);
189 list_t::iterator i
= binnedStats
.begin();
190 list_t::iterator end
= binnedStats
.end();
193 if (stat
->dodisplay())
194 stat
->display(stream
);
198 ccprintf(stream
, "---------------------------------\n");
200 ccprintf(stream
, "**************ALL STATS************\n");
203 list_t::iterator k
= printStats
.begin();
204 list_t::iterator endprint
= printStats
.end();
205 while (k
!= endprint
) {
207 if (stat
->dodisplay() && !stat
->binned())
208 stat
->display(stream
);
214 Database::find(const Stat
*stat
)
216 map_t::const_iterator i
= map
.find(stat
);
227 list_t::iterator i
= allStats
.begin();
228 list_t::iterator end
= allStats
.end();
232 StatData
*data
= find(stat
);
233 if (!data
|| !data
->init
) {
235 cprintf("this is stat number %d\n",(*i
)->number
);
237 panic("Not all stats have been initialized");
241 if (data
->name
.empty())
242 panic("all printable stats must be named");
244 list_t::iterator j
= printStats
.insert(printStats
.end(), *i
);
245 inplace_merge(printStats
.begin(), j
,
246 printStats
.end(), Stat::less
);
256 list_t::iterator i
= allStats
.begin();
257 list_t::iterator end
= allStats
.end();
266 Database::regStat(Stat
*stat
)
268 if (map
.find(stat
) != map
.end())
269 panic("shouldn't register stat twice!");
271 allStats
.push_back(stat
);
273 StatData
*data
= new StatData
;
274 bool success
= (map
.insert(make_pair(stat
, data
))).second
;
275 assert(map
.find(stat
) != map
.end());
276 assert(success
&& "this should never fail");
280 Database::regBin(BinBase
*bin
, std::string name
)
282 if (bin_names
.find(bin
) != bin_names
.end())
283 panic("shouldn't register bin twice");
287 bool success
= (bin_names
.insert(make_pair(bin
,name
))).second
;
288 assert(bin_names
.find(bin
) != bin_names
.end());
289 assert(success
&& "this should not fail");
291 cprintf("registering %s\n", name
);
295 Stat::less(Stat
*stat1
, Stat
*stat2
)
297 const string
&name1
= stat1
->myname();
298 const string
&name2
= stat2
->myname();
303 tokenize(v1
, name1
, '.');
304 tokenize(v2
, name2
, '.');
306 int last
= min(v1
.size(), v2
.size()) - 1;
307 for (int i
= 0; i
< last
; ++i
)
309 return v1
[i
] < v2
[i
];
311 // Special compare for last element.
312 if (v1
[last
] == v2
[last
])
313 return v1
.size() < v2
.size();
315 return v1
[last
] < v2
[last
];
321 Database::print(Stat
*stat
)
323 StatData
*data
= find(stat
);
341 // This assert can help you find that pesky stat.
342 assert(this != (void *)0xbffff5c0);
346 StatDB().regStat(this);
349 number
= ++total_stats
;
350 cprintf("I'm stat number %d\n",number
);
356 { mydata()->init
= true; }
361 StatData
*data
= StatDB().find(this);
370 StatData
*data
= StatDB().find(this);
377 Stat::mysubdata(int index
) const
383 const StatData
*data
= this->mydata();
384 if (!data
->subdata
|| data
->subdata
->size() <= index
)
387 return &(*data
->subdata
)[index
];
391 Stat::mysubdata_create(int index
)
393 int size
= this->size();
394 assert(index
>= 0 && (size
== 0 || size
> 0 && index
< size
));
396 StatData
*data
= this->mydata();
397 if (!data
->subdata
) {
398 if (!data
->subdata
) {
402 data
->subdata
= new vector
<SubData
>(size
);
404 } else if (data
->subdata
->size() <= index
)
405 data
->subdata
->resize(index
+ 1);
407 SubData
*sd
= &(*data
->subdata
)[index
];
415 { return mydata()->name
; }
418 Stat::mysubname(int index
) const
420 const SubData
*sd
= mysubdata(index
);
421 return sd
? sd
->name
: "";
426 { return mydata()->desc
; }
429 Stat::mysubdesc(int index
) const
431 const SubData
*sd
= mysubdata(index
);
432 return sd
? sd
->desc
: "";
436 Stat::myprecision() const
437 { return mydata()->precision
; }
440 Stat::myflags() const
441 { return mydata()->flags
; }
444 Stat::dodisplay() const
445 { return !mydata()->prereq
|| !mydata()->prereq
->zero(); }
450 StatData
*data
= StatDB().print(this);
451 assert(data
&& data
->init
);
457 Stat::name(const string
&name
)
459 print()->name
= name
;
464 Stat::desc(const string
&desc
)
466 print()->desc
= desc
;
471 Stat::precision(int precision
)
473 print()->precision
= precision
;
478 Stat::flags(FormatFlags flags
)
480 if (flags
& __reserved
)
481 panic("Cannot set reserved flags!\n");
483 print()->flags
|= flags
;
488 Stat::prereq(const Stat
&prereq
)
490 print()->prereq
= &prereq
;
495 Stat::subname(int index
, const string
&name
)
498 mysubdata_create(index
)->name
= name
;
502 Stat::subdesc(int index
, const string
&desc
)
505 mysubdata_create(index
)->desc
= desc
;
510 ScalarStat::zero() const
516 VectorStat::zero() const
518 return val()[0] == 0.0;
522 ValueToString(result_t value
, int precision
)
528 val
.precision(precision
);
529 else if (value
== rint(value
))
532 val
.unsetf(ios::showpoint
);
533 val
.setf(ios::fixed
);
536 #ifndef STAT_DISPLAY_COMPAT
539 val
<< "<err: div-0>";
547 PrintOne(ostream
&stream
, result_t value
,
548 const string
&name
, const string
&desc
, int precision
,
549 FormatFlags flags
, result_t pdf
= NAN
, result_t cdf
= NAN
)
551 if (flags
& nozero
&& value
== 0.0 ||
552 flags
& nonan
&& isnan(value
))
555 stringstream pdfstr
, cdfstr
;
558 ccprintf(pdfstr
, "%.2f%%", pdf
* 100.0);
561 ccprintf(cdfstr
, "%.2f%%", cdf
* 100.0);
563 #ifdef STAT_DISPLAY_COMPAT
564 if (flags
& __substat
) {
565 ccprintf(stream
, "%32s%12s%10s%10s", name
,
566 ValueToString(value
, precision
),
571 ccprintf(stream
, "%-40s%12s%10s%10s", name
,
572 ValueToString(value
, precision
), pdfstr
, cdfstr
);
575 if (PrintDescriptions
) {
577 ccprintf(stream
, " # %s", desc
);
583 ScalarStat::display(ostream
&stream
) const
585 PrintOne(stream
, val(), myname(), mydesc(), myprecision(), myflags());
589 VectorStat::display(ostream
&stream
) const
591 bool have_subname
= false;
592 bool have_subdesc
= false;
593 int size
= this->size();
594 for (int i
= 0; i
< size
; ++i
) {
595 if (!mysubname(i
).empty())
597 if (!mysubdesc(i
).empty())
601 vector
<string
> *subnames
= 0;
602 vector
<string
> *subdescs
= 0;
604 subnames
= new vector
<string
>(size
);
605 for (int i
= 0; i
< size
; ++i
)
606 (*subnames
)[i
] = mysubname(i
);
609 subdescs
= new vector
<string
>(size
);
610 for (int i
= 0; i
< size
; ++i
)
611 (*subdescs
)[i
] = mysubdesc(i
);
614 VectorDisplay(stream
, myname(), subnames
, mydesc(), subdescs
,
615 myprecision(), myflags(), val(), total());
618 #ifndef STAT_DISPLAY_COMPAT
624 #ifndef STAT_DISPLAY_COMPAT
626 VectorDisplay(std::ostream
&stream
,
627 const std::string
&myname
,
628 const std::vector
<std::string
> *mysubnames
,
629 const std::string
&mydesc
,
630 const std::vector
<std::string
> *mysubdescs
,
631 int myprecision
, FormatFlags myflags
,
632 const rvec_t
&vec
, result_t mytotal
)
634 int _size
= vec
.size();
635 result_t _total
= 0.0;
636 result_t _pdf
, _cdf
= 0.0;
638 if (myflags
& (pdf
| cdf
)) {
639 for (int i
= 0; i
< _size
; ++i
) {
645 PrintOne(stream
, vec
[0], myname
, mydesc
, myprecision
, myflags
);
647 for (int i
= 0; i
< _size
; ++i
) {
650 subname
= (*mysubnames
)[i
];
654 subname
= to_string(i
);
657 string name
= myname
+ NAMESEP
+ subname
;
658 if (!(myflags
& pdf
))
659 PrintOne(stream
, vec
[i
], name
, mydesc
, myprecision
, myflags
);
661 _pdf
= vec
[i
] / _total
;
663 PrintOne(stream
, vec
[i
], name
, mydesc
, myprecision
, myflags
,
669 PrintOne(stream
, mytotal
, myname
+ NAMESEP
+ "total",
670 mydesc
, myprecision
, myflags
);
675 VectorDisplay(std::ostream
&stream
,
676 const std::string
&myname
,
677 const std::vector
<std::string
> *mysubnames
,
678 const std::string
&mydesc
,
679 const std::vector
<std::string
> *mysubdescs
,
680 int myprecision
, FormatFlags myflags
,
681 const rvec_t
&vec
, result_t mytotal
)
683 int _size
= vec
.size();
684 result_t _total
= 0.0;
685 result_t _pdf
, _cdf
= 0.0;
687 if (myflags
& (pdf
| cdf
)) {
688 for (int i
= 0; i
< _size
; ++i
) {
694 PrintOne(stream
, vec
[0], myname
, mydesc
, myprecision
, myflags
);
697 PrintOne(stream
, mytotal
, myname
, mydesc
, myprecision
, myflags
);
699 if (myflags
& dist
) {
700 ccprintf(stream
, "%s.start_dist\n", myname
);
701 for (int i
= 0; i
< _size
; ++i
) {
702 string subname
, subdesc
;
703 subname
= to_string(i
);
705 if (!subname
.empty()) {
706 subname
= (*mysubnames
)[i
];
710 subdesc
= (*mysubdescs
)[i
];
712 if (!(myflags
& (pdf
| cdf
))) {
713 PrintOne(stream
, vec
[i
], subname
, subdesc
, myprecision
,
714 myflags
| __substat
);
717 _pdf
= vec
[i
] / _total
;
722 if (!(myflags
& cdf
)) {
723 PrintOne(stream
, vec
[i
], subname
, subdesc
, myprecision
,
724 myflags
| __substat
, _pdf
);
726 PrintOne(stream
, vec
[i
], subname
, subdesc
, myprecision
,
727 myflags
| __substat
, _pdf
, _cdf
);
731 ccprintf(stream
, "%s.end_dist\n", myname
);
733 for (int i
= 0; i
< _size
; ++i
) {
736 subname
= (*mysubnames
)[i
];
740 subname
= to_string(i
);
743 string name
= myname
+ NAMESEP
+ subname
;
744 if (!(myflags
& pdf
)) {
745 PrintOne(stream
, vec
[i
], name
, mydesc
, myprecision
,
749 _pdf
= vec
[i
] / _total
;
754 _pdf
= vec
[i
] / _total
;
756 PrintOne(stream
, vec
[i
], name
, mydesc
, myprecision
,
757 myflags
, _pdf
, _cdf
);
765 #ifndef STAT_DISPLAY_COMPAT
767 DistDisplay(ostream
&stream
, const string
&name
, const string
&desc
,
768 int precision
, FormatFlags flags
,
769 result_t min_val
, result_t max_val
,
770 result_t underflow
, result_t overflow
,
771 const rvec_t
&vec
, int min
, int max
, int bucket_size
, int size
);
773 assert(size
== vec
.size());
775 result_t total
= 0.0;
776 result_t pdf
, cdf
= 0.0;
779 for (int i
= 0; i
< size
; ++i
)
783 pdf
= underflow
/ total
;
786 PrintOne(stream
, underflow
, name
+ NAMESEP
+ "underflow", desc
,
787 precision
, myflags
, pdf
, cdf
);
789 for (int i
= 0; i
< size
; ++i
) {
790 stringstream namestr
;
793 int low
= i
* bucket_size
+ min
;
794 int high
= ::std::min((i
+ 1) * bucket_size
+ min
- 1, max
);
797 namestr
<< "-" << high
;
799 pdf
= vec
[i
] / total
;
801 PrintOne(stream
, vec
[i
], namestr
.str(), desc
, precision
, myflags
,
805 pdf
= overflow
/ total
;
807 PrintOne(stream
, overflow
, name
+ NAMESEP
+ "overflow", desc
,
808 precision
, myflags
, pdf
, cdf
);
809 PrintOne(stream
, total
, name
+ NAMESEP
+ "total", desc
,
814 DistDisplay(ostream
&stream
, const string
&name
, const string
&desc
,
815 int precision
, FormatFlags flags
,
816 result_t min_val
, result_t max_val
,
817 result_t underflow
, result_t overflow
,
818 const rvec_t
&vec
, int min
, int max
, int bucket_size
, int size
)
820 assert(size
== vec
.size());
823 result_t total
= 0.0;
826 for (int i
= 0; i
< size
; ++i
)
830 ccprintf(stream
, "%-42s", name
+ ".start_dist");
831 if (PrintDescriptions
&& !desc
.empty())
832 ccprintf(stream
, " # %s", desc
);
835 PrintOne(stream
, total
, name
+ ".samples", blank
, precision
, flags
);
836 PrintOne(stream
, min_val
, name
+ ".min_value", blank
, precision
, flags
);
839 PrintOne(stream
, min_val
, name
+ ".underflows", blank
, precision
,
843 result_t _pdf
, _cdf
, mypdf
, mycdf
;
846 for (int i
= 0; i
< size
; ++i
) {
847 if (flags
& nozero
&& vec
[i
] == 0.0 ||
848 flags
& nonan
&& isnan(vec
[i
]))
851 _min
= i
* bucket_size
+ min
;
852 _pdf
= vec
[i
] / total
* 100.0;
855 mypdf
= (flags
& pdf
) ? _pdf
: NAN
;
856 mycdf
= (flags
& cdf
) ? _cdf
: NAN
;
858 PrintOne(stream
, vec
[i
], ValueToString(_min
, 0), blank
, precision
,
859 flags
| __substat
, mypdf
, mycdf
);
863 PrintOne(stream
, overflow
, name
+ ".overflows", blank
, precision
,
865 PrintOne(stream
, max_val
, name
+ ".max_value", blank
, precision
, flags
);
866 ccprintf(stream
, "%s.end_dist\n\n", name
);
871 FancyDisplay(ostream
&stream
, const string
&name
, const string
&desc
,
872 int precision
, FormatFlags flags
, result_t mean
,
875 result_t stdev
= isnan(variance
) ? NAN
: sqrt(variance
);
876 PrintOne(stream
, mean
, name
+ NAMESEP
+ "mean", desc
, precision
, flags
);
877 PrintOne(stream
, stdev
, name
+ NAMESEP
+ "stdev", desc
, precision
, flags
);
880 BinBase::BinBase(size_t size
)
881 : memsize(CeilPow2(size
)), mem(NULL
)
895 mem
= new char[memsize
];
896 memset(mem
, 0, memsize
);
903 BinBase::regBin(BinBase
*bin
, std::string name
)
905 StatDB().regBin(bin
, name
);
908 } // namespace Detail
913 Detail::StatDB().check();
917 dump(ostream
&stream
)
919 Detail::StatDB().dump(stream
);
922 CallbackQueue resetQueue
;
925 regReset(Callback
*cb
)
933 Detail::StatDB().reset();
934 resetQueue
.process();
937 } // namespace Statistics