gem5/base/statistics.hh
Nathan Binkert a4d7bb113a Make a new stat type of Value which is a scalar stat that
proxies for a real C/C++ scalar value or scalar functor.
This replaces the scalar() and functor() terms that were
previously used in formulas.  This helps when dumping
statistics because the formulas are not supposed to change.

cpu/base_cpu.cc:
    Add a number of cycles stat to the cpu object that tracks the
    number of cycles that the cpu has executed.  This starts to pave
    the way for cpu cycles being different from event ticks.
cpu/base_cpu.hh:
    provide a functor for calculating all simulated instructions
    of all CPUs and a virtual function for determining that number.
    To deal with the change from functor() to Value::functor()
cpu/simple_cpu/simple_cpu.cc:
    simTicks -> numCycles
    numInsts is now a real Scalar stat, not a Formula
cpu/simple_cpu/simple_cpu.hh:
    numInsts is now a real Scalar stat, not a Formula
    count all instructions
sim/stat_control.cc:
    simInsts, simTicks, hostMemory, and hostSeconds are no
    longer Statistics::Formula but rather Statistics::Value
    add new stat for tick frequency
sim/stats.hh:
    don't need everything to be extern.
test/Makefile:
    Make stuff work a tad bit better
test/stattest.cc:
    test out Statistics::Value

--HG--
extra : convert_revision : c812e8baa2b17c08abf3a68ed1e1125dc6f2cfb4
2004-05-12 15:49:01 -04:00

2902 lines
71 KiB
C++

/*
* Copyright (c) 2003-2004 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.
*/
/** @file
* Declaration of Statistics objects.
*/
/**
* @todo
*
* Generalized N-dimensinal vector
* documentation
* key stats
* interval stats
* -- these both can use the same function that prints out a
* specific set of stats
* VectorStandardDeviation totals
* Document Namespaces
*/
#ifndef __BASE_STATISTICS_HH__
#define __BASE_STATISTICS_HH__
#include <algorithm>
#include <cassert>
#include <cmath>
#include <functional>
#include <iosfwd>
#include <sstream>
#include <string>
#include <vector>
#include "base/cprintf.hh"
#include "base/intmath.hh"
#include "base/refcnt.hh"
#include "base/str.hh"
#include "base/stats/bin.hh"
#include "base/stats/flags.hh"
#include "base/stats/visit.hh"
#include "base/stats/types.hh"
#include "sim/host.hh"
class Callback;
/** The current simulated cycle. */
extern Tick curTick;
/* A namespace for all of the Statistics */
namespace Statistics {
/* Contains the statistic implementation details */
//////////////////////////////////////////////////////////////////////
//
// Statistics Framework Base classes
//
//////////////////////////////////////////////////////////////////////
struct StatData
{
/** The name of the stat. */
std::string name;
/** The description of the stat. */
std::string desc;
/** The formatting flags. */
StatFlags flags;
/** The display precision. */
int precision;
/** A pointer to a prerequisite Stat. */
const StatData *prereq;
/**
* A unique stat ID for each stat in the simulator.
* Can be used externally for lookups as well as for debugging.
*/
int id;
StatData();
virtual ~StatData();
/**
* @return true if the stat is binned.
*/
virtual bool binned() const = 0;
/**
* Reset the corresponding stat to the default state.
*/
virtual void reset() = 0;
/**
* @return true if this stat has a value and satisfies its
* requirement as a prereq
*/
virtual bool zero() const = 0;
/**
* Check that this stat has been set up properly and is ready for
* use
* @return true for success
*/
virtual bool check() const = 0;
bool baseCheck() const;
/**
* Visitor entry for outputing statistics data
*/
virtual void visit(Visit &visitor) = 0;
/**
* Checks if the first stat's name is alphabetically less than the second.
* This function breaks names up at periods and considers each subname
* separately.
* @param stat1 The first stat.
* @param stat2 The second stat.
* @return stat1's name is alphabetically before stat2's
*/
static bool less(StatData *stat1, StatData *stat2);
};
class ScalarData : public StatData
{
public:
virtual Counter value() const = 0;
virtual Result result() const = 0;
virtual Result total() const = 0;
virtual void visit(Visit &visitor) { visitor.visit(*this); }
};
template <class Stat>
class ScalarStatData : public ScalarData
{
protected:
Stat &s;
public:
ScalarStatData(Stat &stat) : s(stat) {}
virtual bool binned() const { return s.binned(); }
virtual bool check() const { return s.check(); }
virtual Counter value() const { return s.value(); }
virtual Result result() const { return s.result(); }
virtual Result total() const { return s.total(); }
virtual void reset() { s.reset(); }
virtual bool zero() const { return s.zero(); }
};
struct VectorData : public StatData
{
/** Names and descriptions of subfields. */
mutable std::vector<std::string> subnames;
mutable std::vector<std::string> subdescs;
virtual size_t size() const = 0;
virtual const VCounter &value() const = 0;
virtual const VResult &result() const = 0;
virtual Result total() const = 0;
void update()
{
if (!subnames.empty()) {
int s = size();
if (subnames.size() < s)
subnames.resize(s);
if (subdescs.size() < s)
subdescs.resize(s);
}
}
};
template <class Stat>
class VectorStatData : public VectorData
{
protected:
Stat &s;
mutable VCounter cvec;
mutable VResult rvec;
public:
VectorStatData(Stat &stat) : s(stat) {}
virtual bool binned() const { return s.binned(); }
virtual bool check() const { return s.check(); }
virtual bool zero() const { return s.zero(); }
virtual void reset() { s.reset(); }
virtual size_t size() const { return s.size(); }
virtual VCounter &value() const
{
s.value(cvec);
return cvec;
}
virtual const VResult &result() const
{
s.result(rvec);
return rvec;
}
virtual Result total() const { return s.total(); }
virtual void visit(Visit &visitor)
{
update();
s.update(this);
visitor.visit(*this);
}
};
struct DistDataData
{
Counter min_val;
Counter max_val;
Counter underflow;
Counter overflow;
VCounter cvec;
Counter sum;
Counter squares;
Counter samples;
Counter min;
Counter max;
Counter bucket_size;
int size;
bool fancy;
};
struct DistData : public StatData
{
/** Local storage for the entry values, used for printing. */
DistDataData data;
};
template <class Stat>
class DistStatData : public DistData
{
protected:
Stat &s;
public:
DistStatData(Stat &stat) : s(stat) {}
virtual bool binned() const { return s.binned(); }
virtual bool check() const { return s.check(); }
virtual void reset() { s.reset(); }
virtual bool zero() const { return s.zero(); }
virtual void visit(Visit &visitor)
{
s.update(this);
visitor.visit(*this);
}
};
struct VectorDistData : public StatData
{
std::vector<DistDataData> data;
/** Names and descriptions of subfields. */
mutable std::vector<std::string> subnames;
mutable std::vector<std::string> subdescs;
/** Local storage for the entry values, used for printing. */
mutable VResult rvec;
virtual size_t size() const = 0;
void update()
{
int s = size();
if (subnames.size() < s)
subnames.resize(s);
if (subdescs.size() < s)
subdescs.resize(s);
}
};
template <class Stat>
class VectorDistStatData : public VectorDistData
{
protected:
Stat &s;
typedef typename Stat::bin_t bin_t;
public:
VectorDistStatData(Stat &stat) : s(stat) {}
virtual bool binned() const { return bin_t::binned; }
virtual bool check() const { return s.check(); }
virtual void reset() { s.reset(); }
virtual size_t size() const { return s.size(); }
virtual bool zero() const { return s.zero(); }
virtual void visit(Visit &visitor)
{
update();
s.update(this);
visitor.visit(*this);
}
};
struct Vector2dData : public StatData
{
/** Names and descriptions of subfields. */
std::vector<std::string> subnames;
std::vector<std::string> subdescs;
std::vector<std::string> y_subnames;
/** Local storage for the entry values, used for printing. */
mutable VCounter cvec;
mutable int x;
mutable int y;
void update()
{
if (subnames.size() < x)
subnames.resize(x);
}
};
template <class Stat>
class Vector2dStatData : public Vector2dData
{
protected:
Stat &s;
typedef typename Stat::bin_t bin_t;
public:
Vector2dStatData(Stat &stat) : s(stat) {}
virtual bool binned() const { return bin_t::binned; }
virtual bool check() const { return s.check(); }
virtual void reset() { s.reset(); }
virtual bool zero() const { return s.zero(); }
virtual void visit(Visit &visitor)
{
update();
s.update(this);
visitor.visit(*this);
}
};
class DataAccess
{
protected:
StatData *find() const;
void map(StatData *data);
StatData *statData();
const StatData *statData() const;
void setInit();
void setPrint();
};
template <class Parent, class Child, template <class> class Data>
class Wrap : public Child
{
protected:
Parent &self() { return *reinterpret_cast<Parent *>(this); }
protected:
Data<Child> *statData()
{
StatData *__data = DataAccess::statData();
Data<Child> *ptr = dynamic_cast<Data<Child> *>(__data);
assert(ptr);
return ptr;
}
public:
const Data<Child> *statData() const
{
const StatData *__data = DataAccess::statData();
const Data<Child> *ptr = dynamic_cast<const Data<Child> *>(__data);
assert(ptr);
return ptr;
}
protected:
/**
* Copy constructor, copies are not allowed.
*/
Wrap(const Wrap &stat);
/**
* Can't copy stats.
*/
void operator=(const Wrap &);
public:
Wrap()
{
map(new Data<Child>(*this));
}
/**
* Set the name and marks this stat to print at the end of simulation.
* @param name The new name.
* @return A reference to this stat.
*/
Parent &name(const std::string &_name)
{
Data<Child> *data = statData();
data->name = _name;
setPrint();
return self();
}
/**
* Set the description and marks this stat to print at the end of
* simulation.
* @param desc The new description.
* @return A reference to this stat.
*/
Parent &desc(const std::string &_desc)
{
statData()->desc = _desc;
return self();
}
/**
* Set the precision and marks this stat to print at the end of simulation.
* @param p The new precision
* @return A reference to this stat.
*/
Parent &precision(int _precision)
{
statData()->precision = _precision;
return self();
}
/**
* Set the flags and marks this stat to print at the end of simulation.
* @param f The new flags.
* @return A reference to this stat.
*/
Parent &flags(StatFlags _flags)
{
statData()->flags |= _flags;
return self();
}
/**
* Set the prerequisite stat and marks this stat to print at the end of
* simulation.
* @param prereq The prerequisite stat.
* @return A reference to this stat.
*/
template <class Stat>
Parent &prereq(const Stat &prereq)
{
statData()->prereq = prereq.statData();
return self();
}
};
template <class Parent, class Child, template <class Child> class Data>
class WrapVec : public Wrap<Parent, Child, Data>
{
public:
// The following functions are specific to vectors. If you use them
// in a non vector context, you will get a nice compiler error!
/**
* Set the subfield name for the given index, and marks this stat to print
* at the end of simulation.
* @param index The subfield index.
* @param name The new name of the subfield.
* @return A reference to this stat.
*/
Parent &subname(int index, const std::string &name)
{
std::vector<std::string> &subn = statData()->subnames;
if (subn.size() <= index)
subn.resize(index + 1);
subn[index] = name;
return self();
}
/**
* Set the subfield description for the given index and marks this stat to
* print at the end of simulation.
* @param index The subfield index.
* @param desc The new description of the subfield
* @return A reference to this stat.
*/
Parent &subdesc(int index, const std::string &desc)
{
std::vector<std::string> &subd = statData()->subdescs;
if (subd.size() <= index)
subd.resize(index + 1);
subd[index] = desc;
return self();
}
};
template <class Parent, class Child, template <class Child> class Data>
class WrapVec2d : public WrapVec<Parent, Child, Data>
{
public:
/**
* @warning This makes the assumption that if you're gonna subnames a 2d
* vector, you're subnaming across all y
*/
Parent &ysubnames(const char **names)
{
Data<Child> *data = statData();
data->y_subnames.resize(y);
for (int i = 0; i < y; ++i)
data->y_subnames[i] = names[i];
return self();
}
Parent &ysubname(int index, const std::string subname)
{
Data<Child> *data = statData();
assert(index < y);
data->y_subnames.resize(y);
data->y_subnames[index] = subname.c_str();
return self();
}
};
//////////////////////////////////////////////////////////////////////
//
// Simple Statistics
//
//////////////////////////////////////////////////////////////////////
/**
* Templatized storage and interface for a simple scalar stat.
*/
struct StatStor
{
public:
/** The paramaters for this storage type, none for a scalar. */
struct Params { };
private:
/** The statistic value. */
Counter data;
public:
/**
* Builds this storage element and calls the base constructor of the
* datatype.
*/
StatStor(const Params &) : data(Counter()) {}
/**
* The the stat to the given value.
* @param val The new value.
* @param p The paramters of this storage type.
*/
void set(Counter val, const Params &p) { data = val; }
/**
* Increment the stat by the given value.
* @param val The new value.
* @param p The paramters of this storage type.
*/
void inc(Counter val, const Params &p) { data += val; }
/**
* Decrement the stat by the given value.
* @param val The new value.
* @param p The paramters of this storage type.
*/
void dec(Counter val, const Params &p) { data -= val; }
/**
* Return the value of this stat as its base type.
* @param p The params of this storage type.
* @return The value of this stat.
*/
Counter value(const Params &p) const { return data; }
/**
* Return the value of this stat as a result type.
* @param p The parameters of this storage type.
* @return The value of this stat.
*/
Result result(const Params &p) const { return (Result)data; }
/**
* Reset stat value to default
*/
void reset() { data = Counter(); }
/**
* @return true if zero value
*/
bool zero() const { return data == Counter(); }
};
/**
* Templatized storage and interface to a per-cycle average stat. This keeps
* a current count and updates a total (count * cycles) when this count
* changes. This allows the quick calculation of a per cycle count of the item
* being watched. This is good for keeping track of residencies in structures
* among other things.
* @todo add lateny to the stat and fix binning.
*/
struct AvgStor
{
public:
/** The paramaters for this storage type */
struct Params
{
/**
* The current count. We stash this here because the current
* value is not a binned value.
*/
Counter current;
};
private:
/** The total count for all cycles. */
mutable Result total;
/** The cycle that current last changed. */
mutable Tick last;
public:
/**
* Build and initializes this stat storage.
*/
AvgStor(Params &p) : total(0), last(0) { p.current = Counter(); }
/**
* Set the current count to the one provided, update the total and last
* set values.
* @param val The new count.
* @param p The parameters for this storage.
*/
void set(Counter val, Params &p) {
total += p.current * (curTick - last);
last = curTick;
p.current = val;
}
/**
* Increment the current count by the provided value, calls set.
* @param val The amount to increment.
* @param p The parameters for this storage.
*/
void inc(Counter val, Params &p) { set(p.current + val, p); }
/**
* Deccrement the current count by the provided value, calls set.
* @param val The amount to decrement.
* @param p The parameters for this storage.
*/
void dec(Counter val, Params &p) { set(p.current - val, p); }
/**
* Return the current count.
* @param p The parameters for this storage.
* @return The current count.
*/
Counter value(const Params &p) const { return p.current; }
/**
* Return the current average.
* @param p The parameters for this storage.
* @return The current average.
*/
Result result(const Params &p) const
{
total += p.current * (curTick - last);
last = curTick;
return (Result)(total + p.current) / (Result)(curTick + 1);
}
/**
* Reset stat value to default
*/
void reset()
{
total = 0;
last = curTick;
}
/**
* @return true if zero value
*/
bool zero() const { return total == 0.0; }
};
/**
* Implementation of a scalar stat. The type of stat is determined by the
* Storage template. The storage for this stat is held within the Bin class.
* This allows for breaking down statistics across multiple bins easily.
*/
template <class Storage, class Bin>
class ScalarBase : public DataAccess
{
public:
/** Define the params of the storage class. */
typedef typename Storage::Params params_t;
/** Define the bin type. */
typedef typename Bin::Bin<Storage> bin_t;
protected:
/** The bin of this stat. */
bin_t bin;
/** The parameters for this stat. */
params_t params;
protected:
/**
* Retrieve the storage from the bin.
* @return The storage object for this stat.
*/
Storage *data() { return bin.data(params); }
/**
* Retrieve a const pointer to the storage from the bin.
* @return A const pointer to the storage object for this stat.
*/
const Storage *data() const
{
bin_t *_bin = const_cast<bin_t *>(&bin);
params_t *_params = const_cast<params_t *>(&params);
return _bin->data(*_params);
}
public:
/**
* Return the current value of this stat as its base type.
* @return The current value.
*/
Counter value() const { return data()->value(params); }
public:
/**
* Create and initialize this stat, register it with the database.
*/
ScalarBase()
{
bin.init(params);
}
public:
// Common operators for stats
/**
* Increment the stat by 1. This calls the associated storage object inc
* function.
*/
void operator++() { data()->inc(1, params); }
/**
* Decrement the stat by 1. This calls the associated storage object dec
* function.
*/
void operator--() { data()->dec(1, params); }
/** Increment the stat by 1. */
void operator++(int) { ++*this; }
/** Decrement the stat by 1. */
void operator--(int) { --*this; }
/**
* Set the data value to the given value. This calls the associated storage
* object set function.
* @param v The new value.
*/
template <typename U>
void operator=(const U &v) { data()->set(v, params); }
/**
* Increment the stat by the given value. This calls the associated
* storage object inc function.
* @param v The value to add.
*/
template <typename U>
void operator+=(const U &v) { data()->inc(v, params); }
/**
* Decrement the stat by the given value. This calls the associated
* storage object dec function.
* @param v The value to substract.
*/
template <typename U>
void operator-=(const U &v) { data()->dec(v, params); }
/**
* Return the number of elements, always 1 for a scalar.
* @return 1.
*/
size_t size() const { return 1; }
/**
* Return true if stat is binned.
*@return True is stat is binned.
*/
bool binned() const { return bin_t::binned; }
bool check() const { return bin.initialized(); }
/**
* Reset stat value to default
*/
void reset() { bin.reset(); }
Counter value() { return data()->value(params); }
Result result() { return data()->result(params); }
Result total() { return result(); }
bool zero() { return result() == 0.0; }
};
class ProxyData : public ScalarData
{
public:
virtual void visit(Visit &visitor) { visitor.visit(*this); }
virtual bool binned() const { return false; }
virtual std::string str() const { return to_string(value()); }
virtual size_t size() const { return 1; }
virtual bool zero() const { return value() == 0; }
virtual bool check() const { return true; }
virtual void reset() { }
};
template <class T>
class ValueProxy : public ProxyData
{
private:
T *scalar;
public:
ValueProxy(T &val) : scalar(&val) {}
virtual Counter value() const { return *scalar; }
virtual Result result() const { return *scalar; }
virtual Result total() const { return *scalar; }
};
template <class T>
class FunctorProxy : public ProxyData
{
private:
T *functor;
public:
FunctorProxy(T &func) : functor(&func) {}
virtual Counter value() const { return (*functor)(); }
virtual Result result() const { return (*functor)(); }
virtual Result total() const { return (*functor)(); }
};
class ValueBase : public DataAccess
{
private:
ProxyData *proxy;
public:
ValueBase() : proxy(NULL) { }
~ValueBase() { if (proxy) delete proxy; }
template <class T>
void scalar(T &value)
{
proxy = new ValueProxy<T>(value);
setInit();
}
template <class T>
void functor(T &func)
{
proxy = new FunctorProxy<T>(func);
setInit();
}
Counter value() { return proxy->value(); }
Result result() const { return proxy->result(); }
Result total() const { return proxy->total(); };
size_t size() const { return proxy->size(); }
bool binned() const { return proxy->binned(); }
std::string str() const { return proxy->str(); }
bool zero() const { return proxy->zero(); }
bool check() const { return proxy != NULL; }
void reset() { }
};
//////////////////////////////////////////////////////////////////////
//
// Vector Statistics
//
//////////////////////////////////////////////////////////////////////
template <class Storage, class Bin>
class ScalarProxy;
/**
* Implementation of a vector of stats. The type of stat is determined by the
* Storage class. @sa ScalarBase
*/
template <class Storage, class Bin>
class VectorBase : public DataAccess
{
public:
/** Define the params of the storage class. */
typedef typename Storage::Params params_t;
/** Define the bin type. */
typedef typename Bin::VectorBin<Storage> bin_t;
protected:
/** The bin of this stat. */
bin_t bin;
/** The parameters for this stat. */
params_t params;
protected:
/**
* Retrieve the storage from the bin for the given index.
* @param index The vector index to access.
* @return The storage object at the given index.
*/
Storage *data(int index) { return bin.data(index, params); }
/**
* Retrieve a const pointer to the storage from the bin
* for the given index.
* @param index The vector index to access.
* @return A const pointer to the storage object at the given index.
*/
const Storage *data(int index) const
{
bin_t *_bin = const_cast<bin_t *>(&bin);
params_t *_params = const_cast<params_t *>(&params);
return _bin->data(index, *_params);
}
public:
void value(VCounter &vec) const
{
vec.resize(size());
for (int i = 0; i < size(); ++i)
vec[i] = data(i)->value(params);
}
/**
* Copy the values to a local vector and return a reference to it.
* @return A reference to a vector of the stat values.
*/
void result(VResult &vec) const
{
vec.resize(size());
for (int i = 0; i < size(); ++i)
vec[i] = data(i)->result(params);
}
/**
* @return True is stat is binned.
*/
bool binned() const { return bin_t::binned; }
/**
* Return a total of all entries in this vector.
* @return The total of all vector entries.
*/
Result total() const {
Result total = 0.0;
for (int i = 0; i < size(); ++i)
total += data(i)->result(params);
return total;
}
/**
* @return the number of elements in this vector.
*/
size_t size() const { return bin.size(); }
bool zero() const
{
for (int i = 0; i < size(); ++i)
if (data(i)->zero())
return true;
return false;
}
bool check() const { return bin.initialized(); }
void reset() { bin.reset(); }
public:
VectorBase() {}
/** Friend this class with the associated scalar proxy. */
friend class ScalarProxy<Storage, Bin>;
/**
* Return a reference (ScalarProxy) to the stat at the given index.
* @param index The vector index to access.
* @return A reference of the stat.
*/
ScalarProxy<Storage, Bin> operator[](int index);
void update(StatData *data) {}
};
const StatData * getStatData(const void *stat);
/**
* A proxy class to access the stat at a given index in a VectorBase stat.
* Behaves like a ScalarBase.
*/
template <class Storage, class Bin>
class ScalarProxy
{
public:
/** Define the params of the storage class. */
typedef typename Storage::Params params_t;
/** Define the bin type. */
typedef typename Bin::VectorBin<Storage> bin_t;
private:
/** Pointer to the bin in the parent VectorBase. */
bin_t *bin;
/** Pointer to the params in the parent VectorBase. */
params_t *params;
/** The index to access in the parent VectorBase. */
int index;
/** Keep a pointer to the original stat so was can get data */
void *stat;
protected:
/**
* Retrieve the storage from the bin.
* @return The storage from the bin for this stat.
*/
Storage *data() { return bin->data(index, *params); }
/**
* Retrieve a const pointer to the storage from the bin.
* @return A const pointer to the storage for this stat.
*/
const Storage *data() const
{
bin_t *_bin = const_cast<bin_t *>(bin);
params_t *_params = const_cast<params_t *>(params);
return _bin->data(index, *_params);
}
public:
/**
* Return the current value of this stat as its base type.
* @return The current value.
*/
Counter value() const { return data()->value(*params); }
/**
* Return the current value of this statas a result type.
* @return The current value.
*/
Result result() const { return data()->result(*params); }
public:
/**
* Create and initialize this proxy, do not register it with the database.
* @param b The bin to use.
* @param p The params to use.
* @param i The index to access.
*/
ScalarProxy(bin_t &b, params_t &p, int i, void *s)
: bin(&b), params(&p), index(i), stat(s) {}
/**
* Create a copy of the provided ScalarProxy.
* @param sp The proxy to copy.
*/
ScalarProxy(const ScalarProxy &sp)
: bin(sp.bin), params(sp.params), index(sp.index), stat(sp.stat) {}
/**
* Set this proxy equal to the provided one.
* @param sp The proxy to copy.
* @return A reference to this proxy.
*/
const ScalarProxy &operator=(const ScalarProxy &sp) {
bin = sp.bin;
params = sp.params;
index = sp.index;
stat = sp.stat;
return *this;
}
public:
// Common operators for stats
/**
* Increment the stat by 1. This calls the associated storage object inc
* function.
*/
void operator++() { data()->inc(1, *params); }
/**
* Decrement the stat by 1. This calls the associated storage object dec
* function.
*/
void operator--() { data()->dec(1, *params); }
/** Increment the stat by 1. */
void operator++(int) { ++*this; }
/** Decrement the stat by 1. */
void operator--(int) { --*this; }
/**
* Set the data value to the given value. This calls the associated storage
* object set function.
* @param v The new value.
*/
template <typename U>
void operator=(const U &v) { data()->set(v, *params); }
/**
* Increment the stat by the given value. This calls the associated
* storage object inc function.
* @param v The value to add.
*/
template <typename U>
void operator+=(const U &v) { data()->inc(v, *params); }
/**
* Decrement the stat by the given value. This calls the associated
* storage object dec function.
* @param v The value to substract.
*/
template <typename U>
void operator-=(const U &v) { data()->dec(v, *params); }
/**
* Return the number of elements, always 1 for a scalar.
* @return 1.
*/
size_t size() const { return 1; }
/**
* Return true if stat is binned.
*@return false since Proxies aren't printed/binned
*/
bool binned() const { return false; }
/**
* This stat has no state. Nothing to reset
*/
void reset() { }
public:
const StatData *statData() const { return getStatData(stat); }
std::string str() const
{
return csprintf("%s[%d]", statData()->name, index);
}
};
template <class Storage, class Bin>
inline ScalarProxy<Storage, Bin>
VectorBase<Storage, Bin>::operator[](int index)
{
assert (index >= 0 && index < size());
return ScalarProxy<Storage, Bin>(bin, params, index, this);
}
template <class Storage, class Bin>
class VectorProxy;
template <class Storage, class Bin>
class Vector2dBase : public DataAccess
{
public:
typedef typename Storage::Params params_t;
typedef typename Bin::VectorBin<Storage> bin_t;
protected:
size_t x;
size_t y;
bin_t bin;
params_t params;
protected:
Storage *data(int index) { return bin.data(index, params); }
const Storage *data(int index) const
{
bin_t *_bin = const_cast<bin_t *>(&bin);
params_t *_params = const_cast<params_t *>(&params);
return _bin->data(index, *_params);
}
public:
Vector2dBase() {}
void update(Vector2dData *data)
{
int size = this->size();
data->cvec.resize(size);
for (int i = 0; i < size; ++i)
data->cvec[i] = this->data(i)->value(params);
}
std::string ysubname(int i) const { return (*y_subnames)[i]; }
friend class VectorProxy<Storage, Bin>;
VectorProxy<Storage, Bin> operator[](int index);
size_t size() const { return bin.size(); }
bool zero() const { return data(0)->value(params) == 0.0; }
/**
* Reset stat value to default
*/
void reset() { bin.reset(); }
bool check() { return bin.initialized(); }
};
template <class Storage, class Bin>
class VectorProxy
{
public:
typedef typename Storage::Params params_t;
typedef typename Bin::VectorBin<Storage> bin_t;
private:
bin_t *bin;
params_t *params;
int offset;
int len;
void *stat;
private:
mutable VResult *vec;
Storage *data(int index) {
assert(index < len);
return bin->data(offset + index, *params);
}
const Storage *data(int index) const {
bin_t *_bin = const_cast<bin_t *>(bin);
params_t *_params = const_cast<params_t *>(params);
return _bin->data(offset + index, *_params);
}
public:
const VResult &result() const {
if (vec)
vec->resize(size());
else
vec = new VResult(size());
for (int i = 0; i < size(); ++i)
(*vec)[i] = data(i)->result(*params);
return *vec;
}
Result total() const {
Result total = 0.0;
for (int i = 0; i < size(); ++i)
total += data(i)->result(*params);
return total;
}
public:
VectorProxy(bin_t &b, params_t &p, int o, int l, void *s)
: bin(&b), params(&p), offset(o), len(l), stat(s), vec(NULL)
{
}
VectorProxy(const VectorProxy &sp)
: bin(sp.bin), params(sp.params), offset(sp.offset), len(sp.len),
stat(sp.stat), vec(NULL)
{
}
~VectorProxy()
{
if (vec)
delete vec;
}
const VectorProxy &operator=(const VectorProxy &sp)
{
bin = sp.bin;
params = sp.params;
offset = sp.offset;
len = sp.len;
stat = sp.stat;
if (vec)
delete vec;
vec = NULL;
return *this;
}
ScalarProxy<Storage, Bin> operator[](int index)
{
assert (index >= 0 && index < size());
return ScalarProxy<Storage, Bin>(*bin, *params, offset + index, stat);
}
size_t size() const { return len; }
/**
* Return true if stat is binned.
*@return false since Proxies aren't printed/binned
*/
bool binned() const { return false; }
/**
* This stat has no state. Nothing to reset.
*/
void reset() { }
};
template <class Storage, class Bin>
inline VectorProxy<Storage, Bin>
Vector2dBase<Storage, Bin>::operator[](int index)
{
int offset = index * y;
assert (index >= 0 && offset < size());
return VectorProxy<Storage, Bin>(bin, params, offset, y, this);
}
//////////////////////////////////////////////////////////////////////
//
// Non formula statistics
//
//////////////////////////////////////////////////////////////////////
/**
* Templatized storage and interface for a distrbution stat.
*/
struct DistStor
{
public:
/** The parameters for a distribution stat. */
struct Params
{
/** The minimum value to track. */
Counter min;
/** The maximum value to track. */
Counter max;
/** The number of entries in each bucket. */
Counter bucket_size;
/** The number of buckets. Equal to (max-min)/bucket_size. */
int size;
};
enum { fancy = false };
private:
/** The smallest value sampled. */
Counter min_val;
/** The largest value sampled. */
Counter max_val;
/** The number of values sampled less than min. */
Counter underflow;
/** The number of values sampled more than max. */
Counter overflow;
/** The current sum. */
Counter sum;
/** The sum of squares. */
Counter squares;
/** The number of samples. */
Counter samples;
/** Counter for each bucket. */
VCounter cvec;
public:
/**
* Construct this storage with the supplied params.
* @param params The parameters.
*/
DistStor(const Params &params)
: min_val(INT_MAX), max_val(INT_MIN), underflow(Counter()),
overflow(Counter()), sum(Counter()), squares(Counter()),
samples(Counter()), cvec(params.size)
{
reset();
}
/**
* Add a value to the distribution for the given number of times.
* @param val The value to add.
* @param number The number of times to add the value.
* @param params The paramters of the distribution.
*/
void sample(Counter val, int number, const Params &params)
{
if (val < params.min)
underflow += number;
else if (val > params.max)
overflow += number;
else {
int index = (int)floor((val - params.min) / params.bucket_size);
assert(index < size(params));
cvec[index] += number;
}
if (val < min_val)
min_val = val;
if (val > max_val)
max_val = val;
Counter sample = val * number;
sum += sample;
squares += sample * sample;
samples += number;
}
/**
* Return the number of buckets in this distribution.
* @return the number of buckets.
* @todo Is it faster to return the size from the parameters?
*/
size_t size(const Params &) const { return cvec.size(); }
/**
* Returns true if any calls to sample have been made.
* @param params The paramters of the distribution.
* @return True if any values have been sampled.
*/
bool zero(const Params &params) const
{
return samples == Counter();
}
void update(DistDataData *data, const Params &params)
{
data->min = params.min;
data->max = params.max;
data->bucket_size = params.bucket_size;
data->size = params.size;
data->min_val = (min_val == INT_MAX) ? 0 : min_val;
data->max_val = (max_val == INT_MIN) ? 0 : max_val;
data->underflow = underflow;
data->overflow = overflow;
data->cvec.resize(params.size);
for (int i = 0; i < params.size; ++i)
data->cvec[i] = cvec[i];
data->sum = sum;
data->squares = squares;
data->samples = samples;
}
/**
* Reset stat value to default
*/
void reset()
{
min_val = INT_MAX;
max_val = INT_MIN;
underflow = 0;
overflow = 0;
int size = cvec.size();
for (int i = 0; i < size; ++i)
cvec[i] = Counter();
sum = Counter();
squares = Counter();
samples = Counter();
}
};
/**
* Templatized storage and interface for a distribution that calculates mean
* and variance.
*/
struct FancyStor
{
public:
/**
* No paramters for this storage.
*/
struct Params {};
enum { fancy = true };
private:
/** The current sum. */
Counter sum;
/** The sum of squares. */
Counter squares;
/** The number of samples. */
Counter samples;
public:
/**
* Create and initialize this storage.
*/
FancyStor(const Params &)
: sum(Counter()), squares(Counter()), samples(Counter())
{ }
/**
* Add a value the given number of times to this running average.
* Update the running sum and sum of squares, increment the number of
* values seen by the given number.
* @param val The value to add.
* @param number The number of times to add the value.
* @param p The parameters of this stat.
*/
void sample(Counter val, int number, const Params &p)
{
Counter value = val * number;
sum += value;
squares += value * value;
samples += number;
}
void update(DistDataData *data, const Params &params)
{
data->sum = sum;
data->squares = squares;
data->samples = samples;
}
/**
* Return the number of entries in this stat, 1
* @return 1.
*/
size_t size(const Params &) const { return 1; }
/**
* Return true if no samples have been added.
* @return True if no samples have been added.
*/
bool zero(const Params &) const { return samples == Counter(); }
/**
* Reset stat value to default
*/
void reset()
{
sum = Counter();
squares = Counter();
samples = Counter();
}
};
/**
* Templatized storage for distribution that calculates per cycle mean and
* variance.
*/
struct AvgFancy
{
public:
/** No parameters for this storage. */
struct Params {};
enum { fancy = true };
private:
/** Current total. */
Counter sum;
/** Current sum of squares. */
Counter squares;
public:
/**
* Create and initialize this storage.
*/
AvgFancy(const Params &) : sum(Counter()), squares(Counter()) {}
/**
* Add a value to the distribution for the given number of times.
* Update the running sum and sum of squares.
* @param val The value to add.
* @param number The number of times to add the value.
* @param p The paramters of the distribution.
*/
void sample(Counter val, int number, const Params &p)
{
Counter value = val * number;
sum += value;
squares += value * value;
}
void update(DistDataData *data, const Params &params)
{
data->sum = sum;
data->squares = squares;
data->samples = curTick;
}
/**
* Return the number of entries, in this case 1.
* @return 1.
*/
size_t size(const Params &params) const { return 1; }
/**
* Return true if no samples have been added.
* @return True if the sum is zero.
*/
bool zero(const Params &params) const { return sum == Counter(); }
/**
* Reset stat value to default
*/
void reset()
{
sum = Counter();
squares = Counter();
}
};
/**
* Implementation of a distribution stat. The type of distribution is
* determined by the Storage template. @sa ScalarBase
*/
template <class Storage, class Bin>
class DistBase : public DataAccess
{
public:
/** Define the params of the storage class. */
typedef typename Storage::Params params_t;
/** Define the bin type. */
typedef typename Bin::Bin<Storage> bin_t;
protected:
/** The bin of this stat. */
bin_t bin;
/** The parameters for this stat. */
params_t params;
protected:
/**
* Retrieve the storage from the bin.
* @return The storage object for this stat.
*/
Storage *data() { return bin.data(params); }
/**
* Retrieve a const pointer to the storage from the bin.
* @return A const pointer to the storage object for this stat.
*/
const Storage *data() const
{
bin_t *_bin = const_cast<bin_t *>(&bin);
params_t *_params = const_cast<params_t *>(&params);
return _bin->data(*_params);
}
public:
DistBase() { }
/**
* Add a value to the distribtion n times. Calls sample on the storage
* class.
* @param v The value to add.
* @param n The number of times to add it, defaults to 1.
*/
template <typename U>
void sample(const U &v, int n = 1) { data()->sample(v, n, params); }
/**
* Return the number of entries in this stat.
* @return The number of entries.
*/
size_t size() const { return data()->size(params); }
/**
* Return true if no samples have been added.
* @return True if there haven't been any samples.
*/
bool zero() const { return data()->zero(params); }
void update(DistData *base)
{
base->data.fancy = Storage::fancy;
data()->update(&(base->data), params);
}
/**
* @return True is stat is binned.
*/
bool binned() const { return bin_t::binned; }
/**
* Reset stat value to default
*/
void reset()
{
bin.reset();
}
bool check() { return bin.initialized(); }
};
template <class Storage, class Bin>
class DistProxy;
template <class Storage, class Bin>
class VectorDistBase : public DataAccess
{
public:
typedef typename Storage::Params params_t;
typedef typename Bin::VectorBin<Storage> bin_t;
protected:
bin_t bin;
params_t params;
protected:
Storage *data(int index) { return bin.data(index, params); }
const Storage *data(int index) const
{
bin_t *_bin = const_cast<bin_t *>(&bin);
params_t *_params = const_cast<params_t *>(&params);
return _bin->data(index, *_params);
}
public:
VectorDistBase() {}
friend class DistProxy<Storage, Bin>;
DistProxy<Storage, Bin> operator[](int index);
const DistProxy<Storage, Bin> operator[](int index) const;
size_t size() const { return bin.size(); }
bool zero() const { return false; }
/**
* Return true if stat is binned.
*@return True is stat is binned.
*/
bool binned() const { return bin_t::binned; }
/**
* Reset stat value to default
*/
void reset() { bin.reset(); }
bool check() { return bin.initialized(); }
void update(VectorDistData *base)
{
int size = this->size();
base->data.resize(size);
for (int i = 0; i < size; ++i) {
base->data[i].fancy = Storage::fancy;
data(i)->update(&(base->data[i]), params);
}
}
};
template <class Storage, class Bin>
class DistProxy
{
public:
typedef typename Storage::Params params_t;
typedef typename Bin::Bin<Storage> bin_t;
typedef VectorDistBase<Storage, Bin> base_t;
private:
union {
base_t *stat;
const base_t *cstat;
};
int index;
protected:
Storage *data() { return stat->data(index); }
const Storage *data() const { return cstat->data(index); }
public:
DistProxy(const VectorDistBase<Storage, Bin> &s, int i)
: cstat(&s), index(i) {}
DistProxy(const DistProxy &sp)
: cstat(sp.cstat), index(sp.index) {}
const DistProxy &operator=(const DistProxy &sp) {
cstat = sp.cstat; index = sp.index; return *this;
}
public:
template <typename U>
void sample(const U &v, int n = 1) { data()->sample(v, n, cstat->params); }
size_t size() const { return 1; }
bool zero() const { return data()->zero(cstat->params); }
/**
* Return true if stat is binned.
*@return false since Proxies are not binned/printed.
*/
bool binned() const { return false; }
/**
* Proxy has no state. Nothing to reset.
*/
void reset() { }
};
template <class Storage, class Bin>
inline DistProxy<Storage, Bin>
VectorDistBase<Storage, Bin>::operator[](int index)
{
assert (index >= 0 && index < size());
return DistProxy<Storage, Bin>(*this, index);
}
template <class Storage, class Bin>
inline const DistProxy<Storage, Bin>
VectorDistBase<Storage, Bin>::operator[](int index) const
{
assert (index >= 0 && index < size());
return DistProxy<Storage, Bin>(*this, index);
}
#if 0
template <class Storage, class Bin>
Result
VectorDistBase<Storage, Bin>::total(int index) const
{
int total = 0;
for (int i=0; i < x_size(); ++i) {
total += data(i)->result(*params);
}
}
#endif
//////////////////////////////////////////////////////////////////////
//
// Formula Details
//
//////////////////////////////////////////////////////////////////////
/**
* Base class for formula statistic node. These nodes are used to build a tree
* that represents the formula.
*/
class Node : public RefCounted
{
public:
/**
* Return the number of nodes in the subtree starting at this node.
* @return the number of nodes in this subtree.
*/
virtual size_t size() const = 0;
/**
* Return the result vector of this subtree.
* @return The result vector of this subtree.
*/
virtual const VResult &result() const = 0;
/**
* Return the total of the result vector.
* @return The total of the result vector.
*/
virtual Result total() const = 0;
/**
* Return true if stat is binned.
*@return True is stat is binned.
*/
virtual bool binned() const = 0;
/**
*
*/
virtual std::string str() const = 0;
};
/** Reference counting pointer to a function Node. */
typedef RefCountingPtr<Node> NodePtr;
class ScalarStatNode : public Node
{
private:
const ScalarData *data;
mutable VResult vresult;
public:
ScalarStatNode(const ScalarData *d) : data(d), vresult(1) {}
virtual const VResult &result() const
{
vresult[0] = data->result();
return vresult;
}
virtual Result total() const { return data->result(); };
virtual size_t size() const { return 1; }
/**
* Return true if stat is binned.
*@return True is stat is binned.
*/
virtual bool binned() const { return data->binned(); }
/**
*
*/
virtual std::string str() const { return data->name; }
};
template <class Storage, class Bin>
class ScalarProxyNode : public Node
{
private:
const ScalarProxy<Storage, Bin> proxy;
mutable VResult vresult;
public:
ScalarProxyNode(const ScalarProxy<Storage, Bin> &p)
: proxy(p), vresult(1) { }
virtual const VResult &result() const
{
vresult[0] = proxy.result();
return vresult;
}
virtual Result total() const { return proxy.result(); };
virtual size_t size() const { return 1; }
/**
* Return true if stat is binned.
*@return True is stat is binned.
*/
virtual bool binned() const { return proxy.binned(); }
/**
*
*/
virtual std::string str() const { return proxy.str(); }
};
class VectorStatNode : public Node
{
private:
const VectorData *data;
public:
VectorStatNode(const VectorData *d) : data(d) { }
virtual const VResult &result() const { return data->result(); }
virtual Result total() const { return data->total(); };
virtual size_t size() const { return data->size(); }
/**
* Return true if stat is binned.
*@return True is stat is binned.
*/
virtual bool binned() const { return data->binned(); }
virtual std::string str() const { return data->name; }
};
template <class T>
class ConstNode : public Node
{
private:
VResult vresult;
public:
ConstNode(T s) : vresult(1, (Result)s) {}
const VResult &result() const { return vresult; }
virtual Result total() const { return vresult[0]; };
virtual size_t size() const { return 1; }
/**
* Return true if stat is binned.
*@return False since constants aren't binned.
*/
virtual bool binned() const { return false; }
virtual std::string str() const { return to_string(vresult[0]); }
};
template <class Op>
struct OpString;
template<>
struct OpString<std::plus<Result> >
{
static std::string str() { return "+"; }
};
template<>
struct OpString<std::minus<Result> >
{
static std::string str() { return "-"; }
};
template<>
struct OpString<std::multiplies<Result> >
{
static std::string str() { return "*"; }
};
template<>
struct OpString<std::divides<Result> >
{
static std::string str() { return "/"; }
};
template<>
struct OpString<std::modulus<Result> >
{
static std::string str() { return "%"; }
};
template<>
struct OpString<std::negate<Result> >
{
static std::string str() { return "-"; }
};
template <class Op>
class UnaryNode : public Node
{
public:
NodePtr l;
mutable VResult vresult;
public:
UnaryNode(NodePtr &p) : l(p) {}
const VResult &result() const
{
const VResult &lvec = l->result();
int size = lvec.size();
assert(size > 0);
vresult.resize(size);
Op op;
for (int i = 0; i < size; ++i)
vresult[i] = op(lvec[i]);
return vresult;
}
Result total() const {
Op op;
return op(l->total());
}
virtual size_t size() const { return l->size(); }
/**
* Return true if child of node is binned.
*@return True if child of node is binned.
*/
virtual bool binned() const { return l->binned(); }
virtual std::string str() const
{
return OpString<Op>::str() + l->str();
}
};
template <class Op>
class BinaryNode : public Node
{
public:
NodePtr l;
NodePtr r;
mutable VResult vresult;
public:
BinaryNode(NodePtr &a, NodePtr &b) : l(a), r(b) {}
const VResult &result() const
{
Op op;
const VResult &lvec = l->result();
const VResult &rvec = r->result();
assert(lvec.size() > 0 && rvec.size() > 0);
if (lvec.size() == 1 && rvec.size() == 1) {
vresult.resize(1);
vresult[0] = op(lvec[0], rvec[0]);
} else if (lvec.size() == 1) {
int size = rvec.size();
vresult.resize(size);
for (int i = 0; i < size; ++i)
vresult[i] = op(lvec[0], rvec[i]);
} else if (rvec.size() == 1) {
int size = lvec.size();
vresult.resize(size);
for (int i = 0; i < size; ++i)
vresult[i] = op(lvec[i], rvec[0]);
} else if (rvec.size() == lvec.size()) {
int size = rvec.size();
vresult.resize(size);
for (int i = 0; i < size; ++i)
vresult[i] = op(lvec[i], rvec[i]);
}
return vresult;
}
Result total() const {
Op op;
return op(l->total(), r->total());
}
virtual size_t size() const {
int ls = l->size();
int rs = r->size();
if (ls == 1)
return rs;
else if (rs == 1)
return ls;
else {
assert(ls == rs && "Node vector sizes are not equal");
return ls;
}
}
/**
* Return true if any children of node are binned
*@return True if either child of node is binned.
*/
virtual bool binned() const { return (l->binned() || r->binned()); }
virtual std::string str() const
{
return csprintf("(%s %s %s)", l->str(), OpString<Op>::str(), r->str());
}
};
template <class Op>
class SumNode : public Node
{
public:
NodePtr l;
mutable VResult vresult;
public:
SumNode(NodePtr &p) : l(p), vresult(1) {}
const VResult &result() const
{
const VResult &lvec = l->result();
int size = lvec.size();
assert(size > 0);
vresult[0] = 0.0;
Op op;
for (int i = 0; i < size; ++i)
vresult[0] = op(vresult[0], lvec[i]);
return vresult;
}
Result total() const
{
const VResult &lvec = l->result();
int size = lvec.size();
assert(size > 0);
Result vresult = 0.0;
Op op;
for (int i = 0; i < size; ++i)
vresult = op(vresult, lvec[i]);
return vresult;
}
virtual size_t size() const { return 1; }
/**
* Return true if child of node is binned.
*@return True if child of node is binned.
*/
virtual bool binned() const { return l->binned(); }
virtual std::string str() const
{
return csprintf("total(%s)", l->str());
}
};
//////////////////////////////////////////////////////////////////////
//
// Visible Statistics Types
//
//////////////////////////////////////////////////////////////////////
/**
* @defgroup VisibleStats "Statistic Types"
* These are the statistics that are used in the simulator. By default these
* store counters and don't use binning, but are templatized to accept any type
* and any Bin class.
* @{
*/
/**
* This is an easy way to assign all your stats to be binned or not
* binned. If the typedef is NoBin, nothing is binned. If it is
* MainBin, then all stats are binned under that Bin.
*/
#if defined(FS_MEASURE)
typedef MainBin DefaultBin;
#else
typedef NoBin DefaultBin;
#endif
/**
* This is a simple scalar statistic, like a counter.
* @sa Stat, ScalarBase, StatStor
*/
template <class Bin = DefaultBin>
class Scalar
: public Wrap<Scalar<Bin>,
ScalarBase<StatStor, Bin>,
ScalarStatData>
{
public:
/** The base implementation. */
typedef ScalarBase<StatStor, Bin> Base;
Scalar()
{
setInit();
}
/**
* Sets the stat equal to the given value. Calls the base implementation
* of operator=
* @param v The new value.
*/
template <typename U>
void operator=(const U &v) { Base::operator=(v); }
};
class Value
: public Wrap<Value,
ValueBase,
ScalarStatData>
{
public:
/** The base implementation. */
typedef ValueBase Base;
template <class T>
Value &scalar(T &value)
{
Base::scalar(value);
return *this;
}
template <class T>
Value &functor(T &func)
{
Base::functor(func);
return *this;
}
};
/**
* A stat that calculates the per cycle average of a value.
* @sa Stat, ScalarBase, AvgStor
*/
template <class Bin = DefaultBin>
class Average
: public Wrap<Average<Bin>,
ScalarBase<AvgStor, Bin>,
ScalarStatData>
{
public:
/** The base implementation. */
typedef ScalarBase<AvgStor, Bin> Base;
Average()
{
setInit();
}
/**
* Sets the stat equal to the given value. Calls the base implementation
* of operator=
* @param v The new value.
*/
template <typename U>
void operator=(const U &v) { Base::operator=(v); }
};
/**
* A vector of scalar stats.
* @sa Stat, VectorBase, StatStor
*/
template <class Bin = DefaultBin>
class Vector
: public WrapVec<Vector<Bin>,
VectorBase<StatStor, Bin>,
VectorStatData>
{
public:
/** The base implementation. */
typedef ScalarBase<StatStor, Bin> Base;
/**
* Set this vector to have the given size.
* @param size The new size.
* @return A reference to this stat.
*/
Vector &init(size_t size) {
bin.init(size, params);
setInit();
return *this;
}
};
/**
* A vector of Average stats.
* @sa Stat, VectorBase, AvgStor
*/
template <class Bin = DefaultBin>
class AverageVector
: public WrapVec<AverageVector<Bin>,
VectorBase<AvgStor, Bin>,
VectorStatData>
{
public:
/**
* Set this vector to have the given size.
* @param size The new size.
* @return A reference to this stat.
*/
AverageVector &init(size_t size) {
bin.init(size, params);
setInit();
return *this;
}
};
/**
* A 2-Dimensional vecto of scalar stats.
* @sa Stat, Vector2dBase, StatStor
*/
template <class Bin = DefaultBin>
class Vector2d
: public WrapVec2d<Vector2d<Bin>,
Vector2dBase<StatStor, Bin>,
Vector2dStatData>
{
public:
Vector2d &init(size_t _x, size_t _y) {
statData()->x = x = _x;
statData()->y = y = _y;
bin.init(x * y, params);
setInit();
return *this;
}
};
/**
* A simple distribution stat.
* @sa Stat, DistBase, DistStor
*/
template <class Bin = DefaultBin>
class Distribution
: public Wrap<Distribution<Bin>,
DistBase<DistStor, Bin>,
DistStatData>
{
public:
/** Base implementation. */
typedef DistBase<DistStor, Bin> Base;
/** The Parameter type. */
typedef typename DistStor::Params Params;
public:
/**
* Set the parameters of this distribution. @sa DistStor::Params
* @param min The minimum value of the distribution.
* @param max The maximum value of the distribution.
* @param bkt The number of values in each bucket.
* @return A reference to this distribution.
*/
Distribution &init(Counter min, Counter max, Counter bkt) {
params.min = min;
params.max = max;
params.bucket_size = bkt;
params.size = (int)rint((max - min) / bkt + 1.0);
bin.init(params);
setInit();
return *this;
}
};
/**
* Calculates the mean and variance of all the samples.
* @sa Stat, DistBase, FancyStor
*/
template <class Bin = DefaultBin>
class StandardDeviation
: public Wrap<StandardDeviation<Bin>,
DistBase<FancyStor, Bin>,
DistStatData>
{
public:
/** The base implementation */
typedef DistBase<DistStor, Bin> Base;
/** The parameter type. */
typedef typename DistStor::Params Params;
public:
/**
* Construct and initialize this distribution.
*/
StandardDeviation() {
bin.init(params);
setInit();
}
};
/**
* Calculates the per cycle mean and variance of the samples.
* @sa Stat, DistBase, AvgFancy
*/
template <class Bin = DefaultBin>
class AverageDeviation
: public Wrap<AverageDeviation<Bin>,
DistBase<AvgFancy, Bin>,
DistStatData>
{
public:
/** The base implementation */
typedef DistBase<DistStor, Bin> Base;
/** The parameter type. */
typedef typename DistStor::Params Params;
public:
/**
* Construct and initialize this distribution.
*/
AverageDeviation()
{
bin.init(params);
setInit();
}
};
/**
* A vector of distributions.
* @sa Stat, VectorDistBase, DistStor
*/
template <class Bin = DefaultBin>
class VectorDistribution
: public WrapVec<VectorDistribution<Bin>,
VectorDistBase<DistStor, Bin>,
VectorDistStatData>
{
public:
/** The base implementation */
typedef VectorDistBase<DistStor, Bin> Base;
/** The parameter type. */
typedef typename DistStor::Params Params;
public:
/**
* Initialize storage and parameters for this distribution.
* @param size The size of the vector (the number of distributions).
* @param min The minimum value of the distribution.
* @param max The maximum value of the distribution.
* @param bkt The number of values in each bucket.
* @return A reference to this distribution.
*/
VectorDistribution &init(int size, Counter min, Counter max, Counter bkt) {
params.min = min;
params.max = max;
params.bucket_size = bkt;
params.size = (int)rint((max - min) / bkt + 1.0);
bin.init(size, params);
setInit();
return *this;
}
};
/**
* This is a vector of StandardDeviation stats.
* @sa Stat, VectorDistBase, FancyStor
*/
template <class Bin = DefaultBin>
class VectorStandardDeviation
: public WrapVec<VectorStandardDeviation<Bin>,
VectorDistBase<FancyStor, Bin>,
VectorDistStatData>
{
public:
/** The base implementation */
typedef VectorDistBase<FancyStor, Bin> Base;
/** The parameter type. */
typedef typename DistStor::Params Params;
public:
/**
* Initialize storage for this distribution.
* @param size The size of the vector.
* @return A reference to this distribution.
*/
VectorStandardDeviation &init(int size) {
bin.init(size, params);
setInit();
return *this;
}
};
/**
* This is a vector of AverageDeviation stats.
* @sa Stat, VectorDistBase, AvgFancy
*/
template <class Bin = DefaultBin>
class VectorAverageDeviation
: public WrapVec<VectorAverageDeviation<Bin>,
VectorDistBase<AvgFancy, Bin>,
VectorDistStatData>
{
public:
/** The base implementation */
typedef VectorDistBase<AvgFancy, Bin> Base;
/** The parameter type. */
typedef typename DistStor::Params Params;
public:
/**
* Initialize storage for this distribution.
* @param size The size of the vector.
* @return A reference to this distribution.
*/
VectorAverageDeviation &init(int size) {
bin.init(size, params);
setInit();
return *this;
}
};
/**
* A formula for statistics that is calculated when printed. A formula is
* stored as a tree of Nodes that represent the equation to calculate.
* @sa Stat, ScalarStat, VectorStat, Node, Temp
*/
class FormulaBase : public DataAccess
{
protected:
/** The root of the tree which represents the Formula */
NodePtr root;
friend class Temp;
public:
/**
* Return the result of the Fomula in a vector. If there were no Vector
* components to the Formula, then the vector is size 1. If there were,
* like x/y with x being a vector of size 3, then the result returned will
* be x[0]/y, x[1]/y, x[2]/y, respectively.
* @return The result vector.
*/
void result(VResult &vec) const;
/**
* Return the total Formula result. If there is a Vector
* component to this Formula, then this is the result of the
* Formula if the formula is applied after summing all the
* components of the Vector. For example, if Formula is x/y where
* x is size 3, then total() will return (x[1]+x[2]+x[3])/y. If
* there is no Vector component, total() returns the same value as
* the first entry in the VResult val() returns.
* @return The total of the result vector.
*/
Result total() const;
/**
* Return the number of elements in the tree.
*/
size_t size() const;
/**
* Return true if Formula is binned. i.e. any of its children
* nodes are binned
* @return True if Formula is binned.
*/
bool binned() const;
bool check() const { return true; }
/**
* Formulas don't need to be reset
*/
void reset();
/**
*
*/
bool zero() const;
/**
*
*/
void update(StatData *);
std::string str() const;
};
class FormulaData : public VectorData
{
public:
virtual std::string str() const = 0;
virtual bool check() const { return true; }
};
template <class Stat>
class FormulaStatData : public FormulaData
{
protected:
Stat &s;
mutable VResult vec;
mutable VCounter cvec;
public:
FormulaStatData(Stat &stat) : s(stat) {}
virtual bool binned() const { return s.binned(); }
virtual bool zero() const { return s.zero(); }
virtual void reset() { s.reset(); }
virtual size_t size() const { return s.size(); }
virtual const VResult &result() const
{
s.result(vec);
return vec;
}
virtual Result total() const { return s.total(); }
virtual VCounter &value() const { return cvec; }
virtual void visit(Visit &visitor)
{
update();
s.update(this);
visitor.visit(*this);
}
virtual std::string str() const { return s.str(); }
};
class Temp;
class Formula
: public WrapVec<Formula,
FormulaBase,
FormulaStatData>
{
public:
/**
* Create and initialize thie formula, and register it with the database.
*/
Formula();
/**
* Create a formula with the given root node, register it with the
* database.
* @param r The root of the expression tree.
*/
Formula(Temp r);
/**
* Set an unitialized Formula to the given root.
* @param r The root of the expression tree.
* @return a reference to this formula.
*/
const Formula &operator=(Temp r);
/**
* Add the given tree to the existing one.
* @param r The root of the expression tree.
* @return a reference to this formula.
*/
const Formula &operator+=(Temp r);
};
class FormulaNode : public Node
{
private:
const Formula &formula;
mutable VResult vec;
public:
FormulaNode(const Formula &f) : formula(f) {}
virtual size_t size() const { return formula.size(); }
virtual const VResult &result() const { formula.result(vec); return vec; }
virtual Result total() const { return formula.total(); }
virtual bool binned() const { return formula.binned(); }
virtual std::string str() const { return formula.str(); }
};
/**
* Helper class to construct formula node trees.
*/
class Temp
{
protected:
/**
* Pointer to a Node object.
*/
NodePtr node;
public:
/**
* Copy the given pointer to this class.
* @param n A pointer to a Node object to copy.
*/
Temp(NodePtr n) : node(n) { }
/**
* Return the node pointer.
* @return the node pointer.
*/
operator NodePtr&() { return node;}
public:
/**
* Create a new ScalarStatNode.
* @param s The ScalarStat to place in a node.
*/
template <class Bin>
Temp(const Scalar<Bin> &s)
: node(new ScalarStatNode(s.statData())) { }
/**
* Create a new ScalarStatNode.
* @param s The ScalarStat to place in a node.
*/
Temp(const Value &s)
: node(new ScalarStatNode(s.statData())) { }
/**
* Create a new ScalarStatNode.
* @param s The ScalarStat to place in a node.
*/
template <class Bin>
Temp(const Average<Bin> &s)
: node(new ScalarStatNode(s.statData())) { }
/**
* Create a new VectorStatNode.
* @param s The VectorStat to place in a node.
*/
template <class Bin>
Temp(const Vector<Bin> &s)
: node(new VectorStatNode(s.statData())) { }
/**
*
*/
Temp(const Formula &f)
: node(new FormulaNode(f)) { }
/**
* Create a new ScalarProxyNode.
* @param p The ScalarProxy to place in a node.
*/
template <class Storage, class Bin>
Temp(const ScalarProxy<Storage, Bin> &p)
: node(new ScalarProxyNode<Storage, Bin>(p)) { }
/**
* Create a ConstNode
* @param value The value of the const node.
*/
Temp(signed char value)
: node(new ConstNode<signed char>(value)) {}
/**
* Create a ConstNode
* @param value The value of the const node.
*/
Temp(unsigned char value)
: node(new ConstNode<unsigned char>(value)) {}
/**
* Create a ConstNode
* @param value The value of the const node.
*/
Temp(signed short value)
: node(new ConstNode<signed short>(value)) {}
/**
* Create a ConstNode
* @param value The value of the const node.
*/
Temp(unsigned short value)
: node(new ConstNode<unsigned short>(value)) {}
/**
* Create a ConstNode
* @param value The value of the const node.
*/
Temp(signed int value)
: node(new ConstNode<signed int>(value)) {}
/**
* Create a ConstNode
* @param value The value of the const node.
*/
Temp(unsigned int value)
: node(new ConstNode<unsigned int>(value)) {}
/**
* Create a ConstNode
* @param value The value of the const node.
*/
Temp(signed long value)
: node(new ConstNode<signed long>(value)) {}
/**
* Create a ConstNode
* @param value The value of the const node.
*/
Temp(unsigned long value)
: node(new ConstNode<unsigned long>(value)) {}
/**
* Create a ConstNode
* @param value The value of the const node.
*/
Temp(signed long long value)
: node(new ConstNode<signed long long>(value)) {}
/**
* Create a ConstNode
* @param value The value of the const node.
*/
Temp(unsigned long long value)
: node(new ConstNode<unsigned long long>(value)) {}
/**
* Create a ConstNode
* @param value The value of the const node.
*/
Temp(float value)
: node(new ConstNode<float>(value)) {}
/**
* Create a ConstNode
* @param value The value of the const node.
*/
Temp(double value)
: node(new ConstNode<double>(value)) {}
};
/**
* @}
*/
void check();
void reset();
void registerResetCallback(Callback *cb);
inline Temp
operator+(Temp l, Temp r)
{
return NodePtr(new BinaryNode<std::plus<Result> >(l, r));
}
inline Temp
operator-(Temp l, Temp r)
{
return NodePtr(new BinaryNode<std::minus<Result> >(l, r));
}
inline Temp
operator*(Temp l, Temp r)
{
return NodePtr(new BinaryNode<std::multiplies<Result> >(l, r));
}
inline Temp
operator/(Temp l, Temp r)
{
return NodePtr(new BinaryNode<std::divides<Result> >(l, r));
}
inline Temp
operator%(Temp l, Temp r)
{
return NodePtr(new BinaryNode<std::modulus<Result> >(l, r));
}
inline Temp
operator-(Temp l)
{
return NodePtr(new UnaryNode<std::negate<Result> >(l));
}
template <typename T>
inline Temp
constant(T val)
{
return NodePtr(new ConstNode<T>(val));
}
inline Temp
sum(Temp val)
{
return NodePtr(new SumNode<std::plus<Result> >(val));
}
/* namespace Statistics */ }
#endif // __BASE_STATISTICS_HH__