Search:

SENF Extensible Network Framework

  • Home
  • Download
  • Wiki
  • BerliOS
  • ChangeLog
  • Browse SVN
  • Bug Tracker
  • Overview
  • Examples
  • HowTos
  • Glossary
  • PPI
  • Packets
  • Scheduler
  • Socket
  • Utils
  • Console
  • Daemon
  • Logger
  • Termlib
  • Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

Statistics.cc

Go to the documentation of this file.
00001 // $Id: Statistics.cc 1781 2011-04-11 12:10:19Z tho $
00002 //
00003 // Copyright (C) 2008
00004 // Fraunhofer (FOKUS)
00005 // Competence Center NETwork research (NET), St. Augustin, GERMANY
00006 //     Stefan Bund <g0dil@berlios.de>
00007 //
00008 // This program is free software; you can redistribute it and/or modify
00009 // it under the terms of the GNU General Public License as published by
00010 // the Free Software Foundation; either version 2 of the License, or
00011 // (at your option) any later version.
00012 //
00013 // This program is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 // GNU General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU General Public License
00019 // along with this program; if not, write to the
00020 // Free Software Foundation, Inc.,
00021 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022 
00026 #include "Statistics.hh"
00027 //#include "Statistics.ih"
00028 
00029 // Custom includes
00030 #include <cmath>
00031 #include <cstdlib>
00032 #include <sstream>
00033 #include <senf/Utils/Format.hh>
00034 #include <senf/Utils/Console/STLSupport.hh>
00035 #include "StatisticsTargets.hh"
00036 
00037 //#include "Statistics.mpp"
00038 #define prefix_
00039 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00040 
00041 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00042 // senf::StatisticsBase
00043 
00044 prefix_ void senf::StatisticsBase::enter(unsigned n, float min, float avg, float max, float dev)
00045 {
00046     min_ = min;
00047     avg_ = avg;
00048     max_ = max;
00049     dev_ = dev;
00050     for (unsigned i (0); i < n; ++i)
00051         generateOutput();
00052     Children::iterator i (children_.begin());
00053     Children::iterator const i_end  (children_.end());
00054     for (; i != i_end; ++i)
00055         i->second.enter(n, min_, avg_, max_, dev_);
00056 }
00057 
00058 prefix_ senf::Collector & senf::StatisticsBase::operator[](unsigned rank)
00059 {
00060     Children::iterator i (children_.find(rank));
00061     if (i == children_.end())
00062         throw InvalidRankException();
00063     return i->second;
00064 }
00065 
00066 prefix_ senf::Collector const & senf::StatisticsBase::operator[](unsigned rank)
00067     const
00068 {
00069     Children::const_iterator i (children_.find(rank));
00070     if (i == children_.end())
00071         throw InvalidRankException();
00072     return i->second;
00073 }
00074 
00075 prefix_ senf::Collector & senf::StatisticsBase::collect(unsigned rank)
00076 {
00077     std::pair<Children::iterator, bool> state (
00078         children_.insert(std::make_pair(rank, Collector(this, rank))) );
00079     if (! state.second)
00080         throw DuplicateRankException();
00081     return state.first->second;
00082 }
00083 
00084 prefix_ senf::StatisticsBase::OutputProxy<senf::StatisticsBase>
00085 senf::StatisticsBase::output(unsigned n)
00086 {
00087     OutputMap::iterator i (outputs_.find(n));
00088     if (i == outputs_.end()) {
00089         i = outputs_.insert(std::make_pair(n, OutputEntry(n))).first;
00090         std::stringstream nm;
00091         nm << "output" << path() << ":" << n;
00092         base().dir.node().add(nm.str(), i->second.dir);
00093         detail::StatisticsLoggerRegistry::instance().apply(*this, n, i->second.dir);
00094     }
00095     if (n > maxQueueLen_)
00096         maxQueueLen_ = n;
00097     return OutputProxy<StatisticsBase>(this, &(i->second));
00098 }
00099 
00100 prefix_ void senf::StatisticsBase::consoleList(unsigned level, std::ostream & os)
00101     const
00102 {
00103     namespace fmt = senf::format;
00104 
00105     os << boost::format("%s%-5d%|15t|  %12.5g  %19.5g  %12.5g\n")
00106         % std::string(2*level,' ') % rank()
00107         % fmt::eng(min()).setw() % fmt::eng(avg(),dev()).setw() % fmt::eng(max()).setw();
00108     {
00109         OutputMap::const_iterator i (outputs_.begin());
00110         OutputMap::const_iterator i_end (outputs_.end());
00111         for (; i != i_end; ++i)
00112             os << boost::format("            %3d  %12.5g  %19.5g  %12.5g\n")
00113                 % i->second.n
00114                 % fmt::eng(i->second.min).setw()
00115                 % fmt::eng(i->second.avg, i->second.dev).setw()
00116                 % fmt::eng(i->second.max).setw();
00117     }
00118     {
00119         Children::const_iterator i (children_.begin());
00120         Children::const_iterator const i_end (children_.end());
00121         for (; i != i_end; ++i)
00122             i->second.consoleList(level+1, os);
00123     }
00124 }
00125 
00126 prefix_ void senf::StatisticsBase::generateOutput()
00127 {
00128     queue_.push_front(QueueEntry(min_, avg_, max_, dev_));
00129     while (queue_.size() > maxQueueLen_)
00130         queue_.pop_back();
00131 
00132     OutputMap::iterator i (outputs_.begin());
00133     OutputMap::iterator const i_end (outputs_.end());
00134     for (; i != i_end; ++i) {
00135         i->second.min = i->second.avg = i->second.max = i->second.dev = 0.0f;
00136         Queue::const_iterator j (queue_.begin());
00137         Queue::const_iterator const j_end (queue_.end());
00138         unsigned n (0);
00139         for (; n < i->second.n && j != j_end; ++n, ++j) {
00140             i->second.min += j->min;
00141             i->second.avg += j->avg;
00142             i->second.max += j->max;
00143             i->second.dev += j->dev;
00144         }
00145         i->second.min /= n;
00146         i->second.avg /= n;
00147         i->second.max /= n;
00148         i->second.dev /= n;
00149         i->second.signal(i->second.min, i->second.avg, i->second.max, i->second.dev);
00150     }
00151 }
00152 
00153 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00154 // senf::StatisticsBase::OutputEntry
00155 
00156 prefix_ void senf::StatisticsBase::OutputEntry::consoleList(std::ostream & os)
00157 {
00158     for (boost::ptr_vector<TargetBase>::iterator i (targets_.begin());
00159          i != targets_.end(); ++i)
00160         if (! i->label.empty())
00161             os << i->label << "\n";
00162 }
00163 
00164 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00165 // senf::Statistics
00166 
00167 prefix_ senf::Statistics::Statistics()
00168 #ifndef SENF_DISABLE_CONSOLE
00169     : dir (this)
00170 #endif
00171 {
00172 #ifndef SENF_DISABLE_CONSOLE
00173     namespace fty = console::factory;
00174 
00175     dir.add("list", fty::Command(&Statistics::consoleList, this)
00176             .doc("List statistics collection intervals and current values.\n"
00177                  "\n"
00178                  "Columns:\n"
00179                  "    RANK    Number of values collected. Since the statistics collectors form\n"
00180                  "            a tree, the value is indented according to it's tree location.\n"
00181                  "    WIN     Size of output average window.\n"
00182                  "    MIN     Last entered minimum value.\n"
00183                  "    AVG     Last entered average value.\n"
00184                  "    DEV     Standard deviation of average value over the collector rank.\n"
00185                  "    MAX     Last entered maximum value.") );
00186     dir.add("collect", fty::Command(&Statistics::consoleCollect, this)
00187             .doc("Add statistics collection groups. The argument gives a sequence of collector\n"
00188                  "ranks each building on the preceding collector:\n"
00189                  "\n"
00190                  "    $ collect (10 60 60)\n"
00191                  "\n"
00192                  "Will start by collecting every 10 values together to a new value. 60 of such\n"
00193                  "combined values will be collected together in the next step again followed by\n"
00194                  "a collection of 60 values. If the statistics is entered with a frequency of\n"
00195                  "10 values per second, this will provide combined statistics over the second,\n"
00196                  "minutes and hours ranges.\n"
00197                  "\n"
00198                  "You may call collect multiple times. Any missing collection ranks will be\n"
00199                  "added.")
00200             .arg("ranks","chain of collector ranks") );
00201     dir.add("output", fty::Command(&Statistics::consoleOutput, this)
00202             .doc("Generate statistics output. This statement will add an additional output\n"
00203                  "generator. This generator will be attached to the collector specified by\n"
00204                  "the {rank} parameter. This parameter is a chain of successive rank values\n"
00205                  "which specifies the exact collector to use. If the collector does not\n"
00206                  "exist, it will be created (this is like automatically calling 'collect'\n"
00207                  "with {rank} as argument).\n"
00208                  "\n"
00209                  "If the output is to be sent somewhere it must be connected to a statistics\n"
00210                  "target.\n"
00211                  "\n"
00212                  "The output may optionally be built using a sliding average over the last\n"
00213                  "{window} values.\n"
00214                  "\n"
00215                  "    $ output ()\n"
00216                  "\n"
00217                  "will output the basic statistics value each time a new value is entered.\n"
00218                  "\n"
00219                  "    $ output (10 60) 5\n"
00220                  "\n"
00221                  "Assuming that new data values are entered 10 times per second, this command\n"
00222                  "will generate output once every minute. The value will be the average over\n"
00223                  "the last 5 minutes.")
00224             .arg("rank","Rank chain selecting the value to generate output for")
00225             .arg("window","Optional size of sliding average window",
00226                  console::kw::default_value = 1u) );
00227 #endif
00228 }
00229 
00230 prefix_ void senf::Statistics::consoleList(std::ostream & os)
00231 {
00232     os << "RANK        WIN       MIN          AVG                   MAX\n";
00233     StatisticsBase::consoleList(0, os);
00234 }
00235 
00236 prefix_ void senf::Statistics::consoleCollect(std::vector<unsigned> & ranks)
00237 {
00238     StatisticsBase * stats (this);
00239     std::vector<unsigned>::const_iterator i (ranks.begin());
00240     std::vector<unsigned>::const_iterator const i_end (ranks.end());
00241 
00242     try {
00243         for (; i != i_end; ++i)
00244             stats = &(*stats)[*i];
00245     }
00246     catch (InvalidRankException &) {}
00247 
00248     for (; i != i_end; ++i)
00249         stats = & (stats->collect(*i));
00250 
00251 }
00252 
00253 prefix_  boost::shared_ptr<senf::console::DirectoryNode>
00254 senf::Statistics::consoleOutput(std::vector<unsigned> & ranks, unsigned window)
00255 {
00256     StatisticsBase * stats (this);
00257     std::vector<unsigned>::const_iterator i (ranks.begin());
00258     std::vector<unsigned>::const_iterator const i_end (ranks.end());
00259 
00260     try {
00261         for (; i != i_end; ++i)
00262             stats = &(*stats)[*i];
00263     }
00264     catch (InvalidRankException &) {}
00265 
00266     for (; i != i_end; ++i)
00267         stats = & (stats->collect(*i));
00268 
00269     return stats->output(window).dir().node().thisptr();
00270 }
00271 
00272 prefix_ senf::Statistics & senf::Statistics::v_base()
00273 {
00274     return *this;
00275 }
00276 
00277 prefix_ std::string senf::Statistics::v_path()
00278     const
00279 {
00280     return "";
00281 }
00282 
00283 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00284 // senf::Collector
00285 
00286 prefix_ void senf::Collector::enter(unsigned n, float min, float avg, float max, float dev)
00287 {
00288     if (min < accMin_) accMin_ = min;
00289     if (max > accMax_) accMax_ = max;
00290 
00291     if (i_ + n >= rank_) {
00292         accSum_ += (rank_-i_)*avg;
00293         accSumSq_ += (rank_-i_)*(rank_-i_)*(avg*avg + dev*dev);
00294         float accAvg (accSum_ / rank_);
00295         float accDev (std::sqrt(std::max(0.0f,accSumSq_ / rank_ - accAvg*accAvg)));
00296         StatisticsBase::enter(1, accMin_, accAvg, accMax_, accDev);
00297         accMin_ = FLT_MAX;
00298         accSum_ = 0.0f;
00299         accSumSq_ = 0.0f;
00300         accMax_ = -FLT_MAX;
00301         n -= (rank_ - i_);
00302         i_ = 0;
00303 
00304         if (n >= rank_) {
00305             std::div_t d (std::div(int(n), int(rank_)));
00306             StatisticsBase::enter(d.quot, min, avg, max, dev);
00307             n = d.rem;
00308         }
00309     }
00310 
00311     if (n>0) {
00312         accSum_ += n*avg;
00313         accSumSq_ += n*n*(avg*avg+dev*dev);
00314         i_ += n;
00315         if (min < accMin_) accMin_ = min;
00316         if (max > accMax_) accMax_ = max;
00317     }
00318 }
00319 
00320 prefix_ senf::Statistics & senf::Collector::v_base()
00321 {
00322     return owner_->base();
00323 }
00324 
00325 prefix_ std::string senf::Collector::v_path()
00326     const
00327 {
00328     return owner_->path() + "-" + senf::str(rank_);
00329 }
00330 
00331 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00332 #undef prefix_
00333 //#include "Statistics.mpp"
00334 
00335 
00336 // Local Variables:
00337 // mode: c++
00338 // fill-column: 100
00339 // comment-column: 40
00340 // c-file-style: "senf"
00341 // indent-tabs-mode: nil
00342 // ispell-local-dictionary: "american"
00343 // compile-command: "scons -u test"
00344 // End:

Contact: senf-dev@lists.berlios.de | © 2006-2010 Fraunhofer Institute for Open Communication Systems, Network Research