X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=senf%2FUtils%2FStatistics.cc;h=51753886996a79e95eb711ab1af909a9c6d110bb;hb=5b2e9a63a43027c71ac470ac9bdecb72e8974951;hp=7506e078e41e1b511011d6e0c47994b8a96dab45;hpb=f37680c43dd9aab620388e9b966ed2328c56a15e;p=senf.git diff --git a/senf/Utils/Statistics.cc b/senf/Utils/Statistics.cc index 7506e07..5175388 100644 --- a/senf/Utils/Statistics.cc +++ b/senf/Utils/Statistics.cc @@ -1,6 +1,6 @@ // $Id$ // -// Copyright (C) 2008 +// Copyright (C) 2008 // Fraunhofer Institute for Open Communication Systems (FOKUS) // Competence Center NETwork research (NET), St. Augustin, GERMANY // Stefan Bund @@ -28,25 +28,30 @@ // Custom includes #include +#include #include -#include +#include #include "StatisticsTargets.hh" //#include "Statistics.mpp" #define prefix_ -///////////////////////////////cc.p//////////////////////////////////////// +//-///////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////// +//-///////////////////////////////////////////////////////////////////////////////////////////////// // senf::StatisticsBase -prefix_ void senf::StatisticsBase::enter(float min, float avg, float max, float dev) +prefix_ void senf::StatisticsBase::enter(unsigned n, float min, float avg, float max, float dev) { min_ = min; avg_ = avg; max_ = max; dev_ = dev; - generateOutput(); - signalChildren(); + for (unsigned i (0); i < n; ++i) + generateOutput(); + Children::iterator i (children_.begin()); + Children::iterator const i_end (children_.end()); + for (; i != i_end; ++i) + i->second.enter(n, min_, avg_, max_, dev_); } prefix_ senf::Collector & senf::StatisticsBase::operator[](unsigned rank) @@ -57,6 +62,15 @@ prefix_ senf::Collector & senf::StatisticsBase::operator[](unsigned rank) return i->second; } +prefix_ senf::Collector const & senf::StatisticsBase::operator[](unsigned rank) + const +{ + Children::const_iterator i (children_.find(rank)); + if (i == children_.end()) + throw InvalidRankException(); + return i->second; +} + prefix_ senf::Collector & senf::StatisticsBase::collect(unsigned rank) { std::pair state ( @@ -82,63 +96,23 @@ senf::StatisticsBase::output(unsigned n) return OutputProxy(this, &(i->second)); } -// -// generate an engineering style notation -// -std::string format_eng( float f) -{ - char buf[16]; - if (f > 0) { - int n = 0; - while( f >= 1000.0f) { - f /= 1000.0f; - n+=3; - } - - if( n >=3) - sprintf( buf, " %3.2fe%+03d", f, n); - else - sprintf( buf, " %3.2f", f); - } - else if (f < 0) { - int n = 0; - while( f <= -1000.0f) { - f *= 1000.0f; - n+=3; - } - if( n >=3) - sprintf( buf, " %3.2fe%+03d", f, n); - else - sprintf( buf, " %3.2f", f); - } - else{ - sprintf( buf, " 0.00"); - } - - return buf; -} - - prefix_ void senf::StatisticsBase::consoleList(unsigned level, std::ostream & os) const { - os << boost::format("%s%-5d%|15t| %12s %12s %12s %12s\n") - % std::string(2*level,' ') - % rank() - % format_eng(min()) - % format_eng(avg()) - % format_eng(dev()) - % format_eng(max()); + namespace fmt = senf::format; + + os << boost::format("%s%-5d%|15t| %12.5g %19.5g %12.5g\n") + % std::string(2*level,' ') % rank() + % fmt::eng(min()).setw() % fmt::eng(avg(),dev()).setw() % fmt::eng(max()).setw(); { OutputMap::const_iterator i (outputs_.begin()); OutputMap::const_iterator i_end (outputs_.end()); for (; i != i_end; ++i) - os << boost::format(" %3d %12s %12s %12s %12s\n") - % i->second.n - % format_eng(i->second.min/i->second.n) - % format_eng(i->second.avg/i->second.n) - % format_eng(i->second.dev/i->second.n) - % format_eng(i->second.max/i->second.n); + os << boost::format(" %3d %12.5g %19.5g %12.5g\n") + % i->second.n + % fmt::eng(i->second.min).setw() + % fmt::eng(i->second.avg, i->second.dev).setw() + % fmt::eng(i->second.max).setw(); } { Children::const_iterator i (children_.begin()); @@ -167,19 +141,26 @@ prefix_ void senf::StatisticsBase::generateOutput() i->second.max += j->max; i->second.dev += j->dev; } - i->second.signal(i->second.min/n, i->second.avg/n, i->second.max/n, i->second.dev/n); + i->second.min /= n; + i->second.avg /= n; + i->second.max /= n; + i->second.dev /= n; + i->second.signal(i->second.min, i->second.avg, i->second.max, i->second.dev); } } -prefix_ void senf::StatisticsBase::signalChildren() +//-///////////////////////////////////////////////////////////////////////////////////////////////// +// senf::StatisticsBase::OutputEntry + +prefix_ void senf::StatisticsBase::OutputEntry::consoleList(std::ostream & os) { - Children::iterator i (children_.begin()); - Children::iterator const i_end (children_.end()); - for (; i != i_end; ++i) - i->second.enter(min_, avg_, max_, dev_); + for (boost::ptr_vector::iterator i (targets_.begin()); + i != targets_.end(); ++i) + if (! i->label.empty()) + os << i->label << "\n"; } -/////////////////////////////////////////////////////////////////////////// +//-///////////////////////////////////////////////////////////////////////////////////////////////// // senf::Statistics prefix_ senf::Statistics::Statistics() @@ -188,64 +169,66 @@ prefix_ senf::Statistics::Statistics() #endif { #ifndef SENF_DISABLE_CONSOLE - dir.add("list", &Statistics::consoleList) - .doc("List statistics collection intervals and current values.\n" - "\n" - "Columns:\n" - " RANK Number of values collected. Since the statistics collectors form\n" - " a tree, the value is indented according to it's tree location.\n" - " WIN Size of output average window.\n" - " MIN Last entered minimum value.\n" - " AVG Last entered average value.\n" - " DEV Standard deviation of average value over the collector rank.\n" - " MAX Last entered maximum value."); - dir.add("collect", &Statistics::consoleCollect) - .doc("Add statistics collection groups. The argument gives a sequence of collector\n" - "ranks each building on the preceding collector:\n" - "\n" - " $ collect (10 60 60)\n" - "\n" - "Will start by collecting every 10 values together to a new value. 60 of such\n" - "combined values will be collected together in the next step again followed by\n" - "a collection of 60 values. If the statistics is entered with a frequency of\n" - "10 values per second, this will provide combined statistics over the second,\n" - "minutes and hours ranges.\n" - "\n" - "You may call collect multiple times. Any missing collection ranks will be\n" - "added.") - .arg("ranks","chain of collector ranks"); - dir.add("output", &Statistics::consoleOutput) - .doc("Generate statistics output. This statement will add an additional output\n" - "generator. This generator will be attached to the collector specified by\n" - "the {rank} parameter. This parameter is a chain of successive rank values\n" - "which specifies the exact collector to use. If the collector does not\n" - "exist, it will be created (this is like automatically calling 'collect'\n" - "with {rank} as argument).\n" - "\n" - "If the output is to be sent somewhere it must be connected to a statistics\n" - "target.\n" - "\n" - "The output may optionally be built using a sliding average over the last\n" - "{window} values.\n" - "\n" - " $ output ()\n" - "\n" - "will output the basic statistics value each time a new value is entered.\n" - "\n" - " $ output (10 60) 5\n" - "\n" - "Assuming that new data values are entered 10 times per second, this command\n" - "will generate output once every minute. The value will be the average over\n" - "the last 5 minutes.") - .arg("rank","Rank chain selecting the value to generate output for") - .arg("window","Optional size of sliding average window", - senf::console::kw::default_value = 1u); + namespace fty = console::factory; + + dir.add("list", fty::Command(&Statistics::consoleList, this) + .doc("List statistics collection intervals and current values.\n" + "\n" + "Columns:\n" + " RANK Number of values collected. Since the statistics collectors form\n" + " a tree, the value is indented according to it's tree location.\n" + " WIN Size of output average window.\n" + " MIN Last entered minimum value.\n" + " AVG Last entered average value.\n" + " DEV Standard deviation of average value over the collector rank.\n" + " MAX Last entered maximum value.") ); + dir.add("collect", fty::Command(&Statistics::consoleCollect, this) + .doc("Add statistics collection groups. The argument gives a sequence of collector\n" + "ranks each building on the preceding collector:\n" + "\n" + " $ collect (10 60 60)\n" + "\n" + "Will start by collecting every 10 values together to a new value. 60 of such\n" + "combined values will be collected together in the next step again followed by\n" + "a collection of 60 values. If the statistics is entered with a frequency of\n" + "10 values per second, this will provide combined statistics over the second,\n" + "minutes and hours ranges.\n" + "\n" + "You may call collect multiple times. Any missing collection ranks will be\n" + "added.") + .arg("ranks","chain of collector ranks") ); + dir.add("output", fty::Command(&Statistics::consoleOutput, this) + .doc("Generate statistics output. This statement will add an additional output\n" + "generator. This generator will be attached to the collector specified by\n" + "the {rank} parameter. This parameter is a chain of successive rank values\n" + "which specifies the exact collector to use. If the collector does not\n" + "exist, it will be created (this is like automatically calling 'collect'\n" + "with {rank} as argument).\n" + "\n" + "If the output is to be sent somewhere it must be connected to a statistics\n" + "target.\n" + "\n" + "The output may optionally be built using a sliding average over the last\n" + "{window} values.\n" + "\n" + " $ output ()\n" + "\n" + "will output the basic statistics value each time a new value is entered.\n" + "\n" + " $ output (10 60) 5\n" + "\n" + "Assuming that new data values are entered 10 times per second, this command\n" + "will generate output once every minute. The value will be the average over\n" + "the last 5 minutes.") + .arg("rank","Rank chain selecting the value to generate output for") + .arg("window","Optional size of sliding average window", + console::kw::default_value = 1u) ); #endif } prefix_ void senf::Statistics::consoleList(std::ostream & os) { - os << "RANK WIN MIN AVG DEV MAX\n"; + os << "RANK WIN MIN AVG MAX\n"; StatisticsBase::consoleList(0, os); } @@ -263,7 +246,7 @@ prefix_ void senf::Statistics::consoleCollect(std::vector & ranks) for (; i != i_end; ++i) stats = & (stats->collect(*i)); - + } prefix_ boost::shared_ptr @@ -272,7 +255,7 @@ senf::Statistics::consoleOutput(std::vector & ranks, unsigned window) StatisticsBase * stats (this); std::vector::const_iterator i (ranks.begin()); std::vector::const_iterator const i_end (ranks.end()); - + try { for (; i != i_end; ++i) stats = &(*stats)[*i]; @@ -281,7 +264,7 @@ senf::Statistics::consoleOutput(std::vector & ranks, unsigned window) for (; i != i_end; ++i) stats = & (stats->collect(*i)); - + return stats->output(window).dir().node().thisptr(); } @@ -296,24 +279,40 @@ prefix_ std::string senf::Statistics::v_path() return ""; } -/////////////////////////////////////////////////////////////////////////// +//-///////////////////////////////////////////////////////////////////////////////////////////////// // senf::Collector -prefix_ void senf::Collector::enter(float min, float avg, float max, float dev) +prefix_ void senf::Collector::enter(unsigned n, float min, float avg, float max, float dev) { - accSum_ += avg; - accSumSq_ += avg*avg + dev*dev; if (min < accMin_) accMin_ = min; if (max > accMax_) accMax_ = max; - if (++i_ >= rank_) { - float accAvg (accSum_ / i_); - float accDev (std::sqrt(accSumSq_ / i_ - accAvg*accAvg)); - StatisticsBase::enter(accMin_, accAvg, accMax_, accDev); - i_ = 0; + + if (i_ + n >= rank_) { + accSum_ += (rank_-i_)*avg; + accSumSq_ += (rank_-i_)*(rank_-i_)*(avg*avg + dev*dev); + float accAvg (accSum_ / rank_); + float accDev (std::sqrt(std::max(0.0f,accSumSq_ / rank_ - accAvg*accAvg))); + StatisticsBase::enter(1, accMin_, accAvg, accMax_, accDev); accMin_ = FLT_MAX; accSum_ = 0.0f; accSumSq_ = 0.0f; accMax_ = -FLT_MAX; + n -= (rank_ - i_); + i_ = 0; + + if (n >= rank_) { + std::div_t d (std::div(int(n), int(rank_))); + StatisticsBase::enter(d.quot, min, avg, max, dev); + n = d.rem; + } + } + + if (n>0) { + accSum_ += n*avg; + accSumSq_ += n*n*(avg*avg+dev*dev); + i_ += n; + if (min < accMin_) accMin_ = min; + if (max > accMax_) accMax_ = max; } } @@ -328,7 +327,7 @@ prefix_ std::string senf::Collector::v_path() return owner_->path() + "-" + senf::str(rank_); } -///////////////////////////////cc.e//////////////////////////////////////// +//-///////////////////////////////////////////////////////////////////////////////////////////////// #undef prefix_ //#include "Statistics.mpp"