base: Fix squares of stats
[gem5.git] / src / base / statistics.hh
index 6f2da2f3ed6f7c1d15b0637052ccd45d3b9ea38a..fd16c3a36b0a6564d68331eff67fc81bc10454ed 100644 (file)
@@ -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,6 +39,7 @@
  * 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(); }
 
@@ -237,136 +151,46 @@ class VectorInfo : public InfoWrap<Stat, VectorInfoBase>
     }
 
     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 */
@@ -378,10 +202,13 @@ class InfoAccess
     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
@@ -397,46 +224,50 @@ class InfoAccess
     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;
     }
 
     /**
@@ -445,13 +276,31 @@ class DataWrap : public Base
      * @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
@@ -484,9 +333,9 @@ class DataWrap : public Base
      * @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();
     }
 
@@ -505,15 +354,17 @@ class DataWrap : public Base
     }
 };
 
-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!
 
@@ -527,13 +378,20 @@ class DataWrapVec : public DataWrap<Derived, Base, Info>
     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.
@@ -544,7 +402,9 @@ class DataWrapVec : public DataWrap<Derived, Base, Info>
     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;
@@ -552,17 +412,40 @@ class DataWrapVec : public DataWrap<Derived, Base, Info>
         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
@@ -570,22 +453,33 @@ class DataWrapVec2d : public DataWrapVec<Derived, Base, Info>
     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];
     }
+
 };
 
 //////////////////////////////////////////////////////////////////////
@@ -640,6 +534,10 @@ class StatStor
      * @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
      */
@@ -663,6 +561,8 @@ class AvgStor
   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. */
@@ -676,7 +576,7 @@ class AvgStor
      * Build and initializes this stat storage.
      */
     AvgStor(Info *info)
-        : current(0), total(0), last(0)
+        : current(0), lastReset(0), total(0), last(0)
     { }
 
     /**
@@ -687,8 +587,8 @@ class AvgStor
     void
     set(Counter val)
     {
-        total += current * (curTick - last);
-        last = curTick;
+        total += current * (curTick() - last);
+        last = curTick();
         current = val;
     }
 
@@ -717,9 +617,23 @@ class AvgStor
     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();
     }
 
     /**
@@ -729,21 +643,18 @@ class AvgStor
     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;
@@ -780,8 +691,8 @@ class ScalarBase : public InfoAccess
     void
     doInit()
     {
-        new (storage) Storage(info());
-        setInit();
+        new (storage) Storage(this->info());
+        this->setInit();
     }
 
   public:
@@ -792,7 +703,12 @@ class ScalarBase : public InfoAccess
     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
@@ -842,11 +758,6 @@ class ScalarBase : public InfoAccess
      */
     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(); }
@@ -854,17 +765,22 @@ class ScalarBase : public InfoAccess
     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>
@@ -893,29 +809,72 @@ class FunctorProxy : public ProxyInfo
     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(); }
@@ -926,6 +885,7 @@ class ValueBase : public InfoAccess
     std::string str() const { return proxy->str(); }
     bool zero() const { return proxy->zero(); }
     bool check() const { return proxy != NULL; }
+    void prepare() { }
     void reset() { }
 };
 
@@ -944,7 +904,7 @@ class ScalarProxy
 {
   private:
     /** Pointer to the parent Vector. */
-    Stat *stat;
+    Stat &stat;
 
     /** The index to access in the parent VectorBase. */
     off_type index;
@@ -954,23 +914,22 @@ class ScalarProxy
      * 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);
     }
 
     /**
@@ -1000,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); }
+    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; }
@@ -1021,7 +980,7 @@ class ScalarProxy
     void
     operator=(const U &v)
     {
-        stat->data(index)->set(v);
+        stat.data(index)->set(v);
     }
 
     /**
@@ -1033,7 +992,7 @@ class ScalarProxy
     void
     operator+=(const U &v)
     {
-        stat->data(index)->inc(v);
+        stat.data(index)->inc(v);
     }
 
     /**
@@ -1045,7 +1004,7 @@ class ScalarProxy
     void
     operator-=(const U &v)
     {
-        stat->data(index)->dec(v);
+        stat.data(index)->dec(v);
     }
 
     /**
@@ -1058,7 +1017,7 @@ class ScalarProxy
     std::string
     str() const
     {
-        return csprintf("%s[%d]", stat->info()->name, index);
+        return csprintf("%s[%d]", stat.info()->name, index);
     }
 };
 
@@ -1066,17 +1025,17 @@ class ScalarProxy
  * 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. */
@@ -1109,9 +1068,9 @@ class VectorBase : public InfoAccess
         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:
@@ -1168,16 +1127,10 @@ class VectorBase : public InfoAccess
         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()
@@ -1190,6 +1143,19 @@ class VectorBase : public InfoAccess
         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.
@@ -1199,17 +1165,15 @@ class VectorBase : public InfoAccess
     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;
 
@@ -1220,14 +1184,14 @@ class VectorProxy
     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:
@@ -1252,7 +1216,7 @@ class VectorProxy
     }
 
   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)
     {
     }
@@ -1281,15 +1245,18 @@ class VectorProxy
     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;
@@ -1301,13 +1268,30 @@ class Vector2dBase : public InfoAccess
     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;
@@ -1321,41 +1305,17 @@ class Vector2dBase : public InfoAccess
         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);
     }
 
 
@@ -1369,12 +1329,33 @@ class Vector2dBase : public InfoAccess
     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();
     }
 
     /**
@@ -1383,8 +1364,10 @@ class Vector2dBase : public InfoAccess
     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
@@ -1399,15 +1382,21 @@ class Vector2dBase : public InfoAccess
 // 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;
@@ -1418,7 +1407,8 @@ class DistStor
         /** 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:
@@ -1428,8 +1418,6 @@ class DistStor
     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;
@@ -1480,9 +1468,8 @@ class 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;
     }
 
@@ -1503,18 +1490,23 @@ class DistStor
     }
 
     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;
@@ -1535,8 +1527,153 @@ class DistStor
 
         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)
@@ -1545,6 +1682,7 @@ class DistStor
         sum = Counter();
         squares = Counter();
         samples = Counter();
+        logs = Counter();
     }
 };
 
@@ -1552,12 +1690,12 @@ class DistStor
  * 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:
@@ -1572,7 +1710,7 @@ class FancyStor
     /**
      * Create and initialize this storage.
      */
-    FancyStor(Info *info)
+    SampleStor(Info *info)
         : sum(Counter()), squares(Counter()), samples(Counter())
     { }
 
@@ -1586,20 +1724,11 @@ class FancyStor
     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.
@@ -1612,6 +1741,18 @@ class FancyStor
      */
     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
      */
@@ -1628,12 +1769,12 @@ class FancyStor
  * 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:
@@ -1646,7 +1787,7 @@ class AvgFancy
     /**
      * Create and initialize this storage.
      */
-    AvgFancy(Info *info)
+    AvgSampleStor(Info *info)
         : sum(Counter()), squares(Counter())
     {}
 
@@ -1659,17 +1800,8 @@ class AvgFancy
     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;
     }
 
     /**
@@ -1684,6 +1816,18 @@ class AvgFancy
      */
     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
      */
@@ -1699,10 +1843,11 @@ class AvgFancy
  * 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;
 
@@ -1734,12 +1879,15 @@ class DistBase : public InfoAccess
     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
@@ -1762,9 +1910,10 @@ class DistBase : public InfoAccess
     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);
     }
 
     /**
@@ -1773,21 +1922,29 @@ class DistBase : public InfoAccess
     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;
@@ -1816,15 +1973,17 @@ class VectorDistBase : public InfoAccess
         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()
@@ -1837,7 +1996,11 @@ class VectorDistBase : public InfoAccess
         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
@@ -1848,23 +2011,20 @@ class VectorDistBase : public InfoAccess
     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
@@ -1872,31 +2032,21 @@ class VectorDistBase : public InfoAccess
     {
         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)
     {}
 
@@ -1938,25 +2088,6 @@ class DistProxy
     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
@@ -1967,7 +2098,7 @@ VectorDistBase<Storage>::total(off_type 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:
     /**
@@ -1990,19 +2121,21 @@ class Node : public RefCounted
      *
      */
     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
@@ -2065,10 +2198,10 @@ class ScalarProxyNode : public Node
 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(); };
 
@@ -2088,7 +2221,7 @@ class ConstNode : public Node
     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>
@@ -2118,7 +2251,7 @@ class ConstVectorNode : public Node
         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;
     }
@@ -2220,7 +2353,7 @@ class BinaryNode : public Node
     BinaryNode(NodePtr &a, NodePtr &b) : l(a), r(b) {}
 
     const VResult &
-    result() const
+    result() const override
     {
         Op op;
         const VResult &lvec = l->result();
@@ -2252,17 +2385,39 @@ class BinaryNode : public Node
     }
 
     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();
@@ -2277,7 +2432,7 @@ class BinaryNode : public Node
     }
 
     std::string
-    str() const
+    str() const override
     {
         return csprintf("(%s %s %s)", l->str(), OpString<Op>::str(), r->str());
     }
@@ -2316,13 +2471,13 @@ class SumNode : public Node
         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; }
@@ -2350,76 +2505,41 @@ class SumNode : public Node
  * 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);
     }
 };
 
@@ -2427,23 +2547,13 @@ class Average : public DataWrap<Average<N>, ScalarBase<AvgStor>, ScalarInfo>
  * 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;
     }
 };
 
@@ -2451,21 +2561,13 @@ class Vector : public DataWrapVec<Vector<N>, VectorBase<StatStor>, VectorInfo>
  * 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;
     }
 };
 
@@ -2473,16 +2575,13 @@ class AverageVector
  * 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;
     }
 };
 
@@ -2490,15 +2589,15 @@ class Vector2d
  * 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.
@@ -2513,72 +2612,98 @@ class 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).
@@ -2594,28 +2719,28 @@ class VectorDistribution
         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.
@@ -2624,26 +2749,28 @@ class VectorStandardDeviation
     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.
@@ -2652,128 +2779,266 @@ class VectorAverageDeviation
     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.
@@ -2781,6 +3046,53 @@ class Formula : public DataWrapVec<Formula, FormulaBase, FormulaInfo>
      * @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
@@ -2815,7 +3127,9 @@ 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.
@@ -2823,13 +3137,17 @@ class Temp
      */
     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()))
     { }
 
@@ -2845,8 +3163,7 @@ class Temp
      * 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()))
     { }
 
@@ -2854,8 +3171,11 @@ class Temp
      * 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()))
     { }
 
@@ -2977,63 +3297,105 @@ class Temp
  * @}
  */
 
-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__