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.
36 #include "base/callback.hh"
37 #include "base/cprintf.hh"
38 #include "base/misc.hh"
39 #include "base/statistics.hh"
40 #include "base/str.hh"
41 #include "sim/universe.hh"
58 static int total_stats
= 0;
63 // This is a hack to get this parameter from the old stats package.
64 namespace Statistics
{
65 bool PrintDescriptions
= true;
69 * Struct to contain a name and description of statistic subfield.
80 * Struct to contain print data of a Stat.
93 /** True if the stat has been initialized. */
95 /** True if the stat should be printed. */
97 /** The name of the stat. */
99 /** Names and descriptions of subfields. */
100 vector
<SubData
> *subdata
;
101 /** The description of the stat. */
103 /** The display precision. */
105 /** The formatting flags. */
107 /** A pointer to a prerequisite Stat. */
112 : init(false), print(false), subdata(NULL
), precision(-1), flags(none
),
117 StatData::~StatData()
126 Database(const Database
&) {}
129 typedef list
<Stat
*> list_t
;
130 typedef map
<const Stat
*, StatData
*> map_t
;
132 list
<MainBin
*> bins
;
133 map
<const MainBin
*, std::string
> bin_names
;
144 void dump(ostream
&stream
);
146 StatData
*find(const Stat
*stat
);
149 void regStat(Stat
*stat
);
150 StatData
*print(Stat
*stat
);
151 void regBin(MainBin
*bin
, std::string name
);
157 Database::~Database()
161 Database::dump(ostream
&stream
)
164 list_t::iterator i
= printStats
.begin();
165 list_t::iterator end
= printStats
.end();
169 binnedStats
.push_back(stat
);
174 list
<MainBin
*>::iterator j
= bins
.begin();
175 list
<MainBin
*>::iterator bins_end
=bins
.end();
178 ccprintf(stream
, "PRINTING BINNED STATS\n");
179 while (j
!= bins_end
) {
181 map
<const MainBin
*, 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
);
188 list_t::iterator i
= printStats
.begin();
189 list_t::iterator end
= printStats
.end();
191 list_t::iterator i
= binnedStats
.begin();
192 list_t::iterator end
= binnedStats
.end();
196 if (stat
->dodisplay())
197 stat
->display(stream
);
201 ccprintf(stream
, "---------------------------------\n");
204 ccprintf(stream
, "**************ALL STATS************\n");
209 * get bin totals working, then print the stat here (as total), even if
210 * its' binned. (this is only for the case you selectively bin a few stats
213 list_t::iterator k
= printStats
.begin();
214 list_t::iterator endprint
= printStats
.end();
215 while (k
!= endprint
) {
217 if (stat
->dodisplay() && !stat
->binned())
218 stat
->display(stream
);
225 Database::find(const Stat
*stat
)
227 map_t::const_iterator i
= statMap
.find(stat
);
229 if (i
== statMap
.end())
238 list_t::iterator i
= allStats
.begin();
239 list_t::iterator end
= allStats
.end();
243 StatData
*data
= find(stat
);
244 if (!data
|| !data
->init
) {
246 cprintf("this is stat number %d\n",(*i
)->number
);
248 panic("Not all stats have been initialized");
252 if (data
->name
.empty())
253 panic("all printable stats must be named");
255 list_t::iterator j
= printStats
.insert(printStats
.end(), *i
);
256 inplace_merge(printStats
.begin(), j
,
257 printStats
.end(), Stat::less
);
267 list_t::iterator i
= allStats
.begin();
268 list_t::iterator end
= allStats
.end();
275 MainBin
*orig
= MainBin::curBin();
277 list
<MainBin
*>::iterator bi
= bins
.begin();
278 list
<MainBin
*>::iterator be
= bins
.end();
283 i
= allStats
.begin();
297 Database::regStat(Stat
*stat
)
299 if (statMap
.find(stat
) != statMap
.end())
300 panic("shouldn't register stat twice!");
302 allStats
.push_back(stat
);
304 StatData
*data
= new StatData
;
305 bool success
= (statMap
.insert(make_pair(stat
, data
))).second
;
306 assert(statMap
.find(stat
) != statMap
.end());
307 assert(success
&& "this should never fail");
311 Database::regBin(MainBin
*bin
, std::string name
)
313 if (bin_names
.find(bin
) != bin_names
.end())
314 panic("shouldn't register bin twice");
318 bool success
= (bin_names
.insert(make_pair(bin
,name
))).second
;
319 assert(bin_names
.find(bin
) != bin_names
.end());
320 assert(success
&& "this should not fail");
322 cprintf("registering %s\n", name
);
326 Stat::less(Stat
*stat1
, Stat
*stat2
)
328 const string
&name1
= stat1
->myname();
329 const string
&name2
= stat2
->myname();
334 tokenize(v1
, name1
, '.');
335 tokenize(v2
, name2
, '.');
337 int last
= min(v1
.size(), v2
.size()) - 1;
338 for (int i
= 0; i
< last
; ++i
)
340 return v1
[i
] < v2
[i
];
342 // Special compare for last element.
343 if (v1
[last
] == v2
[last
])
344 return v1
.size() < v2
.size();
346 return v1
[last
] < v2
[last
];
352 Database::print(Stat
*stat
)
354 StatData
*data
= find(stat
);
372 // This assert can help you find that pesky stat.
373 assert(this != (void *)0xbffff5c0);
377 StatDB().regStat(this);
380 number
= ++total_stats
;
381 cprintf("I'm stat number %d\n",number
);
387 { mydata()->init
= true; }
392 StatData
*data
= StatDB().find(this);
401 StatData
*data
= StatDB().find(this);
408 Stat::mysubdata(int index
) const
414 const StatData
*data
= this->mydata();
415 if (!data
->subdata
|| data
->subdata
->size() <= index
)
418 return &(*data
->subdata
)[index
];
422 Stat::mysubdata_create(int index
)
424 int size
= this->size();
425 assert(index
>= 0 && (size
== 0 || size
> 0 && index
< size
));
427 StatData
*data
= this->mydata();
428 if (!data
->subdata
) {
429 if (!data
->subdata
) {
433 data
->subdata
= new vector
<SubData
>(size
);
435 } else if (data
->subdata
->size() <= index
)
436 data
->subdata
->resize(index
+ 1);
438 SubData
*sd
= &(*data
->subdata
)[index
];
446 { return mydata()->name
; }
449 Stat::mysubname(int index
) const
451 const SubData
*sd
= mysubdata(index
);
452 return sd
? sd
->name
: "";
457 { return mydata()->desc
; }
460 Stat::mysubdesc(int index
) const
462 const SubData
*sd
= mysubdata(index
);
463 return sd
? sd
->desc
: "";
467 Stat::myprecision() const
468 { return mydata()->precision
; }
471 Stat::myflags() const
472 { return mydata()->flags
; }
475 Stat::dodisplay() const
476 { return !mydata()->prereq
|| !mydata()->prereq
->zero(); }
481 StatData
*data
= StatDB().print(this);
482 assert(data
&& data
->init
);
488 Stat::name(const string
&name
)
490 print()->name
= name
;
495 Stat::desc(const string
&desc
)
497 print()->desc
= desc
;
502 Stat::precision(int precision
)
504 print()->precision
= precision
;
509 Stat::flags(FormatFlags flags
)
511 if (flags
& __reserved
)
512 panic("Cannot set reserved flags!\n");
514 print()->flags
|= flags
;
519 Stat::prereq(const Stat
&prereq
)
521 print()->prereq
= &prereq
;
526 Stat::subname(int index
, const string
&name
)
529 mysubdata_create(index
)->name
= name
;
533 Stat::subdesc(int index
, const string
&desc
)
536 mysubdata_create(index
)->desc
= desc
;
541 ScalarStat::zero() const
547 VectorStat::zero() const
549 return val()[0] == 0.0;
553 ValueToString(result_t value
, int precision
)
559 val
.precision(precision
);
560 else if (value
== rint(value
))
563 val
.unsetf(ios::showpoint
);
564 val
.setf(ios::fixed
);
567 #ifndef STAT_DISPLAY_COMPAT
570 val
<< "<err: div-0>";
578 PrintOne(ostream
&stream
, result_t value
,
579 const string
&name
, const string
&desc
, int precision
,
580 FormatFlags flags
, result_t pdf
= NAN
, result_t cdf
= NAN
)
582 if (flags
& nozero
&& value
== 0.0 ||
583 flags
& nonan
&& isnan(value
))
586 stringstream pdfstr
, cdfstr
;
589 ccprintf(pdfstr
, "%.2f%%", pdf
* 100.0);
592 ccprintf(cdfstr
, "%.2f%%", cdf
* 100.0);
594 #ifdef STAT_DISPLAY_COMPAT
595 if (flags
& __substat
) {
596 ccprintf(stream
, "%32s %12s %10s %10s", name
,
597 ValueToString(value
, precision
),
602 ccprintf(stream
, "%-40s %12s %10s %10s", name
,
603 ValueToString(value
, precision
), pdfstr
, cdfstr
);
606 if (PrintDescriptions
) {
608 ccprintf(stream
, " # %s", desc
);
614 ScalarStat::display(ostream
&stream
) const
616 PrintOne(stream
, val(), myname(), mydesc(), myprecision(), myflags());
620 VectorStat::display(ostream
&stream
) const
622 bool have_subname
= false;
623 bool have_subdesc
= false;
624 int size
= this->size();
625 for (int i
= 0; i
< size
; ++i
) {
626 if (!mysubname(i
).empty())
628 if (!mysubdesc(i
).empty())
632 vector
<string
> *subnames
= 0;
633 vector
<string
> *subdescs
= 0;
635 subnames
= new vector
<string
>(size
);
636 for (int i
= 0; i
< size
; ++i
)
637 (*subnames
)[i
] = mysubname(i
);
640 subdescs
= new vector
<string
>(size
);
641 for (int i
= 0; i
< size
; ++i
)
642 (*subdescs
)[i
] = mysubdesc(i
);
645 VectorDisplay(stream
, myname(), subnames
, mydesc(), subdescs
,
646 myprecision(), myflags(), val(), total());
649 #ifndef STAT_DISPLAY_COMPAT
655 #ifndef STAT_DISPLAY_COMPAT
657 VectorDisplay(std::ostream
&stream
,
658 const std::string
&myname
,
659 const std::vector
<std::string
> *mysubnames
,
660 const std::string
&mydesc
,
661 const std::vector
<std::string
> *mysubdescs
,
662 int myprecision
, FormatFlags myflags
,
663 const rvec_t
&vec
, result_t mytotal
)
665 int _size
= vec
.size();
666 result_t _total
= 0.0;
667 result_t _pdf
, _cdf
= 0.0;
669 if (myflags
& (pdf
| cdf
)) {
670 for (int i
= 0; i
< _size
; ++i
) {
676 PrintOne(stream
, vec
[0], myname
, mydesc
, myprecision
, myflags
);
678 for (int i
= 0; i
< _size
; ++i
) {
681 subname
= (*mysubnames
)[i
];
685 subname
= to_string(i
);
688 string name
= myname
+ NAMESEP
+ subname
;
689 if (!(myflags
& pdf
))
690 PrintOne(stream
, vec
[i
], name
, mydesc
, myprecision
, myflags
);
692 _pdf
= vec
[i
] / _total
;
694 PrintOne(stream
, vec
[i
], name
, mydesc
, myprecision
, myflags
,
700 PrintOne(stream
, mytotal
, myname
+ NAMESEP
+ "total",
701 mydesc
, myprecision
, myflags
);
706 VectorDisplay(std::ostream
&stream
,
707 const std::string
&myname
,
708 const std::vector
<std::string
> *mysubnames
,
709 const std::string
&mydesc
,
710 const std::vector
<std::string
> *mysubdescs
,
711 int myprecision
, FormatFlags myflags
,
712 const rvec_t
&vec
, result_t mytotal
)
714 int _size
= vec
.size();
715 result_t _total
= 0.0;
716 result_t _pdf
, _cdf
= 0.0;
718 if (myflags
& (pdf
| cdf
)) {
719 for (int i
= 0; i
< _size
; ++i
) {
725 PrintOne(stream
, vec
[0], myname
, mydesc
, myprecision
, myflags
);
728 PrintOne(stream
, mytotal
, myname
, mydesc
, myprecision
, myflags
);
730 if (myflags
& dist
) {
731 ccprintf(stream
, "%s.start_dist\n", myname
);
732 for (int i
= 0; i
< _size
; ++i
) {
733 string subname
, subdesc
;
734 subname
= to_string(i
);
736 if (!subname
.empty()) {
737 subname
= (*mysubnames
)[i
];
741 subdesc
= (*mysubdescs
)[i
];
743 if (!(myflags
& (pdf
| cdf
))) {
744 PrintOne(stream
, vec
[i
], subname
, subdesc
, myprecision
,
745 myflags
| __substat
);
748 _pdf
= vec
[i
] / _total
;
753 if (!(myflags
& cdf
)) {
754 PrintOne(stream
, vec
[i
], subname
, subdesc
, myprecision
,
755 myflags
| __substat
, _pdf
);
757 PrintOne(stream
, vec
[i
], subname
, subdesc
, myprecision
,
758 myflags
| __substat
, _pdf
, _cdf
);
762 ccprintf(stream
, "%s.end_dist\n", myname
);
764 for (int i
= 0; i
< _size
; ++i
) {
767 subname
= (*mysubnames
)[i
];
771 subname
= to_string(i
);
774 string name
= myname
+ NAMESEP
+ subname
;
775 if (!(myflags
& pdf
)) {
776 PrintOne(stream
, vec
[i
], name
, mydesc
, myprecision
,
780 _pdf
= vec
[i
] / _total
;
785 PrintOne(stream
, vec
[i
], name
, mydesc
, myprecision
,
786 myflags
, _pdf
, _cdf
);
794 #ifndef STAT_DISPLAY_COMPAT
796 DistDisplay(ostream
&stream
, const string
&name
, const string
&desc
,
797 int precision
, FormatFlags flags
,
798 result_t min_val
, result_t max_val
,
799 result_t underflow
, result_t overflow
,
800 const rvec_t
&vec
, int min
, int max
, int bucket_size
, int size
);
802 assert(size
== vec
.size());
804 result_t total
= 0.0;
805 result_t pdf
, cdf
= 0.0;
808 for (int i
= 0; i
< size
; ++i
)
812 pdf
= underflow
/ total
;
815 PrintOne(stream
, underflow
, name
+ NAMESEP
+ "underflow", desc
,
816 precision
, myflags
, pdf
, cdf
);
818 for (int i
= 0; i
< size
; ++i
) {
819 stringstream namestr
;
822 int low
= i
* bucket_size
+ min
;
823 int high
= ::std::min((i
+ 1) * bucket_size
+ min
- 1, max
);
826 namestr
<< "-" << high
;
828 pdf
= vec
[i
] / total
;
830 PrintOne(stream
, vec
[i
], namestr
.str(), desc
, precision
, myflags
,
834 pdf
= overflow
/ total
;
836 PrintOne(stream
, overflow
, name
+ NAMESEP
+ "overflow", desc
,
837 precision
, myflags
, pdf
, cdf
);
838 PrintOne(stream
, total
, name
+ NAMESEP
+ "total", desc
,
843 DistDisplay(ostream
&stream
, const string
&name
, const string
&desc
,
844 int precision
, FormatFlags flags
,
845 result_t min_val
, result_t max_val
,
846 result_t underflow
, result_t overflow
,
847 const rvec_t
&vec
, int min
, int max
, int bucket_size
, int size
)
849 assert(size
== vec
.size());
852 result_t total
= 0.0;
855 for (int i
= 0; i
< size
; ++i
)
859 ccprintf(stream
, "%-42s", name
+ ".start_dist");
860 if (PrintDescriptions
&& !desc
.empty())
861 ccprintf(stream
, " # %s", desc
);
864 PrintOne(stream
, total
, name
+ ".samples", blank
, precision
, flags
);
865 PrintOne(stream
, min_val
, name
+ ".min_value", blank
, precision
, flags
);
868 PrintOne(stream
, min_val
, name
+ ".underflows", blank
, precision
,
872 result_t _pdf
, _cdf
, mypdf
, mycdf
;
875 for (int i
= 0; i
< size
; ++i
) {
876 if (flags
& nozero
&& vec
[i
] == 0.0 ||
877 flags
& nonan
&& isnan(vec
[i
]))
880 _min
= i
* bucket_size
+ min
;
881 _pdf
= vec
[i
] / total
* 100.0;
884 mypdf
= (flags
& pdf
) ? _pdf
: NAN
;
885 mycdf
= (flags
& cdf
) ? _cdf
: NAN
;
887 PrintOne(stream
, vec
[i
], ValueToString(_min
, 0), blank
, precision
,
888 flags
| __substat
, mypdf
, mycdf
);
892 PrintOne(stream
, overflow
, name
+ ".overflows", blank
, precision
,
894 PrintOne(stream
, max_val
, name
+ ".max_value", blank
, precision
, flags
);
895 ccprintf(stream
, "%s.end_dist\n\n", name
);
900 * @todo get rid of the ugly hack **Ignore for total
903 FancyDisplay(ostream
&stream
, const string
&name
, const string
&desc
,
904 int precision
, FormatFlags flags
, result_t mean
,
905 result_t variance
, result_t total
)
907 result_t stdev
= isnan(variance
) ? NAN
: sqrt(variance
);
908 PrintOne(stream
, mean
, name
+ NAMESEP
+ "mean", desc
, precision
, flags
);
909 PrintOne(stream
, stdev
, name
+ NAMESEP
+ "stdev", desc
, precision
, flags
);
910 PrintOne(stream
, total
, "**Ignore: " + name
+ NAMESEP
+ "TOT", desc
, precision
, flags
);
913 } // namespace Detail
915 MainBin::MainBin(const std::string
&name
)
916 : _name(name
), mem(NULL
), memsize(-1)
918 Detail::StatDB().regBin(this, name
);
928 MainBin::memory(off_t off
)
931 mem
= new char[memsize
];
932 memset(mem
, 0, memsize
);
936 memsize
= CeilPow2((size_t) offset());
938 assert(offset() <= size());
945 Detail::StatDB().check();
949 dump(ostream
&stream
)
951 Detail::StatDB().dump(stream
);
954 CallbackQueue resetQueue
;
957 RegResetCallback(Callback
*cb
)
965 Detail::StatDB().reset();
966 resetQueue
.process();
969 } // namespace Statistics