d7b25c8022
--HG-- extra : convert_revision : 81a644bebf1b9fe11ac767c097c2d457c5698e73
960 lines
22 KiB
C++
960 lines
22 KiB
C++
/*
|
|
* Copyright (c) 2003 The Regents of The University of Michigan
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met: redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer;
|
|
* redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution;
|
|
* neither the name of the copyright holders nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <iomanip>
|
|
#include <iostream>
|
|
#include <list>
|
|
#include <map>
|
|
#include <string>
|
|
#include <sstream>
|
|
|
|
#include "base/callback.hh"
|
|
#include "base/cprintf.hh"
|
|
#include "base/misc.hh"
|
|
#include "base/statistics.hh"
|
|
#include "base/str.hh"
|
|
#include "sim/universe.hh"
|
|
|
|
#ifdef __M5_NAN
|
|
float
|
|
__nan()
|
|
{
|
|
union {
|
|
uint32_t ui;
|
|
float f;
|
|
} nan;
|
|
|
|
nan.ui = 0x7fc00000;
|
|
return nan.f;
|
|
}
|
|
#endif
|
|
|
|
#ifdef STAT_DEBUG
|
|
static int total_stats = 0;
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
// This is a hack to get this parameter from the old stats package.
|
|
namespace Statistics {
|
|
bool PrintDescriptions = true;
|
|
|
|
namespace Detail {
|
|
/**
|
|
* Struct to contain a name and description of statistic subfield.
|
|
*/
|
|
struct SubData
|
|
{
|
|
/** Subfield name. */
|
|
string name;
|
|
/** Subfield desc. */
|
|
string desc;
|
|
};
|
|
|
|
/**
|
|
* Struct to contain print data of a Stat.
|
|
*/
|
|
struct StatData
|
|
{
|
|
/**
|
|
* Create this struct.
|
|
*/
|
|
StatData();
|
|
/**
|
|
* Destructor.
|
|
*/
|
|
~StatData();
|
|
|
|
/** True if the stat has been initialized. */
|
|
bool init;
|
|
/** True if the stat should be printed. */
|
|
bool print;
|
|
/** The name of the stat. */
|
|
string name;
|
|
/** Names and descriptions of subfields. */
|
|
vector<SubData> *subdata;
|
|
/** The description of the stat. */
|
|
string desc;
|
|
/** The display precision. */
|
|
int precision;
|
|
/** The formatting flags. */
|
|
FormatFlags flags;
|
|
/** A pointer to a prerequisite Stat. */
|
|
const Stat *prereq;
|
|
};
|
|
|
|
StatData::StatData()
|
|
: init(false), print(false), subdata(NULL), precision(-1), flags(none),
|
|
prereq(NULL)
|
|
{
|
|
}
|
|
|
|
StatData::~StatData()
|
|
{
|
|
if (subdata)
|
|
delete subdata;
|
|
}
|
|
|
|
class Database
|
|
{
|
|
private:
|
|
Database(const Database &) {}
|
|
|
|
private:
|
|
typedef list<Stat *> list_t;
|
|
typedef map<const Stat *, StatData *> map_t;
|
|
|
|
list<GenBin *> bins;
|
|
map<const GenBin *, std::string > bin_names;
|
|
list_t binnedStats;
|
|
|
|
list_t allStats;
|
|
list_t printStats;
|
|
map_t statMap;
|
|
|
|
public:
|
|
Database();
|
|
~Database();
|
|
|
|
void dump(ostream &stream);
|
|
|
|
StatData *find(const Stat *stat);
|
|
void check();
|
|
void reset();
|
|
void regStat(Stat *stat);
|
|
StatData *print(Stat *stat);
|
|
void regBin(GenBin *bin, std::string name);
|
|
};
|
|
|
|
Database::Database()
|
|
{}
|
|
|
|
Database::~Database()
|
|
{}
|
|
|
|
void
|
|
Database::dump(ostream &stream)
|
|
{
|
|
|
|
#ifndef FS_MEASURE
|
|
list_t::iterator i = printStats.begin();
|
|
list_t::iterator end = printStats.end();
|
|
while (i != end) {
|
|
Stat *stat = *i;
|
|
if (stat->binned())
|
|
binnedStats.push_back(stat);
|
|
++i;
|
|
}
|
|
#endif //FS_MEASURE
|
|
|
|
list<GenBin *>::iterator j = bins.begin();
|
|
list<GenBin *>::iterator bins_end=bins.end();
|
|
|
|
if (!bins.empty()) {
|
|
ccprintf(stream, "PRINTING BINNED STATS\n");
|
|
while (j != bins_end) {
|
|
(*j)->activate();
|
|
map<const GenBin *, std::string>::const_iterator iter;
|
|
iter = bin_names.find(*j);
|
|
if (iter == bin_names.end())
|
|
panic("a binned stat not found in names map!");
|
|
ccprintf(stream,"---%s Bin------------\n", (*iter).second);
|
|
|
|
#ifdef FS_MEASURE
|
|
list_t::iterator i = printStats.begin();
|
|
list_t::iterator end = printStats.end();
|
|
#else
|
|
list_t::iterator i = binnedStats.begin();
|
|
list_t::iterator end = binnedStats.end();
|
|
#endif
|
|
while (i != end) {
|
|
Stat *stat = *i;
|
|
if (stat->dodisplay())
|
|
stat->display(stream);
|
|
++i;
|
|
}
|
|
++j;
|
|
ccprintf(stream, "---------------------------------\n");
|
|
}
|
|
#ifndef FS_MEASURE
|
|
ccprintf(stream, "**************ALL STATS************\n");
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* get bin totals working, then print the stat here (as total), even if
|
|
* its' binned. (this is only for the case you selectively bin a few stats
|
|
*/
|
|
#ifndef FS_MEASURE
|
|
list_t::iterator k = printStats.begin();
|
|
list_t::iterator endprint = printStats.end();
|
|
while (k != endprint) {
|
|
Stat *stat = *k;
|
|
if (stat->dodisplay() && !stat->binned())
|
|
stat->display(stream);
|
|
++k;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
StatData *
|
|
Database::find(const Stat *stat)
|
|
{
|
|
map_t::const_iterator i = statMap.find(stat);
|
|
|
|
if (i == statMap.end())
|
|
return NULL;
|
|
|
|
return (*i).second;
|
|
}
|
|
|
|
void
|
|
Database::check()
|
|
{
|
|
list_t::iterator i = allStats.begin();
|
|
list_t::iterator end = allStats.end();
|
|
|
|
while (i != end) {
|
|
Stat *stat = *i;
|
|
StatData *data = find(stat);
|
|
if (!data || !data->init) {
|
|
#ifdef STAT_DEBUG
|
|
cprintf("this is stat number %d\n",(*i)->number);
|
|
#endif
|
|
panic("Not all stats have been initialized");
|
|
}
|
|
|
|
if (data->print) {
|
|
if (data->name.empty())
|
|
panic("all printable stats must be named");
|
|
|
|
list_t::iterator j = printStats.insert(printStats.end(), *i);
|
|
inplace_merge(printStats.begin(), j,
|
|
printStats.end(), Stat::less);
|
|
}
|
|
|
|
++i;
|
|
}
|
|
}
|
|
|
|
void
|
|
Database::reset()
|
|
{
|
|
list<GenBin *>::iterator bi = bins.begin();
|
|
list<GenBin *>::iterator be = bins.end();
|
|
list_t::iterator i = allStats.begin();
|
|
list_t::iterator end = allStats.end();
|
|
|
|
while (bi != be) {
|
|
(*bi)->activate();
|
|
|
|
while (i != end) {
|
|
(*i)->reset();
|
|
++i;
|
|
}
|
|
++bi;
|
|
}
|
|
}
|
|
|
|
void
|
|
Database::regStat(Stat *stat)
|
|
{
|
|
if (statMap.find(stat) != statMap.end())
|
|
panic("shouldn't register stat twice!");
|
|
|
|
allStats.push_back(stat);
|
|
|
|
StatData *data = new StatData;
|
|
bool success = (statMap.insert(make_pair(stat, data))).second;
|
|
assert(statMap.find(stat) != statMap.end());
|
|
assert(success && "this should never fail");
|
|
}
|
|
|
|
void
|
|
Database::regBin(GenBin *bin, std::string name)
|
|
{
|
|
if (bin_names.find(bin) != bin_names.end())
|
|
panic("shouldn't register bin twice");
|
|
|
|
bins.push_back(bin);
|
|
|
|
bool success = (bin_names.insert(make_pair(bin,name))).second;
|
|
assert(bin_names.find(bin) != bin_names.end());
|
|
assert(success && "this should not fail");
|
|
|
|
cprintf("registering %s\n", name);
|
|
}
|
|
|
|
bool
|
|
Stat::less(Stat *stat1, Stat *stat2)
|
|
{
|
|
const string &name1 = stat1->myname();
|
|
const string &name2 = stat2->myname();
|
|
|
|
vector<string> v1;
|
|
vector<string> v2;
|
|
|
|
tokenize(v1, name1, '.');
|
|
tokenize(v2, name2, '.');
|
|
|
|
int last = min(v1.size(), v2.size()) - 1;
|
|
for (int i = 0; i < last; ++i)
|
|
if (v1[i] != v2[i])
|
|
return v1[i] < v2[i];
|
|
|
|
// Special compare for last element.
|
|
if (v1[last] == v2[last])
|
|
return v1.size() < v2.size();
|
|
else
|
|
return v1[last] < v2[last];
|
|
|
|
return false;
|
|
}
|
|
|
|
StatData *
|
|
Database::print(Stat *stat)
|
|
{
|
|
StatData *data = find(stat);
|
|
assert(data);
|
|
|
|
data->print = true;
|
|
|
|
return data;
|
|
}
|
|
|
|
Database &
|
|
StatDB()
|
|
{
|
|
static Database db;
|
|
return db;
|
|
}
|
|
|
|
Stat::Stat(bool reg)
|
|
{
|
|
#if 0
|
|
// This assert can help you find that pesky stat.
|
|
assert(this != (void *)0xbffff5c0);
|
|
#endif
|
|
|
|
if (reg)
|
|
StatDB().regStat(this);
|
|
|
|
#ifdef STAT_DEBUG
|
|
number = ++total_stats;
|
|
cprintf("I'm stat number %d\n",number);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
Stat::setInit()
|
|
{ mydata()->init = true; }
|
|
|
|
StatData *
|
|
Stat::mydata()
|
|
{
|
|
StatData *data = StatDB().find(this);
|
|
assert(data);
|
|
|
|
return data;
|
|
}
|
|
|
|
const StatData *
|
|
Stat::mydata() const
|
|
{
|
|
StatData *data = StatDB().find(this);
|
|
assert(data);
|
|
|
|
return data;
|
|
}
|
|
|
|
const SubData *
|
|
Stat::mysubdata(int index) const
|
|
{
|
|
assert(index >= 0);
|
|
if (index >= size())
|
|
return NULL;
|
|
|
|
const StatData *data = this->mydata();
|
|
if (!data->subdata || data->subdata->size() <= index)
|
|
return NULL;
|
|
|
|
return &(*data->subdata)[index];
|
|
}
|
|
|
|
SubData *
|
|
Stat::mysubdata_create(int index)
|
|
{
|
|
int size = this->size();
|
|
assert(index >= 0 && (size == 0 || size > 0 && index < size));
|
|
|
|
StatData *data = this->mydata();
|
|
if (!data->subdata) {
|
|
if (!data->subdata) {
|
|
if (size == 0)
|
|
size = index + 1;
|
|
|
|
data->subdata = new vector<SubData>(size);
|
|
}
|
|
} else if (data->subdata->size() <= index)
|
|
data->subdata->resize(index + 1);
|
|
|
|
SubData *sd = &(*data->subdata)[index];
|
|
assert(sd);
|
|
|
|
return sd;
|
|
}
|
|
|
|
string
|
|
Stat::myname() const
|
|
{ return mydata()->name; }
|
|
|
|
string
|
|
Stat::mysubname(int index) const
|
|
{
|
|
const SubData *sd = mysubdata(index);
|
|
return sd ? sd->name : "";
|
|
}
|
|
|
|
string
|
|
Stat::mydesc() const
|
|
{ return mydata()->desc; }
|
|
|
|
string
|
|
Stat::mysubdesc(int index) const
|
|
{
|
|
const SubData *sd = mysubdata(index);
|
|
return sd ? sd->desc : "";
|
|
}
|
|
|
|
int
|
|
Stat::myprecision() const
|
|
{ return mydata()->precision; }
|
|
|
|
FormatFlags
|
|
Stat::myflags() const
|
|
{ return mydata()->flags; }
|
|
|
|
bool
|
|
Stat::dodisplay() const
|
|
{ return !mydata()->prereq || !mydata()->prereq->zero(); }
|
|
|
|
StatData *
|
|
Stat::print()
|
|
{
|
|
StatData *data = StatDB().print(this);
|
|
assert(data && data->init);
|
|
|
|
return data;
|
|
}
|
|
|
|
Stat &
|
|
Stat::name(const string &name)
|
|
{
|
|
print()->name = name;
|
|
return *this;
|
|
}
|
|
|
|
Stat &
|
|
Stat::desc(const string &desc)
|
|
{
|
|
print()->desc = desc;
|
|
return *this;
|
|
}
|
|
|
|
Stat &
|
|
Stat::precision(int precision)
|
|
{
|
|
print()->precision = precision;
|
|
return *this;
|
|
}
|
|
|
|
Stat &
|
|
Stat::flags(FormatFlags flags)
|
|
{
|
|
if (flags & __reserved)
|
|
panic("Cannot set reserved flags!\n");
|
|
|
|
print()->flags |= flags;
|
|
return *this;
|
|
}
|
|
|
|
Stat &
|
|
Stat::prereq(const Stat &prereq)
|
|
{
|
|
print()->prereq = &prereq;
|
|
return *this;
|
|
}
|
|
|
|
Stat &
|
|
Stat::subname(int index, const string &name)
|
|
{
|
|
print();
|
|
mysubdata_create(index)->name = name;
|
|
return *this;
|
|
}
|
|
Stat &
|
|
Stat::subdesc(int index, const string &desc)
|
|
{
|
|
print();
|
|
mysubdata_create(index)->desc = desc;
|
|
return *this;
|
|
}
|
|
|
|
bool
|
|
ScalarStat::zero() const
|
|
{
|
|
return val() == 0.0;
|
|
}
|
|
|
|
bool
|
|
VectorStat::zero() const
|
|
{
|
|
return val()[0] == 0.0;
|
|
}
|
|
|
|
string
|
|
ValueToString(result_t value, int precision)
|
|
{
|
|
stringstream val;
|
|
|
|
if (!isnan(value)) {
|
|
if (precision != -1)
|
|
val.precision(precision);
|
|
else if (value == rint(value))
|
|
val.precision(0);
|
|
|
|
val.unsetf(ios::showpoint);
|
|
val.setf(ios::fixed);
|
|
val << value;
|
|
} else {
|
|
#ifndef STAT_DISPLAY_COMPAT
|
|
val << "no value";
|
|
#else
|
|
val << "<err: div-0>";
|
|
#endif
|
|
}
|
|
|
|
return val.str();
|
|
}
|
|
|
|
void
|
|
PrintOne(ostream &stream, result_t value,
|
|
const string &name, const string &desc, int precision,
|
|
FormatFlags flags, result_t pdf = NAN, result_t cdf = NAN)
|
|
{
|
|
if (flags & nozero && value == 0.0 ||
|
|
flags & nonan && isnan(value))
|
|
return;
|
|
|
|
stringstream pdfstr, cdfstr;
|
|
|
|
if (!isnan(pdf))
|
|
ccprintf(pdfstr, "%.2f%%", pdf * 100.0);
|
|
|
|
if (!isnan(cdf))
|
|
ccprintf(cdfstr, "%.2f%%", cdf * 100.0);
|
|
|
|
#ifdef STAT_DISPLAY_COMPAT
|
|
if (flags & __substat) {
|
|
ccprintf(stream, "%32s%12s%10s%10s", name,
|
|
ValueToString(value, precision),
|
|
pdfstr, cdfstr);
|
|
} else
|
|
#endif
|
|
{
|
|
ccprintf(stream, "%-40s%12s%10s%10s", name,
|
|
ValueToString(value, precision), pdfstr, cdfstr);
|
|
}
|
|
|
|
if (PrintDescriptions) {
|
|
if (!desc.empty())
|
|
ccprintf(stream, " # %s", desc);
|
|
}
|
|
stream << endl;
|
|
}
|
|
|
|
void
|
|
ScalarStat::display(ostream &stream) const
|
|
{
|
|
PrintOne(stream, val(), myname(), mydesc(), myprecision(), myflags());
|
|
}
|
|
|
|
void
|
|
VectorStat::display(ostream &stream) const
|
|
{
|
|
bool have_subname = false;
|
|
bool have_subdesc = false;
|
|
int size = this->size();
|
|
for (int i = 0; i < size; ++i) {
|
|
if (!mysubname(i).empty())
|
|
have_subname = true;
|
|
if (!mysubdesc(i).empty())
|
|
have_subdesc = true;
|
|
}
|
|
|
|
vector<string> *subnames = 0;
|
|
vector<string> *subdescs = 0;
|
|
if (have_subname) {
|
|
subnames = new vector<string>(size);
|
|
for (int i = 0; i < size; ++i)
|
|
(*subnames)[i] = mysubname(i);
|
|
}
|
|
if (have_subdesc) {
|
|
subdescs = new vector<string>(size);
|
|
for (int i = 0; i < size; ++i)
|
|
(*subdescs)[i] = mysubdesc(i);
|
|
}
|
|
|
|
VectorDisplay(stream, myname(), subnames, mydesc(), subdescs,
|
|
myprecision(), myflags(), val(), total());
|
|
}
|
|
|
|
#ifndef STAT_DISPLAY_COMPAT
|
|
#define NAMESEP "::"
|
|
#else
|
|
#define NAMESEP "_"
|
|
#endif
|
|
|
|
#ifndef STAT_DISPLAY_COMPAT
|
|
void
|
|
VectorDisplay(std::ostream &stream,
|
|
const std::string &myname,
|
|
const std::vector<std::string> *mysubnames,
|
|
const std::string &mydesc,
|
|
const std::vector<std::string> *mysubdescs,
|
|
int myprecision, FormatFlags myflags,
|
|
const rvec_t &vec, result_t mytotal)
|
|
{
|
|
int _size = vec.size();
|
|
result_t _total = 0.0;
|
|
result_t _pdf, _cdf = 0.0;
|
|
|
|
if (myflags & (pdf | cdf)) {
|
|
for (int i = 0; i < _size; ++i) {
|
|
_total += vec[i];
|
|
}
|
|
}
|
|
|
|
if (_size == 1) {
|
|
PrintOne(stream, vec[0], myname, mydesc, myprecision, myflags);
|
|
} else {
|
|
for (int i = 0; i < _size; ++i) {
|
|
string subname;
|
|
if (mysubnames) {
|
|
subname = (*mysubnames)[i];
|
|
if (subname.empty())
|
|
continue;
|
|
} else {
|
|
subname = to_string(i);
|
|
}
|
|
|
|
string name = myname + NAMESEP + subname;
|
|
if (!(myflags & pdf))
|
|
PrintOne(stream, vec[i], name, mydesc, myprecision, myflags);
|
|
else {
|
|
_pdf = vec[i] / _total;
|
|
_cdf += _pdf;
|
|
PrintOne(stream, vec[i], name, mydesc, myprecision, myflags,
|
|
_pdf, _cdf);
|
|
}
|
|
}
|
|
|
|
if (myflags & total)
|
|
PrintOne(stream, mytotal, myname + NAMESEP + "total",
|
|
mydesc, myprecision, myflags);
|
|
}
|
|
}
|
|
#else
|
|
void
|
|
VectorDisplay(std::ostream &stream,
|
|
const std::string &myname,
|
|
const std::vector<std::string> *mysubnames,
|
|
const std::string &mydesc,
|
|
const std::vector<std::string> *mysubdescs,
|
|
int myprecision, FormatFlags myflags,
|
|
const rvec_t &vec, result_t mytotal)
|
|
{
|
|
int _size = vec.size();
|
|
result_t _total = 0.0;
|
|
result_t _pdf, _cdf = 0.0;
|
|
|
|
if (myflags & (pdf | cdf)) {
|
|
for (int i = 0; i < _size; ++i) {
|
|
_total += vec[i];
|
|
}
|
|
}
|
|
|
|
if (_size == 1) {
|
|
PrintOne(stream, vec[0], myname, mydesc, myprecision, myflags);
|
|
} else {
|
|
if (myflags & total)
|
|
PrintOne(stream, mytotal, myname, mydesc, myprecision, myflags);
|
|
|
|
if (myflags & dist) {
|
|
ccprintf(stream, "%s.start_dist\n", myname);
|
|
for (int i = 0; i < _size; ++i) {
|
|
string subname, subdesc;
|
|
subname = to_string(i);
|
|
if (mysubnames) {
|
|
if (!subname.empty()) {
|
|
subname = (*mysubnames)[i];
|
|
}
|
|
}
|
|
if (mysubdescs) {
|
|
subdesc = (*mysubdescs)[i];
|
|
}
|
|
if (!(myflags & (pdf | cdf))) {
|
|
PrintOne(stream, vec[i], subname, subdesc, myprecision,
|
|
myflags | __substat);
|
|
} else {
|
|
if (_total) {
|
|
_pdf = vec[i] / _total;
|
|
_cdf += _pdf;
|
|
} else {
|
|
_pdf = _cdf = 0.0;
|
|
}
|
|
if (!(myflags & cdf)) {
|
|
PrintOne(stream, vec[i], subname, subdesc, myprecision,
|
|
myflags | __substat, _pdf);
|
|
} else {
|
|
PrintOne(stream, vec[i], subname, subdesc, myprecision,
|
|
myflags | __substat, _pdf, _cdf);
|
|
}
|
|
}
|
|
}
|
|
ccprintf(stream, "%s.end_dist\n", myname);
|
|
} else {
|
|
for (int i = 0; i < _size; ++i) {
|
|
string subname;
|
|
if (mysubnames) {
|
|
subname = (*mysubnames)[i];
|
|
if (subname.empty())
|
|
continue;
|
|
} else {
|
|
subname = to_string(i);
|
|
}
|
|
|
|
string name = myname + NAMESEP + subname;
|
|
if (!(myflags & pdf)) {
|
|
PrintOne(stream, vec[i], name, mydesc, myprecision,
|
|
myflags);
|
|
} else {
|
|
if (_total) {
|
|
_pdf = vec[i] / _total;
|
|
_cdf += _pdf;
|
|
} else {
|
|
_pdf = _cdf = 0.0;
|
|
}
|
|
_pdf = vec[i] / _total;
|
|
_cdf += _pdf;
|
|
PrintOne(stream, vec[i], name, mydesc, myprecision,
|
|
myflags, _pdf, _cdf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef STAT_DISPLAY_COMPAT
|
|
void
|
|
DistDisplay(ostream &stream, const string &name, const string &desc,
|
|
int precision, FormatFlags flags,
|
|
result_t min_val, result_t max_val,
|
|
result_t underflow, result_t overflow,
|
|
const rvec_t &vec, int min, int max, int bucket_size, int size);
|
|
{
|
|
assert(size == vec.size());
|
|
|
|
result_t total = 0.0;
|
|
result_t pdf, cdf = 0.0;
|
|
|
|
total += underflow;
|
|
for (int i = 0; i < size; ++i)
|
|
total += vec[i];
|
|
total += overflow;
|
|
|
|
pdf = underflow / total;
|
|
cdf += pdf;
|
|
|
|
PrintOne(stream, underflow, name + NAMESEP + "underflow", desc,
|
|
precision, myflags, pdf, cdf);
|
|
|
|
for (int i = 0; i < size; ++i) {
|
|
stringstream namestr;
|
|
namestr << name;
|
|
|
|
int low = i * bucket_size + min;
|
|
int high = ::std::min((i + 1) * bucket_size + min - 1, max);
|
|
namestr << low;
|
|
if (low < high)
|
|
namestr << "-" << high;
|
|
|
|
pdf = vec[i] / total;
|
|
cdf += pdf;
|
|
PrintOne(stream, vec[i], namestr.str(), desc, precision, myflags,
|
|
pdf, cdf);
|
|
}
|
|
|
|
pdf = overflow / total;
|
|
cdf += pdf;
|
|
PrintOne(stream, overflow, name + NAMESEP + "overflow", desc,
|
|
precision, myflags, pdf, cdf);
|
|
PrintOne(stream, total, name + NAMESEP + "total", desc,
|
|
precision, myflags);
|
|
}
|
|
#else
|
|
void
|
|
DistDisplay(ostream &stream, const string &name, const string &desc,
|
|
int precision, FormatFlags flags,
|
|
result_t min_val, result_t max_val,
|
|
result_t underflow, result_t overflow,
|
|
const rvec_t &vec, int min, int max, int bucket_size, int size)
|
|
{
|
|
assert(size == vec.size());
|
|
string blank;
|
|
|
|
result_t total = 0.0;
|
|
|
|
total += underflow;
|
|
for (int i = 0; i < size; ++i)
|
|
total += vec[i];
|
|
total += overflow;
|
|
|
|
ccprintf(stream, "%-42s", name + ".start_dist");
|
|
if (PrintDescriptions && !desc.empty())
|
|
ccprintf(stream, " # %s", desc);
|
|
stream << endl;
|
|
|
|
PrintOne(stream, total, name + ".samples", blank, precision, flags);
|
|
PrintOne(stream, min_val, name + ".min_value", blank, precision, flags);
|
|
|
|
if (underflow > 0)
|
|
PrintOne(stream, min_val, name + ".underflows", blank, precision,
|
|
flags);
|
|
|
|
int _min;
|
|
result_t _pdf, _cdf, mypdf, mycdf;
|
|
|
|
_cdf = 0.0;
|
|
for (int i = 0; i < size; ++i) {
|
|
if (flags & nozero && vec[i] == 0.0 ||
|
|
flags & nonan && isnan(vec[i]))
|
|
continue;
|
|
|
|
_min = i * bucket_size + min;
|
|
_pdf = vec[i] / total * 100.0;
|
|
_cdf += _pdf;
|
|
|
|
mypdf = (flags & pdf) ? _pdf : NAN;
|
|
mycdf = (flags & cdf) ? _cdf : NAN;
|
|
|
|
PrintOne(stream, vec[i], ValueToString(_min, 0), blank, precision,
|
|
flags | __substat, mypdf, mycdf);
|
|
}
|
|
|
|
if (overflow > 0)
|
|
PrintOne(stream, overflow, name + ".overflows", blank, precision,
|
|
flags);
|
|
PrintOne(stream, max_val, name + ".max_value", blank, precision, flags);
|
|
ccprintf(stream, "%s.end_dist\n\n", name);
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @todo get rid of the ugly hack **Ignore for total
|
|
*/
|
|
void
|
|
FancyDisplay(ostream &stream, const string &name, const string &desc,
|
|
int precision, FormatFlags flags, result_t mean,
|
|
result_t variance, result_t total)
|
|
{
|
|
result_t stdev = isnan(variance) ? NAN : sqrt(variance);
|
|
PrintOne(stream, mean, name + NAMESEP + "mean", desc, precision, flags);
|
|
PrintOne(stream, stdev, name + NAMESEP + "stdev", desc, precision, flags);
|
|
PrintOne(stream, total, "**Ignore: " + name + NAMESEP + "TOT", desc, precision, flags);
|
|
}
|
|
|
|
BinBase::BinBase()
|
|
: mem(NULL), memsize(-1)
|
|
{
|
|
}
|
|
|
|
BinBase::~BinBase()
|
|
{
|
|
if (mem)
|
|
delete [] mem;
|
|
}
|
|
|
|
char *
|
|
BinBase::memory()
|
|
{
|
|
if (!mem) {
|
|
mem = new char[memsize];
|
|
memset(mem, 0, memsize);
|
|
}
|
|
|
|
return mem;
|
|
}
|
|
|
|
void
|
|
GenBin::regBin(GenBin *bin, std::string name)
|
|
{
|
|
Detail::StatDB().regBin(bin, name);
|
|
}
|
|
|
|
} // namespace Detail
|
|
|
|
void
|
|
check()
|
|
{
|
|
Detail::StatDB().check();
|
|
}
|
|
|
|
void
|
|
dump(ostream &stream)
|
|
{
|
|
Detail::StatDB().dump(stream);
|
|
}
|
|
|
|
CallbackQueue resetQueue;
|
|
|
|
void
|
|
RegResetCallback(Callback *cb)
|
|
{
|
|
resetQueue.add(cb);
|
|
}
|
|
|
|
void
|
|
reset()
|
|
{
|
|
Detail::StatDB().reset();
|
|
resetQueue.process();
|
|
}
|
|
|
|
} // namespace Statistics
|