/* * Copyright (c) 2003 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * @todo * * Generalized N-dimensinal vector * documentation * fix AvgStor * key stats * interval stats * -- these both can use the same function that prints out a * specific set of stats * VectorStandardDeviation totals * */ #ifndef __STATISTICS_HH__ #define __STATISTICS_HH__ #include #include #include #include #include #include #include #include "host.hh" #include "refcnt.hh" #include "str.hh" #ifndef NAN float __nan(); #define NAN (__nan()) #define __M5_NAN #endif #define STAT_DISPLAY_COMPAT extern Tick curTick; namespace Statistics { typedef double result_t; typedef std::vector rvec_t; typedef u_int32_t FormatFlags; const FormatFlags none = 0x0000; const FormatFlags total = 0x0001; const FormatFlags pdf = 0x0002; const FormatFlags nozero = 0x0004; const FormatFlags nonan = 0x0008; const FormatFlags cdf = 0x0010; const FormatFlags dist = 0x0020; const FormatFlags __substat = 0x8000; const FormatFlags __reserved = __substat; namespace Detail { ////////////////////////////////////////////////////////////////////// // // Statistics Framework Base classes // ////////////////////////////////////////////////////////////////////// struct StatData; struct SubData; class Stat { protected: void setInit(); StatData *mydata(); const StatData *mydata() const; StatData *print(); const SubData *mysubdata(int index) const; SubData *mysubdata_create(int index); public: virtual std::string myname() const; virtual std::string mysubname(int index) const; virtual std::string mydesc() const; virtual std::string mysubdesc(int index) const; virtual FormatFlags myflags() const; virtual bool dodisplay() const; virtual int myprecision() const; public: Stat(bool reg); virtual ~Stat() {} virtual void display(std::ostream &stream) const = 0; virtual size_t size() const = 0; virtual bool zero() const = 0; Stat &name(const std::string &name); Stat &desc(const std::string &desc); Stat &precision(int p); Stat &flags(FormatFlags f); Stat &prereq(const Stat &prereq); Stat &subname(int index, const std::string &name); Stat &subdesc(int index, const std::string &name); public: static bool less(Stat *stat1, Stat *stat2); #ifdef STAT_DEBUG int number; #endif }; // Scalar stats involved in formulas class ScalarStat : public Stat { public: ScalarStat(bool reg) : Stat(reg) {} virtual result_t val() const = 0; virtual bool zero() const; virtual void display(std::ostream &stream) const; }; void VectorDisplay(std::ostream &stream, const std::string &myname, const std::vector *mysubnames, const std::string &mydesc, const std::vector *mysubdescs, int myprecision, FormatFlags myflags, const rvec_t &vec, result_t mytotal); // Vector stats involved in formulas class VectorStat : public Stat { public: VectorStat(bool reg) : Stat(reg) {} virtual const rvec_t &val() const = 0; virtual result_t total() const = 0; virtual bool zero() const; virtual void display(std::ostream &stream) const; }; ////////////////////////////////////////////////////////////////////// // // Simple Statistics // ////////////////////////////////////////////////////////////////////// template struct StatStor { public: struct Params { }; private: T data; public: StatStor(const Params &) : data(T()) {} void set(T val, const Params &p) { data = val; } void inc(T val, const Params &p) { data += val; } void dec(T val, const Params &p) { data -= val; } result_t val(const Params &p) const { return (result_t)data; } T value(const Params &p) const { return data; } }; template struct AvgStor { public: struct Params { }; private: T current; mutable result_t total; mutable Tick last; public: AvgStor(const Params &) : current(T()), total(0), last(0) { } void set(T val, const Params &p) { total += current * (curTick - last); last = curTick; current = val; } void inc(T val, const Params &p) { set(current + val, p); } void dec(T val, const Params &p) { set(current - val, p); } result_t val(const Params &p) const { total += current * (curTick - last); last = curTick; return (result_t)(total + current) / (result_t)(curTick + 1); } T value(const Params &p) const { return current; } }; template class Storage, class Bin> class ScalarBase : public ScalarStat { protected: typedef Storage storage_t; typedef typename storage_t::Params params_t; typedef typename Bin::Bin bin_t; protected: bin_t bin; params_t params; protected: storage_t *data() { return bin.data(params); } const storage_t *data() const { return (const_cast(&bin))->data(params); } protected: // Copying stats is not allowed ScalarBase(const ScalarBase &stat); const ScalarBase &operator=(const ScalarBase &); public: result_t val() const { return data()->val(params); } T value() const { return data()->value(params); } public: ScalarBase() : ScalarStat(true) { bin.init(params); setInit(); } public: // Common operators for stats void operator++() { data()->inc(1, params); } void operator--() { data()->dec(1, params); } void operator++(int) { ++*this; } void operator--(int) { --*this; } template void operator=(const U& v) { data()->set(v, params); } template void operator+=(const U& v) { data()->inc(v, params); } template void operator-=(const U& v) { data()->dec(v, params); } virtual size_t size() const { return 1; } }; ////////////////////////////////////////////////////////////////////// // // Vector Statistics // ////////////////////////////////////////////////////////////////////// template class Storage, class Bin> class ScalarProxy; template class Storage, class Bin> class VectorBase : public VectorStat { protected: typedef Storage storage_t; typedef typename storage_t::Params params_t; typedef typename Bin::VectorBin bin_t; private: mutable rvec_t *vec; protected: bin_t bin; params_t params; protected: storage_t *data(int index) { return bin.data(index, params); } const storage_t *data(int index) const { return (const_cast(&bin))->data(index, params); } protected: // Copying stats is not allowed VectorBase(const VectorBase &stat); const VectorBase &operator=(const VectorBase &); public: const rvec_t &val() const { if (vec) vec->resize(size()); else vec = new rvec_t(size()); for (int i = 0; i < size(); ++i) (*vec)[i] = data(i)->val(params); return *vec; } result_t total() const { result_t total = 0.0; for (int i = 0; i < size(); ++i) total += data(i)->val(params); return total; } public: VectorBase() : VectorStat(true), vec(NULL) {} ~VectorBase() { if (vec) delete vec; } VectorBase &init(size_t size) { bin.init(size, params); setInit(); return *this; } friend class ScalarProxy; ScalarProxy operator[](int index); virtual size_t size() const { return bin.size(); } }; template class Storage, class Bin> class ScalarProxy : public ScalarStat { protected: typedef Storage storage_t; typedef typename storage_t::Params params_t; typedef typename Bin::VectorBin bin_t; private: bin_t *bin; params_t *params; int index; protected: storage_t *data() { return bin->data(index, *params); } const storage_t *data() const { return bin->data(index, *params); } public: result_t val() const { return data()->val(*params); } T value() const { return data()->value(*params); } public: ScalarProxy(bin_t &b, params_t &p, int i) : ScalarStat(false), bin(&b), params(&p), index(i) {} ScalarProxy(const ScalarProxy &sp) : ScalarStat(false), bin(sp.bin), params(sp.params), index(sp.index) {} const ScalarProxy &operator=(const ScalarProxy &sp) { bin = sp.bin; params = sp.params; index = sp.index; return *this; } public: // Common operators for stats void operator++() { data()->inc(1, *params); } void operator--() { data()->dec(1, *params); } void operator++(int) { ++*this; } void operator--(int) { --*this; } template void operator=(const U& v) { data()->set(v, *params); } template void operator+=(const U& v) { data()->inc(v, *params); } template void operator-=(const U& v) { data()->dec(v, *params); } virtual size_t size() const { return 1; } }; template class Storage, class Bin> inline ScalarProxy VectorBase::operator[](int index) { assert (index >= 0 && index < size()); return ScalarProxy(bin, params, index); } template class Storage, class Bin> class VectorProxy; template class Storage, class Bin> class Vector2dBase : public Stat { protected: typedef Storage storage_t; typedef typename storage_t::Params params_t; typedef typename Bin::VectorBin bin_t; protected: size_t x; size_t y; bin_t bin; params_t params; std::vector *y_subnames; protected: storage_t *data(int index) { return bin.data(index, params); } const storage_t *data(int index) const { return (const_cast(&bin))->data(index, params); } protected: // Copying stats is not allowed Vector2dBase(const Vector2dBase &stat); const Vector2dBase &operator=(const Vector2dBase &); public: Vector2dBase() : Stat(true) {} ~Vector2dBase() { } Vector2dBase &init(size_t _x, size_t _y) { x = _x; y = _y; bin.init(x * y, params); setInit(); y_subnames = new std::vector(y); return *this; } /** * This makes the assumption that if you're gonna subnames a 2d vector, * you're subnaming across all y */ Vector2dBase &ysubnames(const char **names) { for (int i=0; i < y; ++i) { (*y_subnames)[i] = names[i]; } return *this; } Vector2dBase &ysubname(int index, const std::string subname) { (*y_subnames)[i] = subname.c_str(); return *this; } std::string ysubname(int i) const { return (*y_subnames)[i]; } friend class VectorProxy; VectorProxy operator[](int index); virtual size_t size() const { return bin.size(); } virtual bool zero() const { return data(0)->value(params) == 0.0; } virtual void display(std::ostream &out) const { bool have_subname = false; for (int i = 0; i < x; ++i) { if (!mysubname(i).empty()) have_subname = true; } rvec_t tot_vec(y); result_t super_total = 0.0; for (int i = 0; i < x; ++i) { std::string subname; if (have_subname) { subname = mysubname(i); if (subname.empty()) continue; } else subname = to_string(i); int iy = i * y; rvec_t vec(y); result_t total = 0.0; for (int j = 0; j < y; ++j) { vec[j] = data(iy + j)->val(params); tot_vec[j] += vec[j]; total += vec[j]; super_total += vec[j]; } std::string desc; if (mysubdesc(i).empty()) { desc = mydesc(); } else { desc = mysubdesc(i); } VectorDisplay(out, myname() + "_" + subname, y_subnames, desc, 0, myprecision(), myflags(), vec, total); } if ((myflags() & ::Statistics::total) && (x > 1)) { VectorDisplay(out, myname(), y_subnames, mydesc(), 0, myprecision(), myflags(), tot_vec, super_total); } } }; template class Storage, class Bin> class VectorProxy : public VectorStat { protected: typedef Storage storage_t; typedef typename storage_t::Params params_t; typedef typename Bin::VectorBin bin_t; private: bin_t *bin; params_t *params; int offset; int len; private: mutable rvec_t *vec; storage_t *data(int index) { assert(index < len); return bin->data(offset + index, *params); } const storage_t *data(int index) const { return (const_cast(bin))->data(offset + index, *params); } public: const rvec_t &val() const { if (vec) vec->resize(size()); else vec = new rvec_t(size()); for (int i = 0; i < size(); ++i) (*vec)[i] = data(i)->val(*params); return *vec; } result_t total() const { result_t total = 0.0; for (int i = 0; i < size(); ++i) total += data(i)->val(*params); return total; } public: VectorProxy(bin_t &b, params_t &p, int o, int l) : VectorStat(false), bin(&b), params(&p), offset(o), len(l), vec(NULL) { } VectorProxy(const VectorProxy &sp) : VectorStat(false), bin(sp.bin), params(sp.params), offset(sp.offset), len(sp.len), vec(NULL) { } ~VectorProxy() { if (vec) delete vec; } const VectorProxy &operator=(const VectorProxy &sp) { bin = sp.bin; params = sp.params; offset = sp.offset; len = sp.len; if (vec) delete vec; vec = NULL; return *this; } virtual size_t size() const { return len; } ScalarProxy operator[](int index) { assert (index >= 0 && index < size()); return ScalarProxy(*bin, *params, offset + index); } }; template class Storage, class Bin> inline VectorProxy Vector2dBase::operator[](int index) { int offset = index * y; assert (index >= 0 && offset < size()); return VectorProxy(bin, params, offset, y); } ////////////////////////////////////////////////////////////////////// // // Non formula statistics // ////////////////////////////////////////////////////////////////////// void DistDisplay(std::ostream &stream, const std::string &name, const std::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); template struct DistStor { public: struct Params { int min; int max; int bucket_size; int size; }; private: T min_val; T max_val; T underflow; T overflow; std::vector vec; public: DistStor(const Params ¶ms) : min_val(INT_MAX), max_val(INT_MIN), underflow(0), overflow(0), vec(params.size) { } void sample(T val, int number, const Params ¶ms) { if (val < params.min) underflow += number; else if (val > params.max) overflow += number; else { int index = (val - params.min) / params.bucket_size; assert(index < size(params)); vec[index] += number; } if (val < min_val) min_val = val; if (val > max_val) max_val = val; } size_t size(const Params &) const { return vec.size(); } bool zero(const Params ¶ms) const { if (underflow != 0 || overflow != 0) return true; int s = size(params); for (int i = 0; i < s; i++) if (vec[i] != 0) return true; return false; } void display(std::ostream &stream, const std::string &name, const std::string &desc, int precision, FormatFlags flags, const Params ¶ms) const { #ifdef STAT_DISPLAY_COMPAT result_t min = params.min; #else result_t min = (min_val == INT_MAX) ? params.min : min_val; #endif result_t max = (max_val == INT_MIN) ? 0 : max_val; rvec_t rvec(params.size); for (int i = 0; i < params.size; ++i) rvec[i] = vec[i]; DistDisplay(stream, name, desc, precision, flags, (result_t)min, (result_t)max, (result_t)underflow, (result_t)overflow, rvec, params.min, params.max, params.bucket_size, params.size); } }; void FancyDisplay(std::ostream &stream, const std::string &name, const std::string &desc, int precision, FormatFlags flags, result_t mean, result_t variance); template struct FancyStor { public: struct Params {}; private: T sum; T squares; int total; public: FancyStor(const Params &) : sum(0), squares(0), total(0) {} void sample(T val, int number, const Params &) { T value = val * number; sum += value; squares += value * value; total += number; } void display(std::ostream &stream, const std::string &name, const std::string &desc, int precision, FormatFlags flags, const Params &) const { result_t mean = NAN; result_t variance = NAN; if (total != 0) { result_t fsum = sum; result_t fsq = squares; result_t ftot = total; mean = fsum / ftot; variance = (ftot * fsq - (fsum * fsum)) / (ftot * (ftot - 1.0)); } FancyDisplay(stream, name, desc, precision, flags, mean, variance); } size_t size(const Params &) const { return 1; } bool zero(const Params &) const { return total == 0; } }; template struct AvgFancy { public: struct Params {}; private: T sum; T squares; public: AvgFancy(const Params &) : sum(0), squares(0) {} void sample(T val, int number, const Params& p) { T value = val * number; sum += value; squares += value * value; } void display(std::ostream &stream, const std::string &name, const std::string &desc, int precision, FormatFlags flags, const Params ¶ms) const { result_t mean = sum / curTick; result_t variance = (squares - sum * sum) / curTick; FancyDisplay(stream, name, desc, precision, flags, mean, variance); } size_t size(const Params ¶ms) const { return 1; } bool zero(const Params ¶ms) const { return sum == 0; } }; template class Storage, class Bin> class DistBase : public Stat { protected: typedef Storage storage_t; typedef typename storage_t::Params params_t; typedef typename Bin::Bin bin_t; protected: bin_t bin; params_t params; protected: storage_t *data() { return bin.data(params); } const storage_t *data() const { return (const_cast(&bin))->data(params); } protected: // Copying stats is not allowed DistBase(const DistBase &stat); const DistBase &operator=(const DistBase &); public: DistBase() : Stat(true) { } ~DistBase() { } template void sample(const U& v, int n = 1) { data()->sample(v, n, params); } virtual size_t size() const { return data()->size(params); } virtual bool zero() const { return data()->zero(params); } virtual void display(std::ostream &stream) const { data()->display(stream, myname(), mydesc(), myprecision(), myflags(), params); } }; template class Storage, class Bin> class VectorDistProxy; template class Storage, class Bin> class VectorDistBase : public Stat { protected: typedef Storage storage_t; typedef typename storage_t::Params params_t; typedef typename Bin::VectorBin bin_t; protected: bin_t bin; params_t params; protected: storage_t *data(int index) { return bin.data(index, params); } const storage_t *data(int index) const { return (const_cast(&bin))->data(index, params); } protected: // Copying stats is not allowed VectorDistBase(const VectorDistBase &stat); const VectorDistBase &operator=(const VectorDistBase &); public: VectorDistBase() : Stat(true) { } ~VectorDistBase() { } friend class VectorDistProxy; VectorDistProxy operator[](int index); const VectorDistProxy operator[](int index) const; virtual size_t size() const { return bin.size(); } virtual bool zero() const { return false; } virtual void display(std::ostream &stream) const; }; template class Storage, class Bin> class VectorDistProxy : public Stat { protected: typedef Storage storage_t; typedef typename storage_t::Params params_t; typedef typename Bin::Bin bin_t; typedef VectorDistBase base_t; private: union { base_t *stat; const base_t *cstat; }; int index; protected: storage_t *data() { return stat->data(index); } const storage_t *data() const { return cstat->data(index); } public: VectorDistProxy(const VectorDistBase &s, int i) : Stat(false), cstat(&s), index(i) {} VectorDistProxy(const VectorDistProxy &sp) : Stat(false), cstat(sp.cstat), index(sp.index) {} const VectorDistProxy &operator=(const VectorDistProxy &sp) { cstat = sp.cstat; index = sp.index; return *this; } public: template void sample(const U& v, int n = 1) { data()->sample(v, n, cstat->params); } virtual size_t size() const { return 1; } virtual bool zero() const { return data()->zero(cstat->params); } virtual void display(std::ostream &stream) const { std::stringstream name, desc; if (!(cstat->mysubname(index).empty())) { name << cstat->myname() << cstat->mysubname(index); } else { name << cstat->myname() << "_" << index; } if (!(cstat->mysubdesc(index).empty())) { desc << cstat->mysubdesc(index); } else { desc << cstat->mydesc(); } data()->display(stream, name.str(), desc.str(), cstat->myprecision(), cstat->myflags(), cstat->params); } }; template class Storage, class Bin> inline VectorDistProxy VectorDistBase::operator[](int index) { assert (index >= 0 && index < size()); return VectorDistProxy(*this, index); } template class Storage, class Bin> inline const VectorDistProxy VectorDistBase::operator[](int index) const { assert (index >= 0 && index < size()); return VectorDistProxy(*this, index); } /** * @todo Need a way to print Distribution totals across the Vector */ template class Storage, class Bin> void VectorDistBase::display(std::ostream &stream) const { for (int i = 0; i < size(); ++i) { VectorDistProxy proxy(*this, i); proxy.display(stream); } } #if 0 result_t VectorDistBase::total(int index) const { int total = 0; for (int i=0; i < x_size(); ++i) { total += data(i)->val(*params); } } #endif ////////////////////////////////////////////////////////////////////// // // Formula Details // ////////////////////////////////////////////////////////////////////// class Node : public RefCounted { public: virtual size_t size() const = 0; virtual const rvec_t &val() const = 0; virtual result_t total() const = 0; }; typedef RefCountingPtr NodePtr; class ScalarStatNode : public Node { private: const ScalarStat &stat; mutable rvec_t result; public: ScalarStatNode(const ScalarStat &s) : stat(s), result(1) {} const rvec_t &val() const { result[0] = stat.val(); return result; } virtual result_t total() const { return stat.val(); }; virtual size_t size() const { return 1; } }; template class Storage, class Bin> class ScalarProxyNode : public Node { private: const ScalarProxy proxy; mutable rvec_t result; public: ScalarProxyNode(const ScalarProxy &p) : proxy(p), result(1) { } const rvec_t &val() const { result[0] = proxy.val(); return result; } virtual result_t total() const { return proxy.val(); }; virtual size_t size() const { return 1; } }; class VectorStatNode : public Node { private: const VectorStat &stat; public: VectorStatNode(const VectorStat &s) : stat(s) {} const rvec_t &val() const { return stat.val(); } virtual result_t total() const { return stat.total(); }; virtual size_t size() const { return stat.size(); } }; template class ConstNode : public Node { private: rvec_t data; public: ConstNode(T s) : data(1, (result_t)s) {} const rvec_t &val() const { return data; } virtual result_t total() const { return data[0]; }; virtual size_t size() const { return 1; } }; template class FunctorNode : public Node { private: T &functor; mutable rvec_t result; public: FunctorNode(T &f) : functor(f) { result.resize(1); } const rvec_t &val() const { result[0] = (result_t)functor(); return result; } virtual result_t total() const { return (result_t)functor(); }; virtual size_t size() const { return 1; } }; template class ScalarNode : public Node { private: T &scalar; mutable rvec_t result; public: ScalarNode(T &s) : scalar(s) { result.resize(1); } const rvec_t &val() const { result[0] = (result_t)scalar; return result; } virtual result_t total() const { return (result_t)scalar; }; virtual size_t size() const { return 1; } }; template class UnaryNode : public Node { public: NodePtr l; mutable rvec_t result; public: UnaryNode(NodePtr p) : l(p) {} const rvec_t &val() const { const rvec_t &lvec = l->val(); int size = lvec.size(); assert(size > 0); result.resize(size); Op op; for (int i = 0; i < size; ++i) result[i] = op(lvec[i]); return result; } result_t total() const { Op op; return op(l->total()); } virtual size_t size() const { return l->size(); } }; template class BinaryNode : public Node { public: NodePtr l; NodePtr r; mutable rvec_t result; public: BinaryNode(NodePtr a, NodePtr b) : l(a), r(b) {} const rvec_t &val() const { Op op; const rvec_t &lvec = l->val(); const rvec_t &rvec = r->val(); assert(lvec.size() > 0 && rvec.size() > 0); if (lvec.size() == 1 && rvec.size() == 1) { result.resize(1); result[0] = op(lvec[0], rvec[0]); } else if (lvec.size() == 1) { int size = rvec.size(); result.resize(size); for (int i = 0; i < size; ++i) result[i] = op(lvec[0], rvec[i]); } else if (rvec.size() == 1) { int size = lvec.size(); result.resize(size); for (int i = 0; i < size; ++i) result[i] = op(lvec[i], rvec[0]); } else if (rvec.size() == lvec.size()) { int size = rvec.size(); result.resize(size); for (int i = 0; i < size; ++i) result[i] = op(lvec[i], rvec[i]); } return result; } result_t total() const { Op op; return op(l->total(), r->total()); } virtual size_t size() const { int ls = l->size(); int rs = r->size(); if (ls == 1) return rs; else if (rs == 1) return ls; else { assert(ls == rs && "Node vector sizes are not equal"); return ls; } } }; template class SumNode : public Node { public: NodePtr l; mutable rvec_t result; public: SumNode(NodePtr p) : l(p), result(1) {} const rvec_t &val() const { const rvec_t &lvec = l->val(); int size = lvec.size(); assert(size > 0); result[0] = 0.0; Op op; for (int i = 0; i < size; ++i) result[0] = op(result[0], lvec[i]); return result; } result_t total() const { const rvec_t &lvec = l->val(); int size = lvec.size(); assert(size > 0); result_t result = 0.0; Op op; for (int i = 0; i < size; ++i) result = op(result, lvec[i]); return result; } virtual size_t size() const { return 1; } }; class Temp { private: NodePtr node; public: Temp(NodePtr n) : node(n) {} Temp(const ScalarStat &s) : node(new ScalarStatNode(s)) {} template class Storage, class Bin> Temp(const ScalarProxy &p) : node(new ScalarProxyNode(p)) {} Temp(const VectorStat &s) : node(new VectorStatNode(s)) {} #define TempSCALAR(T) \ Temp(T value) : node(new ConstNode(value)) {} TempSCALAR( signed char); TempSCALAR(unsigned char); TempSCALAR( signed short); TempSCALAR(unsigned short); TempSCALAR( signed int); TempSCALAR(unsigned int); TempSCALAR( signed long); TempSCALAR(unsigned long); TempSCALAR( signed long long); TempSCALAR(unsigned long long); TempSCALAR(float); TempSCALAR(double); #undef TempSCALAR operator NodePtr() { return node;} }; ////////////////////////////////////////////////////////////////////// // // Binning Interface // ////////////////////////////////////////////////////////////////////// class BinBase { private: off_t memsize; char *mem; protected: off_t size() const { return memsize; } char *memory(); public: BinBase(size_t size); ~BinBase(); }; } // namespace Detail template struct StatBin : public Detail::BinBase { static StatBin *&curBin() { static StatBin *current = NULL; return current; } static void setCurBin(StatBin *bin) { curBin() = bin; } static StatBin *current() { assert(curBin()); return curBin(); } static off_t &offset() { static off_t offset = 0; return offset; } static off_t new_offset(size_t size) { size_t mask = sizeof(u_int64_t) - 1; off_t off = offset(); // That one is for the last trailing flags byte. offset() += (size + 1 + mask) & ~mask; return off; } explicit StatBin(size_t size = 1024) : Detail::BinBase(size) {} char *memory(off_t off) { assert(offset() <= size()); return Detail::BinBase::memory() + off; } static void activate(StatBin &bin) { setCurBin(&bin); } class BinBase { private: int offset; public: BinBase() : offset(-1) {} void allocate(size_t size) { offset = new_offset(size); } char *access() { assert(offset != -1); return current()->memory(offset); } }; template class Bin : public BinBase { public: typedef typename Storage::Params Params; public: Bin() { allocate(sizeof(Storage)); } bool initialized() const { return true; } void init(const Params ¶ms) { } int size() const { return 1; } Storage *data(const Params ¶ms) { assert(initialized()); char *ptr = access(); char *flags = ptr + sizeof(Storage); if (!(*flags & 0x1)) { *flags |= 0x1; new (ptr) Storage(params); } return reinterpret_cast(ptr); } }; template class VectorBin : public BinBase { public: typedef typename Storage::Params Params; private: int _size; public: VectorBin() : _size(0) {} bool initialized() const { return _size > 0; } void init(int s, const Params ¶ms) { assert(!initialized()); assert(s > 0); _size = s; allocate(_size * sizeof(Storage)); } int size() const { return _size; } Storage *data(int index, const Params ¶ms) { assert(initialized()); assert(index >= 0 && index < size()); char *ptr = access(); char *flags = ptr + size() * sizeof(Storage); if (!(*flags & 0x1)) { *flags |= 0x1; for (int i = 0; i < size(); ++i) new (ptr + i * sizeof(Storage)) Storage(params); } return reinterpret_cast(ptr + index * sizeof(Storage)); } }; }; class MainBinType {}; typedef StatBin MainBin; struct NoBin { template struct Bin { public: typedef typename Storage::Params Params; private: char ptr[sizeof(Storage)]; public: bool initialized() const { return true; } void init(const Params ¶ms) { new (ptr) Storage(params); } int size() const{ return 1; } Storage *data(const Params ¶ms) { assert(initialized()); return reinterpret_cast(ptr); } }; template struct VectorBin { public: typedef typename Storage::Params Params; private: char *ptr; int _size; public: VectorBin() : ptr(NULL) { } ~VectorBin() { if (initialized()) delete [] ptr; } bool initialized() const { return ptr != NULL; } void init(int s, const Params ¶ms) { assert(s > 0 && "size must be positive!"); assert(!initialized()); _size = s; ptr = new char[_size * sizeof(Storage)]; for (int i = 0; i < _size; ++i) new (ptr + i * sizeof(Storage)) Storage(params); } int size() const { return _size; } Storage *data(int index, const Params ¶ms) { assert(initialized()); assert(index >= 0 && index < size()); return reinterpret_cast(ptr + index * sizeof(Storage)); } }; }; ////////////////////////////////////////////////////////////////////// // // Visible Statistics Types // ////////////////////////////////////////////////////////////////////// template class Scalar : public Detail::ScalarBase { public: typedef Detail::ScalarBase Base; template void operator=(const U& v) { Base::operator=(v); } }; template class Average : public Detail::ScalarBase { public: typedef Detail::ScalarBase Base; template void operator=(const U& v) { Base::operator=(v); } }; template class Vector : public Detail::VectorBase { }; template class AverageVector : public Detail::VectorBase { }; template class Vector2d : public Detail::Vector2dBase { }; template class Distribution : public Detail::DistBase { private: typedef Detail::DistBase Base; typedef typename Detail::DistStor::Params Params; public: Distribution &init(T min, T max, int bkt) { params.min = min; params.max = max; params.bucket_size = bkt; params.size = (max - min) / bkt + 1; bin.init(params); setInit(); return *this; } }; template class StandardDeviation : public Detail::DistBase { private: typedef Detail::DistBase Base; typedef typename Detail::DistStor::Params Params; public: StandardDeviation() { bin.init(params); setInit(); } }; template class AverageDeviation : public Detail::DistBase { private: typedef Detail::DistBase Base; typedef typename Detail::DistStor::Params Params; public: AverageDeviation() { bin.init(params); setInit(); } }; template class VectorDistribution : public Detail::VectorDistBase { private: typedef Detail::VectorDistBase Base; typedef typename Detail::DistStor::Params Params; public: VectorDistribution &init(int size, T min, T max, int bkt) { params.min = min; params.max = max; params.bucket_size = bkt; params.size = (max - min) / bkt + 1; bin.init(size, params); setInit(); return *this; } }; template class VectorStandardDeviation : public Detail::VectorDistBase { private: typedef Detail::VectorDistBase Base; typedef typename Detail::DistStor::Params Params; public: VectorStandardDeviation &init(int size) { bin.init(size, params); setInit(); return *this; } }; template class VectorAverageDeviation : public Detail::VectorDistBase { private: typedef Detail::VectorDistBase Base; typedef typename Detail::DistStor::Params Params; public: VectorAverageDeviation &init(int size) { bin.init(size, params); setInit(); return *this; } }; class Formula : public Detail::VectorStat { private: Detail::NodePtr root; friend class Detail::Temp; public: Formula() : VectorStat(true) { setInit(); } Formula(Detail::Temp r) : VectorStat(true) { root = r; assert(size()); } const Formula &operator=(Detail::Temp r) { assert(!root && "Can't change formulas"); root = r; assert(size()); return *this; } const Formula &operator+=(Detail::Temp r) { using namespace Detail; if (root) root = NodePtr(new BinaryNode >(root, r)); else root = r; assert(size()); return *this; } const rvec_t &val() const { return root->val(); } result_t total() const { return root->total(); } size_t size() const { if (!root) return 0; else return root->size(); } }; void check(); void dump(std::ostream &stream); inline Detail::Temp operator+(Detail::Temp l, Detail::Temp r) { using namespace Detail; return NodePtr(new BinaryNode >(l, r)); } inline Detail::Temp operator-(Detail::Temp l, Detail::Temp r) { using namespace Detail; return NodePtr(new BinaryNode >(l, r)); } inline Detail::Temp operator*(Detail::Temp l, Detail::Temp r) { using namespace Detail; return NodePtr(new BinaryNode >(l, r)); } inline Detail::Temp operator/(Detail::Temp l, Detail::Temp r) { using namespace Detail; return NodePtr(new BinaryNode >(l, r)); } inline Detail::Temp operator%(Detail::Temp l, Detail::Temp r) { using namespace Detail; return NodePtr(new BinaryNode >(l, r)); } inline Detail::Temp operator-(Detail::Temp l) { using namespace Detail; return NodePtr(new UnaryNode >(l)); } template inline Detail::Temp constant(T val) { using namespace Detail; return NodePtr(new ConstNode(val)); } template inline Detail::Temp functor(T &val) { using namespace Detail; return NodePtr(new FunctorNode(val)); } template inline Detail::Temp scalar(T &val) { using namespace Detail; return NodePtr(new ScalarNode(val)); } inline Detail::Temp sum(Detail::Temp val) { using namespace Detail; return NodePtr(new SumNode >(val)); } extern bool PrintDescriptions; } // namespace statistics #endif // __STATISTICS_HH__