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
;
92 void dump(ostream
&stream
, DisplayMode mode
);
93 void display(ostream
&stream
, DisplayMode mode
);
94 void python_start(const string
&file
);
95 void python_dump(const string
&name
, const string
&subname
);
96 void python(const string
&name
, const string
&subname
,
99 StatData
*find(void *stat
);
100 void mapStat(void *stat
, StatData
*data
);
104 void regBin(MainBin
*bin
, string name
);
105 void regPrint(void *stat
);
107 static std::string
name() { return "Statistics Database"; }
119 ccprintf(*stream
, "\n\nif __name__ == '__main__':\n");
120 ccprintf(*stream
, " program_display()\n");
127 Data::dump(ostream
&stream
, DisplayMode mode
)
129 MainBin
*orig
= MainBin::curBin();
133 case mode_simplescalar
:
134 display(stream
, mode
);
137 warn("invalid display mode!\n");
138 display(stream
, mode_m5
);
147 Data::display(ostream
&stream
, DisplayMode mode
)
150 list
<MainBin
*>::iterator i
= bins
.begin();
151 list
<MainBin
*>::iterator bins_end
= bins
.end();
152 ccprintf(stream
, "PRINTING BINNED STATS\n");
153 while (i
!= bins_end
) {
155 ccprintf(stream
,"---%s Bin------------\n", (*i
)->name());
157 list_t::iterator j
= printStats
.begin();
158 list_t::iterator end
= printStats
.end();
161 if (stat
->dodisplay())
162 stat
->display(stream
, mode
);
166 ccprintf(stream
, "---------------------------------\n");
169 list_t::iterator i
= printStats
.begin();
170 list_t::iterator end
= printStats
.end();
173 if (stat
->dodisplay() && !stat
->binned())
174 stat
->display(stream
, mode
);
181 Data::python_start(const string
&file
)
184 panic("can't start python twice!");
186 stream
= new ofstream(file
.c_str(), ios::trunc
);
187 py
= new Python(*stream
);
189 ccprintf(*stream
, "import sys\n");
190 ccprintf(*stream
, "sys.path.append('.')\n");
191 ccprintf(*stream
, "from m5stats import *\n\n");
195 Data::python_dump(const string
&name
, const string
&subname
)
198 panic("Can't dump python without first opening the file");
201 python(name
, subname
, "");
203 list
<MainBin
*>::iterator i
= bins
.begin();
204 list
<MainBin
*>::iterator end
= bins
.end();
208 python(name
, subname
, (*i
)->name());
215 Data::python(const string
&name
, const string
&subname
, const string
&bin
)
217 py
->name("collections.append");
219 py
->name("Collection");
227 py
->qarg(hostname());
229 py
->qarg(Time::start
.date());
232 list_t::iterator i
= allStats
.begin();
233 list_t::iterator end
= allStats
.end();
250 Data::find(void *stat
)
252 map_t::const_iterator i
= statMap
.find(stat
);
254 if (i
== statMap
.end())
263 list_t::iterator i
= allStats
.begin();
264 list_t::iterator end
= allStats
.end();
273 i
= allStats
.begin();
277 if (!(data
->flags
& print
))
278 data
->name
= "__Stat" + to_string(j
++);
286 // reset non-binned stats
287 list_t::iterator i
= allStats
.begin();
288 list_t::iterator end
= allStats
.end();
296 // save the bin so we can go back to where we were
297 MainBin
*orig
= MainBin::curBin();
299 // reset binned stats
300 list
<MainBin
*>::iterator bi
= bins
.begin();
301 list
<MainBin
*>::iterator be
= bins
.end();
306 i
= allStats
.begin();
317 MainBin::curBin() = orig
;
321 Data::mapStat(void *stat
, StatData
*data
)
323 if (statMap
.find(stat
) != statMap
.end())
324 panic("shouldn't register stat twice!");
326 allStats
.push_back(data
);
331 (statMap
.insert(make_pair(stat
, data
))).second
;
332 assert(statMap
.find(stat
) != statMap
.end());
333 assert(success
&& "this should never fail");
337 Data::regBin(MainBin
*bin
, string _name
)
340 DPRINTF(Stats
, "registering %s\n", _name
);
344 Data::regPrint(void *stat
)
346 StatData
*data
= find(stat
);
348 if (data
->flags
& print
)
351 data
->flags
|= print
;
353 list_t::iterator j
= printStats
.insert(printStats
.end(), data
);
354 inplace_merge(printStats
.begin(), j
, printStats
.end(), StatData::less
);
367 DataAccess::find() const
369 return Database::StatDB().find(const_cast<void *>((const void *)this));
373 getStatData(const void *stat
)
375 return Database::StatDB().find(const_cast<void *>(stat
));
379 DataAccess::map(StatData
*data
)
381 Database::StatDB().mapStat(this, data
);
385 DataAccess::statData()
387 StatData
*ptr
= find();
393 DataAccess::statData() const
395 const StatData
*ptr
= find();
401 DataAccess::setInit()
403 statData()->flags
|= init
;
407 DataAccess::setPrint()
409 Database::StatDB().regPrint(this);
413 : flags(none
), precision(-1), prereq(0)
416 number
= total_stats
++;
420 StatData::~StatData()
425 StatData::less(StatData
*stat1
, StatData
*stat2
)
427 const string
&name1
= stat1
->name
;
428 const string
&name2
= stat2
->name
;
433 tokenize(v1
, name1
, '.');
434 tokenize(v2
, name2
, '.');
436 int last
= min(v1
.size(), v2
.size()) - 1;
437 for (int i
= 0; i
< last
; ++i
)
439 return v1
[i
] < v2
[i
];
441 // Special compare for last element.
442 if (v1
[last
] == v2
[last
])
443 return v1
.size() < v2
.size();
445 return v1
[last
] < v2
[last
];
451 StatData::baseCheck() const
453 if (!(flags
& init
)) {
455 cprintf("this is stat number %d\n", number
);
457 panic("Not all stats have been initialized");
461 if ((flags
& print
) && name
.empty()) {
462 panic("all printable stats must be named");
470 ValueToString(result_t value
, DisplayMode mode
, int precision
)
476 val
.precision(precision
);
477 else if (value
== rint(value
))
480 val
.unsetf(ios::showpoint
);
481 val
.setf(ios::fixed
);
484 val
<< (mode
== mode_m5
? "no value" : "<err: div-0>");
502 : value(0.0), flags(0), mode(DefaultMode
), precision(0),
506 void operator()(ostream
&stream
) const;
510 ScalarPrint::operator()(ostream
&stream
) const
512 if (flags
& nozero
&& value
== 0.0 ||
513 flags
& nonan
&& isnan(value
))
516 stringstream pdfstr
, cdfstr
;
519 ccprintf(pdfstr
, "%.2f%%", pdf
* 100.0);
522 ccprintf(cdfstr
, "%.2f%%", cdf
* 100.0);
524 if (mode
== mode_simplescalar
&& flags
& __substat
) {
525 ccprintf(stream
, "%32s %12s %10s %10s", name
,
526 ValueToString(value
, mode
, precision
), pdfstr
, cdfstr
);
528 ccprintf(stream
, "%-40s %12s %10s %10s", name
,
529 ValueToString(value
, mode
, precision
), pdfstr
, cdfstr
);
532 if (PrintDescriptions
) {
534 ccprintf(stream
, " # %s", desc
);
543 vector
<string
> subnames
;
544 vector
<string
> subdescs
;
552 : subnames(0), subdescs(0), flags(0), mode(DefaultMode
),
553 precision(-1), total(NAN
)
556 void operator()(ostream
&stream
) const;
560 VectorPrint::operator()(std::ostream
&stream
) const
562 int _size
= vec
.size();
563 result_t _total
= 0.0;
565 if (flags
& (pdf
| cdf
)) {
566 for (int i
= 0; i
< _size
; ++i
) {
571 string base
= name
+ ((mode
== mode_simplescalar
) ? "_" : "::");
576 print
.precision
= precision
;
579 bool havesub
= !subnames
.empty();
582 print
.value
= vec
[0];
584 } else if (mode
== mode_m5
) {
585 for (int i
= 0; i
< _size
; ++i
) {
586 if (havesub
&& (i
>= subnames
.size() || subnames
[i
].empty()))
589 print
.name
= base
+ (havesub
? subnames
[i
] : to_string(i
));
590 print
.desc
= subdescs
.empty() ? desc
: subdescs
[i
];
591 print
.value
= vec
[i
];
593 if (_total
&& (flags
& pdf
)) {
594 print
.pdf
= vec
[i
] / _total
;
595 print
.cdf
+= print
.pdf
;
601 if (flags
& ::Statistics::total
) {
602 print
.name
= base
+ "total";
608 if (flags
& ::Statistics::total
) {
616 ccprintf(stream
, "%s.start_dist\n", name
);
617 for (int i
= 0; i
< _size
; ++i
) {
618 print
.name
= havesub
? subnames
[i
] : to_string(i
);
619 print
.desc
= subdescs
.empty() ? desc
: subdescs
[i
];
620 print
.flags
|= __substat
;
621 print
.value
= vec
[i
];
624 _pdf
= vec
[i
] / _total
;
635 ccprintf(stream
, "%s.end_dist\n", name
);
637 for (int i
= 0; i
< _size
; ++i
) {
638 if (havesub
&& subnames
[i
].empty())
642 print
.name
+= havesub
? subnames
[i
] : to_string(i
);
643 print
.desc
= subdescs
.empty() ? desc
: subdescs
[i
];
644 print
.value
= vec
[i
];
647 _pdf
= vec
[i
] / _total
;
687 void operator()(ostream
&stream
) const;
691 DistPrint::operator()(ostream
&stream
) const
695 string base
= name
+ ((mode
== mode_m5
) ? "::" : "_");
697 print
.precision
= precision
;
702 print
.name
= base
+ "mean";
703 print
.value
= samples
? sum
/ samples
: NAN
;
706 print
.name
= base
+ "stdev";
707 print
.value
= samples
? sqrt((samples
* squares
- sum
* sum
) /
708 (samples
* (samples
- 1.0))) : NAN
;
711 print
.name
= "**Ignore: " + base
+ "TOT";
712 print
.value
= samples
;
717 assert(size
== vec
.size());
719 result_t total
= 0.0;
722 for (int i
= 0; i
< size
; ++i
)
726 string base
= name
+ (mode
== mode_m5
? "::" : ".");
729 print
.desc
= (mode
== mode_m5
) ? desc
: "";
732 print
.precision
= precision
;
734 if (mode
== mode_simplescalar
) {
735 ccprintf(stream
, "%-42s", base
+ "start_dist");
736 if (PrintDescriptions
&& !desc
.empty())
737 ccprintf(stream
, " # %s", desc
);
741 print
.name
= base
+ "samples";
742 print
.value
= samples
;
745 print
.name
= base
+ "min_value";
746 print
.value
= min_val
;
749 if (mode
== mode_m5
|| underflow
> 0.0) {
750 print
.name
= base
+ "underflows";
751 print
.value
= underflow
;
752 if (mode
== mode_m5
&& total
) {
753 print
.pdf
= underflow
/ total
;
754 print
.cdf
+= print
.pdf
;
760 if (mode
== mode_m5
) {
761 for (int i
= 0; i
< size
; ++i
) {
762 stringstream namestr
;
765 int low
= i
* bucket_size
+ min
;
766 int high
= ::min((i
+ 1) * bucket_size
+ min
- 1, max
);
769 namestr
<< "-" << high
;
771 print
.name
= namestr
.str();
772 print
.value
= vec
[i
];
774 print
.pdf
= vec
[i
] / total
;
775 print
.cdf
+= print
.pdf
;
785 print
.flags
= flags
| __substat
;
787 for (int i
= 0; i
< size
; ++i
) {
788 if (flags
& nozero
&& vec
[i
] == 0.0 ||
789 flags
& nonan
&& isnan(vec
[i
]))
792 _min
= i
* bucket_size
+ min
;
793 _pdf
= vec
[i
] / total
* 100.0;
797 print
.name
= ValueToString(_min
, mode
, 0);
798 print
.value
= vec
[i
];
799 print
.pdf
= (flags
& pdf
) ? _pdf
: NAN
;
800 print
.cdf
= (flags
& cdf
) ? _cdf
: NAN
;
807 if (mode
== mode_m5
|| overflow
> 0.0) {
808 print
.name
= base
+ "overflows";
809 print
.value
= overflow
;
810 if (mode
== mode_m5
&& total
) {
811 print
.pdf
= overflow
/ total
;
812 print
.cdf
+= print
.pdf
;
823 if (mode
!= mode_simplescalar
) {
824 print
.name
= base
+ "total";
829 print
.name
= base
+ "max_value";
830 print
.value
= max_val
;
833 if (mode
!= mode_simplescalar
&& samples
!= 0) {
834 print
.name
= base
+ "mean";
835 print
.value
= sum
/ samples
;
838 print
.name
= base
+ "stdev";
839 print
.value
= sqrt((samples
* squares
- sum
* sum
) /
840 (samples
* (samples
- 1.0)));
844 if (mode
== mode_simplescalar
)
845 ccprintf(stream
, "%send_dist\n\n", base
);
849 ScalarDataBase::display(ostream
&stream
, DisplayMode mode
) const
857 print
.precision
= precision
;
863 VectorDataBase::display(ostream
&stream
, DisplayMode mode
) const
865 int size
= this->size();
866 const_cast<VectorDataBase
*>(this)->update();
874 print
.precision
= precision
;
876 print
.total
= total();
878 if (!subnames
.empty()) {
879 for (int i
= 0; i
< size
; ++i
) {
880 if (!subnames
[i
].empty()) {
881 print
.subnames
= subnames
;
882 print
.subnames
.resize(size
);
883 for (int i
= 0; i
< size
; ++i
) {
884 if (!subnames
[i
].empty() && !subdescs
[i
].empty()) {
885 print
.subdescs
= subdescs
;
886 print
.subdescs
.resize(size
);
899 Vector2dDataBase::display(ostream
&stream
, DisplayMode mode
) const
901 const_cast<Vector2dDataBase
*>(this)->update();
903 bool havesub
= false;
906 print
.subnames
= y_subnames
;
909 print
.precision
= precision
;
911 if (!subnames
.empty()) {
912 for (int i
= 0; i
< x
; ++i
)
913 if (!subnames
[i
].empty())
918 result_t super_total
= 0.0;
919 for (int i
= 0; i
< x
; ++i
) {
920 if (havesub
&& (i
>= subnames
.size() || subnames
[i
].empty()))
926 result_t total
= 0.0;
927 for (int j
= 0; j
< y
; ++j
) {
928 yvec
[j
] = vec
[iy
+ j
];
929 tot_vec
[j
] += yvec
[j
];
931 super_total
+= yvec
[j
];
934 print
.name
= name
+ "_" + (havesub
? subnames
[i
] : to_string(i
));
941 if ((flags
& ::Statistics::total
) && (x
> 1)) {
945 print
.total
= super_total
;
951 DistDataBase::display(ostream
&stream
, DisplayMode mode
) const
953 const_cast<DistDataBase
*>(this)->update();
961 print
.precision
= precision
;
963 print
.min_val
= data
.min_val
;
964 print
.max_val
= data
.max_val
;
965 print
.underflow
= data
.underflow
;
966 print
.overflow
= data
.overflow
;
967 print
.vec
= data
.vec
;
968 print
.sum
= data
.sum
;
969 print
.squares
= data
.squares
;
970 print
.samples
= data
.samples
;
972 print
.min
= data
.min
;
973 print
.max
= data
.max
;
974 print
.bucket_size
= data
.bucket_size
;
975 print
.size
= data
.size
;
976 print
.fancy
= data
.fancy
;
982 VectorDistDataBase::display(ostream
&stream
, DisplayMode mode
) const
984 const_cast<VectorDistDataBase
*>(this)->update();
986 for (int i
= 0; i
< size(); ++i
) {
990 (subnames
[i
].empty() ? ("_" + to_string(i
)) : subnames
[i
]);
991 print
.desc
= subdescs
[i
].empty() ? desc
: subdescs
[i
];
994 print
.precision
= precision
;
996 print
.min_val
= data
[i
].min_val
;
997 print
.max_val
= data
[i
].max_val
;
998 print
.underflow
= data
[i
].underflow
;
999 print
.overflow
= data
[i
].overflow
;
1000 print
.vec
= data
[i
].vec
;
1001 print
.sum
= data
[i
].sum
;
1002 print
.squares
= data
[i
].squares
;
1003 print
.samples
= data
[i
].samples
;
1005 print
.min
= data
[i
].min
;
1006 print
.max
= data
[i
].max
;
1007 print
.bucket_size
= data
[i
].bucket_size
;
1008 print
.size
= data
[i
].size
;
1009 print
.fancy
= data
[i
].fancy
;
1016 ScalarDataBase::python(Python
&py
) const
1021 py
.kwarg("binned", binned());
1022 py
.kwarg("precision", precision
);
1023 py
.kwarg("flags", flags
);
1025 py
.qkwarg("prereq", prereq
->name
);
1026 py
.kwarg("value", val());
1031 VectorDataBase::python(Python
&py
) const
1033 const_cast<VectorDataBase
*>(this)->update();
1038 py
.kwarg("binned", binned());
1039 py
.kwarg("precision", precision
);
1040 py
.kwarg("flags", flags
);
1042 py
.qkwarg("prereq", prereq
->name
);
1043 py
.kwarg("value", val());
1044 if (!subnames
.empty())
1045 py
.qkwarg("subnames", subnames
);
1046 if (!subdescs
.empty())
1047 py
.qkwarg("subdescs", subdescs
);
1052 DistDataData::python(Python
&py
, const string
&name
) const
1054 string s
= name
.empty() ? "" : name
+ "=";
1056 if (samples
== 0 || fancy
)
1065 if (samples
&& !fancy
) {
1073 py
.arg(bucket_size
);
1080 FormulaDataBase::python(Python
&py
) const
1082 const_cast<FormulaDataBase
*>(this)->update();
1087 py
.kwarg("binned", binned());
1088 py
.kwarg("precision", precision
);
1089 py
.kwarg("flags", flags
);
1091 py
.qkwarg("prereq", prereq
->name
);
1092 py
.qkwarg("formula", str());
1093 if (!subnames
.empty())
1094 py
.qkwarg("subnames", subnames
);
1095 if (!subdescs
.empty())
1096 py
.qkwarg("subdescs", subdescs
);
1101 DistDataBase::python(Python
&py
) const
1103 const_cast<DistDataBase
*>(this)->update();
1108 py
.kwarg("binned", binned());
1109 py
.kwarg("precision", precision
);
1110 py
.kwarg("flags", flags
);
1112 py
.qkwarg("prereq", prereq
->name
);
1113 data
.python(py
, "dist");
1118 VectorDistDataBase::python(Python
&py
) const
1120 const_cast<VectorDistDataBase
*>(this)->update();
1122 py
.name("VectorDist");
1125 py
.kwarg("binned", binned());
1126 py
.kwarg("precision", precision
);
1127 py
.kwarg("flags", flags
);
1129 py
.qkwarg("prereq", prereq
->name
);
1130 if (!subnames
.empty())
1131 py
.qkwarg("subnames", subnames
);
1132 if (!subdescs
.empty())
1133 py
.qkwarg("subdescs", subdescs
);
1136 typedef std::vector
<DistDataData
>::const_iterator iter
;
1137 iter i
= data
.begin();
1138 iter end
= data
.end();
1148 Vector2dDataBase::python(Python
&py
) const
1150 const_cast<Vector2dDataBase
*>(this)->update();
1152 py
.name("Vector2d");
1155 py
.kwarg("binned", binned());
1156 py
.kwarg("precision", precision
);
1157 py
.kwarg("flags", flags
);
1159 py
.qkwarg("prereq", prereq
->name
);
1161 py
.kwarg("value", vec
);
1162 if (!subnames
.empty())
1163 py
.qkwarg("subnames", subnames
);
1164 if (!subdescs
.empty())
1165 py
.qkwarg("subdescs", subdescs
);
1166 if (!y_subnames
.empty())
1167 py
.qkwarg("ysubnames", y_subnames
);
1175 FormulaBase::val(rvec_t
&vec
) const
1182 FormulaBase::total() const
1184 return root
? root
->total() : 0.0;
1188 FormulaBase::size() const
1193 return root
->size();
1197 FormulaBase::binned() const
1199 return root
&& root
->binned();
1203 FormulaBase::reset()
1208 FormulaBase::zero() const
1212 for (int i
= 0; i
< vec
.size(); ++i
)
1219 FormulaBase::update(StatData
*)
1224 FormulaBase::str() const
1226 return root
? root
->str() : "";
1234 Formula::Formula(Temp r
)
1241 Formula::operator=(Temp r
)
1243 assert(!root
&& "Can't change formulas");
1250 Formula::operator+=(Temp r
)
1253 root
= NodePtr(new BinaryNode
<std::plus
<result_t
> >(root
, r
));
1260 MainBin::MainBin(const string
&name
)
1261 : _name(name
), mem(NULL
), memsize(-1)
1263 Database::StatDB().regBin(this, name
);
1273 MainBin::memory(off_t off
)
1276 memsize
= CeilPow2((size_t) offset());
1279 mem
= new char[memsize
];
1280 memset(mem
, 0, memsize
);
1283 assert(offset() <= size());
1290 Database::StatDB().check();
1294 dump(ostream
&stream
, DisplayMode mode
)
1296 Database::StatDB().dump(stream
, mode
);
1300 python_start(const string
&file
)
1302 Database::StatDB().python_start(file
);
1306 python_dump(const string
&name
, const string
&subname
)
1308 Database::StatDB().python_dump(name
, subname
);
1312 CallbackQueue resetQueue
;
1315 registerResetCallback(Callback
*cb
)
1323 Database::StatDB().reset();
1324 resetQueue
.process();
1327 } // namespace Statistics