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/hostinfo.hh"
39 #include "base/misc.hh"
40 #include "base/python.hh"
41 #include "base/statistics.hh"
42 #include "base/str.hh"
43 #include "base/time.hh"
44 #include "base/trace.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;
69 DisplayMode DefaultMode
= mode_simplescalar
;
76 typedef list
<StatData
*> list_t
;
77 typedef map
<void *, StatData
*> map_t
;
86 void dump(ostream
&stream
, const string
&name
, DisplayMode mode
);
87 void display(ostream
&stream
, DisplayMode mode
);
88 void python(ostream
&stream
, const string
&name
);
89 void python(Python
&py
, const string
&name
, const string
&bin
);
91 StatData
*find(void *stat
);
92 void mapStat(void *stat
, StatData
*data
);
96 void regBin(MainBin
*bin
, string name
);
97 void regPrint(void *stat
);
99 static std::string
name() { return "Statistics Database"; }
104 Data::dump(ostream
&stream
, const string
&name
, DisplayMode mode
)
106 MainBin
*orig
= MainBin::curBin();
110 python(stream
, name
);
113 case mode_simplescalar
:
114 display(stream
, mode
);
117 warn("invalid display mode!\n");
118 display(stream
, mode_m5
);
127 Data::display(ostream
&stream
, DisplayMode mode
)
130 list
<MainBin
*>::iterator i
= bins
.begin();
131 list
<MainBin
*>::iterator bins_end
= bins
.end();
132 ccprintf(stream
, "PRINTING BINNED STATS\n");
133 while (i
!= bins_end
) {
135 ccprintf(stream
,"---%s Bin------------\n", (*i
)->name());
137 list_t::iterator j
= printStats
.begin();
138 list_t::iterator end
= printStats
.end();
141 if (stat
->dodisplay())
142 stat
->display(stream
, mode
);
146 ccprintf(stream
, "---------------------------------\n");
149 list_t::iterator i
= printStats
.begin();
150 list_t::iterator end
= printStats
.end();
153 if (stat
->dodisplay() && !stat
->binned())
154 stat
->display(stream
, mode
);
161 Data::python(ostream
&stream
, const string
&name
)
165 ccprintf(stream
, "import sys\n");
166 ccprintf(stream
, "sys.path.append('.')\n");
167 ccprintf(stream
, "from m5stats import *\n\n");
170 python(py
, name
, "");
172 list
<MainBin
*>::iterator i
= bins
.begin();
173 list
<MainBin
*>::iterator end
= bins
.end();
177 python(py
, name
, (*i
)->name());
183 ccprintf(stream
, "if __name__ == '__main__':\n");
184 ccprintf(stream
, " program_display()\n");
188 Data::python(Python
&py
, const string
&name
, const string
&bin
)
190 py
.start("collections.append");
191 py
.start("Collection");
195 py
.qarg(Time::start
.date());
196 list_t::iterator i
= allStats
.begin();
197 list_t::iterator end
= allStats
.end();
208 Data::find(void *stat
)
210 map_t::const_iterator i
= statMap
.find(stat
);
212 if (i
== statMap
.end())
221 list_t::iterator i
= allStats
.begin();
222 list_t::iterator end
= allStats
.end();
231 i
= allStats
.begin();
235 if (!(data
->flags
& print
))
236 data
->name
= "__Stat" + to_string(j
++);
244 // reset non-binned stats
245 list_t::iterator i
= allStats
.begin();
246 list_t::iterator end
= allStats
.end();
254 // save the bin so we can go back to where we were
255 MainBin
*orig
= MainBin::curBin();
257 // reset binned stats
258 list
<MainBin
*>::iterator bi
= bins
.begin();
259 list
<MainBin
*>::iterator be
= bins
.end();
264 i
= allStats
.begin();
275 MainBin::curBin() = orig
;
279 Data::mapStat(void *stat
, StatData
*data
)
281 if (statMap
.find(stat
) != statMap
.end())
282 panic("shouldn't register stat twice!");
284 allStats
.push_back(data
);
289 (statMap
.insert(make_pair(stat
, data
))).second
;
290 assert(statMap
.find(stat
) != statMap
.end());
291 assert(success
&& "this should never fail");
295 Data::regBin(MainBin
*bin
, string _name
)
298 DPRINTF(Stats
, "registering %s\n", _name
);
302 Data::regPrint(void *stat
)
304 StatData
*data
= find(stat
);
306 if (data
->flags
& print
)
309 data
->flags
|= print
;
311 list_t::iterator j
= printStats
.insert(printStats
.end(), data
);
312 inplace_merge(printStats
.begin(), j
, printStats
.end(), StatData::less
);
325 DataAccess::find() const
327 return Database::StatDB().find(const_cast<void *>((const void *)this));
331 getStatData(const void *stat
)
333 return Database::StatDB().find(const_cast<void *>(stat
));
337 DataAccess::map(StatData
*data
)
339 Database::StatDB().mapStat(this, data
);
343 DataAccess::statData()
345 StatData
*ptr
= find();
351 DataAccess::statData() const
353 const StatData
*ptr
= find();
359 DataAccess::setInit()
361 statData()->flags
|= init
;
365 DataAccess::setPrint()
367 Database::StatDB().regPrint(this);
370 StatData::~StatData()
375 StatData::less(StatData
*stat1
, StatData
*stat2
)
377 const string
&name1
= stat1
->name
;
378 const string
&name2
= stat2
->name
;
383 tokenize(v1
, name1
, '.');
384 tokenize(v2
, name2
, '.');
386 int last
= min(v1
.size(), v2
.size()) - 1;
387 for (int i
= 0; i
< last
; ++i
)
389 return v1
[i
] < v2
[i
];
391 // Special compare for last element.
392 if (v1
[last
] == v2
[last
])
393 return v1
.size() < v2
.size();
395 return v1
[last
] < v2
[last
];
401 StatData::baseCheck() const
403 if (!(flags
& init
)) {
405 cprintf("this is stat number %d\n",(*i
)->number
);
407 panic("Not all stats have been initialized");
411 if ((flags
& print
) && name
.empty()) {
412 panic("all printable stats must be named");
420 ValueToString(result_t value
, DisplayMode mode
, int precision
)
426 val
.precision(precision
);
427 else if (value
== rint(value
))
430 val
.unsetf(ios::showpoint
);
431 val
.setf(ios::fixed
);
434 val
<< (mode
== mode_m5
? "no value" : "<err: div-0>");
452 : value(0.0), flags(0), mode(DefaultMode
), precision(0),
456 void operator()(ostream
&stream
) const;
460 ScalarPrint::operator()(ostream
&stream
) const
462 if (flags
& nozero
&& value
== 0.0 ||
463 flags
& nonan
&& isnan(value
))
466 stringstream pdfstr
, cdfstr
;
469 ccprintf(pdfstr
, "%.2f%%", pdf
* 100.0);
472 ccprintf(cdfstr
, "%.2f%%", cdf
* 100.0);
474 if (mode
== mode_simplescalar
&& flags
& __substat
) {
475 ccprintf(stream
, "%32s %12s %10s %10s", name
,
476 ValueToString(value
, mode
, precision
), pdfstr
, cdfstr
);
478 ccprintf(stream
, "%-40s %12s %10s %10s", name
,
479 ValueToString(value
, mode
, precision
), pdfstr
, cdfstr
);
482 if (PrintDescriptions
) {
484 ccprintf(stream
, " # %s", desc
);
493 vector
<string
> subnames
;
494 vector
<string
> subdescs
;
502 : subnames(0), subdescs(0), flags(0), mode(DefaultMode
),
503 precision(-1), total(NAN
)
506 void operator()(ostream
&stream
) const;
510 VectorPrint::operator()(std::ostream
&stream
) const
512 int _size
= vec
.size();
513 result_t _total
= 0.0;
515 if (flags
& (pdf
| cdf
)) {
516 for (int i
= 0; i
< _size
; ++i
) {
521 string base
= name
+ ((mode
== mode_simplescalar
) ? "_" : "::");
526 print
.precision
= precision
;
529 bool havesub
= !subnames
.empty();
532 print
.value
= vec
[0];
534 } else if (mode
== mode_m5
) {
535 for (int i
= 0; i
< _size
; ++i
) {
536 if (havesub
&& (i
>= subnames
.size() || subnames
[i
].empty()))
539 print
.name
= base
+ (havesub
? subnames
[i
] : to_string(i
));
540 print
.desc
= subdescs
.empty() ? desc
: subdescs
[i
];
541 print
.value
= vec
[i
];
543 if (_total
&& (flags
& pdf
)) {
544 print
.pdf
= vec
[i
] / _total
;
545 print
.cdf
+= print
.pdf
;
551 if (flags
& ::Statistics::total
) {
552 print
.name
= base
+ "total";
558 if (flags
& ::Statistics::total
) {
566 ccprintf(stream
, "%s.start_dist\n", name
);
567 for (int i
= 0; i
< _size
; ++i
) {
568 print
.name
= havesub
? subnames
[i
] : to_string(i
);
569 print
.desc
= subdescs
.empty() ? desc
: subdescs
[i
];
570 print
.flags
|= __substat
;
571 print
.value
= vec
[i
];
574 _pdf
= vec
[i
] / _total
;
585 ccprintf(stream
, "%s.end_dist\n", name
);
587 for (int i
= 0; i
< _size
; ++i
) {
588 if (havesub
&& subnames
[i
].empty())
592 print
.name
+= havesub
? subnames
[i
] : to_string(i
);
593 print
.desc
= subdescs
.empty() ? desc
: subdescs
[i
];
594 print
.value
= vec
[i
];
597 _pdf
= vec
[i
] / _total
;
637 void operator()(ostream
&stream
) const;
641 DistPrint::operator()(ostream
&stream
) const
645 string base
= name
+ ((mode
== mode_m5
) ? "::" : "_");
647 print
.precision
= precision
;
652 print
.name
= base
+ "mean";
653 print
.value
= samples
? sum
/ samples
: NAN
;
656 print
.name
= base
+ "stdev";
657 print
.value
= samples
? sqrt((samples
* squares
- sum
* sum
) /
658 (samples
* (samples
- 1.0))) : NAN
;
661 print
.name
= "**Ignore: " + base
+ "TOT";
662 print
.value
= samples
;
667 assert(size
== vec
.size());
669 result_t total
= 0.0;
672 for (int i
= 0; i
< size
; ++i
)
676 string base
= name
+ (mode
== mode_m5
? "::" : ".");
679 print
.desc
= (mode
== mode_m5
) ? desc
: "";
682 print
.precision
= precision
;
684 if (mode
== mode_simplescalar
) {
685 ccprintf(stream
, "%-42s", base
+ "start_dist");
686 if (PrintDescriptions
&& !desc
.empty())
687 ccprintf(stream
, " # %s", desc
);
691 print
.name
= base
+ "samples";
692 print
.value
= samples
;
695 print
.name
= base
+ "min_value";
696 print
.value
= min_val
;
699 if (mode
== mode_m5
|| underflow
> 0.0) {
700 print
.name
= base
+ "underflows";
701 print
.value
= underflow
;
702 if (mode
== mode_m5
&& total
) {
703 print
.pdf
= underflow
/ total
;
704 print
.cdf
+= print
.pdf
;
710 if (mode
== mode_m5
) {
711 for (int i
= 0; i
< size
; ++i
) {
712 stringstream namestr
;
715 int low
= i
* bucket_size
+ min
;
716 int high
= ::min((i
+ 1) * bucket_size
+ min
- 1, max
);
719 namestr
<< "-" << high
;
721 print
.name
= namestr
.str();
722 print
.value
= vec
[i
];
724 print
.pdf
= vec
[i
] / total
;
725 print
.cdf
+= print
.pdf
;
735 print
.flags
= flags
| __substat
;
737 for (int i
= 0; i
< size
; ++i
) {
738 if (flags
& nozero
&& vec
[i
] == 0.0 ||
739 flags
& nonan
&& isnan(vec
[i
]))
742 _min
= i
* bucket_size
+ min
;
743 _pdf
= vec
[i
] / total
* 100.0;
747 print
.name
= ValueToString(_min
, mode
, 0);
748 print
.value
= vec
[i
];
749 print
.pdf
= (flags
& pdf
) ? _pdf
: NAN
;
750 print
.cdf
= (flags
& cdf
) ? _cdf
: NAN
;
757 if (mode
== mode_m5
|| overflow
> 0.0) {
758 print
.name
= base
+ "overflows";
759 print
.value
= overflow
;
760 if (mode
== mode_m5
&& total
) {
761 print
.pdf
= overflow
/ total
;
762 print
.cdf
+= print
.pdf
;
773 if (mode
!= mode_simplescalar
) {
774 print
.name
= base
+ "total";
779 print
.name
= base
+ "max_value";
780 print
.value
= max_val
;
783 if (mode
!= mode_simplescalar
&& samples
!= 0) {
784 print
.name
= base
+ "mean";
785 print
.value
= sum
/ samples
;
788 print
.name
= base
+ "stdev";
789 print
.value
= sqrt((samples
* squares
- sum
* sum
) /
790 (samples
* (samples
- 1.0)));
794 if (mode
== mode_simplescalar
)
795 ccprintf(stream
, "%send_dist\n\n", base
);
799 ScalarDataBase::display(ostream
&stream
, DisplayMode mode
) const
807 print
.precision
= precision
;
813 VectorDataBase::display(ostream
&stream
, DisplayMode mode
) const
815 int size
= this->size();
816 const_cast<VectorDataBase
*>(this)->update();
824 print
.precision
= precision
;
826 print
.total
= total();
828 if (!subnames
.empty()) {
829 for (int i
= 0; i
< size
; ++i
) {
830 if (!subnames
[i
].empty()) {
831 print
.subnames
= subnames
;
832 print
.subnames
.resize(size
);
833 for (int i
= 0; i
< size
; ++i
) {
834 if (!subnames
[i
].empty() && !subdescs
[i
].empty()) {
835 print
.subdescs
= subdescs
;
836 print
.subdescs
.resize(size
);
849 Vector2dDataBase::display(ostream
&stream
, DisplayMode mode
) const
851 const_cast<Vector2dDataBase
*>(this)->update();
853 bool havesub
= false;
856 print
.subnames
= y_subnames
;
859 print
.precision
= precision
;
861 if (!subnames
.empty()) {
862 for (int i
= 0; i
< x
; ++i
)
863 if (!subnames
[i
].empty())
868 result_t super_total
= 0.0;
869 for (int i
= 0; i
< x
; ++i
) {
870 if (havesub
&& (i
>= subnames
.size() || subnames
[i
].empty()))
876 result_t total
= 0.0;
877 for (int j
= 0; j
< y
; ++j
) {
878 yvec
[j
] = vec
[iy
+ j
];
879 tot_vec
[j
] += yvec
[j
];
881 super_total
+= yvec
[j
];
884 print
.name
= name
+ "_" + (havesub
? subnames
[i
] : to_string(i
));
891 if ((flags
& ::Statistics::total
) && (x
> 1)) {
895 print
.total
= super_total
;
901 DistDataBase::display(ostream
&stream
, DisplayMode mode
) const
903 const_cast<DistDataBase
*>(this)->update();
911 print
.precision
= precision
;
913 print
.min_val
= data
.min_val
;
914 print
.max_val
= data
.max_val
;
915 print
.underflow
= data
.underflow
;
916 print
.overflow
= data
.overflow
;
917 print
.vec
= data
.vec
;
918 print
.sum
= data
.sum
;
919 print
.squares
= data
.squares
;
920 print
.samples
= data
.samples
;
922 print
.min
= data
.min
;
923 print
.max
= data
.max
;
924 print
.bucket_size
= data
.bucket_size
;
925 print
.size
= data
.size
;
926 print
.fancy
= data
.fancy
;
932 VectorDistDataBase::display(ostream
&stream
, DisplayMode mode
) const
934 const_cast<VectorDistDataBase
*>(this)->update();
936 for (int i
= 0; i
< size(); ++i
) {
940 (subnames
[i
].empty() ? ("_" + to_string(i
)) : subnames
[i
]);
941 print
.desc
= subdescs
[i
].empty() ? desc
: subdescs
[i
];
944 print
.precision
= precision
;
946 print
.min_val
= data
[i
].min_val
;
947 print
.max_val
= data
[i
].max_val
;
948 print
.underflow
= data
[i
].underflow
;
949 print
.overflow
= data
[i
].overflow
;
950 print
.vec
= data
[i
].vec
;
951 print
.sum
= data
[i
].sum
;
952 print
.squares
= data
[i
].squares
;
953 print
.samples
= data
[i
].samples
;
955 print
.min
= data
[i
].min
;
956 print
.max
= data
[i
].max
;
957 print
.bucket_size
= data
[i
].bucket_size
;
958 print
.size
= data
[i
].size
;
959 print
.fancy
= data
[i
].fancy
;
966 ScalarDataBase::python(Python
&py
) const
971 py
.kwarg("binned", binned());
972 py
.kwarg("precision", precision
);
973 py
.kwarg("flags", flags
);
975 py
.qkwarg("prereq", prereq
->name
);
976 py
.kwarg("value", val());
981 VectorDataBase::python(Python
&py
) const
983 const_cast<VectorDataBase
*>(this)->update();
988 py
.kwarg("binned", binned());
989 py
.kwarg("precision", precision
);
990 py
.kwarg("flags", flags
);
992 py
.qkwarg("prereq", prereq
->name
);
993 py
.kwarg("value", val());
994 if (!subnames
.empty())
995 py
.qkwarg("subnames", subnames
);
996 if (!subdescs
.empty())
997 py
.qkwarg("subdescs", subdescs
);
1002 DistDataData::python(Python
&py
, const string
&name
) const
1004 string s
= name
.empty() ? "" : name
+ "=";
1006 if (samples
== 0 || fancy
)
1015 if (samples
&& !fancy
) {
1023 py
.arg(bucket_size
);
1030 FormulaDataBase::python(Python
&py
) const
1032 const_cast<FormulaDataBase
*>(this)->update();
1034 py
.start("Formula");
1037 py
.kwarg("binned", binned());
1038 py
.kwarg("precision", precision
);
1039 py
.kwarg("flags", flags
);
1041 py
.qkwarg("prereq", prereq
->name
);
1042 py
.qkwarg("formula", str());
1043 if (!subnames
.empty())
1044 py
.qkwarg("subnames", subnames
);
1045 if (!subdescs
.empty())
1046 py
.qkwarg("subdescs", subdescs
);
1051 DistDataBase::python(Python
&py
) const
1053 const_cast<DistDataBase
*>(this)->update();
1058 py
.kwarg("binned", binned());
1059 py
.kwarg("precision", precision
);
1060 py
.kwarg("flags", flags
);
1062 py
.qkwarg("prereq", prereq
->name
);
1063 data
.python(py
, "dist");
1068 VectorDistDataBase::python(Python
&py
) const
1070 const_cast<VectorDistDataBase
*>(this)->update();
1072 py
.start("VectorDist");
1075 py
.kwarg("binned", binned());
1076 py
.kwarg("precision", precision
);
1077 py
.kwarg("flags", flags
);
1079 py
.qkwarg("prereq", prereq
->name
);
1080 if (!subnames
.empty())
1081 py
.qkwarg("subnames", subnames
);
1082 if (!subdescs
.empty())
1083 py
.qkwarg("subdescs", subdescs
);
1086 typedef std::vector
<DistDataData
>::const_iterator iter
;
1087 iter i
= data
.begin();
1088 iter end
= data
.end();
1098 Vector2dDataBase::python(Python
&py
) const
1100 const_cast<Vector2dDataBase
*>(this)->update();
1102 py
.start("Vector2d");
1105 py
.kwarg("binned", binned());
1106 py
.kwarg("precision", precision
);
1107 py
.kwarg("flags", flags
);
1109 py
.qkwarg("prereq", prereq
->name
);
1111 py
.kwarg("value", vec
);
1112 if (!subnames
.empty())
1113 py
.qkwarg("subnames", subnames
);
1114 if (!subdescs
.empty())
1115 py
.qkwarg("subdescs", subdescs
);
1116 if (!y_subnames
.empty())
1117 py
.qkwarg("ysubnames", y_subnames
);
1125 FormulaBase::val(rvec_t
&vec
) const
1131 FormulaBase::total() const
1133 return root
->total();
1137 FormulaBase::size() const
1142 return root
->size();
1146 FormulaBase::binned() const
1148 return root
&& root
->binned();
1152 FormulaBase::reset()
1157 FormulaBase::zero() const
1161 for (int i
= 0; i
< vec
.size(); ++i
)
1168 FormulaBase::update(StatData
*)
1173 FormulaBase::str() const
1175 return root
? root
->str() : "";
1183 Formula::Formula(Temp r
)
1190 Formula::operator=(Temp r
)
1192 assert(!root
&& "Can't change formulas");
1199 Formula::operator+=(Temp r
)
1202 root
= NodePtr(new BinaryNode
<std::plus
<result_t
> >(root
, r
));
1209 MainBin::MainBin(const string
&name
)
1210 : _name(name
), mem(NULL
), memsize(-1)
1212 Database::StatDB().regBin(this, name
);
1222 MainBin::memory(off_t off
)
1225 memsize
= CeilPow2((size_t) offset());
1228 mem
= new char[memsize
];
1229 memset(mem
, 0, memsize
);
1232 assert(offset() <= size());
1239 Database::StatDB().check();
1243 dump(ostream
&stream
, const string
&name
, DisplayMode mode
)
1245 Database::StatDB().dump(stream
, name
, mode
);
1248 CallbackQueue resetQueue
;
1251 registerResetCallback(Callback
*cb
)
1259 Database::StatDB().reset();
1260 resetQueue
.process();
1263 } // namespace Statistics