Rename RegResetCallback to registerResetCallback().
[gem5.git] / base / statistics.cc
index a2734cf37415d081c82ff33918befb59ae3bdb58..fe20a7281855572a8fef63f4285bfdbbcfe4304b 100644 (file)
 #include <string>
 #include <sstream>
 
-#include <math.h>
-
 #include "base/callback.hh"
 #include "base/cprintf.hh"
-#include "base/intmath.hh"
 #include "base/misc.hh"
 #include "base/statistics.hh"
 #include "base/str.hh"
@@ -66,218 +63,173 @@ using namespace std;
 // This is a hack to get this parameter from the old stats package.
 namespace Statistics {
 bool PrintDescriptions = true;
+DisplayMode default_mode = mode_simplescalar;
 
-namespace Detail {
-/**
- * Struct to contain a name and description of statistic subfield.
- */
-struct SubData
-{
-    /** Subfield name. */
-    string name;
-    /** Subfield desc. */
-    string desc;
-};
-
-/**
- * Struct to contain print data of a Stat.
- */
-struct StatData
-{
-    /**
-     * Create this struct.
-     */
-    StatData();
-    /**
-     * Destructor.
-     */
-    ~StatData();
-
-    /** True if the stat has been initialized. */
-    bool init;
-    /** True if the stat should be printed. */
-    bool print;
-    /** The name of the stat. */
-    string name;
-    /** Names and descriptions of subfields. */
-    vector<SubData> *subdata;
-    /** The description of the stat. */
-    string desc;
-    /** The display precision. */
-    int precision;
-    /** The formatting flags. */
-    FormatFlags flags;
-    /** A pointer to a prerequisite Stat. */
-    const Stat *prereq;
-};
-
-StatData::StatData()
-    : init(false), print(false), subdata(NULL), precision(-1), flags(none),
-      prereq(NULL)
-{
-}
-
-StatData::~StatData()
-{
-    if (subdata)
-        delete subdata;
-}
-
-class Database
+namespace Database
 {
-  private:
-    Database(const Database &) {}
-
-  private:
-    typedef list<Stat *> list_t;
-    typedef map<const Stat *, StatData *> map_t;
-
-    list<BinBase *> bins;
-    map<const BinBase *, std::string > bin_names;
-    list_t binnedStats;
+    class Data
+    {
+      private:
+        typedef list<StatData *> list_t;
+        typedef map<void *, StatData *> map_t;
 
-    list_t allStats;
-    list_t printStats;
-    map_t map;
+        list<MainBin *> bins;
+        map<const MainBin *, string > bin_names;
+        list_t binnedStats;
 
-  public:
-    Database();
-    ~Database();
+        list_t allStats;
+        list_t printStats;
+        map_t statMap;
 
-    void dump(ostream &stream);
+      public:
+        void dump(ostream &stream);
 
-    StatData *find(const Stat *stat);
-    void check();
-    void reset();
-    void regStat(Stat *stat);
-    StatData *print(Stat *stat);
-    void regBin(BinBase *bin, std::string name);
-};
+        StatData *find(void *stat);
+        void mapStat(void *stat, StatData *data);
 
-Database::Database()
-{}
+        void check();
+        void reset();
+        void regBin(MainBin *bin, string name);
+        void regPrint(void *stat);
+    };
 
-Database::~Database()
-{}
 
 void
-Database::dump(ostream &stream)
+Data::dump(ostream &stream)
 {
-
+#ifndef FS_MEASURE
     list_t::iterator i = printStats.begin();
     list_t::iterator end = printStats.end();
     while (i != end) {
-        Stat *stat = *i;
+        StatData *stat = *i;
         if (stat->binned())
             binnedStats.push_back(stat);
         ++i;
     }
+#endif //FS_MEASURE
 
-    list<BinBase *>::iterator j = bins.begin();
-    list<BinBase *>::iterator bins_end=bins.end();
+    list<MainBin *>::iterator j = bins.begin();
+    list<MainBin *>::iterator bins_end=bins.end();
 
     if (!bins.empty()) {
         ccprintf(stream, "PRINTING BINNED STATS\n");
         while (j != bins_end) {
             (*j)->activate();
-           ::map<const BinBase  *, std::string>::const_iterator iter;
+            map<const MainBin  *, string>::const_iterator iter;
             iter = bin_names.find(*j);
             if (iter == bin_names.end())
                 panic("a binned stat not found in names map!");
             ccprintf(stream,"---%s Bin------------\n", (*iter).second);
 
-           list_t::iterator i = binnedStats.begin();
-           list_t::iterator end = binnedStats.end();
-           while (i != end) {
-               Stat *stat = *i;
-               if (stat->dodisplay())
-                   stat->display(stream);
-               ++i;
-           }
-           ++j;
-           ccprintf(stream, "---------------------------------\n");
+#ifdef FS_MEASURE
+            list_t::iterator i = printStats.begin();
+            list_t::iterator end = printStats.end();
+#else
+            list_t::iterator i = binnedStats.begin();
+            list_t::iterator end = binnedStats.end();
+#endif
+            while (i != end) {
+                StatData *stat = *i;
+                if (stat->dodisplay())
+                    stat->display(stream);
+                ++i;
+            }
+            ++j;
+            ccprintf(stream, "---------------------------------\n");
         }
+#ifndef FS_MEASURE
+        ccprintf(stream, "**************ALL STATS************\n");
+#endif
     }
 
+/**
+ * get bin totals working, then print the stat here (as total), even if
+ * its' binned.  (this is only for the case you selectively bin a few stats
+ */
+#ifndef FS_MEASURE
     list_t::iterator k = printStats.begin();
     list_t::iterator endprint = printStats.end();
-    ccprintf(stream, "*****ALL STATS*****\n");
     while (k != endprint) {
-        Stat *stat = *k;
-        if (stat->dodisplay() && !stat->binned())
+        StatData *stat = *k;
+        if (stat->dodisplay() /*&& !stat->binned()*/)
             stat->display(stream);
         ++k;
     }
+#endif
 }
 
 StatData *
-Database::find(const Stat *stat)
+Data::find(void *stat)
 {
-    map_t::const_iterator i = map.find(stat);
+    map_t::const_iterator i = statMap.find(stat);
 
-    if (i == map.end())
+    if (i == statMap.end())
         return NULL;
 
     return (*i).second;
 }
 
 void
-Database::check()
+Data::check()
 {
     list_t::iterator i = allStats.begin();
     list_t::iterator end = allStats.end();
 
     while (i != end) {
-        Stat *stat = *i;
-        StatData *data = find(stat);
-        if (!data || !data->init) {
-#ifdef STAT_DEBUG
-            cprintf("this is stat number %d\n",(*i)->number);
-#endif
-            panic("Not all stats have been initialized");
-        }
-
-        if (data->print) {
-            if (data->name.empty())
-                panic("all printable stats must be named");
-
-            list_t::iterator j = printStats.insert(printStats.end(), *i);
-            inplace_merge(printStats.begin(), j,
-                          printStats.end(), Stat::less);
-        }
-
+        StatData *stat = *i;
+        assert(stat);
+        stat->check();
         ++i;
     }
 }
 
 void
-Database::reset()
+Data::reset()
 {
     list_t::iterator i = allStats.begin();
     list_t::iterator end = allStats.end();
-
     while (i != end) {
-        (*i)->reset();
+        StatData *stat = *i;
+        stat->reset();
         ++i;
     }
+
+    MainBin *orig = MainBin::curBin();
+
+    list<MainBin *>::iterator bi = bins.begin();
+    list<MainBin *>::iterator be = bins.end();
+    while (bi != be) {
+        MainBin *bin = *bi;
+        bin->activate();
+
+        i = allStats.begin();
+        while (i != end) {
+            StatData *stat = *i;
+            stat->reset();
+            ++i;
+        }
+        ++bi;
+    }
+
+    if (orig)
+        orig->activate();
 }
 
 void
-Database::regStat(Stat *stat)
+Data::mapStat(void *stat, StatData *data)
 {
-    if (map.find(stat) != map.end())
+    if (statMap.find(stat) != statMap.end())
         panic("shouldn't register stat twice!");
 
-    allStats.push_back(stat);
+    allStats.push_back(data);
 
-    StatData *data = new StatData;
-    bool success = (map.insert(make_pair(stat, data))).second;
-    assert(map.find(stat) != map.end());
+    bool success = (statMap.insert(make_pair(stat, data))).second;
+    assert(statMap.find(stat) != statMap.end());
     assert(success && "this should never fail");
 }
 
 void
-Database::regBin(BinBase *bin, std::string name)
+Data::regBin(MainBin *bin, string name)
 {
     if (bin_names.find(bin) != bin_names.end())
         panic("shouldn't register bin twice");
@@ -291,235 +243,121 @@ Database::regBin(BinBase *bin, std::string name)
     cprintf("registering %s\n", name);
 }
 
-bool
-Stat::less(Stat *stat1, Stat *stat2)
-{
-    const string &name1 = stat1->myname();
-    const string &name2 = stat2->myname();
-
-    vector<string> v1;
-    vector<string> v2;
-
-    tokenize(v1, name1, '.');
-    tokenize(v2, name2, '.');
-
-    int last = min(v1.size(), v2.size()) - 1;
-    for (int i = 0; i < last; ++i)
-        if (v1[i] != v2[i])
-            return v1[i] < v2[i];
-
-    // Special compare for last element.
-    if (v1[last] == v2[last])
-        return v1.size() < v2.size();
-    else
-        return v1[last] < v2[last];
-
-    return false;
-}
-
-StatData *
-Database::print(Stat *stat)
+void
+Data::regPrint(void *stat)
 {
     StatData *data = find(stat);
-    assert(data);
 
-    data->print = true;
+    if (!data->print) {
+        data->print = true;
+
+        list_t::iterator j = printStats.insert(printStats.end(), data);
+        inplace_merge(printStats.begin(), j,
+                      printStats.end(), StatData::less);
+    }
 
-    return data;
 }
 
-Database &
+Data &
 StatDB()
 {
-    static Database db;
+    static Data db;
     return db;
 }
 
-Stat::Stat(bool reg)
-{
-#if 0
-    // This assert can help you find that pesky stat.
-    assert(this != (void *)0xbffff5c0);
-#endif
-
-    if (reg)
-        StatDB().regStat(this);
-
-#ifdef STAT_DEBUG
-    number = ++total_stats;
-    cprintf("I'm stat number %d\n",number);
-#endif
 }
 
-void
-Stat::setInit()
-{ mydata()->init = true; }
-
 StatData *
-Stat::mydata()
-{
-    StatData *data = StatDB().find(this);
-    assert(data);
-
-    return data;
-}
-
-const StatData *
-Stat::mydata() const
+DataAccess::find() const
 {
-    StatData *data = StatDB().find(this);
-    assert(data);
-
-    return data;
+    return Database::StatDB().find(const_cast<void *>((const void *)this));
 }
 
-const SubData *
-Stat::mysubdata(int index) const
+void
+DataAccess::map(StatData *data)
 {
-    assert(index >= 0);
-    if (index >= size())
-        return NULL;
-
-    const StatData *data = this->mydata();
-    if (!data->subdata || data->subdata->size() <= index)
-        return NULL;
-
-    return &(*data->subdata)[index];
+    Database::StatDB().mapStat(this, data);
 }
 
-SubData *
-Stat::mysubdata_create(int index)
+StatData *
+DataAccess::statData()
 {
-    int size = this->size();
-    assert(index >= 0 && (size == 0 || size > 0 && index < size));
-
-    StatData *data = this->mydata();
-    if (!data->subdata) {
-        if (!data->subdata) {
-            if (size == 0)
-                size = index + 1;
-
-            data->subdata = new vector<SubData>(size);
-        }
-    } else if (data->subdata->size() <= index)
-            data->subdata->resize(index + 1);
-
-    SubData *sd = &(*data->subdata)[index];
-    assert(sd);
-
-    return sd;
+    StatData *ptr = find();
+    assert(ptr);
+    return ptr;
 }
 
-string
-Stat::myname() const
-{ return mydata()->name; }
-
-string
-Stat::mysubname(int index) const
+const StatData *
+DataAccess::statData() const
 {
-    const SubData *sd = mysubdata(index);
-    return sd ? sd->name : "";
+    const StatData *ptr = find();
+    assert(ptr);
+    return ptr;
 }
 
-string
-Stat::mydesc() const
-{ return mydata()->desc; }
-
-string
-Stat::mysubdesc(int index) const
+void
+DataAccess::setInit()
 {
-    const SubData *sd = mysubdata(index);
-    return sd ? sd->desc : "";
+    statData()->init = true;
 }
 
-int
-Stat::myprecision() const
-{ return mydata()->precision; }
-
-FormatFlags
-Stat::myflags() const
-{ return mydata()->flags; }
-
-bool
-Stat::dodisplay() const
-{ return !mydata()->prereq || !mydata()->prereq->zero(); }
-
-StatData *
-Stat::print()
+void
+DataAccess::setPrint()
 {
-    StatData *data = StatDB().print(this);
-    assert(data && data->init);
-
-    return data;
+    Database::StatDB().regPrint(this);
 }
 
-Stat &
-Stat::name(const string &name)
+StatData::~StatData()
 {
-    print()->name = name;
-    return *this;
 }
 
-Stat &
-Stat::desc(const string &desc)
+bool
+StatData::less(StatData *stat1, StatData *stat2)
 {
-    print()->desc = desc;
-    return *this;
-}
+    const string &name1 = stat1->name;
+    const string &name2 = stat2->name;
 
-Stat &
-Stat::precision(int precision)
-{
-    print()->precision = precision;
-    return *this;
-}
+    vector<string> v1;
+    vector<string> v2;
 
-Stat &
-Stat::flags(FormatFlags flags)
-{
-    if (flags & __reserved)
-        panic("Cannot set reserved flags!\n");
+    tokenize(v1, name1, '.');
+    tokenize(v2, name2, '.');
 
-    print()->flags |= flags;
-    return *this;
-}
+    int last = min(v1.size(), v2.size()) - 1;
+    for (int i = 0; i < last; ++i)
+        if (v1[i] != v2[i])
+            return v1[i] < v2[i];
 
-Stat &
-Stat::prereq(const Stat &prereq)
-{
-    print()->prereq = &prereq;
-    return *this;
-}
+    // Special compare for last element.
+    if (v1[last] == v2[last])
+        return v1.size() < v2.size();
+    else
+        return v1[last] < v2[last];
 
-Stat &
-Stat::subname(int index, const string &name)
-{
-    print();
-    mysubdata_create(index)->name = name;
-    return *this;
-}
-Stat &
-Stat::subdesc(int index, const string &desc)
-{
-    print();
-    mysubdata_create(index)->desc = desc;
-    return *this;
+    return false;
 }
 
 bool
-ScalarStat::zero() const
+StatData::check() const
 {
-    return val() == 0.0;
-}
+    if (!init) {
+#ifdef STAT_DEBUG
+        cprintf("this is stat number %d\n",(*i)->number);
+#endif
+        panic("Not all stats have been initialized");
+        return false;
+    }
 
-bool
-VectorStat::zero() const
-{
-    return val()[0] == 0.0;
+    if (print && name.empty()) {
+        panic("all printable stats must be named");
+        return false;
+    }
+
+    return true;
 }
 
 string
-ValueToString(result_t value, int precision)
+ValueToString(result_t value, DisplayMode mode, int precision)
 {
     stringstream val;
 
@@ -533,20 +371,33 @@ ValueToString(result_t value, int precision)
         val.setf(ios::fixed);
         val << value;
     } else {
-#ifndef STAT_DISPLAY_COMPAT
-        val << "no value";
-#else
-        val << "<err: div-0>";
-#endif
+        val << (mode == mode_m5 ? "no value" : "<err: div-0>");
     }
 
     return val.str();
 }
 
+struct ScalarPrint
+{
+    result_t value;
+    string name;
+    string desc;
+    int precision;
+    DisplayMode mode;
+    FormatFlags flags;
+    result_t pdf;
+    result_t cdf;
+
+    ScalarPrint()
+        : value(0.0), precision(0), mode(default_mode), flags(0),
+          pdf(NAN), cdf(NAN)
+    {}
+
+    void operator()(ostream &stream) const;
+};
+
 void
-PrintOne(ostream &stream, result_t value,
-         const string &name, const string &desc, int precision,
-         FormatFlags flags, result_t pdf = NAN, result_t cdf = NAN)
+ScalarPrint::operator()(ostream &stream) const
 {
     if (flags & nozero && value == 0.0 ||
         flags & nonan && isnan(value))
@@ -560,16 +411,13 @@ PrintOne(ostream &stream, result_t value,
     if (!isnan(cdf))
         ccprintf(cdfstr, "%.2f%%", cdf * 100.0);
 
-#ifdef STAT_DISPLAY_COMPAT
-    if (flags & __substat) {
-        ccprintf(stream, "%32s%12s%10s%10s", name,
-                 ValueToString(value, precision),
+    if (mode == mode_simplescalar && flags & __substat) {
+        ccprintf(stream, "%32s %12s %10s %10s", name,
+                 ValueToString(value, mode, precision),
                  pdfstr, cdfstr);
-    } else
-#endif
-    {
-        ccprintf(stream, "%-40s%12s%10s%10s", name,
-                 ValueToString(value, precision), pdfstr, cdfstr);
+    } else {
+        ccprintf(stream, "%-40s %12s %10s %10s", name,
+                 ValueToString(value, mode, precision), pdfstr, cdfstr);
     }
 
     if (PrintDescriptions) {
@@ -579,350 +427,602 @@ PrintOne(ostream &stream, result_t value,
     stream << endl;
 }
 
-void
-ScalarStat::display(ostream &stream) const
+struct VectorPrint
 {
-    PrintOne(stream, val(), myname(), mydesc(), myprecision(), myflags());
-}
-
-void
-VectorStat::display(ostream &stream) const
-{
-    bool have_subname = false;
-    bool have_subdesc = false;
-    int size = this->size();
-    for (int i = 0; i < size; ++i) {
-        if (!mysubname(i).empty())
-            have_subname = true;
-        if (!mysubdesc(i).empty())
-            have_subdesc = true;
-    }
-
-    vector<string> *subnames = 0;
-    vector<string> *subdescs = 0;
-    if (have_subname) {
-        subnames = new vector<string>(size);
-        for (int i = 0; i < size; ++i)
-            (*subnames)[i] = mysubname(i);
-    }
-    if (have_subdesc) {
-        subdescs = new vector<string>(size);
-        for (int i = 0; i < size; ++i)
-            (*subdescs)[i] = mysubdesc(i);
-    }
+    string name;
+    string desc;
+    vector<string> subnames;
+    vector<string> subdescs;
+    int precision;
+    DisplayMode mode;
+    FormatFlags flags;
+    rvec_t vec;
+    result_t total;
 
-    VectorDisplay(stream, myname(), subnames, mydesc(), subdescs,
-                  myprecision(), myflags(), val(), total());
-}
+    VectorPrint()
+        : subnames(0), subdescs(0), precision(-1), mode(default_mode),
+          flags(0), total(NAN)
+    {}
 
-#ifndef STAT_DISPLAY_COMPAT
-#define NAMESEP "::"
-#else
-#define NAMESEP "_"
-#endif
+    void operator()(ostream &stream) const;
+};
 
-#ifndef STAT_DISPLAY_COMPAT
 void
-VectorDisplay(std::ostream &stream,
-              const std::string &myname,
-              const std::vector<std::string> *mysubnames,
-              const std::string &mydesc,
-              const std::vector<std::string> *mysubdescs,
-              int myprecision, FormatFlags myflags,
-              const rvec_t &vec, result_t mytotal)
+VectorPrint::operator()(std::ostream &stream) const
 {
     int _size = vec.size();
     result_t _total = 0.0;
-    result_t _pdf, _cdf = 0.0;
 
-    if (myflags & (pdf | cdf)) {
+    if (flags & (pdf | cdf)) {
         for (int i = 0; i < _size; ++i) {
             _total += vec[i];
         }
     }
 
+    string base = name + ((mode == mode_simplescalar) ? "_" : "::");
+
+    ScalarPrint print;
+    print.name = name;
+    print.desc = desc;
+    print.precision = precision;
+    print.flags = flags;
+
+    bool havesub = !subnames.empty();
+
     if (_size == 1) {
-        PrintOne(stream, vec[0], myname, mydesc, myprecision, myflags);
-    } else {
+        print.value = vec[0];
+        print(stream);
+    } else if (mode == mode_m5) {
         for (int i = 0; i < _size; ++i) {
-            string subname;
-            if (mysubnames) {
-                subname = (*mysubnames)[i];
-                if (subname.empty())
-                    continue;
-            } else {
-                subname = to_string(i);
-            }
+            if (havesub && (i >= subnames.size() || subnames[i].empty()))
+                continue;
 
-            string name = myname + NAMESEP + subname;
-            if (!(myflags & pdf))
-                PrintOne(stream, vec[i], name, mydesc, myprecision, myflags);
-            else {
-                _pdf = vec[i] / _total;
-                _cdf += _pdf;
-                PrintOne(stream, vec[i], name, mydesc, myprecision, myflags,
-                         _pdf, _cdf);
-            }
-        }
+            print.name = base + (havesub ? subnames[i] : to_string(i));
+            print.desc = subdescs.empty() ? desc : subdescs[i];
+            print.value = vec[i];
 
-        if (myflags & total)
-            PrintOne(stream, mytotal, myname + NAMESEP + "total",
-                     mydesc, myprecision, myflags);
-    }
-}
-#else
-void
-VectorDisplay(std::ostream &stream,
-              const std::string &myname,
-              const std::vector<std::string> *mysubnames,
-              const std::string &mydesc,
-              const std::vector<std::string> *mysubdescs,
-              int myprecision, FormatFlags myflags,
-              const rvec_t &vec, result_t mytotal)
-{
-    int _size = vec.size();
-    result_t _total = 0.0;
-    result_t _pdf, _cdf = 0.0;
+            if (_total && (flags & pdf)) {
+                print.pdf = vec[i] / _total;
+                print.cdf += print.pdf;
+            }
 
-    if (myflags & (pdf | cdf)) {
-        for (int i = 0; i < _size; ++i) {
-            _total += vec[i];
+            print(stream);
         }
-    }
 
-    if (_size == 1) {
-        PrintOne(stream, vec[0], myname, mydesc, myprecision, myflags);
+        if (flags & ::Statistics::total) {
+            print.name = base + "total";
+            print.desc = desc;
+            print.value = total;
+            print(stream);
+        }
     } else {
-        if (myflags & total)
-            PrintOne(stream, mytotal, myname, mydesc, myprecision, myflags);
+        if (flags & ::Statistics::total) {
+            print.value = total;
+            print(stream);
+        }
 
-        if (myflags & dist) {
-            ccprintf(stream, "%s.start_dist\n", myname);
+        result_t _pdf = 0.0;
+        result_t _cdf = 0.0;
+        if (flags & dist) {
+            ccprintf(stream, "%s.start_dist\n", name);
             for (int i = 0; i < _size; ++i) {
-                string subname, subdesc;
-                subname = to_string(i);
-                if (mysubnames) {
-                    if (!subname.empty()) {
-                        subname = (*mysubnames)[i];
-                    }
-                }
-                if (mysubdescs) {
-                    subdesc = (*mysubdescs)[i];
-                }
-                if (!(myflags & (pdf | cdf))) {
-                    PrintOne(stream, vec[i], subname, subdesc, myprecision,
-                             myflags | __substat);
-                } else {
-                    if (_total) {
-                        _pdf = vec[i] / _total;
-                        _cdf += _pdf;
-                    } else {
-                        _pdf = _cdf = 0.0;
-                    }
-                    if (!(myflags & cdf)) {
-                        PrintOne(stream, vec[i], subname, subdesc, myprecision,
-                                 myflags | __substat, _pdf);
-                    } else {
-                        PrintOne(stream, vec[i], subname, subdesc, myprecision,
-                                 myflags | __substat, _pdf, _cdf);
-                    }
+                print.name = havesub ? subnames[i] : to_string(i);
+                print.desc = subdescs.empty() ? desc : subdescs[i];
+                print.flags |= __substat;
+                print.value = vec[i];
+
+                if (_total) {
+                    _pdf = vec[i] / _total;
+                    _cdf += _pdf;
                 }
+
+                if (flags & pdf)
+                    print.pdf = _pdf;
+                if (flags & cdf)
+                    print.cdf = _cdf;
+
+                print(stream);
             }
-            ccprintf(stream, "%s.end_dist\n", myname);
+            ccprintf(stream, "%s.end_dist\n", name);
         } else {
             for (int i = 0; i < _size; ++i) {
-                string subname;
-                if (mysubnames) {
-                    subname = (*mysubnames)[i];
-                    if (subname.empty())
-                        continue;
-                } else {
-                    subname = to_string(i);
-                }
+                if (havesub && subnames[i].empty())
+                    continue;
 
-                string name = myname + NAMESEP + subname;
-                if (!(myflags & pdf)) {
-                    PrintOne(stream, vec[i], name, mydesc, myprecision,
-                             myflags);
-                } else {
-                    if (_total) {
-                        _pdf = vec[i] / _total;
-                        _cdf += _pdf;
-                    } else {
-                        _pdf = _cdf = 0.0;
-                    }
+                print.name = base;
+                print.name += havesub ? subnames[i] : to_string(i);
+                print.desc = subdescs.empty() ? desc : subdescs[i];
+                print.value = vec[i];
+
+                if (_total) {
                     _pdf = vec[i] / _total;
                     _cdf += _pdf;
-                    PrintOne(stream, vec[i], name, mydesc, myprecision,
-                             myflags, _pdf, _cdf);
+                } else {
+                    _pdf = _cdf = NAN;
+                }
+
+                if (flags & pdf) {
+                    print.pdf = _pdf;
+                    print.cdf = _cdf;
                 }
+
+                print(stream);
             }
         }
     }
 }
-#endif
 
-#ifndef STAT_DISPLAY_COMPAT
+struct DistPrint
+{
+    string name;
+    string desc;
+    int precision;
+    DisplayMode mode;
+    FormatFlags flags;
+
+    result_t min_val;
+    result_t max_val;
+    result_t underflow;
+    result_t overflow;
+    rvec_t vec;
+    result_t sum;
+    result_t squares;
+    result_t samples;
+
+    int min;
+    int max;
+    int bucket_size;
+    int size;
+    bool fancy;
+
+    void operator()(ostream &stream) const;
+};
+
 void
-DistDisplay(ostream &stream, const string &name, const string &desc,
-            int precision, FormatFlags flags,
-            result_t min_val, result_t max_val,
-            result_t underflow, result_t overflow,
-            const rvec_t &vec, int min, int max, int bucket_size, int size);
+DistPrint::operator()(ostream &stream) const
 {
+    if (fancy) {
+        ScalarPrint print;
+        string base = name + ((mode == mode_m5) ? "::" : "_");
+
+        print.precision = precision;
+        print.flags = flags;
+        print.desc = desc;
+
+        print.name = base + "mean";
+        print.value = samples ? sum / samples : NAN;
+        print(stream);
+
+        print.name = base + "stdev";
+        print.value = samples ? sqrt((samples * squares - sum * sum) /
+                                     (samples * (samples - 1.0))) : NAN;
+        print(stream);
+
+        print.name = "**Ignore: " + base + "TOT";
+        print.value = samples;
+        print(stream);
+        return;
+    }
+
     assert(size == vec.size());
 
     result_t total = 0.0;
-    result_t pdf, cdf = 0.0;
 
     total += underflow;
     for (int i = 0; i < size; ++i)
         total += vec[i];
     total += overflow;
 
-    pdf = underflow / total;
-    cdf += pdf;
+    string base = name + (mode == mode_m5 ? "::" : ".");
 
-    PrintOne(stream, underflow, name + NAMESEP + "underflow", desc,
-             precision, myflags, pdf, cdf);
+    ScalarPrint print;
+    print.desc = (mode == mode_m5) ? desc : "";
+    print.precision = precision;
+    print.mode = mode;
+    print.flags = flags;
 
-    for (int i = 0; i < size; ++i) {
-        stringstream namestr;
-        namestr << name;
-
-        int low = i * bucket_size + min;
-        int high = ::std::min((i + 1) * bucket_size + min - 1, max);
-        namestr << low;
-        if (low < high)
-            namestr << "-" << high;
-
-        pdf = vec[i] / total;
-        cdf += pdf;
-        PrintOne(stream, vec[i], namestr.str(), desc, precision, myflags,
-                 pdf, cdf);
+    if (mode == mode_simplescalar) {
+        ccprintf(stream, "%-42s", base + "start_dist");
+        if (PrintDescriptions && !desc.empty())
+            ccprintf(stream, "                     # %s", desc);
+        stream << endl;
+    }
+
+    print.name = base + "samples";
+    print.value = samples;
+    print(stream);
+
+    print.name = base + "min_value";
+    print.value = min_val;
+    print(stream);
+
+    if (mode == mode_m5 || underflow > 0.0) {
+        print.name = base + "underflows";
+        print.value = underflow;
+        if (mode == mode_m5 && total) {
+            print.pdf = underflow / total;
+            print.cdf += print.pdf;
+        }
+        print(stream);
+    }
+
+
+    if (mode == mode_m5) {
+        for (int i = 0; i < size; ++i) {
+            stringstream namestr;
+            namestr << name;
+
+            int low = i * bucket_size + min;
+            int high = ::min((i + 1) * bucket_size + min - 1, max);
+            namestr << low;
+            if (low < high)
+                namestr << "-" << high;
+
+            print.name = namestr.str();
+            print.value = vec[i];
+            if (total) {
+                print.pdf = vec[i] / total;
+                print.cdf += print.pdf;
+            }
+            print(stream);
+        }
+
+    } else {
+        int _min;
+        result_t _pdf;
+        result_t _cdf = 0.0;
+
+        print.flags = flags | __substat;
+
+        for (int i = 0; i < size; ++i) {
+            if (flags & nozero && vec[i] == 0.0 ||
+                flags & nonan && isnan(vec[i]))
+                continue;
+
+            _min = i * bucket_size + min;
+            _pdf = vec[i] / total * 100.0;
+            _cdf += _pdf;
+
+
+            print.name = ValueToString(_min, mode, 0);
+            print.value = vec[i];
+            print.pdf = (flags & pdf) ? _pdf : NAN;
+            print.cdf = (flags & cdf) ? _cdf : NAN;
+            print(stream);
+        }
+
+        print.flags = flags;
+        if (flags & (pdf || cdf)) {
+            print.pdf = NAN;
+            print.cdf = NAN;
+        }
+    }
+
+    if (mode == mode_m5 || overflow > 0.0) {
+        print.name = base + "overflows";
+        print.value = overflow;
+        if (mode == mode_m5 && total) {
+            print.pdf = overflow / total;
+            print.cdf += print.pdf;
+        }
+        print(stream);
+    }
+
+    print.pdf = NAN;
+    print.cdf = NAN;
+
+    if (mode != mode_simplescalar) {
+        print.name = base + "total";
+        print.value = total;
+        print(stream);
+    }
+
+    print.name = base + "max_value";
+    print.value = max_val;
+    print(stream);
+
+    if (mode != mode_simplescalar && samples != 0) {
+        print.name = base + "mean";
+        print.value = sum / samples;
+        print(stream);
+
+        print.name = base + "stdev";
+        print.value = sqrt((samples * squares - sum * sum) /
+                           (samples * (samples - 1.0)));
+        print(stream);
     }
 
-    pdf = overflow / total;
-    cdf += pdf;
-    PrintOne(stream, overflow, name + NAMESEP + "overflow", desc,
-             precision, myflags, pdf, cdf);
-    PrintOne(stream, total, name + NAMESEP + "total", desc,
-             precision, myflags);
+    if (mode == mode_simplescalar)
+        ccprintf(stream, "%send_dist\n\n", base);
 }
-#else
+
 void
-DistDisplay(ostream &stream, const string &name, const string &desc,
-            int precision, FormatFlags flags,
-            result_t min_val, result_t max_val,
-            result_t underflow, result_t overflow,
-            const rvec_t &vec, int min, int max, int bucket_size, int size)
+ScalarDataBase::display(ostream &stream) const
 {
-    assert(size == vec.size());
-    string blank;
+    ScalarPrint print;
+    print.value = val();
+    print.name = name;
+    print.desc = desc;
+    print.precision = precision;
+    print.flags = flags;
+
+    print(stream);
+}
 
-    result_t total = 0.0;
+void
+VectorDataBase::display(ostream &stream) const
+{
+    int size = this->size();
+    const_cast<VectorDataBase *>(this)->update();
 
-    total += underflow;
-    for (int i = 0; i < size; ++i)
-        total += vec[i];
-    total += overflow;
+    VectorPrint print;
 
-    ccprintf(stream, "%-42s", name + ".start_dist");
-    if (PrintDescriptions && !desc.empty())
-        ccprintf(stream, "                     # %s", desc);
-    stream << endl;
+    print.name = name;
+    print.desc = desc;
+    print.mode = mode;
+    print.flags = flags;
+    print.precision = precision;
+    print.vec = val();
+    print.total = total();
 
-    PrintOne(stream, total, name + ".samples", blank, precision, flags);
-    PrintOne(stream, min_val, name + ".min_value", blank, precision, flags);
+    for (int i = 0; i < size; ++i) {
+        if (!subnames[i].empty()) {
+            print.subnames = subnames;
+            print.subnames.resize(size);
+            for (int i = 0; i < size; ++i) {
+                if (!subnames[i].empty() && !subdescs[i].empty()) {
+                    print.subdescs = subdescs;
+                    print.subdescs.resize(size);
+                    break;
+                }
+            }
+            break;
+        }
+    }
 
-    if (underflow > 0)
-        PrintOne(stream, min_val, name + ".underflows", blank, precision,
-                 flags);
 
-    int _min;
-    result_t _pdf, _cdf, mypdf, mycdf;
+    print(stream);
+}
 
-    _cdf = 0.0;
-    for (int i = 0; i < size; ++i) {
-        if (flags & nozero && vec[i] == 0.0 ||
-            flags & nonan && isnan(vec[i]))
-            return;
+void
+Vector2dDataBase::display(ostream &stream) const
+{
+    const_cast<Vector2dDataBase *>(this)->update();
+
+    bool havesub = false;
+    VectorPrint print;
+
+    print.subnames = y_subnames;
+    print.mode = mode;
+    print.flags = flags;
+    print.precision = precision;
+
+    if (!subnames.empty()) {
+        for (int i = 0; i < x; ++i)
+            if (!subnames[i].empty())
+                havesub = true;
+    }
 
-        _min = i * bucket_size + min;
-        _pdf = vec[i] / total * 100.0;
-        _cdf += _pdf;
+    rvec_t tot_vec(y);
+    result_t super_total = 0.0;
+    for (int i = 0; i < x; ++i) {
+        if (havesub && (i >= subnames.size() || subnames[i].empty()))
+            continue;
+
+        int iy = i * y;
+        rvec_t yvec(y);
+
+        result_t total = 0.0;
+        for (int j = 0; j < y; ++j) {
+            yvec[j] = vec[iy + j];
+            tot_vec[j] += yvec[j];
+            total += yvec[j];
+            super_total += yvec[j];
+        }
 
-        mypdf = (flags & pdf) ? _pdf : NAN;
-        mycdf = (flags & cdf) ? _cdf : NAN;
+        print.name = name + "_" + (havesub ? subnames[i] : to_string(i));
+        print.desc = desc;
+        print.vec = yvec;
+        print.total = total;
+        print(stream);
+    }
 
-        PrintOne(stream, vec[i], ValueToString(_min, 0), blank, precision,
-                 flags | __substat, mypdf, mycdf);
+    if ((flags & ::Statistics::total) && (x > 1)) {
+        print.name = name;
+        print.desc = desc;
+        print.vec = tot_vec;
+        print.total = super_total;
+        print(stream);
     }
+}
 
-    if (overflow > 0)
-        PrintOne(stream, overflow, name + ".overflows", blank, precision,
-                 flags);
-    PrintOne(stream, max_val, name + ".max_value", blank, precision, flags);
-    ccprintf(stream, "%s.end_dist\n\n", name);
+void
+DistDataBase::display(ostream &stream) const
+{
+    const_cast<DistDataBase *>(this)->update();
+
+    DistPrint print;
+
+    print.name = name;
+    print.desc = desc;
+    print.precision = precision;
+    print.mode = mode;
+    print.flags = flags;
+
+    print.min_val = data.min_val;
+    print.max_val = data.max_val;
+    print.underflow = data.underflow;
+    print.overflow = data.overflow;
+    print.vec = data.vec;
+    print.sum = data.sum;
+    print.squares = data.squares;
+    print.samples = data.samples;
+
+    print.min = data.min;
+    print.max = data.max;
+    print.bucket_size = data.bucket_size;
+    print.size = data.size;
+    print.fancy = data.fancy;
+
+    print(stream);
+}
+
+void
+VectorDistDataBase::display(ostream &stream) const
+{
+    const_cast<VectorDistDataBase *>(this)->update();
+
+    for (int i = 0; i < size(); ++i) {
+        DistPrint print;
+
+        print.name = name +
+            (subnames[i].empty() ? ("_" + to_string(i)) : subnames[i]);
+        print.desc = subdescs[i].empty() ? desc : subdescs[i];
+        print.precision = precision;
+        print.mode = mode;
+        print.flags = flags;
+
+        print.min_val = data[i].min_val;
+        print.max_val = data[i].max_val;
+        print.underflow = data[i].underflow;
+        print.overflow = data[i].overflow;
+        print.vec = data[i].vec;
+        print.sum = data[i].sum;
+        print.squares = data[i].squares;
+        print.samples = data[i].samples;
+
+        print.min = data[i].min;
+        print.max = data[i].max;
+        print.bucket_size = data[i].bucket_size;
+        print.size = data[i].size;
+        print.fancy = data[i].fancy;
+
+        print(stream);
+    }
 }
-#endif
 
 void
-FancyDisplay(ostream &stream, const string &name, const string &desc,
-             int precision, FormatFlags flags, result_t mean,
-             result_t variance)
+FormulaBase::val(rvec_t &vec) const
 {
-    result_t stdev = isnan(variance) ? NAN : sqrt(variance);
-    PrintOne(stream, mean, name + NAMESEP + "mean", desc, precision, flags);
-    PrintOne(stream, stdev, name + NAMESEP + "stdev", desc, precision, flags);
+    vec = root->val();
 }
 
-BinBase::BinBase(size_t size)
-    : memsize(CeilPow2(size)), mem(NULL)
+result_t
+FormulaBase::total() const
 {
+    return root->total();
 }
 
-BinBase::~BinBase()
+size_t
+FormulaBase::size() const
+{
+    if (!root)
+        return 0;
+    else
+        return root->size();
+}
+
+bool
+FormulaBase::binned() const
+{
+    return root->binned();
+}
+
+void
+FormulaBase::reset()
+{
+}
+
+bool
+FormulaBase::zero() const
+{
+    rvec_t vec;
+    val(vec);
+    for (int i = 0; i < vec.size(); ++i)
+        if (vec[i] != 0.0)
+            return false;
+    return true;
+}
+
+void
+FormulaBase::update(StatData *)
+{
+}
+
+Formula::Formula()
+{
+    setInit();
+}
+
+Formula::Formula(Temp r)
+{
+    root = r;
+    assert(size());
+}
+
+const Formula &
+Formula::operator=(Temp r)
+{
+    assert(!root && "Can't change formulas");
+    root = r;
+    assert(size());
+    return *this;
+}
+
+const Formula &
+Formula::operator+=(Temp r)
+{
+    if (root)
+        root = NodePtr(new BinaryNode<std::plus<result_t> >(root, r));
+    else
+        root = r;
+    assert(size());
+    return *this;
+}
+
+MainBin::MainBin(const string &name)
+    : _name(name), mem(NULL), memsize(-1)
+{
+    Database::StatDB().regBin(this, name);
+}
+
+MainBin::~MainBin()
 {
     if (mem)
         delete [] mem;
 }
 
 char *
-BinBase::memory()
+MainBin::memory(off_t off)
 {
+    if (memsize == -1)
+        memsize = CeilPow2((size_t) offset());
+
     if (!mem) {
         mem = new char[memsize];
         memset(mem, 0, memsize);
     }
 
-    return mem;
+    assert(offset() <= size());
+    return mem + off;
 }
 
-void
-BinBase::regBin(BinBase *bin, std::string name)
-{
-    StatDB().regBin(bin, name);
-}
-
-} // namespace Detail
-
 void
 check()
 {
-    Detail::StatDB().check();
+    Database::StatDB().check();
 }
 
 void
 dump(ostream &stream)
 {
-    Detail::StatDB().dump(stream);
+    Database::StatDB().dump(stream);
 }
 
 CallbackQueue resetQueue;
 
 void
-regReset(Callback *cb)
+registerResetCallback(Callback *cb)
 {
     resetQueue.add(cb);
 }
@@ -930,7 +1030,7 @@ regReset(Callback *cb)
 void
 reset()
 {
-    Detail::StatDB().reset();
+    Database::StatDB().reset();
     resetQueue.process();
 }