From 3f1ae35c6db3321b5f7e0ef4a90e2610a468692b Mon Sep 17 00:00:00 2001 From: Thomas Grass Date: Fri, 19 Aug 2011 15:08:05 -0500 Subject: [PATCH] Stats: Add a sparse histogram stat object. --- src/base/statistics.hh | 185 +++++++++++++++++++++++++++++++++++++++ src/base/stats/info.hh | 14 +++ src/base/stats/output.hh | 2 + src/base/stats/text.cc | 86 ++++++++++++++++++ src/base/stats/text.hh | 1 + src/base/stats/types.hh | 3 + src/python/swig/stats.i | 1 + src/unittest/stattest.cc | 11 +++ 8 files changed, 303 insertions(+) diff --git a/src/base/statistics.hh b/src/base/statistics.hh index cf8349d24..d98c79414 100644 --- a/src/base/statistics.hh +++ b/src/base/statistics.hh @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -2608,6 +2609,190 @@ class FormulaInfoProxy : public InfoProxy std::string str() const { return this->s.str(); } }; +template +class SparseHistInfoProxy : public InfoProxy +{ + public: + SparseHistInfoProxy(Stat &stat) : InfoProxy(stat) {} +}; + +/** + * Implementation of a sparse histogram stat. The storage class is + * determined by the Storage template. + */ +template +class SparseHistBase : public DataWrap +{ + public: + typedef SparseHistInfoProxy Info; + typedef Stor Storage; + typedef typename Stor::Params Params; + + protected: + /** The storage for this stat. */ + char storage[sizeof(Storage)]; + + protected: + /** + * Retrieve the storage. + * @return The storage object for this stat. + */ + Storage * + data() + { + return reinterpret_cast(storage); + } + + /** + * Retrieve a const pointer to the storage. + * @return A const pointer to the storage object for this stat. + */ + const Storage * + data() const + { + return reinterpret_cast(storage); + } + + void + doInit() + { + new (storage) Storage(this->info()); + this->setInit(); + } + + public: + SparseHistBase() { } + + /** + * Add a value to the distribtion n times. Calls sample on the storage + * class. + * @param v The value to add. + * @param n The number of times to add it, defaults to 1. + */ + template + void sample(const U &v, int n = 1) { data()->sample(v, n); } + + /** + * Return the number of entries in this stat. + * @return The number of entries. + */ + size_type size() const { return data()->size(); } + /** + * Return true if no samples have been added. + * @return True if there haven't been any samples. + */ + bool zero() const { return data()->zero(); } + + void + prepare() + { + Info *info = this->info(); + data()->prepare(info, info->data); + } + + /** + * Reset stat value to default + */ + void + reset() + { + data()->reset(this->info()); + } +}; + +/** + * Templatized storage and interface for a sparse histogram stat. + */ +class SparseHistStor +{ + public: + /** The parameters for a sparse histogram stat. */ + struct Params : public DistParams + { + Params() : DistParams(Hist) {} + }; + + private: + /** Counter for number of samples */ + Counter samples; + /** Counter for each bucket. */ + MCounter cmap; + + public: + SparseHistStor(Info *info) + { + reset(info); + } + + /** + * Add a value to the distribution for the given number of times. + * @param val The value to add. + * @param number The number of times to add the value. + */ + void + sample(Counter val, int number) + { + cmap[val] += number; + samples += number; + } + + /** + * 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 + { + return samples == Counter(); + } + + void + prepare(Info *info, SparseHistData &data) + { + MCounter::iterator it; + data.cmap.clear(); + for (it = cmap.begin(); it != cmap.end(); it++) { + data.cmap[(*it).first] = (*it).second; + } + + data.samples = samples; + } + + /** + * Reset stat value to default + */ + void + reset(Info *info) + { + cmap.clear(); + samples = 0; + } +}; + +class SparseHistogram : public SparseHistBase +{ + public: + /** + * Set the parameters of this histogram. @sa HistStor::Params + * @param size The number of buckets in the histogram + * @return A reference to this histogram. + */ + 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 diff --git a/src/base/stats/info.hh b/src/base/stats/info.hh index fa7c8cc3d..2c5b44a38 100644 --- a/src/base/stats/info.hh +++ b/src/base/stats/info.hh @@ -234,6 +234,20 @@ class FormulaInfo : public VectorInfo virtual std::string str() const = 0; }; +/** Data structure of sparse histogram */ +struct SparseHistData +{ + MCounter cmap; + Counter samples; +}; + + +class SparseHistInfo : public Info +{ + public: + /** Local storage for the entry values, used for printing. */ + SparseHistData data; +}; } // namespace Stats diff --git a/src/base/stats/output.hh b/src/base/stats/output.hh index 26c4c5bbd..9cd33a5f9 100644 --- a/src/base/stats/output.hh +++ b/src/base/stats/output.hh @@ -43,6 +43,7 @@ class DistInfo; class VectorDistInfo; class Vector2dInfo; class FormulaInfo; +class SparseHistInfo; // Sparse histogram struct Output { @@ -57,6 +58,7 @@ struct Output virtual void visit(const VectorDistInfo &info) = 0; virtual void visit(const Vector2dInfo &info) = 0; virtual void visit(const FormulaInfo &info) = 0; + virtual void visit(const SparseHistInfo &info) = 0; // Sparse histogram }; } // namespace Stats diff --git a/src/base/stats/text.cc b/src/base/stats/text.cc index 45d59ff29..f8471f1a1 100644 --- a/src/base/stats/text.cc +++ b/src/base/stats/text.cc @@ -581,6 +581,92 @@ Text::visit(const FormulaInfo &info) visit((const VectorInfo &)info); } +/* + This struct implements the output methods for the sparse + histogram stat +*/ +struct SparseHistPrint +{ + string name; + string separatorString; + string desc; + Flags flags; + bool descriptions; + int precision; + + const SparseHistData &data; + + SparseHistPrint(const Text *text, const SparseHistInfo &info); + void init(const Text *text, const Info &info); + void operator()(ostream &stream) const; +}; + +/* Call initialization function */ +SparseHistPrint::SparseHistPrint(const Text *text, const SparseHistInfo &info) + : data(info.data) +{ + init(text, info); +} + +/* Initialization function */ +void +SparseHistPrint::init(const Text *text, const Info &info) +{ + name = info.name; + separatorString = info.separatorString; + desc = info.desc; + flags = info.flags; + precision = info.precision; + descriptions = text->descriptions; +} + +/* Grab data from map and write to output stream */ +void +SparseHistPrint::operator()(ostream &stream) const +{ + string base = name + separatorString; + + ScalarPrint print; + print.precision = precision; + print.flags = flags; + print.descriptions = descriptions; + print.desc = desc; + print.pdf = NAN; + print.cdf = NAN; + + print.name = base + "samples"; + print.value = data.samples; + print(stream); + + MCounter::const_iterator it; + for (it = data.cmap.begin(); it != data.cmap.end(); it++) { + stringstream namestr; + namestr << base; + + namestr <<(*it).first; + print.name = namestr.str(); + print.value = (*it).second; + print(stream); + } + + print.pdf = NAN; + print.cdf = NAN; + + print.name = base + "total"; + print.value = total; + print(stream); +} + +void +Text::visit(const SparseHistInfo &info) +{ + if (noOutput(info)) + return; + + SparseHistPrint print(this, info); + print(*stream); +} + Output * initText(const string &filename, bool desc) { diff --git a/src/base/stats/text.hh b/src/base/stats/text.hh index 24abaac97..7f7edaa91 100644 --- a/src/base/stats/text.hh +++ b/src/base/stats/text.hh @@ -67,6 +67,7 @@ class Text : public Output virtual void visit(const VectorDistInfo &info); virtual void visit(const Vector2dInfo &info); virtual void visit(const FormulaInfo &info); + virtual void visit(const SparseHistInfo &info); // Implement Output virtual bool valid() const; diff --git a/src/base/stats/types.hh b/src/base/stats/types.hh index 9faa8d33d..831cc6db5 100644 --- a/src/base/stats/types.hh +++ b/src/base/stats/types.hh @@ -32,6 +32,7 @@ #define __BASE_STATS_TYPES_HH__ #include +#include #include #include "base/types.hh" @@ -42,6 +43,8 @@ namespace Stats { typedef double Counter; /** vector of counters. */ typedef std::vector VCounter; +/** map of counters */ +typedef std::map MCounter; typedef std::numeric_limits CounterLimits; diff --git a/src/python/swig/stats.i b/src/python/swig/stats.i index 0213d5c01..87810d305 100644 --- a/src/python/swig/stats.i +++ b/src/python/swig/stats.i @@ -137,6 +137,7 @@ template T cast_info(Info *info); %template(dynamic_VectorDistInfo) cast_info; %template(dynamic_Vector2dInfo) cast_info; %template(dynamic_FormulaInfo) cast_info; +%template(dynamic_SparseHistInfo) cast_info; void initSimStats(); Output *initText(const std::string &filename, bool desc); diff --git a/src/unittest/stattest.cc b/src/unittest/stattest.cc index c5e39888d..ccce2173b 100644 --- a/src/unittest/stattest.cc +++ b/src/unittest/stattest.cc @@ -92,6 +92,7 @@ struct StatTest Histogram h10; Histogram h11; Histogram h12; + SparseHistogram sh1; Formula f1; Formula f2; @@ -316,6 +317,12 @@ StatTest::init() .desc("this is histogram 12") ; + sh1 + .init(0) + .name("SparseHistogram1") + .desc("this is sparse histogram 1") + ; + f1 .name("Formula1") .desc("this is formula 1") @@ -623,4 +630,8 @@ StatTest::run() h11.sample(i); h12.sample(i); } + + for (int i = 0; i < 1000; i++) { + sh1.sample(random() % 10000); + } } -- 2.30.2