X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fbase%2Fstatistics.hh;h=f4fa123e970d71780883f1c2495adae18dd8deee;hb=6f38428abbe106d63318dd86bfa82a03b6b368ee;hp=d8e8b4c1511fce5138785d3023f6f81e834bab4c;hpb=6d9d0c68b574ceba53fc36d34b83f7109e00b1d0;p=gem5.git diff --git a/src/base/statistics.hh b/src/base/statistics.hh index d8e8b4c15..f4fa123e9 100644 --- a/src/base/statistics.hh +++ b/src/base/statistics.hh @@ -1,5 +1,18 @@ /* + * Copyright (c) 2019 Arm Limited + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2003-2005 The Regents of The University of Michigan + * Copyright (c) 2017, Centre National de la Recherche Scientifique * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,7 +39,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Nathan Binkert - * Erik Hallnor + * Pierre-Yves Peneau */ /** @file @@ -56,349 +69,205 @@ #include #include #include +#include +#include +#include #include #include +#include "base/stats/group.hh" +#include "base/stats/info.hh" +#include "base/stats/output.hh" +#include "base/stats/types.hh" +#include "base/cast.hh" #include "base/cprintf.hh" #include "base/intmath.hh" -#include "base/refcnt.hh" #include "base/str.hh" -#include "base/stats/flags.hh" -#include "base/stats/visit.hh" -#include "base/stats/types.hh" -#include "sim/host.hh" +#include "base/types.hh" class Callback; -/** The current simulated cycle. */ -extern Tick curTick; +/** The current simulated tick. */ +extern Tick curTick(); /* A namespace for all of the Statistics */ namespace Stats { -/* 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(); - - /** - * 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 ScalarStatData : public ScalarData +template +class InfoProxy : public Base { protected: Stat &s; public: - ScalarStatData(Stat &stat) : s(stat) {} + InfoProxy(Stat &stat) : s(stat) {} - 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(); } + bool check() const { return s.check(); } + void prepare() { s.prepare(); } + void reset() { s.reset(); } + void + visit(Output &visitor) + { + visitor.visit(*static_cast(this)); + } + bool zero() const { return s.zero(); } }; -struct VectorData : public StatData +template +class ScalarInfoProxy : public InfoProxy { - /** Names and descriptions of subfields. */ - mutable std::vector subnames; - mutable std::vector 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); + public: + ScalarInfoProxy(Stat &stat) : InfoProxy(stat) {} - if (subdescs.size() < s) - subdescs.resize(s); - } - } + Counter value() const { return this->s.value(); } + Result result() const { return this->s.result(); } + Result total() const { return this->s.total(); } }; template -class VectorStatData : public VectorData +class VectorInfoProxy : public InfoProxy { protected: - Stat &s; mutable VCounter cvec; mutable VResult rvec; public: - VectorStatData(Stat &stat) : s(stat) {} + VectorInfoProxy(Stat &stat) : InfoProxy(stat) {} - virtual bool check() const { return s.check(); } - virtual bool zero() const { return s.zero(); } - virtual void reset() { s.reset(); } + size_type size() const { return this->s.size(); } - virtual size_t size() const { return s.size(); } - virtual VCounter &value() const + VCounter & + value() const { - s.value(cvec); + this->s.value(cvec); return cvec; } - virtual const VResult &result() const + + const VResult & + result() const { - s.result(rvec); + this->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; + Result total() const { return this->s.total(); } }; template -class DistStatData : public DistData +class DistInfoProxy : public InfoProxy { - protected: - Stat &s; - public: - DistStatData(Stat &stat) : s(stat) {} - - 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); - } + DistInfoProxy(Stat &stat) : InfoProxy(stat) {} }; -struct VectorDistData : public StatData +template +class VectorDistInfoProxy : public InfoProxy { - std::vector data; - - /** Names and descriptions of subfields. */ - mutable std::vector subnames; - mutable std::vector 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); + public: + VectorDistInfoProxy(Stat &stat) : InfoProxy(stat) {} - if (subdescs.size() < s) - subdescs.resize(s); - } + size_type size() const { return this->s.size(); } }; template -class VectorDistStatData : public VectorDistData +class Vector2dInfoProxy : public InfoProxy { - protected: - Stat &s; - public: - VectorDistStatData(Stat &stat) : s(stat) {} + Vector2dInfoProxy(Stat &stat) : InfoProxy(stat) {} - 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); - } + Result total() const { return this->s.total(); } }; -struct Vector2dData : public StatData +struct StorageParams { - /** Names and descriptions of subfields. */ - std::vector subnames; - std::vector subdescs; - std::vector 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); - } + virtual ~StorageParams(); }; -template -class Vector2dStatData : public Vector2dData +class InfoAccess { + private: + Info *_info; + protected: - Stat &s; + /** Set up an info class for this statistic */ + void setInfo(Group *parent, Info *info); + /** Save Storage class parameters if any */ + void setParams(const StorageParams *params); + /** Save Storage class parameters if any */ + void setInit(); - public: - Vector2dStatData(Stat &stat) : s(stat) {} + /** Grab the information class for this statistic */ + Info *info(); + /** Grab the information class for this statistic */ + const Info *info() const; - 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); - } -}; + public: + InfoAccess() + : _info(nullptr) {}; -class DataAccess -{ - protected: - StatData *find() const; - void map(StatData *data); + /** + * Reset the stat to the default state. + */ + void reset() { } - StatData *statData(); - const StatData *statData() const; + /** + * @return true if this stat has a value and satisfies its + * requirement as a prereq + */ + bool zero() const { return true; } - void setInit(); - void setPrint(); + /** + * Check that this stat has been set up properly and is ready for + * use + * @return true for success + */ + bool check() const { return true; } }; -template class Data> -class Wrap : public Child +template class InfoProxyType> +class DataWrap : public InfoAccess { + public: + typedef InfoProxyType Info; + protected: - Parent &self() { return *reinterpret_cast(this); } + Derived &self() { return *static_cast(this); } protected: - Data *statData() + Info * + info() { - StatData *__data = DataAccess::statData(); - Data *ptr = dynamic_cast *>(__data); - assert(ptr); - return ptr; + return safe_cast(InfoAccess::info()); } public: - const Data *statData() const + const Info * + info() const { - const StatData *__data = DataAccess::statData(); - const Data *ptr = dynamic_cast *>(__data); - assert(ptr); - return ptr; + return safe_cast(InfoAccess::info()); } - protected: - /** - * Copy constructor, copies are not allowed. - */ - Wrap(const Wrap &stat); - /** - * Can't copy stats. - */ - void operator=(const Wrap &); - public: - Wrap() + DataWrap() = delete; + DataWrap(const DataWrap &) = delete; + DataWrap &operator=(const DataWrap &) = delete; + + + DataWrap(Group *parent, const char *name, const char *desc) { - map(new Data(*this)); + auto info = new Info(self()); + this->setInfo(parent, info); + + if (parent) + parent->addStat(info); + + if (name) { + info->setName(name); + info->flags.set(display); + } + + if (desc) + info->desc = desc; } /** @@ -406,13 +275,32 @@ class Wrap : public Child * @param name The new name. * @return A reference to this stat. */ - Parent &name(const std::string &_name) + Derived & + name(const std::string &name) { - Data *data = this->statData(); - data->name = _name; - this->setPrint(); + Info *info = this->info(); + info->setName(name); + info->flags.set(display); return this->self(); } + const std::string &name() const { return this->info()->name; } + + /** + * Set the character(s) used between the name and vector number + * on vectors, dist, etc. + * @param _sep The new separator string + * @return A reference to this stat. + */ + Derived & + setSeparator(const std::string &_sep) + { + this->info()->setSeparator(_sep); + return this->self(); + } + const std::string &setSeparator() const + { + return this->info()->separatorString; + } /** * Set the description and marks this stat to print at the end of @@ -420,20 +308,22 @@ class Wrap : public Child * @param desc The new description. * @return A reference to this stat. */ - Parent &desc(const std::string &_desc) + Derived & + desc(const std::string &_desc) { - this->statData()->desc = _desc; + this->info()->desc = _desc; return this->self(); } /** * Set the precision and marks this stat to print at the end of simulation. - * @param p The new precision + * @param _precision The new precision * @return A reference to this stat. */ - Parent &precision(int _precision) + Derived & + precision(int _precision) { - this->statData()->precision = _precision; + this->info()->precision = _precision; return this->self(); } @@ -442,9 +332,10 @@ class Wrap : public Child * @param f The new flags. * @return A reference to this stat. */ - Parent &flags(StatFlags _flags) + Derived & + flags(Flags _flags) { - this->statData()->flags |= _flags; + this->info()->flags.set(_flags); return this->self(); } @@ -455,17 +346,25 @@ class Wrap : public Child * @return A reference to this stat. */ template - Parent &prereq(const Stat &prereq) + Derived & + prereq(const Stat &prereq) { - this->statData()->prereq = prereq.statData(); + this->info()->prereq = prereq.info(); return this->self(); } }; -template class Data> -class WrapVec : public Wrap +template class InfoProxyType> +class DataWrapVec : public DataWrap { public: + typedef InfoProxyType Info; + + DataWrapVec(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : DataWrap(parent, name, desc) + {} + // The following functions are specific to vectors. If you use them // in a non vector context, you will get a nice compiler error! @@ -476,15 +375,23 @@ class WrapVec : public Wrap * @param name The new name of the subfield. * @return A reference to this stat. */ - Parent &subname(int index, const std::string &name) + Derived & + subname(off_type index, const std::string &name) { - std::vector &subn = this->statData()->subnames; + Derived &self = this->self(); + Info *info = self.info(); + + std::vector &subn = info->subnames; if (subn.size() <= index) subn.resize(index + 1); subn[index] = name; - return this->self(); + return self; } + // The following functions are specific to 2d vectors. If you use + // them in a non vector context, you will get a nice compiler + // error because info doesn't have the right variables. + /** * Set the subfield description for the given index and marks this stat to * print at the end of simulation. @@ -492,9 +399,12 @@ class WrapVec : public Wrap * @param desc The new description of the subfield * @return A reference to this stat. */ - Parent &subdesc(int index, const std::string &desc) + Derived & + subdesc(off_type index, const std::string &desc) { - std::vector &subd = this->statData()->subdescs; + Info *info = this->info(); + + std::vector &subd = info->subdescs; if (subd.size() <= index) subd.resize(index + 1); subd[index] = desc; @@ -502,32 +412,74 @@ class WrapVec : public Wrap return this->self(); } + void + prepare() + { + Derived &self = this->self(); + Info *info = this->info(); + + size_t size = self.size(); + for (off_type i = 0; i < size; ++i) + self.data(i)->prepare(info); + } + + void + reset() + { + Derived &self = this->self(); + Info *info = this->info(); + + size_t size = self.size(); + for (off_type i = 0; i < size; ++i) + self.data(i)->reset(info); + } }; -template class Data> -class WrapVec2d : public WrapVec +template class InfoProxyType> +class DataWrapVec2d : public DataWrapVec { public: + typedef InfoProxyType Info; + + DataWrapVec2d(Group *parent, const char *name, const char *desc) + : DataWrapVec(parent, name, desc) + { + } + /** * @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) + Derived & + ysubnames(const char **names) { - Data *data = this->statData(); - data->y_subnames.resize(this->y); - for (int i = 0; i < this->y; ++i) - data->y_subnames[i] = names[i]; - return this->self(); + Derived &self = this->self(); + Info *info = this->info(); + + info->y_subnames.resize(self.y); + for (off_type i = 0; i < self.y; ++i) + info->y_subnames[i] = names[i]; + return self; + } + + Derived & + ysubname(off_type index, const std::string &subname) + { + Derived &self = this->self(); + Info *info = this->info(); + + assert(index < self.y); + info->y_subnames.resize(self.y); + info->y_subnames[index] = subname.c_str(); + return self; } - Parent &ysubname(int index, const std::string subname) + + std::string + ysubname(off_type i) const { - Data *data = this->statData(); - assert(index < this->y); - data->y_subnames.resize(this->y); - data->y_subnames[index] = subname.c_str(); - return this->self(); + return this->info()->y_subnames[i]; } + }; ////////////////////////////////////////////////////////////////////// @@ -539,57 +491,57 @@ class WrapVec2d : public WrapVec /** * Templatized storage and interface for a simple scalar stat. */ -struct StatStor +class StatStor { - public: - /** The paramaters for this storage type, none for a scalar. */ - struct Params { }; - private: /** The statistic value. */ Counter data; + public: + struct Params : public StorageParams {}; + public: /** * Builds this storage element and calls the base constructor of the * datatype. */ - StatStor(const Params &) : data(Counter()) {} + StatStor(Info *info) + : 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; } + void set(Counter val) { 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; } + void inc(Counter val) { 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; } + void dec(Counter val) { 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; } + Counter value() 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; } + Result result() const { return (Result)data; } + /** + * Prepare stat data for dumping or serialization + */ + void prepare(Info *info) { } /** * Reset stat value to default */ - void reset() { data = Counter(); } + void reset(Info *info) { data = Counter(); } /** * @return true if zero value @@ -598,112 +550,120 @@ struct StatStor }; /** - * 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 + * Templatized storage and interface to a per-tick average stat. This keeps + * a current count and updates a total (count * ticks) when this count + * changes. This allows the quick calculation of a per tick count of the item * being watched. This is good for keeping track of residencies in structures * among other things. */ -struct AvgStor +class AvgStor { - public: - /** The paramaters for this storage type */ - struct Params { }; - private: /** The current count. */ Counter current; - /** The total count for all cycles. */ + /** The tick of the last reset */ + Tick lastReset; + /** The total count for all tick. */ mutable Result total; - /** The cycle that current last changed. */ + /** The tick that current last changed. */ mutable Tick last; + public: + struct Params : public StorageParams {}; + public: /** * Build and initializes this stat storage. */ - AvgStor(Params &p) : current(0), total(0), last(0) { } + AvgStor(Info *info) + : current(0), lastReset(0), total(0), last(0) + { } /** * 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 += current * (curTick - last); - last = curTick; + void + set(Counter val) + { + total += current * (curTick() - last); + last = curTick(); 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(current + val, p); } + void inc(Counter val) { set(current + val); } /** * 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(current - val, p); } + void dec(Counter val) { set(current - val); } /** * Return the current count. - * @param p The parameters for this storage. * @return The current count. */ - Counter value(const Params &p) const { return current; } + Counter value() const { return current; } /** * Return the current average. - * @param p The parameters for this storage. * @return The current average. */ - Result result(const Params &p) const + Result + result() const { - total += current * (curTick - last); - last = curTick; - return (Result)(total + current) / (Result)(curTick + 1); + assert(last == curTick()); + return (Result)(total + current) / (Result)(curTick() - lastReset + 1); } /** - * Reset stat value to default + * @return true if zero value + */ + bool zero() const { return total == 0.0; } + + /** + * Prepare stat data for dumping or serialization */ - void reset() + void + prepare(Info *info) { - total = 0; - last = curTick; + total += current * (curTick() - last); + last = curTick(); } /** - * @return true if zero value + * Reset stat value to default */ - bool zero() const { return total == 0.0; } + void + reset(Info *info) + { + total = 0.0; + last = curTick(); + lastReset = curTick(); + } + }; /** * Implementation of a scalar stat. The type of stat is determined by the * Storage template. */ -template -class ScalarBase : public DataAccess +template +class ScalarBase : public DataWrap { public: typedef Stor Storage; - - /** Define the params of the storage class. */ - typedef typename Storage::Params Params; + typedef typename Stor::Params Params; protected: /** The storage of this stat. */ char storage[sizeof(Storage)] __attribute__ ((aligned (8))); - /** The parameters for this stat. */ - Params params; - protected: /** * Retrieve the storage. @@ -731,8 +691,8 @@ class ScalarBase : public DataAccess void doInit() { - new (storage) Storage(params); - setInit(); + new (storage) Storage(this->info()); + this->setInit(); } public: @@ -740,14 +700,15 @@ class ScalarBase : public DataAccess * Return the current value of this stat as its base type. * @return The current value. */ - Counter value() const { return data()->value(params); } + Counter value() const { return data()->value(); } public: - /** - * Create and initialize this stat, register it with the database. - */ - ScalarBase() - { } + ScalarBase(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : DataWrap(parent, name, desc) + { + this->doInit(); + } public: // Common operators for stats @@ -755,12 +716,12 @@ class ScalarBase : public DataAccess * Increment the stat by 1. This calls the associated storage object inc * function. */ - void operator++() { data()->inc(1, params); } + void operator++() { data()->inc(1); } /** * Decrement the stat by 1. This calls the associated storage object dec * function. */ - void operator--() { data()->dec(1, params); } + void operator--() { data()->dec(1); } /** Increment the stat by 1. */ void operator++(int) { ++*this; } @@ -773,7 +734,7 @@ class ScalarBase : public DataAccess * @param v The new value. */ template - void operator=(const U &v) { data()->set(v, params); } + void operator=(const U &v) { data()->set(v); } /** * Increment the stat by the given value. This calls the associated @@ -781,7 +742,7 @@ class ScalarBase : public DataAccess * @param v The value to add. */ template - void operator+=(const U &v) { data()->inc(v, params); } + void operator+=(const U &v) { data()->inc(v); } /** * Decrement the stat by the given value. This calls the associated @@ -789,99 +750,142 @@ class ScalarBase : public DataAccess * @param v The value to substract. */ template - void operator-=(const U &v) { data()->dec(v, params); } + void operator-=(const U &v) { data()->dec(v); } /** * Return the number of elements, always 1 for a scalar. * @return 1. */ - size_t size() const { return 1; } - - bool check() const { return true; } - - /** - * Reset stat value to default - */ - void reset() { data()->reset(); } + size_type size() const { return 1; } - Counter value() { return data()->value(params); } + Counter value() { return data()->value(); } - Result result() { return data()->result(params); } + Result result() { return data()->result(); } Result total() { return result(); } bool zero() { return result() == 0.0; } + void reset() { data()->reset(this->info()); } + void prepare() { data()->prepare(this->info()); } }; -class ProxyData : public ScalarData +class ProxyInfo : public ScalarInfo { public: - virtual void visit(Visit &visitor) { visitor.visit(*this); } - 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() { } + std::string str() const { return std::to_string(value()); } + size_type size() const { return 1; } + bool check() const { return true; } + void prepare() { } + void reset() { } + bool zero() const { return value() == 0; } + + void visit(Output &visitor) { visitor.visit(*this); } }; template -class ValueProxy : public ProxyData +class ValueProxy : public ProxyInfo { 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; } + Counter value() const { return *scalar; } + Result result() const { return *scalar; } + Result total() const { return *scalar; } }; template -class FunctorProxy : public ProxyData +class FunctorProxy : public ProxyInfo { 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)(); } + Counter value() const { return (*functor)(); } + Result result() const { return (*functor)(); } + Result total() const { return (*functor)(); } +}; + +/** + * A proxy similar to the FunctorProxy, but allows calling a method of a bound + * object, instead of a global free-standing function. + */ +template +class MethodProxy : public ProxyInfo +{ + private: + T *object; + typedef V (T::*MethodPointer) () const; + MethodPointer method; + + public: + MethodProxy(T *obj, MethodPointer meth) : object(obj), method(meth) {} + Counter value() const { return (object->*method)(); } + Result result() const { return (object->*method)(); } + Result total() const { return (object->*method)(); } }; -class ValueBase : public DataAccess +template +class ValueBase : public DataWrap { private: - ProxyData *proxy; + ProxyInfo *proxy; public: - ValueBase() : proxy(NULL) { } + ValueBase(Group *parent, const char *name, const char *desc) + : DataWrap(parent, name, desc), + proxy(NULL) + { + } + ~ValueBase() { if (proxy) delete proxy; } template - void scalar(T &value) + Derived & + scalar(T &value) { proxy = new ValueProxy(value); - setInit(); + this->setInit(); + return this->self(); } template - void functor(T &func) + Derived & + functor(T &func) { proxy = new FunctorProxy(func); - setInit(); + this->setInit(); + return this->self(); + } + + /** + * Extended functor that calls the specified method of the provided object. + * + * @param obj Pointer to the object whose method should be called. + * @param method Pointer of the function / method of the object. + * @return Updated stats item. + */ + template + Derived & + method(T *obj, V (T::*method)() const) + { + proxy = new MethodProxy(obj, method); + this->setInit(); + return this->self(); } Counter value() { return proxy->value(); } Result result() const { return proxy->result(); } Result total() const { return proxy->total(); }; - size_t size() const { return proxy->size(); } + size_type size() const { return proxy->size(); } std::string str() const { return proxy->str(); } bool zero() const { return proxy->zero(); } bool check() const { return proxy != NULL; } + void prepare() { } void reset() { } }; @@ -900,34 +904,32 @@ class ScalarProxy { private: /** Pointer to the parent Vector. */ - Stat *stat; + Stat &stat; /** The index to access in the parent VectorBase. */ - int index; + off_type index; public: /** * Return the current value of this stat as its base type. * @return The current value. */ - Counter value() const { return stat->data(index)->value(stat->params); } + Counter value() const { return stat.data(index)->value(); } /** * Return the current value of this statas a result type. * @return The current value. */ - Result result() const { return stat->data(index)->result(stat->params); } + Result result() const { return stat.data(index)->result(); } public: /** * Create and initialize this proxy, do not register it with the database. - * @param p The params to use. * @param i The index to access. */ - ScalarProxy(Stat *s, int i) + ScalarProxy(Stat &s, off_type i) : stat(s), index(i) { - assert(stat); } /** @@ -943,7 +945,9 @@ class ScalarProxy * @param sp The proxy to copy. * @return A reference to this proxy. */ - const ScalarProxy &operator=(const ScalarProxy &sp) { + const ScalarProxy & + operator=(const ScalarProxy &sp) + { stat = sp.stat; index = sp.index; return *this; @@ -955,12 +959,12 @@ class ScalarProxy * Increment the stat by 1. This calls the associated storage object inc * function. */ - void operator++() { stat->data(index)->inc(1, stat->params); } + void operator++() { stat.data(index)->inc(1); } /** * Decrement the stat by 1. This calls the associated storage object dec * function. */ - void operator--() { stat->data(index)->dec(1, stat->params); } + void operator--() { stat.data(index)->dec(1); } /** Increment the stat by 1. */ void operator++(int) { ++*this; } @@ -973,7 +977,11 @@ class ScalarProxy * @param v The new value. */ template - void operator=(const U &v) { stat->data(index)->set(v, stat->params); } + void + operator=(const U &v) + { + stat.data(index)->set(v); + } /** * Increment the stat by the given value. This calls the associated @@ -981,7 +989,11 @@ class ScalarProxy * @param v The value to add. */ template - void operator+=(const U &v) { stat->data(index)->inc(v, stat->params); } + void + operator+=(const U &v) + { + stat.data(index)->inc(v); + } /** * Decrement the stat by the given value. This calls the associated @@ -989,25 +1001,23 @@ class ScalarProxy * @param v The value to substract. */ template - void operator-=(const U &v) { stat->data(index)->dec(v, stat->params); } + void + operator-=(const U &v) + { + stat.data(index)->dec(v); + } /** * Return the number of elements, always 1 for a scalar. * @return 1. */ - size_t size() const { return 1; } - - /** - * This stat has no state. Nothing to reset - */ - void reset() { } + size_type size() const { return 1; } public: std::string str() const { - return csprintf("%s[%d]", stat->str(), index); - + return csprintf("%s[%d]", stat.info()->name, index); } }; @@ -1015,27 +1025,22 @@ class ScalarProxy * Implementation of a vector of stats. The type of stat is determined by the * Storage class. @sa ScalarBase */ -template -class VectorBase : public DataAccess +template +class VectorBase : public DataWrapVec { public: typedef Stor Storage; - - /** Define the params of the storage class. */ - typedef typename Storage::Params Params; + typedef typename Stor::Params Params; /** Proxy type */ - typedef ScalarProxy > Proxy; - - friend class ScalarProxy >; + typedef ScalarProxy Proxy; + friend class ScalarProxy; + friend class DataWrapVec; protected: /** The storage of this stat. */ Storage *storage; - size_t _size; - - /** The parameters for this stat. */ - Params params; + size_type _size; protected: /** @@ -1043,17 +1048,17 @@ class VectorBase : public DataAccess * @param index The vector index to access. * @return The storage object at the given index. */ - Storage *data(int index) { return &storage[index]; } + Storage *data(off_type index) { return &storage[index]; } /** * Retrieve a const pointer to the storage. * @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 { return &storage[index]; } + const Storage *data(off_type index) const { return &storage[index]; } void - doInit(int s) + doInit(size_type s) { assert(s > 0 && "size must be positive!"); assert(!storage && "already initialized"); @@ -1062,51 +1067,55 @@ class VectorBase : public DataAccess char *ptr = new char[_size * sizeof(Storage)]; storage = reinterpret_cast(ptr); - for (int i = 0; i < _size; ++i) - new (&storage[i]) Storage(params); + for (off_type i = 0; i < _size; ++i) + new (&storage[i]) Storage(this->info()); - setInit(); + this->setInit(); } public: - void value(VCounter &vec) const + void + value(VCounter &vec) const { vec.resize(size()); - for (int i = 0; i < size(); ++i) - vec[i] = data(i)->value(params); + for (off_type i = 0; i < size(); ++i) + vec[i] = data(i)->value(); } /** * 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 + void + result(VResult &vec) const { vec.resize(size()); - for (int i = 0; i < size(); ++i) - vec[i] = data(i)->result(params); + for (off_type i = 0; i < size(); ++i) + vec[i] = data(i)->result(); } /** * Return a total of all entries in this vector. * @return The total of all vector entries. */ - Result total() const { + Result + total() const + { Result total = 0.0; - for (int i = 0; i < size(); ++i) - total += data(i)->result(params); + for (off_type i = 0; i < size(); ++i) + total += data(i)->result(); return total; } /** * @return the number of elements in this vector. */ - size_t size() const { return _size; } + size_type size() const { return _size; } bool zero() const { - for (int i = 0; i < size(); ++i) + for (off_type i = 0; i < size(); ++i) if (data(i)->zero()) return false; return true; @@ -1118,16 +1127,10 @@ class VectorBase : public DataAccess return storage != NULL; } - void - reset() - { - for (int i = 0; i < size(); ++i) - data(i)->reset(); - } - public: - VectorBase() - : storage(NULL) + VectorBase(Group *parent, const char *name, const char *desc) + : DataWrapVec(parent, name, desc), + storage(nullptr), _size(0) {} ~VectorBase() @@ -1135,49 +1138,60 @@ class VectorBase : public DataAccess if (!storage) return; - for (int i = 0; i < _size; ++i) + for (off_type i = 0; i < _size; ++i) data(i)->~Storage(); delete [] reinterpret_cast(storage); } + /** + * Set this vector to have the given size. + * @param size The new size. + * @return A reference to this stat. + */ + Derived & + init(size_type size) + { + Derived &self = this->self(); + self.doInit(size); + return self; + } + /** * Return a reference (ScalarProxy) to the stat at the given index. * @param index The vector index to access. * @return A reference of the stat. */ Proxy - operator[](int index) + operator[](off_type index) { assert (index >= 0 && index < size()); - return Proxy(this, index); + return Proxy(this->self(), index); } - - void update(StatData *data) {} }; template class VectorProxy { private: - Stat *stat; - int offset; - int len; + Stat &stat; + off_type offset; + size_type len; private: mutable VResult vec; typename Stat::Storage * - data(int index) + data(off_type index) { assert(index < len); - return stat->data(offset + index); + return stat.data(offset + index); } const typename Stat::Storage * - data(int index) const + data(off_type index) const { assert(index < len); - return const_cast(stat)->data(offset + index); + return stat.data(offset + index); } public: @@ -1186,8 +1200,8 @@ class VectorProxy { vec.resize(size()); - for (int i = 0; i < size(); ++i) - vec[i] = data(i)->result(stat->params); + for (off_type i = 0; i < size(); ++i) + vec[i] = data(i)->result(); return vec; } @@ -1195,14 +1209,14 @@ class VectorProxy Result total() const { - Result total = 0; - for (int i = 0; i < size(); ++i) - total += data(i)->result(stat->params); + Result total = 0.0; + for (off_type i = 0; i < size(); ++i) + total += data(i)->result(); return total; } public: - VectorProxy(Stat *s, int o, int l) + VectorProxy(Stat &s, off_type o, size_type l) : stat(s), offset(o), len(l) { } @@ -1221,100 +1235,91 @@ class VectorProxy return *this; } - ScalarProxy operator[](int index) + ScalarProxy + operator[](off_type index) { assert (index >= 0 && index < size()); return ScalarProxy(stat, offset + index); } - size_t size() const { return len; } - - /** - * This stat has no state. Nothing to reset. - */ - void reset() { } + size_type size() const { return len; } }; -template -class Vector2dBase : public DataAccess +template +class Vector2dBase : public DataWrapVec2d { public: + typedef Vector2dInfoProxy Info; typedef Stor Storage; - typedef typename Storage::Params Params; - typedef VectorProxy > Proxy; - friend class ScalarProxy >; - friend class VectorProxy >; + typedef typename Stor::Params Params; + typedef VectorProxy Proxy; + friend class ScalarProxy; + friend class VectorProxy; + friend class DataWrapVec; + friend class DataWrapVec2d; protected: - size_t x; - size_t y; - size_t _size; + size_type x; + size_type y; + size_type _size; Storage *storage; - Params params; protected: - Storage *data(int index) { return &storage[index]; } - const Storage *data(int index) const { return &storage[index]; } + Storage *data(off_type index) { return &storage[index]; } + const Storage *data(off_type index) const { return &storage[index]; } - void - doInit(int _x, int _y) + public: + Vector2dBase(Group *parent, const char *name, const char *desc) + : DataWrapVec2d(parent, name, desc), + x(0), y(0), _size(0), storage(nullptr) + {} + + ~Vector2dBase() + { + if (!storage) + return; + + for (off_type i = 0; i < _size; ++i) + data(i)->~Storage(); + delete [] reinterpret_cast(storage); + } + + Derived & + init(size_type _x, size_type _y) { assert(_x > 0 && _y > 0 && "sizes must be positive!"); assert(!storage && "already initialized"); - Vector2dData *statdata = dynamic_cast(find()); + Derived &self = this->self(); + Info *info = this->info(); x = _x; y = _y; - statdata->x = _x; - statdata->y = _y; + info->x = _x; + info->y = _y; _size = x * y; char *ptr = new char[_size * sizeof(Storage)]; storage = reinterpret_cast(ptr); - for (int i = 0; i < _size; ++i) - new (&storage[i]) Storage(params); - - setInit(); - } - - public: - Vector2dBase() - : storage(NULL) - {} - - ~Vector2dBase() - { - if (!storage) - return; + for (off_type i = 0; i < _size; ++i) + new (&storage[i]) Storage(info); - for (int i = 0; i < _size; ++i) - data(i)->~Storage(); - delete [] reinterpret_cast(storage); - } + this->setInit(); - void - update(Vector2dData *newdata) - { - int size = this->size(); - newdata->cvec.resize(size); - for (int i = 0; i < size; ++i) - newdata->cvec[i] = data(i)->value(params); + return self; } - std::string ysubname(int i) const { return (*this->y_subnames)[i]; } - Proxy - operator[](int index) + operator[](off_type index) { - int offset = index * y; - assert (index >= 0 && offset + index < size()); - return Proxy(this, offset, y); + off_type offset = index * y; + assert (index >= 0 && offset + y <= size()); + return Proxy(this->self(), offset, y); } - size_t + size_type size() const { return _size; @@ -1324,12 +1329,33 @@ class Vector2dBase : public DataAccess zero() const { return data(0)->zero(); -#if 0 - for (int i = 0; i < size(); ++i) - if (!data(i)->zero()) - return false; - return true; -#endif + } + + /** + * Return a total of all entries in this vector. + * @return The total of all vector entries. + */ + Result + total() const + { + Result total = 0.0; + for (off_type i = 0; i < size(); ++i) + total += data(i)->result(); + return total; + } + + void + prepare() + { + Info *info = this->info(); + size_type size = this->size(); + + for (off_type i = 0; i < size; ++i) + data(i)->prepare(info); + + info->cvec.resize(size); + for (off_type i = 0; i < size; ++i) + info->cvec[i] = data(i)->value(); } /** @@ -1338,12 +1364,14 @@ class Vector2dBase : public DataAccess void reset() { - for (int i = 0; i < size(); ++i) - data(i)->reset(); + Info *info = this->info(); + size_type size = this->size(); + for (off_type i = 0; i < size; ++i) + data(i)->reset(info); } bool - check() + check() const { return storage != NULL; } @@ -1354,15 +1382,21 @@ class Vector2dBase : public DataAccess // Non formula statistics // ////////////////////////////////////////////////////////////////////// +/** The parameters for a distribution stat. */ +struct DistParams : public StorageParams +{ + const DistType type; + DistParams(DistType t) : type(t) {} +}; /** - * Templatized storage and interface for a distrbution stat. + * Templatized storage and interface for a distribution stat. */ -struct DistStor +class DistStor { public: /** The parameters for a distribution stat. */ - struct Params + struct Params : public DistParams { /** The minimum value to track. */ Counter min; @@ -1371,11 +1405,20 @@ struct DistStor /** The number of entries in each bucket. */ Counter bucket_size; /** The number of buckets. Equal to (max-min)/bucket_size. */ - int size; + size_type buckets; + + Params() : DistParams(Dist), min(0), max(0), bucket_size(0), + buckets(0) {} }; - enum { fancy = false }; private: + /** The minimum value to track. */ + Counter min_track; + /** The maximum value to track. */ + Counter max_track; + /** The number of entries in each bucket. */ + Counter bucket_size; + /** The smallest value sampled. */ Counter min_val; /** The largest value sampled. */ @@ -1394,27 +1437,28 @@ struct DistStor VCounter cvec; public: - DistStor(const Params ¶ms) - : cvec(params.size) + DistStor(Info *info) + : cvec(safe_cast(info->storageParams)->buckets) { - reset(); + reset(info); } /** * 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 ¶ms) + void + sample(Counter val, int number) { - if (val < params.min) + if (val < min_track) underflow += number; - else if (val > params.max) + else if (val > max_track) overflow += number; else { - int index = (int)std::floor((val - params.min) / params.bucket_size); - assert(index < size(params)); + size_type index = + (size_type)std::floor((val - min_track) / bucket_size); + assert(index < size()); cvec[index] += number; } @@ -1424,61 +1468,70 @@ struct DistStor if (val > max_val) max_val = val; - Counter sample = val * number; - sum += sample; - squares += sample * sample; + sum += val * number; + squares += val * val * number; 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(); } + size_type size() 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 ¶ms) const + bool + zero() const { return samples == Counter(); } - void update(DistDataData *data, const Params ¶ms) + void + prepare(Info *info, DistData &data) { - data->min = params.min; - data->max = params.max; - data->bucket_size = params.bucket_size; - data->size = params.size; + const Params *params = safe_cast(info->storageParams); + + assert(params->type == Dist); + data.type = params->type; + data.min = params->min; + data.max = params->max; + data.bucket_size = params->bucket_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.min_val = (min_val == CounterLimits::max()) ? 0 : min_val; + data.max_val = (max_val == CounterLimits::min()) ? 0 : max_val; + data.underflow = underflow; + data.overflow = overflow; - data->sum = sum; - data->squares = squares; - data->samples = samples; + data.cvec.resize(params->buckets); + for (off_type i = 0; i < params->buckets; ++i) + data.cvec[i] = cvec[i]; + + data.sum = sum; + data.squares = squares; + data.samples = samples; } /** * Reset stat value to default */ - void reset() + void + reset(Info *info) { - min_val = INT_MAX; - max_val = INT_MIN; - underflow = 0; - overflow = 0; + const Params *params = safe_cast(info->storageParams); + min_track = params->min; + max_track = params->max; + bucket_size = params->bucket_size; - int size = cvec.size(); - for (int i = 0; i < size; ++i) + min_val = CounterLimits::max(); + max_val = CounterLimits::min(); + underflow = Counter(); + overflow = Counter(); + + size_type size = cvec.size(); + for (off_type i = 0; i < size; ++i) cvec[i] = Counter(); sum = Counter(); @@ -1488,17 +1541,162 @@ struct DistStor }; /** - * Templatized storage and interface for a distribution that calculates mean - * and variance. + * Templatized storage and interface for a histogram stat. */ -struct FancyStor +class HistStor { public: + /** The parameters for a distribution stat. */ + struct Params : public DistParams + { + /** The number of buckets.. */ + size_type buckets; + + Params() : DistParams(Hist), buckets(0) {} + }; + + private: + /** The minimum value to track. */ + Counter min_bucket; + /** The maximum value to track. */ + Counter max_bucket; + /** The number of entries in each bucket. */ + Counter bucket_size; + + /** The current sum. */ + Counter sum; + /** The sum of logarithm of each sample, used to compute geometric mean. */ + Counter logs; + /** The sum of squares. */ + Counter squares; + /** The number of samples. */ + Counter samples; + /** Counter for each bucket. */ + VCounter cvec; + + public: + HistStor(Info *info) + : cvec(safe_cast(info->storageParams)->buckets) + { + reset(info); + } + + void grow_up(); + void grow_out(); + void grow_convert(); + void add(HistStor *); + + /** + * 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. + */ + void + sample(Counter val, int number) + { + assert(min_bucket < max_bucket); + if (val < min_bucket) { + if (min_bucket == 0) + grow_convert(); + + while (val < min_bucket) + grow_out(); + } else if (val >= max_bucket + bucket_size) { + if (min_bucket == 0) { + while (val >= max_bucket + bucket_size) + grow_up(); + } else { + while (val >= max_bucket + bucket_size) + grow_out(); + } + } + + size_type index = + (int64_t)std::floor((val - min_bucket) / bucket_size); + + assert(index < size()); + cvec[index] += number; + + sum += val * number; + squares += val * val * number; + logs += log(val) * number; + samples += number; + } + /** - * No paramters for this storage. + * Return the number of buckets in this distribution. + * @return the number of buckets. + */ + size_type size() const { return cvec.size(); } + + /** + * Returns true if any calls to sample have been made. + * @return True if any values have been sampled. + */ + bool + zero() const + { + return samples == Counter(); + } + + void + prepare(Info *info, DistData &data) + { + const Params *params = safe_cast(info->storageParams); + + assert(params->type == Hist); + data.type = params->type; + data.min = min_bucket; + data.max = max_bucket + bucket_size - 1; + data.bucket_size = bucket_size; + + data.min_val = min_bucket; + data.max_val = max_bucket; + + int buckets = params->buckets; + data.cvec.resize(buckets); + for (off_type i = 0; i < buckets; ++i) + data.cvec[i] = cvec[i]; + + data.sum = sum; + data.logs = logs; + data.squares = squares; + data.samples = samples; + } + + /** + * Reset stat value to default */ - struct Params {}; - enum { fancy = true }; + void + reset(Info *info) + { + const Params *params = safe_cast(info->storageParams); + min_bucket = 0; + max_bucket = params->buckets - 1; + bucket_size = 1; + + size_type size = cvec.size(); + for (off_type i = 0; i < size; ++i) + cvec[i] = Counter(); + + sum = Counter(); + squares = Counter(); + samples = Counter(); + logs = Counter(); + } +}; + +/** + * Templatized storage and interface for a distribution that calculates mean + * and variance. + */ +class SampleStor +{ + public: + struct Params : public DistParams + { + Params() : DistParams(Deviation) {} + }; private: /** The current sum. */ @@ -1512,7 +1710,7 @@ struct FancyStor /** * Create and initialize this storage. */ - FancyStor(const Params &) + SampleStor(Info *info) : sum(Counter()), squares(Counter()), samples(Counter()) { } @@ -1522,9 +1720,9 @@ struct FancyStor * 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) + void + sample(Counter val, int number) { Counter value = val * number; sum += value; @@ -1532,29 +1730,35 @@ struct FancyStor samples += number; } - void update(DistDataData *data, const Params ¶ms) - { - 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; } + size_type size() 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(); } + bool zero() const { return samples == Counter(); } + + void + prepare(Info *info, DistData &data) + { + const Params *params = safe_cast(info->storageParams); + + assert(params->type == Deviation); + data.type = params->type; + data.sum = sum; + data.squares = squares; + data.samples = samples; + } /** * Reset stat value to default */ - void reset() + void + reset(Info *info) { sum = Counter(); squares = Counter(); @@ -1563,15 +1767,16 @@ struct FancyStor }; /** - * Templatized storage for distribution that calculates per cycle mean and + * Templatized storage for distribution that calculates per tick mean and * variance. */ -struct AvgFancy +class AvgSampleStor { public: - /** No parameters for this storage. */ - struct Params {}; - enum { fancy = true }; + struct Params : public DistParams + { + Params() : DistParams(Deviation) {} + }; private: /** Current total. */ @@ -1583,43 +1788,53 @@ struct AvgFancy /** * Create and initialize this storage. */ - AvgFancy(const Params &) : sum(Counter()), squares(Counter()) {} + AvgSampleStor(Info *info) + : 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) + void + sample(Counter val, int number) { Counter value = val * number; sum += value; squares += value * value; } - void update(DistDataData *data, const Params ¶ms) - { - 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 ¶ms) const { return 1; } + size_type size() const { return 1; } + /** * Return true if no samples have been added. * @return True if the sum is zero. */ - bool zero(const Params ¶ms) const { return sum == Counter(); } + bool zero() const { return sum == Counter(); } + + void + prepare(Info *info, DistData &data) + { + const Params *params = safe_cast(info->storageParams); + + assert(params->type == Deviation); + data.type = params->type; + data.sum = sum; + data.squares = squares; + data.samples = curTick(); + } + /** * Reset stat value to default */ - void reset() + void + reset(Info *info) { sum = Counter(); squares = Counter(); @@ -1630,27 +1845,25 @@ struct AvgFancy * Implementation of a distribution stat. The type of distribution is * determined by the Storage template. @sa ScalarBase */ -template -class DistBase : public DataAccess +template +class DistBase : public DataWrap { public: + typedef DistInfoProxy Info; typedef Stor Storage; - /** Define the params of the storage class. */ - typedef typename Storage::Params Params; + typedef typename Stor::Params Params; protected: /** The storage for this stat. */ char storage[sizeof(Storage)] __attribute__ ((aligned (8))); - /** The parameters for this stat. */ - Params params; - protected: /** * Retrieve the storage. * @return The storage object for this stat. */ - Storage *data() + Storage * + data() { return reinterpret_cast(storage); } @@ -1668,12 +1881,15 @@ class DistBase : public DataAccess void doInit() { - new (storage) Storage(params); - setInit(); + new (storage) Storage(this->info()); + this->setInit(); } public: - DistBase() { } + DistBase(Group *parent, const char *name, const char *desc) + : DataWrap(parent, name, desc) + { + } /** * Add a value to the distribtion n times. Calls sample on the storage @@ -1682,23 +1898,24 @@ class DistBase : public DataAccess * @param n The number of times to add it, defaults to 1. */ template - void sample(const U &v, int n = 1) { data()->sample(v, n, params); } + void sample(const U &v, int n = 1) { data()->sample(v, n); } /** * Return the number of entries in this stat. * @return The number of entries. */ - size_t size() const { return data()->size(params); } + size_type size() const { return data()->size(); } /** * Return true if no samples have been added. * @return True if there haven't been any samples. */ - bool zero() const { return data()->zero(params); } + bool zero() const { return data()->zero(); } - void update(DistData *base) + void + prepare() { - base->data.fancy = Storage::fancy; - data()->update(&(base->data), params); + Info *info = this->info(); + data()->prepare(info, info->data); } /** @@ -1707,48 +1924,49 @@ class DistBase : public DataAccess void reset() { - data()->reset(); + data()->reset(this->info()); } - bool - check() - { - return true; - } + /** + * Add the argument distribution to the this distribution. + */ + void add(DistBase &d) { data()->add(d.data()); } + }; template class DistProxy; -template -class VectorDistBase : public DataAccess +template +class VectorDistBase : public DataWrapVec { public: + typedef VectorDistInfoProxy Info; typedef Stor Storage; - typedef typename Storage::Params Params; - typedef DistProxy > Proxy; - friend class DistProxy >; + typedef typename Stor::Params Params; + typedef DistProxy Proxy; + friend class DistProxy; + friend class DataWrapVec; protected: Storage *storage; - size_t _size; - Params params; + size_type _size; protected: Storage * - data(int index) + data(off_type index) { return &storage[index]; } const Storage * - data(int index) const + data(off_type index) const { return &storage[index]; } void - doInit(int s) + doInit(size_type s) { assert(s > 0 && "size must be positive!"); assert(!storage && "already initialized"); @@ -1757,15 +1975,17 @@ class VectorDistBase : public DataAccess char *ptr = new char[_size * sizeof(Storage)]; storage = reinterpret_cast(ptr); - for (int i = 0; i < _size; ++i) - new (&storage[i]) Storage(params); + Info *info = this->info(); + for (off_type i = 0; i < _size; ++i) + new (&storage[i]) Storage(info); - setInit(); + this->setInit(); } public: - VectorDistBase() - : storage(NULL) + VectorDistBase(Group *parent, const char *name, const char *desc) + : DataWrapVec(parent, name, desc), + storage(NULL) {} ~VectorDistBase() @@ -1773,14 +1993,18 @@ class VectorDistBase : public DataAccess if (!storage) return ; - for (int i = 0; i < _size; ++i) + for (off_type i = 0; i < _size; ++i) data(i)->~Storage(); delete [] reinterpret_cast(storage); } - Proxy operator[](int index); + Proxy operator[](off_type index) + { + assert(index >= 0 && index < size()); + return Proxy(this->self(), index); + } - size_t + size_type size() const { return _size; @@ -1789,56 +2013,42 @@ class VectorDistBase : public DataAccess bool zero() const { - return false; -#if 0 - for (int i = 0; i < size(); ++i) - if (!data(i)->zero(params)) + for (off_type i = 0; i < size(); ++i) + if (!data(i)->zero()) return false; return true; -#endif } - /** - * Reset stat value to default - */ void - reset() + prepare() { - for (int i = 0; i < size(); ++i) - data(i)->reset(); + Info *info = this->info(); + size_type size = this->size(); + info->data.resize(size); + for (off_type i = 0; i < size; ++i) + data(i)->prepare(info, info->data[i]); } bool - check() + check() const { return storage != NULL; } - - 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 DistProxy { private: - Stat *stat; - int index; + Stat &stat; + off_type index; protected: - typename Stat::Storage *data() { return stat->data(index); } - const typename Stat::Storage *data() const { return stat->data(index); } + typename Stat::Storage *data() { return stat.data(index); } + const typename Stat::Storage *data() const { return stat.data(index); } public: - DistProxy(Stat *s, int i) + DistProxy(Stat &s, off_type i) : stat(s), index(i) {} @@ -1846,7 +2056,8 @@ class DistProxy : stat(sp.stat), index(sp.index) {} - const DistProxy &operator=(const DistProxy &sp) + const DistProxy & + operator=(const DistProxy &sp) { stat = sp.stat; index = sp.index; @@ -1858,10 +2069,10 @@ class DistProxy void sample(const U &v, int n = 1) { - data()->sample(v, n, stat->params); + data()->sample(v, n); } - size_t + size_type size() const { return 1; @@ -1870,7 +2081,7 @@ class DistProxy bool zero() const { - return data()->zero(stat->params); + return data()->zero(); } /** @@ -1879,26 +2090,6 @@ class DistProxy void reset() { } }; -template -inline typename VectorDistBase::Proxy -VectorDistBase::operator[](int index) -{ - assert (index >= 0 && index < size()); - return typename VectorDistBase::Proxy(this, index); -} - -#if 0 -template -Result -VectorDistBase::total(int index) const -{ - int total = 0; - for (int i = 0; i < x_size(); ++i) { - total += data(i)->result(stat->params); - } -} -#endif - ////////////////////////////////////////////////////////////////////// // // Formula Details @@ -1909,14 +2100,14 @@ VectorDistBase::total(int index) const * Base class for formula statistic node. These nodes are used to build a tree * that represents the formula. */ -class Node : public RefCounted +class Node { 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; + virtual size_type size() const = 0; /** * Return the result vector of this subtree. * @return The result vector of this subtree. @@ -1932,32 +2123,37 @@ class Node : public RefCounted * */ virtual std::string str() const = 0; + + virtual ~Node() {}; }; -/** Reference counting pointer to a function Node. */ -typedef RefCountingPtr NodePtr; +/** Shared pointer to a function Node. */ +typedef std::shared_ptr NodePtr; class ScalarStatNode : public Node { private: - const ScalarData *data; + const ScalarInfo *data; mutable VResult vresult; public: - ScalarStatNode(const ScalarData *d) : data(d), vresult(1) {} - virtual const VResult &result() const + ScalarStatNode(const ScalarInfo *d) : data(d), vresult(1) {} + + const VResult & + result() const { vresult[0] = data->result(); return vresult; } - virtual Result total() const { return data->result(); }; - virtual size_t size() const { return 1; } + Result total() const { return data->result(); }; + + size_type size() const { return 1; } /** * */ - virtual std::string str() const { return data->name; } + std::string str() const { return data->name; } }; template @@ -1972,20 +2168,20 @@ class ScalarProxyNode : public Node : proxy(p), vresult(1) { } - virtual const VResult & + const VResult & result() const { vresult[0] = proxy.result(); return vresult; } - virtual Result + Result total() const { return proxy.result(); } - virtual size_t + size_type size() const { return 1; @@ -1994,7 +2190,7 @@ class ScalarProxyNode : public Node /** * */ - virtual std::string + std::string str() const { return proxy.str(); @@ -2004,16 +2200,16 @@ class ScalarProxyNode : public Node class VectorStatNode : public Node { private: - const VectorData *data; + const VectorInfo *data; public: - VectorStatNode(const VectorData *d) : data(d) { } - virtual const VResult &result() const { return data->result(); } - virtual Result total() const { return data->total(); }; + VectorStatNode(const VectorInfo *d) : data(d) { } + const VResult &result() const { return data->result(); } + Result total() const { return data->total(); }; - virtual size_t size() const { return data->size(); } + size_type size() const { return data->size(); } - virtual std::string str() const { return data->name; } + std::string str() const { return data->name; } }; template @@ -2025,25 +2221,58 @@ class ConstNode : public Node 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; } - virtual std::string str() const { return to_string(vresult[0]); } + Result total() const { return vresult[0]; }; + size_type size() const { return 1; } + std::string str() const { return std::to_string(vresult[0]); } }; -template -struct OpString; - -template<> -struct OpString > +template +class ConstVectorNode : public Node { - static std::string str() { return "+"; } -}; + private: + VResult vresult; -template<> -struct OpString > -{ - static std::string str() { return "-"; } -}; + public: + ConstVectorNode(const T &s) : vresult(s.begin(), s.end()) {} + const VResult &result() const { return vresult; } + + Result + total() const + { + size_type size = this->size(); + Result tmp = 0; + for (off_type i = 0; i < size; i++) + tmp += vresult[i]; + return tmp; + } + + size_type size() const { return vresult.size(); } + std::string + str() const + { + size_type size = this->size(); + std::string tmp = "("; + for (off_type i = 0; i < size; i++) + tmp += csprintf("%s ", std::to_string(vresult[i])); + tmp += ")"; + return tmp; + } +}; + +template +struct OpString; + +template<> +struct OpString > +{ + static std::string str() { return "+"; } +}; + +template<> +struct OpString > +{ + static std::string str() { return "-"; } +}; template<> struct OpString > @@ -2079,29 +2308,36 @@ class UnaryNode : public Node public: UnaryNode(NodePtr &p) : l(p) {} - const VResult &result() const + const VResult & + result() const { const VResult &lvec = l->result(); - int size = lvec.size(); + size_type size = lvec.size(); assert(size > 0); vresult.resize(size); Op op; - for (int i = 0; i < size; ++i) + for (off_type i = 0; i < size; ++i) vresult[i] = op(lvec[i]); return vresult; } - Result total() const { - Op op; - return op(l->total()); + Result + total() const + { + const VResult &vec = this->result(); + Result total = 0.0; + for (off_type i = 0; i < size(); i++) + total += vec[i]; + return total; } - virtual size_t size() const { return l->size(); } + size_type size() const { return l->size(); } - virtual std::string str() const + std::string + str() const { return OpString::str() + l->str(); } @@ -2118,7 +2354,8 @@ class BinaryNode : public Node public: BinaryNode(NodePtr &a, NodePtr &b) : l(a), r(b) {} - const VResult &result() const + const VResult & + result() const override { Op op; const VResult &lvec = l->result(); @@ -2130,44 +2367,74 @@ class BinaryNode : public Node vresult.resize(1); vresult[0] = op(lvec[0], rvec[0]); } else if (lvec.size() == 1) { - int size = rvec.size(); + size_type size = rvec.size(); vresult.resize(size); - for (int i = 0; i < size; ++i) + for (off_type i = 0; i < size; ++i) vresult[i] = op(lvec[0], rvec[i]); } else if (rvec.size() == 1) { - int size = lvec.size(); + size_type size = lvec.size(); vresult.resize(size); - for (int i = 0; i < size; ++i) + for (off_type i = 0; i < size; ++i) vresult[i] = op(lvec[i], rvec[0]); } else if (rvec.size() == lvec.size()) { - int size = rvec.size(); + size_type size = rvec.size(); vresult.resize(size); - for (int i = 0; i < size; ++i) + for (off_type i = 0; i < size; ++i) vresult[i] = op(lvec[i], rvec[i]); } return vresult; } - Result total() const { + Result + total() const override + { + const VResult &vec = this->result(); + const VResult &lvec = l->result(); + const VResult &rvec = r->result(); + Result total = 0.0; + Result lsum = 0.0; + Result rsum = 0.0; Op op; - return op(l->total(), r->total()); + + assert(lvec.size() > 0 && rvec.size() > 0); + assert(lvec.size() == rvec.size() || + lvec.size() == 1 || rvec.size() == 1); + + /** If vectors are the same divide their sums (x0+x1)/(y0+y1) */ + if (lvec.size() == rvec.size() && lvec.size() > 1) { + for (off_type i = 0; i < size(); ++i) { + lsum += lvec[i]; + rsum += rvec[i]; + } + return op(lsum, rsum); + } + + /** Otherwise divide each item by the divisor */ + for (off_type i = 0; i < size(); ++i) { + total += vec[i]; + } + + return total; } - virtual size_t size() const { - int ls = l->size(); - int rs = r->size(); - if (ls == 1) + size_type + size() const override + { + size_type ls = l->size(); + size_type rs = r->size(); + if (ls == 1) { return rs; - else if (rs == 1) + } else if (rs == 1) { return ls; - else { + } else { assert(ls == rs && "Node vector sizes are not equal"); return ls; } } - virtual std::string str() const + std::string + str() const override { return csprintf("(%s %s %s)", l->str(), OpString::str(), r->str()); } @@ -2183,39 +2450,42 @@ class SumNode : public Node public: SumNode(NodePtr &p) : l(p), vresult(1) {} - const VResult &result() const + const VResult & + result() const { const VResult &lvec = l->result(); - int size = lvec.size(); + size_type size = lvec.size(); assert(size > 0); vresult[0] = 0.0; Op op; - for (int i = 0; i < size; ++i) + for (off_type i = 0; i < size; ++i) vresult[0] = op(vresult[0], lvec[i]); return vresult; } - Result total() const + Result + total() const { const VResult &lvec = l->result(); - int size = lvec.size(); + size_type size = lvec.size(); assert(size > 0); - Result vresult = 0.0; + Result result = 0.0; Op op; - for (int i = 0; i < size; ++i) - vresult = op(vresult, lvec[i]); + for (off_type i = 0; i < size; ++i) + result = op(result, lvec[i]); - return vresult; + return result; } - virtual size_t size() const { return 1; } + size_type size() const { return 1; } - virtual std::string str() const + std::string + str() const { return csprintf("total(%s)", l->str()); } @@ -2237,92 +2507,55 @@ class SumNode : public Node * This is a simple scalar statistic, like a counter. * @sa Stat, ScalarBase, StatStor */ -template -class Scalar : public Wrap, ScalarBase, ScalarStatData> +class Scalar : public ScalarBase { public: - /** The base implementation. */ - typedef ScalarBase Base; + using ScalarBase::operator=; - Scalar() + Scalar(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : ScalarBase(parent, name, desc) { - this->doInit(); } - - /** - * Sets the stat equal to the given value. Calls the base implementation - * of operator= - * @param v The new value. - */ - template - void operator=(const U &v) { Base::operator=(v); } }; -class Value : public Wrap +/** + * A stat that calculates the per tick average of a value. + * @sa Stat, ScalarBase, AvgStor + */ +class Average : public ScalarBase { public: - /** The base implementation. */ - typedef ValueBase Base; + using ScalarBase::operator=; - template - Value &scalar(T &value) + Average(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : ScalarBase(parent, name, desc) { - Base::scalar(value); - return *this; - } - - template - 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 Average : public Wrap, ScalarBase, ScalarStatData> +class Value : public ValueBase { public: - /** The base implementation. */ - typedef ScalarBase Base; - - Average() + Value(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : ValueBase(parent, name, desc) { - this->doInit(); } - - /** - * Sets the stat equal to the given value. Calls the base implementation - * of operator= - * @param v The new value. - */ - template - void operator=(const U &v) { Base::operator=(v); } }; /** * A vector of scalar stats. * @sa Stat, VectorBase, StatStor */ -template -class Vector : public WrapVec, VectorBase, VectorStatData> +class Vector : public VectorBase { public: - /** The base implementation. */ - typedef ScalarBase 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) { - this->doInit(size); - return *this; + Vector(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : VectorBase(parent, name, desc) + { } }; @@ -2330,19 +2563,13 @@ class Vector : public WrapVec, VectorBase, VectorStatData> * A vector of Average stats. * @sa Stat, VectorBase, AvgStor */ -template -class AverageVector - : public WrapVec, VectorBase, VectorStatData> +class AverageVector : public VectorBase { 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) { - this->doInit(size); - return *this; + AverageVector(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : VectorBase(parent, name, desc) + { } }; @@ -2350,14 +2577,13 @@ class AverageVector * A 2-Dimensional vecto of scalar stats. * @sa Stat, Vector2dBase, StatStor */ -template -class Vector2d - : public WrapVec2d, Vector2dBase, Vector2dStatData> +class Vector2d : public Vector2dBase { public: - Vector2d &init(size_t x, size_t y) { - this->doInit(x, y); - return *this; + Vector2d(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : Vector2dBase(parent, name, desc) + { } }; @@ -2365,17 +2591,15 @@ class Vector2d * A simple distribution stat. * @sa Stat, DistBase, DistStor */ -template -class Distribution - : public Wrap, DistBase, DistStatData> +class Distribution : public DistBase { public: - /** Base implementation. */ - typedef DistBase Base; - /** The Parameter type. */ - typedef DistStor::Params Params; + Distribution(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : DistBase(parent, name, desc) + { + } - public: /** * Set the parameters of this distribution. @sa DistStor::Params * @param min The minimum value of the distribution. @@ -2383,80 +2607,105 @@ class Distribution * @param bkt The number of values in each bucket. * @return A reference to this distribution. */ - Distribution &init(Counter min, Counter max, Counter bkt) { - this->params.min = min; - this->params.max = max; - this->params.bucket_size = bkt; - this->params.size = (int)rint((max - min) / bkt + 1.0); + Distribution & + init(Counter min, Counter max, Counter bkt) + { + DistStor::Params *params = new DistStor::Params; + params->min = min; + params->max = max; + params->bucket_size = bkt; + // Division by zero is especially serious in an Aarch64 host, + // where it gets rounded to allocate 32GiB RAM. + assert(bkt > 0); + params->buckets = (size_type)ceil((max - min + 1.0) / bkt); + this->setParams(params); this->doInit(); - return *this; + return this->self(); } }; /** - * Calculates the mean and variance of all the samples. - * @sa Stat, DistBase, FancyStor + * A simple histogram stat. + * @sa Stat, DistBase, HistStor */ -template -class StandardDeviation - : public Wrap, DistBase, DistStatData> +class Histogram : public DistBase { public: - /** The base implementation */ - typedef DistBase Base; - /** The parameter type. */ - typedef DistStor::Params Params; + Histogram(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : DistBase(parent, name, desc) + { + } - public: /** - * Construct and initialize this distribution. + * Set the parameters of this histogram. @sa HistStor::Params + * @param size The number of buckets in the histogram + * @return A reference to this histogram. */ - StandardDeviation() { + Histogram & + init(size_type size) + { + HistStor::Params *params = new HistStor::Params; + params->buckets = size; + this->setParams(params); this->doInit(); + return this->self(); } }; /** - * Calculates the per cycle mean and variance of the samples. - * @sa Stat, DistBase, AvgFancy + * Calculates the mean and variance of all the samples. + * @sa DistBase, SampleStor */ -template -class AverageDeviation - : public Wrap, DistBase, DistStatData> +class StandardDeviation : public DistBase { public: - /** The base implementation */ - typedef DistBase Base; - /** The parameter type. */ - typedef DistStor::Params Params; + /** + * Construct and initialize this distribution. + */ + StandardDeviation(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : DistBase(parent, name, desc) + { + SampleStor::Params *params = new SampleStor::Params; + this->doInit(); + this->setParams(params); + } +}; +/** + * Calculates the per tick mean and variance of the samples. + * @sa DistBase, AvgSampleStor + */ +class AverageDeviation : public DistBase +{ public: /** * Construct and initialize this distribution. */ - AverageDeviation() + AverageDeviation(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : DistBase(parent, name, desc) { + AvgSampleStor::Params *params = new AvgSampleStor::Params; this->doInit(); + this->setParams(params); } }; /** * A vector of distributions. - * @sa Stat, VectorDistBase, DistStor + * @sa VectorDistBase, DistStor */ -template -class VectorDistribution - : public WrapVec, - VectorDistBase, - VectorDistStatData> +class VectorDistribution : public VectorDistBase { public: - /** The base implementation */ - typedef VectorDistBase Base; - /** The parameter type. */ - typedef DistStor::Params Params; + VectorDistribution(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : VectorDistBase(parent, name, desc) + { + } - public: /** * Initialize storage and parameters for this distribution. * @param size The size of the vector (the number of distributions). @@ -2465,194 +2714,333 @@ class VectorDistribution * @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) { - this->params.min = min; - this->params.max = max; - this->params.bucket_size = bkt; - this->params.size = (int)rint((max - min) / bkt + 1.0); + VectorDistribution & + init(size_type size, Counter min, Counter max, Counter bkt) + { + DistStor::Params *params = new DistStor::Params; + params->min = min; + params->max = max; + params->bucket_size = bkt; + params->buckets = (size_type)ceil((max - min + 1.0) / bkt); + this->setParams(params); this->doInit(size); - return *this; + return this->self(); } }; /** * This is a vector of StandardDeviation stats. - * @sa Stat, VectorDistBase, FancyStor + * @sa VectorDistBase, SampleStor */ -template class VectorStandardDeviation - : public WrapVec, - VectorDistBase, - VectorDistStatData> + : public VectorDistBase { public: - /** The base implementation */ - typedef VectorDistBase Base; - /** The parameter type. */ - typedef DistStor::Params Params; + VectorStandardDeviation(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : VectorDistBase(parent, name, + desc) + { + } - public: /** * Initialize storage for this distribution. * @param size The size of the vector. * @return A reference to this distribution. */ - VectorStandardDeviation &init(int size) { + VectorStandardDeviation & + init(size_type size) + { + SampleStor::Params *params = new SampleStor::Params; this->doInit(size); - return *this; + this->setParams(params); + return this->self(); } }; /** * This is a vector of AverageDeviation stats. - * @sa Stat, VectorDistBase, AvgFancy + * @sa VectorDistBase, AvgSampleStor */ -template class VectorAverageDeviation - : public WrapVec, - VectorDistBase, - VectorDistStatData> + : public VectorDistBase { public: - /** The base implementation */ - typedef VectorDistBase Base; - /** The parameter type. */ - typedef DistStor::Params Params; + VectorAverageDeviation(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : VectorDistBase(parent, name, + desc) + { + } - public: /** * Initialize storage for this distribution. * @param size The size of the vector. * @return A reference to this distribution. */ - VectorAverageDeviation &init(int size) { + VectorAverageDeviation & + init(size_type size) + { + AvgSampleStor::Params *params = new AvgSampleStor::Params; this->doInit(size); - return *this; + this->setParams(params); + return this->self(); + } +}; + +template +class FormulaInfoProxy : public InfoProxy +{ + protected: + mutable VResult vec; + mutable VCounter cvec; + + public: + FormulaInfoProxy(Stat &stat) : InfoProxy(stat) {} + + size_type size() const { return this->s.size(); } + + const VResult & + result() const + { + this->s.result(vec); + return vec; } + Result total() const { return this->s.total(); } + VCounter &value() const { return cvec; } + + std::string str() const { return this->s.str(); } +}; + +template +class SparseHistInfoProxy : public InfoProxy +{ + public: + SparseHistInfoProxy(Stat &stat) : InfoProxy(stat) {} }; /** - * 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 + * Implementation of a sparse histogram stat. The storage class is + * determined by the Storage template. */ -class FormulaBase : public DataAccess +template +class SparseHistBase : public DataWrap { + public: + typedef SparseHistInfoProxy Info; + typedef Stor Storage; + typedef typename Stor::Params Params; + protected: - /** The root of the tree which represents the Formula */ - NodePtr root; - friend class Temp; + /** The storage for this stat. */ + char storage[sizeof(Storage)]; - public: + protected: /** - * 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. + * Retrieve the storage. + * @return The storage object for this stat. */ - void result(VResult &vec) const; + Storage * + data() + { + return reinterpret_cast(storage); + } /** - * 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. + * Retrieve a const pointer to the storage. + * @return A const pointer to the storage object for this stat. */ - Result total() const; + const Storage * + data() const + { + return reinterpret_cast(storage); + } - /** - * Return the number of elements in the tree. - */ - size_t size() const; + void + doInit() + { + new (storage) Storage(this->info()); + this->setInit(); + } - bool check() const { return true; } + public: + SparseHistBase(Group *parent, const char *name, const char *desc) + : DataWrap(parent, name, desc) + { + } /** - * Formulas don't need to be reset + * 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. */ - void reset(); + template + void sample(const U &v, int n = 1) { data()->sample(v, n); } /** - * + * Return the number of entries in this stat. + * @return The number of entries. */ - bool zero() const; - + size_type size() const { return data()->size(); } /** - * + * Return true if no samples have been added. + * @return True if there haven't been any samples. */ - void update(StatData *); + bool zero() const { return data()->zero(); } - std::string str() const; + void + prepare() + { + Info *info = this->info(); + data()->prepare(info, info->data); + } + + /** + * Reset stat value to default + */ + void + reset() + { + data()->reset(this->info()); + } }; -class FormulaData : public VectorData +/** + * Templatized storage and interface for a sparse histogram stat. + */ +class SparseHistStor { public: - virtual std::string str() const = 0; - virtual bool check() const { return true; } -}; + /** The parameters for a sparse histogram stat. */ + struct Params : public DistParams + { + Params() : DistParams(Hist) {} + }; -template -class FormulaStatData : public FormulaData -{ - protected: - Stat &s; - mutable VResult vec; - mutable VCounter cvec; + private: + /** Counter for number of samples */ + Counter samples; + /** Counter for each bucket. */ + MCounter cmap; public: - FormulaStatData(Stat &stat) : s(stat) {} + SparseHistStor(Info *info) + { + reset(info); + } + + /** + * 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. + */ + void + sample(Counter val, int number) + { + cmap[val] += number; + samples += number; + } - virtual bool zero() const { return s.zero(); } - virtual void reset() { s.reset(); } + /** + * Return the number of buckets in this distribution. + * @return the number of buckets. + */ + size_type size() const { return cmap.size(); } - virtual size_t size() const { return s.size(); } - virtual const VResult &result() const + /** + * Returns true if any calls to sample have been made. + * @return True if any values have been sampled. + */ + bool + zero() const { - s.result(vec); - return vec; + return samples == Counter(); } - virtual Result total() const { return s.total(); } - virtual VCounter &value() const { return cvec; } - virtual void visit(Visit &visitor) + + void + prepare(Info *info, SparseHistData &data) { - update(); - s.update(this); - visitor.visit(*this); + MCounter::iterator it; + data.cmap.clear(); + for (it = cmap.begin(); it != cmap.end(); it++) { + data.cmap[(*it).first] = (*it).second; + } + + data.samples = samples; + } + + /** + * Reset stat value to default + */ + void + reset(Info *info) + { + cmap.clear(); + samples = 0; } - virtual std::string str() const { return s.str(); } }; -class Temp; -class Formula - : public WrapVec +class SparseHistogram : public SparseHistBase { public: + SparseHistogram(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr) + : SparseHistBase(parent, name, desc) + { + } + /** - * Create and initialize thie formula, and register it with the database. + * Set the parameters of this histogram. @sa HistStor::Params + * @param size The number of buckets in the histogram + * @return A reference to this histogram. */ - Formula(); + SparseHistogram & + init(size_type size) + { + SparseHistStor::Params *params = new SparseHistStor::Params; + this->setParams(params); + this->doInit(); + return this->self(); + } +}; +class Temp; +/** + * 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 Formula : public DataWrapVec +{ + protected: + /** The root of the tree which represents the Formula */ + NodePtr root; + friend class Temp; + + public: /** - * Create a formula with the given root node, register it with the - * database. - * @param r The root of the expression tree. + * Create and initialize thie formula, and register it with the database. */ - Formula(Temp r); + Formula(Group *parent = nullptr, const char *name = nullptr, + const char *desc = nullptr); + + Formula(Group *parent, const char *name, const char *desc, + const 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); + const Formula &operator=(const Temp &r); + + template + const Formula &operator=(const T &v) + { + *this = Temp(v); + return *this; + } /** * Add the given tree to the existing one. @@ -2660,6 +3048,53 @@ class Formula * @return a reference to this formula. */ const Formula &operator+=(Temp r); + + /** + * Divide the existing tree by the given one. + * @param r The root of the expression tree. + * @return a reference to this formula. + */ + const Formula &operator/=(Temp r); + + /** + * 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_type size() const; + + void prepare() { } + + /** + * Formulas don't need to be reset + */ + void reset(); + + /** + * + */ + bool zero() const; + + std::string str() const; }; class FormulaNode : public Node @@ -2671,11 +3106,11 @@ class FormulaNode : public Node 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(); } + size_type size() const { return formula.size(); } + const VResult &result() const { formula.result(vec); return vec; } + Result total() const { return formula.total(); } - virtual std::string str() const { return formula.str(); } + std::string str() const { return formula.str(); } }; /** @@ -2694,51 +3129,64 @@ class Temp * Copy the given pointer to this class. * @param n A pointer to a Node object to copy. */ - Temp(NodePtr n) : node(n) { } + Temp(const NodePtr &n) : node(n) { } + + Temp(NodePtr &&n) : node(std::move(n)) { } /** * Return the node pointer. * @return the node pointer. */ - operator NodePtr&() { return node;} + operator NodePtr&() { return node; } + + /** + * Makde gcc < 4.6.3 happy and explicitly get the underlying node. + */ + NodePtr getNodePtr() const { return node; } public: /** * Create a new ScalarStatNode. * @param s The ScalarStat to place in a node. */ - template - Temp(const Scalar &s) - : node(new ScalarStatNode(s.statData())) { } + Temp(const Scalar &s) + : node(new ScalarStatNode(s.info())) + { } /** * Create a new ScalarStatNode. * @param s The ScalarStat to place in a node. */ Temp(const Value &s) - : node(new ScalarStatNode(s.statData())) { } + : node(new ScalarStatNode(s.info())) + { } /** * Create a new ScalarStatNode. * @param s The ScalarStat to place in a node. */ - template - Temp(const Average &s) - : node(new ScalarStatNode(s.statData())) { } + Temp(const Average &s) + : node(new ScalarStatNode(s.info())) + { } /** * Create a new VectorStatNode. * @param s The VectorStat to place in a node. */ - template - Temp(const Vector &s) - : node(new VectorStatNode(s.statData())) { } + Temp(const Vector &s) + : node(new VectorStatNode(s.info())) + { } + + Temp(const AverageVector &s) + : node(new VectorStatNode(s.info())) + { } /** * */ Temp(const Formula &f) - : node(new FormulaNode(f)) { } + : node(new FormulaNode(f)) + { } /** * Create a new ScalarProxyNode. @@ -2746,91 +3194,104 @@ class Temp */ template Temp(const ScalarProxy &p) - : node(new ScalarProxyNode(p)) { } + : node(new ScalarProxyNode(p)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(signed char value) - : node(new ConstNode(value)) {} + : node(new ConstNode(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(unsigned char value) - : node(new ConstNode(value)) {} + : node(new ConstNode(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(signed short value) - : node(new ConstNode(value)) {} + : node(new ConstNode(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(unsigned short value) - : node(new ConstNode(value)) {} + : node(new ConstNode(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(signed int value) - : node(new ConstNode(value)) {} + : node(new ConstNode(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(unsigned int value) - : node(new ConstNode(value)) {} + : node(new ConstNode(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(signed long value) - : node(new ConstNode(value)) {} + : node(new ConstNode(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(unsigned long value) - : node(new ConstNode(value)) {} + : node(new ConstNode(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(signed long long value) - : node(new ConstNode(value)) {} + : node(new ConstNode(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(unsigned long long value) - : node(new ConstNode(value)) {} + : node(new ConstNode(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(float value) - : node(new ConstNode(value)) {} + : node(new ConstNode(value)) + { } /** * Create a ConstNode * @param value The value of the const node. */ Temp(double value) - : node(new ConstNode(value)) {} + : node(new ConstNode(value)) + { } }; @@ -2838,53 +3299,105 @@ class Temp * @} */ -void check(); -void reset(); -void registerResetCallback(Callback *cb); - inline Temp operator+(Temp l, Temp r) { - return NodePtr(new BinaryNode >(l, r)); + return Temp(std::make_shared > >(l, r)); } inline Temp operator-(Temp l, Temp r) { - return NodePtr(new BinaryNode >(l, r)); + return Temp(std::make_shared > >(l, r)); } inline Temp operator*(Temp l, Temp r) { - return NodePtr(new BinaryNode >(l, r)); + return Temp(std::make_shared > >(l, r)); } inline Temp operator/(Temp l, Temp r) { - return NodePtr(new BinaryNode >(l, r)); + return Temp(std::make_shared > >(l, r)); } inline Temp operator-(Temp l) { - return NodePtr(new UnaryNode >(l)); + return Temp(std::make_shared > >(l)); } template inline Temp constant(T val) { - return NodePtr(new ConstNode(val)); + return Temp(std::make_shared >(val)); +} + +template +inline Temp +constantVector(T val) +{ + return Temp(std::make_shared >(val)); } inline Temp sum(Temp val) { - return NodePtr(new SumNode >(val)); + return Temp(std::make_shared > >(val)); } -/* namespace Stats */ } +/** Dump all statistics data to the registered outputs */ +void dump(); +void reset(); +void enable(); +bool enabled(); + +/** + * Register reset and dump handlers. These are the functions which + * will actually perform the whole statistics reset/dump actions + * including processing the reset/dump callbacks + */ +typedef void (*Handler)(); + +void registerHandlers(Handler reset_handler, Handler dump_handler); + +/** + * Register a callback that should be called whenever statistics are + * reset + */ +void registerResetCallback(Callback *cb); + +/** + * Register a callback that should be called whenever statistics are + * about to be dumped + */ +void registerDumpCallback(Callback *cb); + +/** + * Process all the callbacks in the reset callbacks queue + */ +void processResetQueue(); + +/** + * Process all the callbacks in the dump callbacks queue + */ +void processDumpQueue(); + +std::list &statsList(); + +typedef std::map MapType; +MapType &statsMap(); + +typedef std::map NameMapType; +NameMapType &nameMap(); + +bool validateStatName(const std::string &name); + +} // namespace Stats + +void debugDumpStats(); #endif // __BASE_STATISTICS_HH__