/*
+ * 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
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
+ * Pierre-Yves Peneau
*/
/** @file
#include <functional>
#include <iosfwd>
#include <list>
+#include <map>
+#include <memory>
#include <string>
#include <vector>
+#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 tick. */
-extern Tick curTick;
+extern Tick curTick();
/* A namespace for all of the Statistics */
namespace Stats {
-struct StorageParams
-{
- virtual ~StorageParams();
-};
-
-//////////////////////////////////////////////////////////////////////
-//
-// Statistics Framework Base classes
-//
-//////////////////////////////////////////////////////////////////////
-class Info
-{
- public:
- /** 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 Info *prereq;
- /**
- * A unique stat ID for each stat in the simulator.
- * Can be used externally for lookups as well as for debugging.
- */
- static int id_count;
- int id;
-
- public:
- const StorageParams *storageParams;
-
- public:
- Info();
- virtual ~Info();
-
- /**
- * Reset the 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(Info *stat1, Info *stat2);
-};
-
template <class Stat, class Base>
-class InfoWrap : public Base
+class InfoProxy : public Base
{
protected:
Stat &s;
public:
- InfoWrap(Stat &stat) : s(stat) {}
+ InfoProxy(Stat &stat) : s(stat) {}
bool check() const { return s.check(); }
+ void prepare() { s.prepare(); }
void reset() { s.reset(); }
+ void
+ visit(Output &visitor)
+ {
+ visitor.visit(*static_cast<Base *>(this));
+ }
bool zero() const { return s.zero(); }
};
-class ScalarInfoBase : public Info
-{
- public:
- virtual Counter value() const = 0;
- virtual Result result() const = 0;
- virtual Result total() const = 0;
- void visit(Visit &visitor) { visitor.visit(*this); }
-};
-
template <class Stat>
-class ScalarInfo : public InfoWrap<Stat, ScalarInfoBase>
+class ScalarInfoProxy : public InfoProxy<Stat, ScalarInfo>
{
public:
- ScalarInfo(Stat &stat) : InfoWrap<Stat, ScalarInfoBase>(stat) {}
+ ScalarInfoProxy(Stat &stat) : InfoProxy<Stat, ScalarInfo>(stat) {}
Counter value() const { return this->s.value(); }
Result result() const { return this->s.result(); }
Result total() const { return this->s.total(); }
};
-class VectorInfoBase : public Info
-{
- public:
- /** Names and descriptions of subfields. */
- mutable std::vector<std::string> subnames;
- mutable std::vector<std::string> subdescs;
-
- public:
- virtual size_type 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()) {
- size_type s = size();
- if (subnames.size() < s)
- subnames.resize(s);
-
- if (subdescs.size() < s)
- subdescs.resize(s);
- }
- }
-};
-
template <class Stat>
-class VectorInfo : public InfoWrap<Stat, VectorInfoBase>
+class VectorInfoProxy : public InfoProxy<Stat, VectorInfo>
{
protected:
mutable VCounter cvec;
mutable VResult rvec;
public:
- VectorInfo(Stat &stat) : InfoWrap<Stat, VectorInfoBase>(stat) {}
+ VectorInfoProxy(Stat &stat) : InfoProxy<Stat, VectorInfo>(stat) {}
size_type size() const { return this->s.size(); }
}
Result total() const { return this->s.total(); }
-
- void
- visit(Visit &visitor)
- {
- this->update();
- this->s.update(this);
- visitor.visit(*this);
- }
-};
-
-struct DistData
-{
- Counter min_val;
- Counter max_val;
- Counter underflow;
- Counter overflow;
- VCounter cvec;
- Counter sum;
- Counter squares;
- Counter samples;
-};
-
-class DistInfoBase : public Info
-{
- public:
- /** Local storage for the entry values, used for printing. */
- DistData data;
};
template <class Stat>
-class DistInfo : public InfoWrap<Stat, DistInfoBase>
-{
- public:
- DistInfo(Stat &stat) : InfoWrap<Stat, DistInfoBase>(stat) {}
-
- void
- visit(Visit &visitor)
- {
- this->s.update(this);
- visitor.visit(*this);
- }
-};
-
-class VectorDistInfoBase : public Info
+class DistInfoProxy : public InfoProxy<Stat, DistInfo>
{
public:
- std::vector<DistData> data;
-
- /** Names and descriptions of subfields. */
- mutable std::vector<std::string> subnames;
- mutable std::vector<std::string> subdescs;
-
- protected:
- /** Local storage for the entry values, used for printing. */
- mutable VResult rvec;
-
- public:
- virtual size_type size() const = 0;
-
- void
- update()
- {
- size_type s = size();
- if (subnames.size() < s)
- subnames.resize(s);
-
- if (subdescs.size() < s)
- subdescs.resize(s);
- }
+ DistInfoProxy(Stat &stat) : InfoProxy<Stat, DistInfo>(stat) {}
};
template <class Stat>
-class VectorDistInfo : public InfoWrap<Stat, VectorDistInfoBase>
+class VectorDistInfoProxy : public InfoProxy<Stat, VectorDistInfo>
{
public:
- VectorDistInfo(Stat &stat) : InfoWrap<Stat, VectorDistInfoBase>(stat) {}
+ VectorDistInfoProxy(Stat &stat) : InfoProxy<Stat, VectorDistInfo>(stat) {}
size_type size() const { return this->s.size(); }
-
- void
- visit(Visit &visitor)
- {
- this->update();
- this->s.update(this);
- visitor.visit(*this);
- }
};
-class Vector2dInfoBase : public Info
+template <class Stat>
+class Vector2dInfoProxy : public InfoProxy<Stat, Vector2dInfo>
{
public:
- /** Names and descriptions of subfields. */
- std::vector<std::string> subnames;
- std::vector<std::string> subdescs;
- std::vector<std::string> y_subnames;
+ Vector2dInfoProxy(Stat &stat) : InfoProxy<Stat, Vector2dInfo>(stat) {}
- /** Local storage for the entry values, used for printing. */
- mutable VCounter cvec;
- mutable size_type x;
- mutable size_type y;
-
- public:
- void
- update()
- {
- if (subnames.size() < x)
- subnames.resize(x);
- }
+ Result total() const { return this->s.total(); }
};
-template <class Stat>
-class Vector2dInfo : public InfoWrap<Stat, Vector2dInfoBase>
+struct StorageParams
{
- public:
- Vector2dInfo(Stat &stat) : InfoWrap<Stat, Vector2dInfoBase>(stat) {}
-
- void
- visit(Visit &visitor)
- {
- this->update();
- this->s.update(this);
- visitor.visit(*this);
- }
+ virtual ~StorageParams();
};
class InfoAccess
{
+ private:
+ Info *_info;
+
protected:
/** Set up an info class for this statistic */
- void setInfo(Info *info);
+ void setInfo(Group *parent, Info *info);
/** Save Storage class parameters if any */
void setParams(const StorageParams *params);
/** Save Storage class parameters if any */
const Info *info() const;
public:
+ InfoAccess()
+ : _info(nullptr) {};
+
/**
* Reset the stat to the default state.
*/
- void reset() {}
+ void reset() { }
/**
* @return true if this stat has a value and satisfies its
bool check() const { return true; }
};
-template <class Derived, class Base, template <class> class Info>
-class DataWrap : public Base
+template <class Derived, template <class> class InfoProxyType>
+class DataWrap : public InfoAccess
{
public:
- typedef Derived DerivedType;
- typedef Base BaseType;
- typedef Info<Base> InfoType;
+ typedef InfoProxyType<Derived> Info;
protected:
- Derived &self() { return *reinterpret_cast<Derived *>(this); }
+ Derived &self() { return *static_cast<Derived *>(this); }
protected:
- InfoType *
+ Info *
info()
{
- return safe_cast<InfoType *>(InfoAccess::info());
+ return safe_cast<Info *>(InfoAccess::info());
}
public:
- const InfoType *
+ const Info *
info() const
{
- return safe_cast<const InfoType *>(InfoAccess::info());
+ return safe_cast<const Info *>(InfoAccess::info());
}
- protected:
- /**
- * Copy constructor, copies are not allowed.
- */
- DataWrap(const DataWrap &stat);
+ public:
+ DataWrap() = delete;
+ DataWrap(const DataWrap &) = delete;
+ DataWrap &operator=(const DataWrap &) = delete;
- /**
- * Can't copy stats.
- */
- void operator=(const DataWrap &);
- public:
- DataWrap()
+ DataWrap(Group *parent, const char *name, const char *desc)
{
- this->setInfo(new InfoType(*this));
+ auto info = new Info(self());
+ this->setInfo(parent, info);
+
+ if (parent)
+ parent->addStat(info);
+
+ if (name) {
+ info->setName(parent, name);
+ info->flags.set(display);
+ }
+
+ if (desc)
+ info->desc = desc;
}
/**
* @return A reference to this stat.
*/
Derived &
- name(const std::string &_name)
+ name(const std::string &name)
{
- InfoType *info = this->info();
- info->name = _name;
- info->flags |= print;
+ 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
* @return A reference to this stat.
*/
Derived &
- flags(StatFlags _flags)
+ flags(Flags _flags)
{
- this->info()->flags |= _flags;
+ this->info()->flags.set(_flags);
return this->self();
}
}
};
-template <class Derived, class Base, template <class Base> class Info>
-class DataWrapVec : public DataWrap<Derived, Base, Info>
+template <class Derived, template <class> class InfoProxyType>
+class DataWrapVec : public DataWrap<Derived, InfoProxyType>
{
public:
- typedef Derived DerivedType;
- typedef Base BaseType;
- typedef Info<Base> InfoType;
+ typedef InfoProxyType<Derived> Info;
+
+ DataWrapVec(Group *parent = nullptr, const char *name = nullptr,
+ const char *desc = nullptr)
+ : DataWrap<Derived, InfoProxyType>(parent, name, desc)
+ {}
- public:
// The following functions are specific to vectors. If you use them
// in a non vector context, you will get a nice compiler error!
Derived &
subname(off_type index, const std::string &name)
{
- std::vector<std::string> &subn = this->info()->subnames;
+ Derived &self = this->self();
+ Info *info = self.info();
+
+ std::vector<std::string> &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.
Derived &
subdesc(off_type index, const std::string &desc)
{
- std::vector<std::string> &subd = this->info()->subdescs;
+ Info *info = this->info();
+
+ std::vector<std::string> &subd = info->subdescs;
if (subd.size() <= index)
subd.resize(index + 1);
subd[index] = desc;
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 Derived, class Base, template <class Base> class Info>
-class DataWrapVec2d : public DataWrapVec<Derived, Base, Info>
+template <class Derived, template <class> class InfoProxyType>
+class DataWrapVec2d : public DataWrapVec<Derived, InfoProxyType>
{
public:
- typedef Derived DerivedType;
- typedef Base BaseType;
- typedef Info<Base> InfoType;
+ typedef InfoProxyType<Derived> Info;
+
+ DataWrapVec2d(Group *parent, const char *name, const char *desc)
+ : DataWrapVec<Derived, InfoProxyType>(parent, name, desc)
+ {
+ }
- public:
/**
* @warning This makes the assumption that if you're gonna subnames a 2d
* vector, you're subnaming across all y
Derived &
ysubnames(const char **names)
{
- InfoType *info = this->info();
- info->y_subnames.resize(this->y);
- for (off_type i = 0; i < this->y; ++i)
+ 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 this->self();
+ return self;
}
Derived &
- ysubname(off_type index, const std::string subname)
+ ysubname(off_type index, const std::string &subname)
{
- InfoType *info = this->info();
- assert(index < this->y);
- info->y_subnames.resize(this->y);
+ 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 this->self();
+ return self;
+ }
+
+ std::string
+ ysubname(off_type i) const
+ {
+ return this->info()->y_subnames[i];
}
+
};
//////////////////////////////////////////////////////////////////////
* @return The value of this stat.
*/
Result result() const { return (Result)data; }
+ /**
+ * Prepare stat data for dumping or serialization
+ */
+ void prepare(Info *info) { }
/**
* Reset stat value to default
*/
private:
/** The current count. */
Counter current;
+ /** The tick of the last reset */
+ Tick lastReset;
/** The total count for all tick. */
mutable Result total;
/** The tick that current last changed. */
* Build and initializes this stat storage.
*/
AvgStor(Info *info)
- : current(0), total(0), last(0)
+ : current(0), lastReset(0), total(0), last(0)
{ }
/**
void
set(Counter val)
{
- total += current * (curTick - last);
- last = curTick;
+ total += current * (curTick() - last);
+ last = curTick();
current = val;
}
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);
+ }
+
+ /**
+ * @return true if zero value
+ */
+ bool zero() const { return total == 0.0; }
+
+ /**
+ * Prepare stat data for dumping or serialization
+ */
+ void
+ prepare(Info *info)
+ {
+ total += current * (curTick() - last);
+ last = curTick();
}
/**
reset(Info *info)
{
total = 0.0;
- last = curTick;
+ last = curTick();
+ lastReset = curTick();
}
- /**
- * @return true if zero value
- */
- bool zero() const { return total == 0.0; }
};
/**
* Implementation of a scalar stat. The type of stat is determined by the
* Storage template.
*/
-template <class Stor>
-class ScalarBase : public InfoAccess
+template <class Derived, class Stor>
+class ScalarBase : public DataWrap<Derived, ScalarInfoProxy>
{
public:
typedef Stor Storage;
void
doInit()
{
- new (storage) Storage(info());
- setInit();
+ new (storage) Storage(this->info());
+ this->setInit();
}
public:
Counter value() const { return data()->value(); }
public:
- ScalarBase() { }
+ ScalarBase(Group *parent = nullptr, const char *name = nullptr,
+ const char *desc = nullptr)
+ : DataWrap<Derived, ScalarInfoProxy>(parent, name, desc)
+ {
+ this->doInit();
+ }
public:
// Common operators for stats
*/
size_type size() const { return 1; }
- /**
- * Reset stat value to default
- */
- void reset() { data()->reset(info()); }
-
Counter value() { return data()->value(); }
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 ProxyInfo : public ScalarInfoBase
+class ProxyInfo : public ScalarInfo
{
public:
- void visit(Visit &visitor) { visitor.visit(*this); }
- std::string str() const { return to_string(value()); }
+ std::string str() const { return std::to_string(value()); }
size_type size() const { return 1; }
bool check() const { return true; }
- void reset() {}
+ void prepare() { }
+ void reset() { }
bool zero() const { return value() == 0; }
+
+ void visit(Output &visitor) { visitor.visit(*this); }
};
template <class T>
Result total() const { return (*functor)(); }
};
-class ValueBase : public InfoAccess
+/**
+ * A proxy similar to the FunctorProxy, but allows calling a method of a bound
+ * object, instead of a global free-standing function.
+ */
+template <class T, class V>
+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)(); }
+};
+
+template <class Derived>
+class ValueBase : public DataWrap<Derived, ScalarInfoProxy>
{
private:
ProxyInfo *proxy;
public:
- ValueBase() : proxy(NULL) { }
+ ValueBase(Group *parent, const char *name, const char *desc)
+ : DataWrap<Derived, ScalarInfoProxy>(parent, name, desc),
+ proxy(NULL)
+ {
+ }
+
~ValueBase() { if (proxy) delete proxy; }
template <class T>
- void
+ Derived &
scalar(T &value)
{
proxy = new ValueProxy<T>(value);
- setInit();
+ this->setInit();
+ return this->self();
}
template <class T>
- void
+ Derived &
functor(T &func)
{
proxy = new FunctorProxy<T>(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 <class T, class V>
+ Derived &
+ method(T *obj, V (T::*method)() const)
+ {
+ proxy = new MethodProxy<T,V>(obj, method);
+ this->setInit();
+ return this->self();
}
Counter value() { return proxy->value(); }
std::string str() const { return proxy->str(); }
bool zero() const { return proxy->zero(); }
bool check() const { return proxy != NULL; }
+ void prepare() { }
void reset() { }
};
{
private:
/** Pointer to the parent Vector. */
- Stat *stat;
+ Stat &stat;
/** The index to access in the parent VectorBase. */
off_type index;
* Return the current value of this stat as its base type.
* @return The current value.
*/
- Counter value() const { return stat->data(index)->value(); }
+ 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(); }
+ Result result() const { return stat.data(index)->result(); }
public:
/**
* Create and initialize this proxy, do not register it with the database.
* @param i The index to access.
*/
- ScalarProxy(Stat *s, off_type i)
+ ScalarProxy(Stat &s, off_type i)
: stat(s), index(i)
{
- assert(stat);
}
/**
* Increment the stat by 1. This calls the associated storage object inc
* function.
*/
- void operator++() { stat->data(index)->inc(1); }
+ 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); }
+ void operator--() { stat.data(index)->dec(1); }
/** Increment the stat by 1. */
void operator++(int) { ++*this; }
void
operator=(const U &v)
{
- stat->data(index)->set(v);
+ stat.data(index)->set(v);
}
/**
void
operator+=(const U &v)
{
- stat->data(index)->inc(v);
+ stat.data(index)->inc(v);
}
/**
void
operator-=(const U &v)
{
- stat->data(index)->dec(v);
+ stat.data(index)->dec(v);
}
/**
std::string
str() const
{
- return csprintf("%s[%d]", stat->info()->name, index);
+ return csprintf("%s[%d]", stat.info()->name, index);
}
};
* Implementation of a vector of stats. The type of stat is determined by the
* Storage class. @sa ScalarBase
*/
-template <class Stor>
-class VectorBase : public InfoAccess
+template <class Derived, class Stor>
+class VectorBase : public DataWrapVec<Derived, VectorInfoProxy>
{
public:
typedef Stor Storage;
typedef typename Stor::Params Params;
/** Proxy type */
- typedef ScalarProxy<VectorBase<Storage> > Proxy;
-
- friend class ScalarProxy<VectorBase<Storage> >;
+ typedef ScalarProxy<Derived> Proxy;
+ friend class ScalarProxy<Derived>;
+ friend class DataWrapVec<Derived, VectorInfoProxy>;
protected:
/** The storage of this stat. */
storage = reinterpret_cast<Storage *>(ptr);
for (off_type i = 0; i < _size; ++i)
- new (&storage[i]) Storage(info());
+ new (&storage[i]) Storage(this->info());
- setInit();
+ this->setInit();
}
public:
return storage != NULL;
}
- void
- reset()
- {
- for (off_type i = 0; i < size(); ++i)
- data(i)->reset(info());
- }
-
public:
- VectorBase()
- : storage(NULL)
+ VectorBase(Group *parent, const char *name, const char *desc)
+ : DataWrapVec<Derived, VectorInfoProxy>(parent, name, desc),
+ storage(nullptr), _size(0)
{}
~VectorBase()
delete [] reinterpret_cast<char *>(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.
operator[](off_type index)
{
assert (index >= 0 && index < size());
- return Proxy(this, index);
+ return Proxy(this->self(), index);
}
-
- void update(Info *data) {}
};
template <class Stat>
class VectorProxy
{
private:
- Stat *stat;
+ Stat &stat;
off_type offset;
size_type len;
data(off_type index)
{
assert(index < len);
- return stat->data(offset + index);
+ return stat.data(offset + index);
}
const typename Stat::Storage *
data(off_type index) const
{
assert(index < len);
- return const_cast<Stat *>(stat)->data(offset + index);
+ return stat.data(offset + index);
}
public:
}
public:
- VectorProxy(Stat *s, off_type o, size_type l)
+ VectorProxy(Stat &s, off_type o, size_type l)
: stat(s), offset(o), len(l)
{
}
size_type size() const { return len; }
};
-template <class Stor>
-class Vector2dBase : public InfoAccess
+template <class Derived, class Stor>
+class Vector2dBase : public DataWrapVec2d<Derived, Vector2dInfoProxy>
{
public:
+ typedef Vector2dInfoProxy<Derived> Info;
typedef Stor Storage;
typedef typename Stor::Params Params;
- typedef VectorProxy<Vector2dBase<Storage> > Proxy;
- friend class ScalarProxy<Vector2dBase<Storage> >;
- friend class VectorProxy<Vector2dBase<Storage> >;
+ typedef VectorProxy<Derived> Proxy;
+ friend class ScalarProxy<Derived>;
+ friend class VectorProxy<Derived>;
+ friend class DataWrapVec<Derived, Vector2dInfoProxy>;
+ friend class DataWrapVec2d<Derived, Vector2dInfoProxy>;
protected:
size_type x;
Storage *data(off_type index) { return &storage[index]; }
const Storage *data(off_type index) const { return &storage[index]; }
- void
- doInit(size_type _x, size_type _y)
- {
- assert(_x > 0 && _y > 0 && "sizes must be positive!");
+ public:
+ Vector2dBase(Group *parent, const char *name, const char *desc)
+ : DataWrapVec2d<Derived, Vector2dInfoProxy>(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<char *>(storage);
+ }
+
+ Derived &
+ init(size_type _x, size_type _y)
+ {
+ assert(_x > 0 && _y > 0 && "sizes must be positive!");
assert(!storage && "already initialized");
- Vector2dInfoBase *info = safe_cast<Vector2dInfoBase *>(this->info());
+ Derived &self = this->self();
+ Info *info = this->info();
x = _x;
y = _y;
for (off_type i = 0; i < _size; ++i)
new (&storage[i]) Storage(info);
- setInit();
- }
-
- public:
- Vector2dBase()
- : storage(NULL)
- {}
-
- ~Vector2dBase()
- {
- if (!storage)
- return;
-
- for (off_type i = 0; i < _size; ++i)
- data(i)->~Storage();
- delete [] reinterpret_cast<char *>(storage);
- }
+ this->setInit();
- void
- update(Vector2dInfoBase *newinfo)
- {
- size_type size = this->size();
- newinfo->cvec.resize(size);
- for (off_type i = 0; i < size; ++i)
- newinfo->cvec[i] = data(i)->value();
+ return self;
}
- std::string ysubname(off_type i) const { return (*this->y_subnames)[i]; }
-
Proxy
operator[](off_type index)
{
off_type offset = index * y;
- assert (index >= 0 && offset + index < size());
- return Proxy(this, offset, y);
+ assert (index >= 0 && offset + y <= size());
+ return Proxy(this->self(), offset, y);
}
zero() const
{
return data(0)->zero();
-#if 0
+ }
+
+ /**
+ * 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)
- if (!data(i)->zero())
- return false;
- return true;
-#endif
+ 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();
}
/**
void
reset()
{
- for (off_type i = 0; i < size(); ++i)
- data(i)->reset(info());
+ Info *info = this->info();
+ size_type size = this->size();
+ for (off_type i = 0; i < size; ++i)
+ data(i)->reset(info);
}
bool
// 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.
*/
class DistStor
{
public:
/** The parameters for a distribution stat. */
- struct Params : public StorageParams
+ struct Params : public DistParams
{
/** The minimum value to track. */
Counter min;
/** The number of buckets. Equal to (max-min)/bucket_size. */
size_type buckets;
- enum { fancy = false };
+ Params() : DistParams(Dist), min(0), max(0), bucket_size(0),
+ buckets(0) {}
};
private:
Counter max_track;
/** The number of entries in each bucket. */
Counter bucket_size;
- /** The number of buckets. Equal to (max-min)/bucket_size. */
- size_type buckets;
/** The smallest value sampled. */
Counter min_val;
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;
}
}
void
- update(Info *info, DistData &data)
+ prepare(Info *info, DistData &data)
{
const Params *params = safe_cast<const Params *>(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 == CounterLimits::max()) ? 0 : min_val;
data.max_val = (max_val == CounterLimits::min()) ? 0 : max_val;
data.underflow = underflow;
data.overflow = overflow;
- int buckets = params->buckets;
- data.cvec.resize(buckets);
- for (off_type i = 0; i < buckets; ++i)
+ data.cvec.resize(params->buckets);
+ for (off_type i = 0; i < params->buckets; ++i)
data.cvec[i] = cvec[i];
data.sum = sum;
min_val = CounterLimits::max();
max_val = CounterLimits::min();
- underflow = 0;
- overflow = 0;
+ underflow = Counter();
+ overflow = Counter();
+
+ size_type size = cvec.size();
+ for (off_type i = 0; i < size; ++i)
+ cvec[i] = Counter();
+
+ sum = Counter();
+ squares = Counter();
+ samples = Counter();
+ }
+};
+
+/**
+ * Templatized storage and interface for a histogram stat.
+ */
+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<const Params *>(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;
+ }
+
+ /**
+ * 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<const Params *>(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
+ */
+ void
+ reset(Info *info)
+ {
+ const Params *params = safe_cast<const Params *>(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)
sum = Counter();
squares = Counter();
samples = Counter();
+ logs = Counter();
}
};
* Templatized storage and interface for a distribution that calculates mean
* and variance.
*/
-class FancyStor
+class SampleStor
{
public:
- struct Params : public StorageParams
+ struct Params : public DistParams
{
- enum { fancy = true };
+ Params() : DistParams(Deviation) {}
};
private:
/**
* Create and initialize this storage.
*/
- FancyStor(Info *info)
+ SampleStor(Info *info)
: sum(Counter()), squares(Counter()), samples(Counter())
{ }
void
sample(Counter val, int number)
{
- Counter value = val * number;
- sum += value;
- squares += value * value;
+ sum += val * number;
+ squares += val * val * number;
samples += number;
}
- void
- update(Info *info, DistData &data)
- {
- data.sum = sum;
- data.squares = squares;
- data.samples = samples;
- }
-
/**
* Return the number of entries in this stat, 1
* @return 1.
*/
bool zero() const { return samples == Counter(); }
+ void
+ prepare(Info *info, DistData &data)
+ {
+ const Params *params = safe_cast<const Params *>(info->storageParams);
+
+ assert(params->type == Deviation);
+ data.type = params->type;
+ data.sum = sum;
+ data.squares = squares;
+ data.samples = samples;
+ }
+
/**
* Reset stat value to default
*/
* Templatized storage for distribution that calculates per tick mean and
* variance.
*/
-class AvgFancy
+class AvgSampleStor
{
public:
- struct Params : public StorageParams
+ struct Params : public DistParams
{
- enum { fancy = true };
+ Params() : DistParams(Deviation) {}
};
private:
/**
* Create and initialize this storage.
*/
- AvgFancy(Info *info)
+ AvgSampleStor(Info *info)
: sum(Counter()), squares(Counter())
{}
void
sample(Counter val, int number)
{
- Counter value = val * number;
- sum += value;
- squares += value * value;
- }
-
- void
- update(Info *info, DistData &data)
- {
- data.sum = sum;
- data.squares = squares;
- data.samples = curTick;
+ sum += val * number;
+ squares += val * val * number;
}
/**
*/
bool zero() const { return sum == Counter(); }
+ void
+ prepare(Info *info, DistData &data)
+ {
+ const Params *params = safe_cast<const Params *>(info->storageParams);
+
+ assert(params->type == Deviation);
+ data.type = params->type;
+ data.sum = sum;
+ data.squares = squares;
+ data.samples = curTick();
+ }
+
/**
* Reset stat value to default
*/
* Implementation of a distribution stat. The type of distribution is
* determined by the Storage template. @sa ScalarBase
*/
-template <class Stor>
-class DistBase : public InfoAccess
+template <class Derived, class Stor>
+class DistBase : public DataWrap<Derived, DistInfoProxy>
{
public:
+ typedef DistInfoProxy<Derived> Info;
typedef Stor Storage;
typedef typename Stor::Params Params;
void
doInit()
{
- new (storage) Storage(info());
- setInit();
+ new (storage) Storage(this->info());
+ this->setInit();
}
public:
- DistBase() { }
+ DistBase(Group *parent, const char *name, const char *desc)
+ : DataWrap<Derived, DistInfoProxy>(parent, name, desc)
+ {
+ }
/**
* Add a value to the distribtion n times. Calls sample on the storage
bool zero() const { return data()->zero(); }
void
- update(DistInfoBase *base)
+ prepare()
{
- data()->update(info(), base->data);
+ Info *info = this->info();
+ data()->prepare(info, info->data);
}
/**
void
reset()
{
- data()->reset(info());
+ data()->reset(this->info());
}
+
+ /**
+ * Add the argument distribution to the this distribution.
+ */
+ void add(DistBase &d) { data()->add(d.data()); }
+
};
template <class Stat>
class DistProxy;
-template <class Stor>
-class VectorDistBase : public InfoAccess
+template <class Derived, class Stor>
+class VectorDistBase : public DataWrapVec<Derived, VectorDistInfoProxy>
{
public:
+ typedef VectorDistInfoProxy<Derived> Info;
typedef Stor Storage;
typedef typename Stor::Params Params;
- typedef DistProxy<VectorDistBase<Storage> > Proxy;
- friend class DistProxy<VectorDistBase<Storage> >;
+ typedef DistProxy<Derived> Proxy;
+ friend class DistProxy<Derived>;
+ friend class DataWrapVec<Derived, VectorDistInfoProxy>;
protected:
Storage *storage;
char *ptr = new char[_size * sizeof(Storage)];
storage = reinterpret_cast<Storage *>(ptr);
+ Info *info = this->info();
for (off_type i = 0; i < _size; ++i)
- new (&storage[i]) Storage(info());
+ new (&storage[i]) Storage(info);
- setInit();
+ this->setInit();
}
public:
- VectorDistBase()
- : storage(NULL)
+ VectorDistBase(Group *parent, const char *name, const char *desc)
+ : DataWrapVec<Derived, VectorDistInfoProxy>(parent, name, desc),
+ storage(NULL)
{}
~VectorDistBase()
delete [] reinterpret_cast<char *>(storage);
}
- Proxy operator[](off_type index);
+ Proxy operator[](off_type index)
+ {
+ assert(index >= 0 && index < size());
+ return Proxy(this->self(), index);
+ }
size_type
size() const
bool
zero() const
{
- return false;
-#if 0
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 (off_type i = 0; i < size(); ++i)
- data(i)->reset(info());
+ 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
{
return storage != NULL;
}
-
- void
- update(VectorDistInfoBase *base)
- {
- size_type size = this->size();
- base->data.resize(size);
- for (off_type i = 0; i < size; ++i) {
- data(i)->update(info(), base->data[i]);
- }
- }
};
template <class Stat>
class DistProxy
{
private:
- Stat *stat;
+ 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, off_type i)
+ DistProxy(Stat &s, off_type i)
: stat(s), index(i)
{}
void reset() { }
};
-template <class Storage>
-inline typename VectorDistBase<Storage>::Proxy
-VectorDistBase<Storage>::operator[](off_type index)
-{
- assert (index >= 0 && index < size());
- return typename VectorDistBase<Storage>::Proxy(this, index);
-}
-
-#if 0
-template <class Storage>
-Result
-VectorDistBase<Storage>::total(off_type index) const
-{
- Result total = 0.0;
- for (off_type i = 0; i < x_size(); ++i)
- total += data(i)->result();
-}
-#endif
-
//////////////////////////////////////////////////////////////////////
//
// Formula Details
* Base class for formula statistic node. These nodes are used to build a tree
* that represents the formula.
*/
-class Node : public RefCounted
+class Node
{
public:
/**
*
*/
virtual std::string str() const = 0;
+
+ virtual ~Node() {};
};
-/** Reference counting pointer to a function Node. */
-typedef RefCountingPtr<Node> NodePtr;
+/** Shared pointer to a function Node. */
+typedef std::shared_ptr<Node> NodePtr;
class ScalarStatNode : public Node
{
private:
- const ScalarInfoBase *data;
+ const ScalarInfo *data;
mutable VResult vresult;
public:
- ScalarStatNode(const ScalarInfoBase *d) : data(d), vresult(1) {}
+ ScalarStatNode(const ScalarInfo *d) : data(d), vresult(1) {}
const VResult &
result() const
class VectorStatNode : public Node
{
private:
- const VectorInfoBase *data;
+ const VectorInfo *data;
public:
- VectorStatNode(const VectorInfoBase *d) : data(d) { }
+ VectorStatNode(const VectorInfo *d) : data(d) { }
const VResult &result() const { return data->result(); }
Result total() const { return data->total(); };
const VResult &result() const { return vresult; }
Result total() const { return vresult[0]; };
size_type size() const { return 1; }
- std::string str() const { return to_string(vresult[0]); }
+ std::string str() const { return std::to_string(vresult[0]); }
};
template <class T>
size_type size = this->size();
std::string tmp = "(";
for (off_type i = 0; i < size; i++)
- tmp += csprintf("%s ",to_string(vresult[i]));
+ tmp += csprintf("%s ", std::to_string(vresult[i]));
tmp += ")";
return tmp;
}
BinaryNode(NodePtr &a, NodePtr &b) : l(a), r(b) {}
const VResult &
- result() const
+ result() const override
{
Op op;
const VResult &lvec = l->result();
}
Result
- total() const
+ total() const override
{
const VResult &vec = this->result();
+ const VResult &lvec = l->result();
+ const VResult &rvec = r->result();
Result total = 0.0;
- for (off_type i = 0; i < size(); i++)
+ Result lsum = 0.0;
+ Result rsum = 0.0;
+ Op op;
+
+ 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;
}
size_type
- size() const
+ size() const override
{
size_type ls = l->size();
size_type rs = r->size();
}
std::string
- str() const
+ str() const override
{
return csprintf("(%s %s %s)", l->str(), OpString<Op>::str(), r->str());
}
size_type size = lvec.size();
assert(size > 0);
- Result vresult = 0.0;
+ Result result = 0.0;
Op op;
for (off_type i = 0; i < size; ++i)
- vresult = op(vresult, lvec[i]);
+ result = op(result, lvec[i]);
- return vresult;
+ return result;
}
size_type size() const { return 1; }
* This is a simple scalar statistic, like a counter.
* @sa Stat, ScalarBase, StatStor
*/
-template<int N = 0>
-class Scalar : public DataWrap<Scalar<N>, ScalarBase<StatStor>, ScalarInfo>
+class Scalar : public ScalarBase<Scalar, StatStor>
{
public:
- /** The base implementation. */
- typedef ScalarBase<StatStor> Base;
+ using ScalarBase<Scalar, StatStor>::operator=;
- Scalar()
+ Scalar(Group *parent = nullptr, const char *name = nullptr,
+ const char *desc = nullptr)
+ : ScalarBase<Scalar, StatStor>(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 <typename U>
- void operator=(const U &v) { Base::operator=(v); }
};
-class Value : public DataWrap<Value, ValueBase, ScalarInfo>
+/**
+ * A stat that calculates the per tick average of a value.
+ * @sa Stat, ScalarBase, AvgStor
+ */
+class Average : public ScalarBase<Average, AvgStor>
{
public:
- /** The base implementation. */
- typedef ValueBase Base;
+ using ScalarBase<Average, AvgStor>::operator=;
- template <class T>
- Value &
- scalar(T &value)
+ Average(Group *parent = nullptr, const char *name = nullptr,
+ const char *desc = nullptr)
+ : ScalarBase<Average, AvgStor>(parent, name, desc)
{
- Base::scalar(value);
- return *this;
}
+};
- template <class T>
- Value &
- functor(T &func)
- {
- Base::functor(func);
- return *this;
- }
-};
-
-/**
- * A stat that calculates the per tick average of a value.
- * @sa Stat, ScalarBase, AvgStor
- */
-template<int N = 0>
-class Average : public DataWrap<Average<N>, ScalarBase<AvgStor>, ScalarInfo>
+class Value : public ValueBase<Value>
{
public:
- /** The base implementation. */
- typedef ScalarBase<AvgStor> Base;
-
- Average()
+ Value(Group *parent = nullptr, const char *name = nullptr,
+ const char *desc = nullptr)
+ : ValueBase<Value>(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 <typename U>
- void
- operator=(const U &v)
- {
- Base::operator=(v);
}
};
* A vector of scalar stats.
* @sa Stat, VectorBase, StatStor
*/
-template<int N = 0>
-class Vector : public DataWrapVec<Vector<N>, VectorBase<StatStor>, VectorInfo>
+class Vector : public VectorBase<Vector, StatStor>
{
public:
- /** The base implementation. */
- typedef ScalarBase<StatStor> Base;
-
- /**
- * Set this vector to have the given size.
- * @param size The new size.
- * @return A reference to this stat.
- */
- Vector &
- init(size_type size)
+ Vector(Group *parent = nullptr, const char *name = nullptr,
+ const char *desc = nullptr)
+ : VectorBase<Vector, StatStor>(parent, name, desc)
{
- this->doInit(size);
- return *this;
}
};
* A vector of Average stats.
* @sa Stat, VectorBase, AvgStor
*/
-template<int N = 0>
-class AverageVector
- : public DataWrapVec<AverageVector<N>, VectorBase<AvgStor>, VectorInfo>
+class AverageVector : public VectorBase<AverageVector, AvgStor>
{
public:
- /**
- * Set this vector to have the given size.
- * @param size The new size.
- * @return A reference to this stat.
- */
- AverageVector &
- init(size_type size)
+ AverageVector(Group *parent = nullptr, const char *name = nullptr,
+ const char *desc = nullptr)
+ : VectorBase<AverageVector, AvgStor>(parent, name, desc)
{
- this->doInit(size);
- return *this;
}
};
* A 2-Dimensional vecto of scalar stats.
* @sa Stat, Vector2dBase, StatStor
*/
-template<int N = 0>
-class Vector2d
- : public DataWrapVec2d<Vector2d<N>, Vector2dBase<StatStor>, Vector2dInfo>
+class Vector2d : public Vector2dBase<Vector2d, StatStor>
{
public:
- Vector2d &
- init(size_type x, size_type y)
+ Vector2d(Group *parent = nullptr, const char *name = nullptr,
+ const char *desc = nullptr)
+ : Vector2dBase<Vector2d, StatStor>(parent, name, desc)
{
- this->doInit(x, y);
- return *this;
}
};
* A simple distribution stat.
* @sa Stat, DistBase, DistStor
*/
-template<int N = 0>
-class Distribution
- : public DataWrap<Distribution<N>, DistBase<DistStor>, DistInfo>
+class Distribution : public DistBase<Distribution, DistStor>
{
public:
- /** Base implementation. */
- typedef DistBase<DistStor> Base;
+ Distribution(Group *parent = nullptr, const char *name = nullptr,
+ const char *desc = nullptr)
+ : DistBase<Distribution, DistStor>(parent, name, desc)
+ {
+ }
- public:
/**
* Set the parameters of this distribution. @sa DistStor::Params
* @param min The minimum value of the distribution.
params->min = min;
params->max = max;
params->bucket_size = bkt;
- params->buckets = (size_type)rint((max - min) / bkt + 1.0);
+ // 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<int N = 0>
-class StandardDeviation
- : public DataWrap<StandardDeviation<N>, DistBase<FancyStor>, DistInfo>
+class Histogram : public DistBase<Histogram, HistStor>
{
public:
- /** The base implementation */
- typedef DistBase<DistStor> Base;
+ Histogram(Group *parent = nullptr, const char *name = nullptr,
+ const char *desc = nullptr)
+ : DistBase<Histogram, HistStor>(parent, name, desc)
+ {
+ }
+ /**
+ * Set the parameters of this histogram. @sa HistStor::Params
+ * @param size The number of buckets in the histogram
+ * @return A reference to this histogram.
+ */
+ Histogram &
+ init(size_type size)
+ {
+ HistStor::Params *params = new HistStor::Params;
+ params->buckets = size;
+ this->setParams(params);
+ this->doInit();
+ return this->self();
+ }
+};
+
+/**
+ * Calculates the mean and variance of all the samples.
+ * @sa DistBase, SampleStor
+ */
+class StandardDeviation : public DistBase<StandardDeviation, SampleStor>
+{
public:
/**
* Construct and initialize this distribution.
*/
- StandardDeviation()
+ StandardDeviation(Group *parent = nullptr, const char *name = nullptr,
+ const char *desc = nullptr)
+ : DistBase<StandardDeviation, SampleStor>(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 Stat, DistBase, AvgFancy
+ * @sa DistBase, AvgSampleStor
*/
-template<int N = 0>
-class AverageDeviation
- : public DataWrap<AverageDeviation<N>, DistBase<AvgFancy>, DistInfo>
+class AverageDeviation : public DistBase<AverageDeviation, AvgSampleStor>
{
- public:
- /** The base implementation */
- typedef DistBase<DistStor> Base;
-
public:
/**
* Construct and initialize this distribution.
*/
- AverageDeviation()
+ AverageDeviation(Group *parent = nullptr, const char *name = nullptr,
+ const char *desc = nullptr)
+ : DistBase<AverageDeviation, AvgSampleStor>(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<int N = 0>
-class VectorDistribution
- : public DataWrapVec<VectorDistribution<N>,
- VectorDistBase<DistStor>,
- VectorDistInfo>
+class VectorDistribution : public VectorDistBase<VectorDistribution, DistStor>
{
public:
- /** The base implementation */
- typedef VectorDistBase<DistStor> Base;
+ VectorDistribution(Group *parent = nullptr, const char *name = nullptr,
+ const char *desc = nullptr)
+ : VectorDistBase<VectorDistribution, DistStor>(parent, name, desc)
+ {
+ }
- public:
/**
* Initialize storage and parameters for this distribution.
* @param size The size of the vector (the number of distributions).
params->min = min;
params->max = max;
params->bucket_size = bkt;
- params->buckets = rint((max - min) / bkt + 1.0);
+ 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<int N = 0>
class VectorStandardDeviation
- : public DataWrapVec<VectorStandardDeviation<N>,
- VectorDistBase<FancyStor>,
- VectorDistInfo>
+ : public VectorDistBase<VectorStandardDeviation, SampleStor>
{
public:
- /** The base implementation */
- typedef VectorDistBase<FancyStor> Base;
+ VectorStandardDeviation(Group *parent = nullptr, const char *name = nullptr,
+ const char *desc = nullptr)
+ : VectorDistBase<VectorStandardDeviation, SampleStor>(parent, name,
+ desc)
+ {
+ }
- public:
/**
* Initialize storage for this distribution.
* @param size The size of the vector.
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<int N = 0>
class VectorAverageDeviation
- : public DataWrapVec<VectorAverageDeviation<N>,
- VectorDistBase<AvgFancy>,
- VectorDistInfo>
+ : public VectorDistBase<VectorAverageDeviation, AvgSampleStor>
{
public:
- /** The base implementation */
- typedef VectorDistBase<AvgFancy> Base;
+ VectorAverageDeviation(Group *parent = nullptr, const char *name = nullptr,
+ const char *desc = nullptr)
+ : VectorDistBase<VectorAverageDeviation, AvgSampleStor>(parent, name,
+ desc)
+ {
+ }
- public:
/**
* Initialize storage for this distribution.
* @param size The size of the vector.
VectorAverageDeviation &
init(size_type size)
{
+ AvgSampleStor::Params *params = new AvgSampleStor::Params;
this->doInit(size);
- return *this;
+ this->setParams(params);
+ return this->self();
+ }
+};
+
+template <class Stat>
+class FormulaInfoProxy : public InfoProxy<Stat, FormulaInfo>
+{
+ protected:
+ mutable VResult vec;
+ mutable VCounter cvec;
+
+ public:
+ FormulaInfoProxy(Stat &stat) : InfoProxy<Stat, FormulaInfo>(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 Stat>
+class SparseHistInfoProxy : public InfoProxy<Stat, SparseHistInfo>
+{
+ public:
+ SparseHistInfoProxy(Stat &stat) : InfoProxy<Stat, SparseHistInfo>(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 InfoAccess
+template <class Derived, class Stor>
+class SparseHistBase : public DataWrap<Derived, SparseHistInfoProxy>
{
+ public:
+ typedef SparseHistInfoProxy<Derived> 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 *>(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<const Storage *>(storage);
+ }
+
+ void
+ doInit()
+ {
+ new (storage) Storage(this->info());
+ this->setInit();
+ }
+
+ public:
+ SparseHistBase(Group *parent, const char *name, const char *desc)
+ : DataWrap<Derived, SparseHistInfoProxy>(parent, name, desc)
+ {
+ }
/**
- * Return the number of elements in the tree.
+ * 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.
*/
- size_type size() const;
+ template <typename U>
+ void sample(const U &v, int n = 1) { data()->sample(v, n); }
/**
- * Formulas don't need to be reset
+ * Return the number of entries in this stat.
+ * @return The number of entries.
*/
- void reset();
-
+ 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;
+ bool zero() const { return data()->zero(); }
+
+ void
+ prepare()
+ {
+ Info *info = this->info();
+ data()->prepare(info, info->data);
+ }
/**
- *
+ * Reset stat value to default
*/
- void update(Info *);
-
- std::string str() const;
+ void
+ reset()
+ {
+ data()->reset(this->info());
+ }
};
-class FormulaInfoBase : public VectorInfoBase
+/**
+ * Templatized storage and interface for a sparse histogram stat.
+ */
+class SparseHistStor
{
public:
- virtual std::string str() const = 0;
-};
+ /** The parameters for a sparse histogram stat. */
+ struct Params : public DistParams
+ {
+ Params() : DistParams(Hist) {}
+ };
-template <class Stat>
-class FormulaInfo : public InfoWrap<Stat, FormulaInfoBase>
-{
- protected:
- mutable VResult vec;
- mutable VCounter cvec;
+ private:
+ /** Counter for number of samples */
+ Counter samples;
+ /** Counter for each bucket. */
+ MCounter cmap;
public:
- FormulaInfo(Stat &stat) : InfoWrap<Stat, FormulaInfoBase>(stat) {}
+ SparseHistStor(Info *info)
+ {
+ reset(info);
+ }
- size_type size() const { return this->s.size(); }
+ /**
+ * 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;
+ }
- const VResult &
- result() const
+ /**
+ * Return the number of buckets in this distribution.
+ * @return the number of buckets.
+ */
+ size_type size() const { return cmap.size(); }
+
+ /**
+ * Returns true if any calls to sample have been made.
+ * @return True if any values have been sampled.
+ */
+ bool
+ zero() const
{
- this->s.result(vec);
- return vec;
+ return samples == Counter();
}
- Result total() const { return this->s.total(); }
- VCounter &value() const { return cvec; }
void
- visit(Visit &visitor)
+ prepare(Info *info, SparseHistData &data)
{
- this->update();
- this->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;
}
- std::string str() const { return this->s.str(); }
+ /**
+ * Reset stat value to default
+ */
+ void
+ reset(Info *info)
+ {
+ cmap.clear();
+ samples = 0;
+ }
};
-class Temp;
-class Formula : public DataWrapVec<Formula, FormulaBase, FormulaInfo>
+class SparseHistogram : public SparseHistBase<SparseHistogram, SparseHistStor>
{
public:
+ SparseHistogram(Group *parent = nullptr, const char *name = nullptr,
+ const char *desc = nullptr)
+ : SparseHistBase<SparseHistogram, SparseHistStor>(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<Formula, FormulaInfoProxy>
+{
+ 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<typename T>
+ const Formula &operator=(const T &v)
+ {
+ *this = Temp(v);
+ return *this;
+ }
/**
* Add the given tree to the existing one.
* @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
* 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.
*/
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 <int N>
- Temp(const Scalar<N> &s)
+ Temp(const Scalar &s)
: node(new ScalarStatNode(s.info()))
{ }
* Create a new ScalarStatNode.
* @param s The ScalarStat to place in a node.
*/
- template <int N>
- Temp(const Average<N> &s)
+ Temp(const Average &s)
: node(new ScalarStatNode(s.info()))
{ }
* Create a new VectorStatNode.
* @param s The VectorStat to place in a node.
*/
- template <int N>
- Temp(const Vector<N> &s)
+ Temp(const Vector &s)
+ : node(new VectorStatNode(s.info()))
+ { }
+
+ Temp(const AverageVector &s)
: node(new VectorStatNode(s.info()))
{ }
* @}
*/
-void check();
-void dump();
-void reset();
-void registerResetCallback(Callback *cb);
-
inline Temp
operator+(Temp l, Temp r)
{
- return NodePtr(new BinaryNode<std::plus<Result> >(l, r));
+ return Temp(std::make_shared<BinaryNode<std::plus<Result> > >(l, r));
}
inline Temp
operator-(Temp l, Temp r)
{
- return NodePtr(new BinaryNode<std::minus<Result> >(l, r));
+ return Temp(std::make_shared<BinaryNode<std::minus<Result> > >(l, r));
}
inline Temp
operator*(Temp l, Temp r)
{
- return NodePtr(new BinaryNode<std::multiplies<Result> >(l, r));
+ return Temp(std::make_shared<BinaryNode<std::multiplies<Result> > >(l, r));
}
inline Temp
operator/(Temp l, Temp r)
{
- return NodePtr(new BinaryNode<std::divides<Result> >(l, r));
+ return Temp(std::make_shared<BinaryNode<std::divides<Result> > >(l, r));
}
inline Temp
operator-(Temp l)
{
- return NodePtr(new UnaryNode<std::negate<Result> >(l));
+ return Temp(std::make_shared<UnaryNode<std::negate<Result> > >(l));
}
template <typename T>
inline Temp
constant(T val)
{
- return NodePtr(new ConstNode<T>(val));
+ return Temp(std::make_shared<ConstNode<T> >(val));
}
template <typename T>
inline Temp
constantVector(T val)
{
- return NodePtr(new ConstVectorNode<T>(val));
+ return Temp(std::make_shared<ConstVectorNode<T> >(val));
}
inline Temp
sum(Temp val)
{
- return NodePtr(new SumNode<std::plus<Result> >(val));
+ return Temp(std::make_shared<SumNode<std::plus<Result> > >(val));
}
+/** 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<Info *> &statsList();
-/* namespace Stats */ }
+typedef std::map<const void *, Info *> MapType;
+MapType &statsMap();
+
+typedef std::map<std::string, Info *> NameMapType;
+NameMapType &nameMap();
+
+bool validateStatName(const std::string &name);
+
+} // namespace Stats
+
+void debugDumpStats();
#endif // __BASE_STATISTICS_HH__