--- /dev/null
+// $Id$
+//
+// Copyright (C) 2008
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief RateAnalyzer non-inline non-template implementation */
+
+#include "RateAnalyzer.hh"
+//#include "RateAnalyzer.ih"
+
+// Custom includes
+
+//#include "RateAnalyzer.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+prefix_ senf::ppi::module::RateAnalyzer::RateAnalyzer()
+ : packets_ (0u), bytes_ (0u), minSize_ (0u), maxSize_ (0u), factor_ (0.0f)
+{
+ registerEvent(timer_, &RateAnalyzer::tick);
+}
+
+prefix_ void senf::ppi::module::RateAnalyzer::startStatistics(senf::ClockService::clock_type interval)
+{
+ timer_.interval(interval);
+ factor_ = double(senf::ClockService::in_nanoseconds(interval)) /
+ double(senf::ClockService::in_nanoseconds(
+ senf::ClockService::seconds(1)));
+}
+
+prefix_ void senf::ppi::module::RateAnalyzer::v_handlePacket(Packet const & p)
+{
+ ++packets_;
+ unsigned sz (p.data().size());
+ bytes_ += sz;
+ if (sz < minSize_ || minSize_ == 0u) minSize_ = sz;
+ if (sz > maxSize_) maxSize_ = sz;
+}
+
+prefix_ void senf::ppi::module::RateAnalyzer::tick()
+{
+ signals.packetsPerSecond(packets_/factor_);
+ signals.bytesPerSecond(bytes_/factor_);
+ signals.bytesPerPacket(minSize_, float(bytes_)/float(packets_), maxSize_);
+
+ packets_ = bytes_ = minSize_ = maxSize_ = 0;
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "RateAnalyzer.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2008
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief RateAnalyzer public header */
+
+#ifndef HH_SENF_PPI_RateAnalyzer_
+#define HH_SENF_PPI_RateAnalyzer_ 1
+
+// Custom includes
+#include <boost/function.hpp>
+#include <boost/signal.hpp>
+#include "MonitorModule.hh"
+#include "IntervalTimer.hh"
+
+//#include "RateAnalyzer.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+namespace ppi {
+namespace module {
+
+ /** \brief Generate periodic packet statistics
+
+ This module will periodically generate statistics concerning the traversing packets. The
+ statistics are emitted as Boost.Signals signals:
+
+ \li \c signals.packetsPerSecond: number of packets in the last interval scaled to 1 second
+ \li \c signals.bytesPerSecond; number of bytes in the last interval scaled to 1 second
+ \li \c signals.bytesPerPacket: minimal, average and maximal packet size in the last interval
+
+ These signals are normally connected as needed to senf::Statistics instances.
+
+ \code
+ senf::RateAnalyzer analyzer;
+ senf::Statistics packets;
+ senf::Statistics packetSize;
+
+ analyzer.signals.packetsPerSecond.connect(packets);
+ analyzer.signals.bytesPerPacket.connect(packetSize);
+
+ analyzer.startStatistics(senf::ClockService::milliseconds(100u));
+ \endcode
+
+ Statistics output is only generated after a call to startStatistics()
+
+ \ingroup routing_modules
+ */
+ class RateAnalyzer
+ : public MonitorModule<>
+ {
+ SENF_PPI_MODULE(RateAnalyzer);
+ public:
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Structors and default members
+ ///\{
+
+ RateAnalyzer();
+
+ ///\}
+ ///////////////////////////////////////////////////////////////////////////
+ // Statistics signals
+
+ struct Statistics {
+ boost::signal<void (float)> packetsPerSecond;
+ boost::signal<void (float)> bytesPerSecond;
+ boost::signal<void (unsigned,float,unsigned)> bytesPerPacket;
+ } signals;
+
+ void startStatistics(senf::ClockService::clock_type interval);
+ ///< Start generating statistics at given interval
+
+ private:
+ void v_handlePacket(Packet const & p);
+ void tick();
+
+ senf::ppi::IntervalTimer timer_;
+ unsigned packets_;
+ unsigned bytes_;
+ unsigned minSize_;
+ unsigned maxSize_;
+ double factor_;
+ };
+
+}}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "RateAnalyzer.cci"
+//#include "RateAnalyzer.ct"
+//#include "RateAnalyzer.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2008
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief RateAnalyzer unit tests */
+
+//#include "RateAnalyzer.test.hh"
+//#include "RateAnalyzer.test.ih"
+
+// Custom includes
+#include "RateAnalyzer.hh"
+#include "PPI.hh"
+
+#include "../Utils/auto_unit_test.hh"
+#include <boost/test/test_tools.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace {
+
+ unsigned calls (0u);
+ float ppss[] = { 13.333333f, 20.f, 13.333333f, 20.f, 13.333333f, 20.f };
+
+ float pps;
+ float bps;
+
+ void collectPPS(float packetsPerSecond)
+ {
+ // 2 + 3 + 2 + 3 + 2 + 3 packets / interval
+ // -> 13.333333 + 20. + 13.333333 + 20. + 13.333333 + 20. / 6 pps
+ // -> 16.666666 pps
+ // -> 216.66666 bps
+ // This test sometime fails when system load is to high ...
+ // BOOST_CHECK_CLOSE( packetsPerSecond, ppss[calls], 0.1f );
+ pps += packetsPerSecond;
+ ++ calls;
+ if (calls >= sizeof(ppss) / sizeof(ppss[0]))
+ senf::scheduler::terminate();
+ }
+
+ void collectBPS(float bytesPerSecond)
+ {
+ bps += bytesPerSecond;
+ }
+
+ void collectSize(float min, float avg, float max)
+ {
+ BOOST_CHECK_CLOSE(min, 13.f, 0.01f);
+ BOOST_CHECK_CLOSE(avg, 13.f, 0.01f);
+ BOOST_CHECK_CLOSE(max, 13.f, 0.01f);
+ }
+}
+
+BOOST_AUTO_UNIT_TEST(rateAnalyzer)
+{
+ senf::DataPacket p (senf::DataPacket::create(13u));
+ senf::ppi::module::CloneSource source (p);
+ senf::ppi::module::RateFilter filter (senf::ClockService::milliseconds(58u));
+ senf::ppi::module::RateAnalyzer analyzer;
+ analyzer.startStatistics(senf::ClockService::milliseconds(150u));
+ analyzer.signals.packetsPerSecond.connect(&collectPPS);
+ analyzer.signals.bytesPerSecond.connect(&collectBPS);
+ analyzer.signals.bytesPerPacket.connect(&collectSize);
+
+ senf::ppi::connect(source, filter);
+ senf::ppi::connect(filter, analyzer);
+
+ senf::ppi::run();
+
+ BOOST_CHECK_EQUAL( calls, 6u );
+
+ pps /= calls;
+ bps /= calls;
+
+ BOOST_CHECK_CLOSE( pps, 16.67f, .1f );
+ BOOST_CHECK_CLOSE( bps, 216.67f, .1f );
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
<table class="listing">
<tr><td>\ref exception</td><td>standard exception for system errors (errno)</td></tr>
+ <tr><td>\ref senf_statistics</td><td>statistics functionality</td></tr>
+
<tr><td>\ref hexdump</td><td>a simple but usefull function to write binary data in in
hexadecimal format.</td></tr>
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2008
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief Statistics non-inline non-template implementation */
+
+#include "Statistics.hh"
+//#include "Statistics.ih"
+
+// Custom includes
+#include <sstream>
+#include "Console/Console.hh"
+#include "StatisticsTargets.hh"
+
+//#include "Statistics.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::StatisticsBase
+
+prefix_ void senf::StatisticsBase::enter(float min, float avg, float max)
+{
+ min_ = min;
+ avg_ = avg;
+ max_ = max;
+ generateOutput();
+ signalChildren();
+}
+
+prefix_ senf::Collector & senf::StatisticsBase::operator[](unsigned rank)
+{
+ Children::iterator i (children_.find(rank));
+ if (i == children_.end())
+ throw InvalidRankException();
+ return i->second;
+}
+
+prefix_ senf::Collector & senf::StatisticsBase::collect(unsigned rank)
+{
+ std::pair<Children::iterator, bool> state (
+ children_.insert(std::make_pair(rank, Collector(this, rank))) );
+ if (! state.second)
+ throw DuplicateRankException();
+ return state.first->second;
+}
+
+prefix_ senf::StatisticsBase::OutputProxy<senf::StatisticsBase>
+senf::StatisticsBase::output(unsigned n)
+{
+ OutputMap::iterator i (outputs_.find(n));
+ if (i == outputs_.end()) {
+ i = outputs_.insert(std::make_pair(n, OutputEntry(n))).first;
+ std::stringstream nm;
+ nm << "output" << path() << ":" << n;
+ base().dir.node().add(nm.str(), i->second.dir);
+ detail::StatisticsLoggerRegistry::instance().apply(*this, n, i->second.dir);
+ }
+ if (n > maxQueueLen_)
+ maxQueueLen_ = n;
+ return OutputProxy<StatisticsBase>(this, &(i->second));
+}
+
+prefix_ void senf::StatisticsBase::consoleList(unsigned level, std::ostream & os)
+ const
+{
+ os << boost::format("%s%-5d%|15t| %12g %12g %12g\n")
+ % std::string(2*level,' ') % rank() % min() % avg() % max();
+ {
+ OutputMap::const_iterator i (outputs_.begin());
+ OutputMap::const_iterator i_end (outputs_.end());
+ for (; i != i_end; ++i)
+ os << boost::format(" %3d %12g %12g %12g\n")
+ % i->second.n
+ % (i->second.min/i->second.n)
+ % (i->second.avg/i->second.n)
+ % (i->second.max/i->second.n);
+ }
+ {
+ Children::const_iterator i (children_.begin());
+ Children::const_iterator const i_end (children_.end());
+ for (; i != i_end; ++i)
+ i->second.consoleList(level+1, os);
+ }
+}
+
+prefix_ void senf::StatisticsBase::generateOutput()
+{
+ queue_.push_front(QueueEntry(min_, avg_, max_));
+ while (queue_.size() > maxQueueLen_)
+ queue_.pop_back();
+
+ OutputMap::iterator i (outputs_.begin());
+ OutputMap::iterator const i_end (outputs_.end());
+ for (; i != i_end; ++i) {
+ i->second.min = i->second.avg = i->second.max = 0.0f;
+ Queue::const_iterator j (queue_.begin());
+ Queue::const_iterator const j_end (queue_.end());
+ unsigned n (0);
+ for (; n < i->second.n && j != j_end; ++n, ++j) {
+ i->second.min += j->min;
+ i->second.avg += j->avg;
+ i->second.max += j->max;
+ }
+ i->second.signal(i->second.min/n, i->second.avg/n, i->second.max/n);
+ }
+}
+
+prefix_ void senf::StatisticsBase::signalChildren()
+{
+ Children::iterator i (children_.begin());
+ Children::iterator const i_end (children_.end());
+ for (; i != i_end; ++i)
+ i->second.enter(min_, avg_, max_);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::Statistics
+
+prefix_ senf::Statistics::Statistics()
+#ifndef SENF_DISABLE_CONSOLE
+ : dir (this)
+#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"
+ " 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);
+#endif
+}
+
+prefix_ void senf::Statistics::consoleList(std::ostream & os)
+{
+ os << "RANK WIN MIN AVG MAX\n";
+ StatisticsBase::consoleList(0, os);
+}
+
+prefix_ void senf::Statistics::consoleCollect(std::vector<unsigned> & ranks)
+{
+ StatisticsBase * stats (this);
+ std::vector<unsigned>::const_iterator i (ranks.begin());
+ std::vector<unsigned>::const_iterator const i_end (ranks.end());
+
+ try {
+ for (; i != i_end; ++i)
+ stats = &(*stats)[*i];
+ }
+ catch (InvalidRankException &) {}
+
+ for (; i != i_end; ++i)
+ stats = & (stats->collect(*i));
+
+}
+
+prefix_ boost::shared_ptr<senf::console::DirectoryNode>
+senf::Statistics::consoleOutput(std::vector<unsigned> & ranks, unsigned window)
+{
+ StatisticsBase * stats (this);
+ std::vector<unsigned>::const_iterator i (ranks.begin());
+ std::vector<unsigned>::const_iterator const i_end (ranks.end());
+
+ try {
+ for (; i != i_end; ++i)
+ stats = &(*stats)[*i];
+ }
+ catch (InvalidRankException &) {}
+
+ for (; i != i_end; ++i)
+ stats = & (stats->collect(*i));
+
+ return stats->output(window).dir().node().thisptr();
+}
+
+prefix_ senf::Statistics & senf::Statistics::v_base()
+{
+ return *this;
+}
+
+prefix_ std::string senf::Statistics::v_path()
+ const
+{
+ return "";
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::Collector
+
+prefix_ void senf::Collector::enter(float min, float avg, float max)
+{
+ accAvg_ += avg;
+ if (min < accMin_) accMin_ = min;
+ if (max > accMax_) accMax_ = max;
+ if (++i_ >= rank_) {
+ StatisticsBase::enter(accMin_, accAvg_ / rank_, accMax_);
+ i_ = 0;
+ accMin_ = FLT_MAX;
+ accAvg_ = 0.0f;
+ accMax_ = -FLT_MAX;
+ }
+}
+
+prefix_ senf::Statistics & senf::Collector::v_base()
+{
+ return owner_->base();
+}
+
+prefix_ std::string senf::Collector::v_path()
+ const
+{
+ return owner_->path() + "-" + senf::str(rank_);
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "Statistics.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2008
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief Statistics inline non-template implementation */
+
+//#include "Statistics.ih"
+
+// Custom includes
+#include <float.h>
+#include "Range.hh"
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::StatisticsBase::Transform
+
+prefix_ senf::StatisticsBase::Transform::result_type
+senf::StatisticsBase::Transform::operator()(first_argument_type i)
+ const
+{
+ return i.second;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::StatisticsBase::OutputEntry
+
+prefix_ senf::StatisticsBase::OutputEntry::OutputEntry()
+ : n(), min(), avg(), max()
+{
+ initDir();
+}
+
+prefix_ senf::StatisticsBase::OutputEntry::OutputEntry(unsigned n_)
+ : n(n_), min(), avg(), max()
+{
+ initDir();
+}
+
+prefix_ senf::StatisticsBase::OutputEntry::OutputEntry(const OutputEntry& other)
+ : n(other.n), min(other.min), avg(other.avg), max(other.max)
+{
+ initDir();
+}
+
+prefix_ void senf::StatisticsBase::OutputEntry::initDir()
+{
+ dir.add("list", senf::membind(&OutputEntry::consoleList, this))
+ .doc("List all known connected targets. This list might not be complete.");
+}
+
+prefix_ senf::StatisticsBase::OutputEntry &
+senf::StatisticsBase::OutputEntry::operator=(const OutputEntry& other)
+{
+ n = other.n;
+ min = other.min;
+ avg = other.avg;
+ max = other.max;
+ return *this;
+}
+
+prefix_ void senf::StatisticsBase::OutputEntry::consoleList(std::ostream & os)
+{
+ for (boost::ptr_vector<TargetBase>::iterator i (targets_.begin());
+ i != targets_.end(); ++i)
+ if (! i->label.empty())
+ os << i->label << "\n";
+}
+
+/////////////////////////////////////////////////////////////////////////
+// senf::StatisticsBase
+
+prefix_ senf::StatisticsBase::StatisticsBase()
+ : min_ (0.0f), avg_ (0.0f), max_ (0.0f), maxQueueLen_ (0u)
+{}
+
+prefix_ senf::StatisticsBase::~StatisticsBase()
+{}
+
+prefix_ senf::StatisticsBase::CollectorRange senf::StatisticsBase::collectors()
+{
+ return senf::make_transform_range(children_, Transform());
+}
+
+prefix_ float senf::StatisticsBase::min()
+ const
+{
+ return min_;
+}
+
+prefix_ float senf::StatisticsBase::avg()
+ const
+{
+ return avg_;
+}
+
+prefix_ float senf::StatisticsBase::max()
+ const
+{
+ return max_;
+}
+
+prefix_ unsigned senf::StatisticsBase::rank()
+ const
+{
+ return 1;
+}
+
+prefix_ senf::Statistics & senf::StatisticsBase::base()
+{
+ return v_base();
+}
+
+prefix_ std::string senf::StatisticsBase::path()
+ const
+{
+ return v_path();
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::Collector
+
+prefix_ senf::Collector::Collector(StatisticsBase * owner, unsigned rank)
+ : rank_ (rank), i_ (0u), accMin_ (FLT_MAX), accAvg_ (0.0f), accMax_ (-FLT_MAX),
+ owner_ (owner)
+{}
+
+prefix_ unsigned senf::Collector::rank()
+ const
+{
+ return rank_;
+}
+
+prefix_ senf::StatisticsBase::OutputProxy<senf::Collector>
+senf::Collector::output(unsigned n)
+{
+
+ return StatisticsBase::OutputProxy<Collector>(this, StatisticsBase::output(n));
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::Statistics
+
+prefix_ void senf::Statistics::operator()(float min, float avg, float max)
+{
+ enter(min, avg, max);
+}
+
+prefix_ void senf::Statistics::operator()(float value)
+{
+ enter(value, value, value);
+}
+
+prefix_ senf::StatisticsBase::OutputProxy<senf::Statistics>
+senf::Statistics::output(unsigned n)
+{
+ return StatisticsBase::OutputProxy<Statistics>(this, StatisticsBase::output(n));
+}
+
+///////////////////////////////cci.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2009
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief Statistics inline template implementation */
+
+//#include "Statistics.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::StatisticsBase::OutputProxy
+
+template <class Owner>
+prefix_ senf::StatisticsBase::OutputProxy<Owner>::OutputProxy(Owner * owner, OutputEntry * entry)
+ : owner_ (owner), entry_ (entry)
+{}
+
+template <class Owner>
+template <class OtherOwner>
+prefix_ senf::StatisticsBase::OutputProxy<Owner>::
+OutputProxy(Owner * owner, OutputProxy<OtherOwner> const & other)
+ : owner_ (owner), entry_ (other.entry_)
+{}
+
+template <class Owner>
+template <class Target>
+prefix_ Owner & senf::StatisticsBase::OutputProxy<Owner>::connect(Target & target, std::string label)
+ const
+{
+ if (label.empty())
+ label = prettyName(typeid(Target));
+ entry_->signal.connect(boost::ref(target));
+ entry_->targets_.push_back(new OutputEntry::Target<Target>(label));
+ return * owner_;
+}
+
+template <class Owner>
+template <class PTarget>
+prefix_ Owner &
+senf::StatisticsBase::OutputProxy<Owner>::connect(std::auto_ptr<PTarget> target, std::string label)
+ const
+{
+ if (label.empty())
+ label = prettyName(typeid(PTarget));
+ PTarget * targetp (target.get());
+ entry_->targets_.push_back(new OutputEntry::Target<PTarget>(target,label));
+ entry_->signal.connect(boost::ref(*targetp));
+ return * owner_;
+}
+
+template <class Owner>
+prefix_ Owner & senf::StatisticsBase::OutputProxy<Owner>::noconnect()
+ const
+{
+ return * owner_;
+}
+
+template <class Owner>
+prefix_ senf::console::ScopedDirectory<> & senf::StatisticsBase::OutputProxy<Owner>::dir()
+ const
+{
+ return entry_->dir;
+}
+
+///////////////////////////////cti.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2008
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief Statistics public header */
+
+#ifndef HH_SENF_Utils_Statistics_
+#define HH_SENF_Utils_Statistics_ 1
+
+// Custom includes
+#include <map>
+#include <vector>
+#include <deque>
+#include <boost/iterator/transform_iterator.hpp>
+#include <boost/range/iterator_range.hpp>
+#include <boost/utility.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+#include <boost/signals.hpp>
+#include "Exception.hh"
+#include "Logger/Logger.hh"
+#include "Console/Console.hh"
+
+//#include "Statistics.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+
+ /** \defgroup senf_statistics Statistics
+
+ The statistics functionality has two parts:
+
+ \li the senf::Statistics class
+ \li statistics sources
+
+ Each senf::Statistics instance collects information about a single parameter. Which
+ parameter is set up by connecting the Statistics instance with an arbitrary statistics
+ source.
+
+ %Statistics sources are <a href="http://www.boost.org/doc/libs/1_37_0/doc/html/signals.html">
+ Boost Signals</a> which are emitted periodically to provide new data.
+ */
+
+ class Collector;
+ class Statistics;
+
+ /** \brief Internal: Generic Statistics collection */
+ class StatisticsBase
+ {
+ typedef std::map<unsigned, Collector> Children;
+
+ struct Transform {
+ typedef Children::value_type & first_argument_type;
+ typedef Collector & result_type;
+ result_type operator()(first_argument_type i) const;
+ };
+
+ typedef boost::transform_iterator<Transform,Children::iterator> ValueIterator;
+
+ struct OutputEntry;
+
+ public:
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ typedef boost::iterator_range<ValueIterator> CollectorRange;
+
+ /** \brief Output connection interface
+
+ This class is returned from senf::StatisticsBase::output() and the derived
+ <tt>output()</tt> implementations to allow connecting an output with an arbitrary
+ target.
+
+ There are two types of targets:
+ \li <em>Externally managed targets</em>. These targets live outside of the statistics
+ module, just a reference to those targets is saved. The target should derive from
+ <tt>boost::signals::trackable</tt> to ensure they are automatically disconnected
+ when destroyed.
+ \li <em>Internally managed targets</em>. Those targets are owned by the statistics
+ module and will be destroyed when the statistics class is destroyed.
+
+ Externally managed targets are passed by non-const reference to connect(), internally
+ managed targets are passed using <tt>std::auto_ptr</tt>.
+
+ A target is any callable object which takes three float values as argument: The current
+ minimum, average and maximum value.
+
+ \code
+ // Simple function as statistics target
+ void collect(float min, float avg, float max)
+ { ... }
+
+ // Function object
+ struct Collector
+ {
+ void operator()(float min, float avg, float max)
+ { ... }
+ };
+ \endcode
+
+ \ingroup senf_statistics
+ */
+ template <class Owner>
+ class OutputProxy
+ {
+ public:
+ template <class Target> Owner & connect(Target & target,
+ std::string label="") const;
+ ///< Connect externally managed target
+ template <class PTarget> Owner & connect(std::auto_ptr<PTarget> target,
+ std::string label="") const;
+ ///< Connect internally managed target
+ Owner & noconnect() const; ///< Don't connect the output
+ senf::console::ScopedDirectory<> & dir() const;
+ ///< Get target's console directory
+
+#ifdef DOXYGEN
+ private:
+#endif
+ OutputProxy(Owner * owner, OutputEntry * entry);
+ template <class OtherOwner>
+ OutputProxy(Owner * owner, OutputProxy<OtherOwner> const & other);
+
+ private:
+ Owner * owner_;
+ OutputEntry * entry_;
+
+ template <class OtherOwner> friend class OutputProxy;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Accessing the current value
+ ///\{
+
+ float min() const; ///< Last min value entered
+ float avg() const; ///< Last avg value entered
+ float max() const; ///< Last max value entered
+
+ virtual unsigned rank() const; ///< Return collectors rank value
+ /**< \returns number of basic values collected into each new
+ value by this collector. */
+
+ ///\}
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Child collectors
+ ///\{
+
+ Collector & operator[](unsigned rank);
+ ///< Get child collector
+ /**< This member will return a reference to the collector
+ collecting \a rank values.
+ \param[in] rank Number of values the requested
+ collector collects into each combined value.
+ \throws InvalidRankException if \a rank is not a valid
+ registered rank value. */
+ CollectorRange collectors(); ///< List all child collectors
+ /**< \returns iterator range of child collector
+ references */
+
+ Collector & collect(unsigned rank); ///< Register a new collector
+ /**< Adds a collector collecting \a rank values into each
+ combined value.
+ \param[in] rank number of values to collect
+ \returns Reference to new collector
+ \throws DuplicateRankException if a collector
+ collecting \a rank values already exists. */
+
+ Statistics & base(); ///< Get base statistics object
+ /**< Returns the base statistics object. If this is
+ a child collector, this will return the outermost
+ statistics object, otherwise it will return
+ \c *this. */
+
+ std::string path() const; ///< Get the path to this collector
+ /**< Returns the '-'-separated list of collectors up to
+ here. If this is the basic statistics object, the value
+ is empty, otherwise it is built by joining the
+ collector ranks. */
+
+ ///\}
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Result generation
+
+ OutputProxy<StatisticsBase> output(unsigned n = 1u);
+ ///< Register output
+ /**< This call will request the collector to output
+ statistics build by averaging the last \a n
+ values. This output is generated for every new value in
+ the collector. The output signal can be connected to an
+ arbitrary target using the returned proxy. Example:
+ \code
+ stats.output(4u).connect(
+ senf::StatisticsLogger());
+ \endcode
+ \param[in] n size of sliding average window */
+
+ ///\}
+ ///////////////////////////////////////////////////////////////////////////
+ // Exceptions
+
+ struct InvalidRankException : public senf::Exception
+ { InvalidRankException() : senf::Exception("Invalid rank value") {} };
+
+ struct DuplicateRankException : public senf::Exception
+ { DuplicateRankException() : senf::Exception("Duplicate rank value") {} };
+
+ void consoleList(unsigned level, std::ostream & os) const;
+
+ protected:
+ StatisticsBase();
+ virtual ~StatisticsBase();
+ void enter(float min, float avg, float max);
+
+ private:
+ virtual Statistics & v_base() = 0;
+ virtual std::string v_path() const = 0;
+
+ void generateOutput();
+ void signalChildren();
+
+ float min_;
+ float avg_;
+ float max_;
+ Children children_;
+
+ struct QueueEntry {
+ float min;
+ float avg;
+ float max;
+ QueueEntry() : min(), avg(), max() {}
+ QueueEntry(float min_, float avg_, float max_)
+ : min(min_), avg(avg_), max(max_) {}
+ };
+ typedef std::deque<QueueEntry> Queue;
+ Queue queue_;
+
+ struct OutputEntry {
+ struct TargetBase
+ {
+ explicit TargetBase(std::string const & label_) : label (label_) {}
+ virtual ~TargetBase() {};
+ std::string label;
+ };
+
+ template <class PTarget>
+ struct Target : public TargetBase
+ {
+ boost::scoped_ptr<PTarget> target_;
+ Target(std::auto_ptr<PTarget> target, std::string const & label)
+ : TargetBase (label), target_ (target.release()) {}
+ explicit Target(std::string const & label)
+ : TargetBase (label), target_ (0) {}
+ };
+
+ OutputEntry();
+ explicit OutputEntry(unsigned n_);
+ OutputEntry(const OutputEntry& other);
+ OutputEntry& operator=(const OutputEntry& other);
+
+ void initDir();
+ void consoleList(std::ostream & os);
+
+ unsigned n;
+ float min;
+ float avg;
+ float max;
+
+ boost::signal<void(float,float,float)> signal;
+ boost::ptr_vector<TargetBase> targets_;
+
+ senf::console::ScopedDirectory<> dir;
+ };
+ typedef std::map<unsigned, OutputEntry> OutputMap;
+ OutputMap outputs_;
+ unsigned maxQueueLen_;
+ };
+
+ /** \brief Collect statistics and generate %log messages
+
+ The Statistics class collects information about a single value. The assumption is, that
+ Statistics::operator() is called \e periodically to supply new data.
+
+ Each data entry is comprised of a minimum, average and maximum value. These values should
+ describe the value of whatever parameter is analyzed by a Statistics instance over the last
+ period. The length of the period is defined by the interval, at which data is entered.
+
+ The Statistics class combines successive data values into ever larger groups. These groups
+ form a tree where each node combines a fixed number of data values of it's parent node. An
+ example:
+
+ Let us assume, that Statistics::operator() is called every 100ms. We can than build a chain
+ of collectors:
+ \li The basic statistics module provides information with a resolution of 1/10th of a second
+ \li A collector collecting 10 values provides information with 1 second resolution
+ \li The next collector collects 60 values and provides a resolution of 1 minute
+ \li Again the next collector collects 60 values and provides a resolution of 1 hour
+ \li ... and so on
+
+ This way, we create a hierarchy of values. Each collector manages a minimum, average and
+ maximum value always created over it's the last complete interval.
+
+ It is possible to have more than one collector based on the same basic interval. In above
+ scenario, we might want to add another collector which for example collects information
+ with a 100 second scale. This is possible and changes the list of collectors into a tree.
+
+ Now to turn all this into code:
+
+ \code
+ senf::ppi::module::RateAnalyzer rateAnalyzer;
+ senf::Statistics packetStats;
+
+ rateAnalyzer.signals.packetsPerSecond.connect(boost::ref(packetStats));
+
+ packetStats // called 10 times / second
+ .collect(10u) // seconds
+ .collect(60u) // minutes
+ .collect(60u); // hours
+
+ packetStats[10u].collect(100u); // 100 seconds
+
+ rateAnalyzer.startStatistics(senf::ClockService::milliseconds(100u));
+ \endcode
+
+ This code will collect the statistics as described in the Example above. However, no output
+ will be generated.
+
+ For every collector, any number of outputs may be defined. Each output consists of the
+ number of values to calculate a sliding average over and an identifying label.
+
+ Lets say, we want to produce the following outputs:
+ \li A sliding average of 5 values based on the raw 1/10th second data.
+ \li Three different outputs from the seconds staistics: current value without average,
+ sliding average over 10 seconds and sliding average over 60 seconds.
+ \li Output the minutes and hourly value without averaging.
+
+ To achieve this, we can augment above code in the following way:
+
+ \code
+ packetStats
+ .output( 5u).connect(senf::StatisicsLogger("pps 100ms 5"))
+ .collect(10u)
+ .output( ).noconnect()
+ .output(10u).connect(senf::StatisicsLogger("pps 1s 10"))
+ .output(60u).connect(senf::StatisicsLogger("pps 1s 60"))
+ .collect(60u)
+ .output( ).connect(senf::StatisicsLogger("pps 1min 1"))
+ .collect(60u)
+ .output( ).connect(senf::StatisicsLogger("pps 1h 1"));
+
+ packetStats.output(5u).connect(
+ senf::StatisticsLogger<senf::log::Debug, senf::log::VERBOSE>("pps"));
+
+ senf::log::FileTarget statslog ("stats.log");
+
+ statslog.showArea(false);
+ statslog.showLevel(false);
+ statslog.tag("");
+ statslog.timeFormat("");
+
+ statslog.route<senf::StatisticsStream>();
+ \endcode
+
+ We use a StatisticsLogger to send the log messages to the senf::StatisticsStream log
+ stream. The stream, area an level to send the statistics log messages to may be configured
+ using template arguments to StatisticsLogger.
+
+ It is also possible to skip sending the output to any target or send one output to several
+ targets.
+
+ Here we have opted to use a label which explicitly describes the name of the variable, the
+ basic interval and the size of the sliding average window. However, the label is completely
+ arbitrary.
+
+ All output is generated using the Senf Logger on the senf::StatisticsStream %log stream. In
+ the example above, we have configured a special logfile \c stats.log which contains the
+ statistics values each prefixed with a timestamp in nanoseconds (but no further information
+ like %log level or tag):
+ <pre>
+ 0000000000.000000000 pps 100ms 5 43.3 43.3 43.3
+ 0000000000.010311928 pps 100ms 5 42.5 42.5 42.5
+ ...
+ 0000000001.002413391 pps 100ms 5 62.0 62.0 62.0
+ 0000000001.003920018 pps 1s 1 42.1 53.4 62.0
+ ...
+ </pre>
+ (the nanosecond values will of course be somewhat different ...)
+
+ \see senf::StatisticsBase::OutputProxy for the output proxy (connect) interface
+ \ingroup senf_statistics
+ */
+ class Statistics
+ : public StatisticsBase, boost::noncopyable
+ {
+ public:
+#ifndef SENF_DISABLE_CONSOLE
+ console::ScopedDirectory<Statistics> dir;
+#endif
+
+ Statistics();
+
+ void operator()(float min, float avg, float max);
+ ///< Enter new data
+ /**< This member must be called whenever a new data value is
+ available. It is important to call this member \e
+ periodically. The frequency at which this member is
+ called defines the basic statistics time scale.
+
+ If \a min and \a max values are not available, this
+ member should be called with \a min, \a avg and \a max
+ set to the same value.
+
+ \param[in] min minimal data value since last call
+ \param[in] avg average data value since last call
+ \param[in] max maximal data values since last call */
+
+ void operator()(float value); ///< Same as enter() with \a min == \a avg == \a max
+ /**< Provided so a Statistics instance can be directly used
+ as a signal target. */
+
+ StatisticsBase::OutputProxy<Statistics> output(unsigned n = 1u);
+
+ void consoleList(std::ostream & os);
+ void consoleCollect(std::vector<unsigned> & ranks);
+ boost::shared_ptr<senf::console::DirectoryNode> consoleOutput(
+ std::vector<unsigned> & ranks, unsigned window);
+
+ private:
+ Statistics & v_base();
+ std::string v_path() const;
+ };
+
+ /** \brief Accumulated statistics collector
+
+ This class collects accumulated statistics. It is automatically created by
+ senf::Statistics::collect()
+
+ \see senf::Statistics
+ */
+ class Collector : public StatisticsBase
+ {
+ public:
+ virtual unsigned rank() const;
+
+ StatisticsBase::OutputProxy<Collector> output(unsigned n = 1u);
+
+ private:
+ Collector(StatisticsBase * owner, unsigned rank);
+ void enter(float min, float avg, float max);
+ Statistics & v_base();
+ std::string v_path() const;
+
+ unsigned rank_;
+ unsigned i_;
+ float accMin_;
+ float accAvg_;
+ float accMax_;
+ StatisticsBase * owner_;
+
+ friend class StatisticsBase;
+ };
+
+}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#include "Statistics.cci"
+//#include "Statistics.ct"
+#include "Statistics.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2008
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief Statistics unit tests */
+
+//#include "Statistics.test.hh"
+//#include "Statistics.test.ih"
+
+// Custom includes
+#include "Statistics.hh"
+#include "StatisticsTargets.hh"
+
+#include "auto_unit_test.hh"
+#include <boost/test/test_tools.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace {
+
+ struct GetRange
+ {
+ typedef senf::Collector const & first_argument_type;
+ typedef unsigned result_type;
+ result_type operator()(first_argument_type arg) const
+ { return arg.rank(); }
+ };
+
+}
+
+BOOST_AUTO_UNIT_TEST(statistics)
+{
+ senf::Statistics stats;
+ senf::log::StringTarget statslog;
+
+ statslog.tag("");
+ statslog.showTime(false);
+ statslog.showArea(false);
+ statslog.showLevel(false);
+ statslog.route<senf::StatisticsStream>();
+
+ stats
+ .output(2u).connect(
+ senf::StatisticsLogger("level0"))
+ .collect(4u)
+ .output().connect(
+ senf::StatisticsLogger("level1"))
+ .output(3u).connect(
+ senf::StatisticsLogger("averaged1"))
+ .collect(3u)
+ .collect(2u)
+ .output().connect(
+ senf::StatisticsLogger("level3"));
+
+ unsigned children1[] = { 4u };
+ BOOST_CHECK_EQUAL_COLLECTIONS(
+ boost::make_transform_iterator(stats.collectors().begin(), GetRange()),
+ boost::make_transform_iterator(stats.collectors().end(), GetRange()),
+ children1, children1 + sizeof(children1)/sizeof(children1[0]) );
+
+ unsigned children2[] = { 3u };
+ BOOST_CHECK_EQUAL_COLLECTIONS(
+ boost::make_transform_iterator(stats[4].collectors().begin(), GetRange()),
+ boost::make_transform_iterator(stats[4].collectors().end(), GetRange()),
+ children2, children2 + sizeof(children2)/sizeof(children2[0]) );
+
+ unsigned children3[] = { 2u };
+ BOOST_CHECK_EQUAL_COLLECTIONS(
+ boost::make_transform_iterator(stats[4][3].collectors().begin(), GetRange()),
+ boost::make_transform_iterator(stats[4][3].collectors().end(), GetRange()),
+ children3, children3 + sizeof(children3)/sizeof(children3[0]) );
+
+ float values[][3] = {
+ { -1.0f, 2.3f, 2.5f }, { 0.3f, 2.4f, 3.8f }, { -1.1f, -0.3f, 0.0f },
+ { -0.3f, 3.2f, 3.3f }, { 1.0f, 1.1f, 1.1f }, { 0.5f, 0.5f, 0.5f },
+ { 0.0f, 0.0f, 0.0f }, { -2.0f, -1.8f, -1.0f }, { 0.0f, 2.3f, 2.4f },
+ { 0.4f, 1.2f, 2.0f }, { -1.0f, 2.3f, 2.5f }, { 0.3f, 2.4f, 3.8f },
+ { -1.1f, -0.3f, 0.0f }, { -0.3f, 3.2f, 3.3f }, { 1.0f, 1.1f, 1.1f },
+ { 0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f, 0.0f }, { -2.0f, -1.8f, -1.0f },
+ { 0.0f, 2.3f, 2.4f }, { 0.4f, 1.2f, 2.0f }, { -1.0f, 2.3f, 2.5f },
+ { 0.3f, 2.4f, 3.8f }, { -1.1f, -0.3f, 0.0f }, { -0.3f, 3.2f, 3.3f },
+ { 1.0f, 1.1f, 1.1f }, { 0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f, 0.0f },
+ { -2.0f, -1.8f, -1.0f }, { 0.0f, 2.3f, 2.4f }, { 0.4f, 1.2f, 4.0f } };
+
+ for (unsigned i (0); i < sizeof(values)/sizeof(values[0]); ++i)
+ stats(values[i][0], values[i][1], values[i][2]);
+
+ BOOST_CHECK_CLOSE( stats.min(), 0.4f, .1f );
+ BOOST_CHECK_CLOSE( stats.avg(), 1.2f, .1f );
+ BOOST_CHECK_CLOSE( stats.max(), 4.0f, .1f );
+
+ BOOST_CHECK_CLOSE( stats[4].min(), -2.0f, .1f );
+ BOOST_CHECK_CLOSE( stats[4].avg(), -0.05f, .1f );
+ BOOST_CHECK_CLOSE( stats[4].max(), 1.1f, .1f );
+
+ BOOST_CHECK_CLOSE( stats[4][3].min(), -2.0f, .1f );
+ BOOST_CHECK_CLOSE( stats[4][3].avg(), 1.15f, .1f );
+ BOOST_CHECK_CLOSE( stats[4][3].max(), 3.8f, .1f );
+
+ BOOST_CHECK_EQUAL( statslog.str(),
+ "level0 -1 2.3 2.5\n"
+ "level0 -0.35 2.35 3.15\n"
+ "level0 -0.4 1.05 1.9\n"
+ "level0 -0.7 1.45 1.65\n"
+ "level1 -1.1 1.9 3.8\n"
+ "averaged1 -1.1 1.9 3.8\n"
+ "level0 0.35 2.15 2.2\n"
+ "level0 0.75 0.8 0.8\n"
+ "level0 0.25 0.25 0.25\n"
+ "level0 -1 -0.9 -0.5\n"
+ "level1 -2 -0.05 1.1\n"
+ "averaged1 -1.55 0.925 2.45\n"
+ "level0 -1 0.25 0.7\n"
+ "level0 0.2 1.75 2.2\n"
+ "level0 -0.3 1.75 2.25\n"
+ "level0 -0.35 2.35 3.15\n"
+ "level1 -1 2.05 3.8\n"
+ "averaged1 -1.36667 1.3 2.9\n"
+ "level0 -0.4 1.05 1.9\n"
+ "level0 -0.7 1.45 1.65\n"
+ "level0 0.35 2.15 2.2\n"
+ "level0 0.75 0.8 0.8\n"
+ "level1 -1.1 1.125 3.3\n"
+ "averaged1 -1.36667 1.04167 2.73333\n"
+ "level0 0.25 0.25 0.25\n"
+ "level0 -1 -0.9 -0.5\n"
+ "level0 -1 0.25 0.7\n"
+ "level0 0.2 1.75 2.2\n"
+ "level1 -2 0.425 2.4\n"
+ "averaged1 -1.36667 1.2 3.16667\n"
+ "level0 -0.3 1.75 2.25\n"
+ "level0 -0.35 2.35 3.15\n"
+ "level0 -0.4 1.05 1.9\n"
+ "level0 -0.7 1.45 1.65\n"
+ "level1 -1.1 1.9 3.8\n"
+ "averaged1 -1.4 1.15 3.16667\n"
+ "level3 -2 1.225 3.8\n"
+ "level0 0.35 2.15 2.2\n"
+ "level0 0.75 0.8 0.8\n"
+ "level0 0.25 0.25 0.25\n"
+ "level0 -1 -0.9 -0.5\n"
+ "level1 -2 -0.05 1.1\n"
+ "averaged1 -1.7 0.758333 2.43333\n"
+ "level0 -1 0.25 0.7\n"
+ "level0 0.2 1.75 3.2\n" );
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2009
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief StatisticsTargets non-inline non-template implementation */
+
+#include "StatisticsTargets.hh"
+#include "StatisticsTargets.ih"
+
+// Custom includes
+#include <boost/bind.hpp>
+#include "Console/Console.hh"
+#include "Statistics.hh"
+
+//#include "StatisticsTargets.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::detail::StatisticsLoggerRegistry
+
+prefix_ void
+senf::detail::StatisticsLoggerRegistry::apply(senf::StatisticsBase & stats,
+ unsigned rank,
+ senf::console::DirectoryNode & dir)
+{
+ Adders::const_iterator i (adders_.begin());
+ Adders::const_iterator const i_end (adders_.end());
+ for (; i != i_end; ++i)
+ (*i)(stats, rank, dir);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+namespace {
+
+ struct RegisterStatisticsLogger
+ {
+ RegisterStatisticsLogger();
+
+ static void adder(senf::StatisticsBase & stats,
+ unsigned rank,
+ senf::console::DirectoryNode & dir);
+
+ static void consoleCreate(senf::StatisticsBase & stats,
+ unsigned rank,
+ std::string const & prefix);
+ };
+
+ RegisterStatisticsLogger registerStatisticsLogger;
+}
+
+prefix_ RegisterStatisticsLogger::RegisterStatisticsLogger()
+{
+ senf::detail::StatisticsLoggerRegistry::instance().add(&adder);
+}
+
+prefix_ void RegisterStatisticsLogger::adder(senf::StatisticsBase & stats,
+ unsigned rank,
+ senf::console::DirectoryNode & dir)
+{
+ namespace kw = senf::console::kw;
+
+ dir.add("logger", boost::function<void (std::string const &)>(
+ boost::bind(&consoleCreate, boost::ref(stats), rank, _1)))
+ .arg("prefix","Optional prefix string to add to each log message",
+ kw::default_value = "")
+ .doc("Send log messages to statistics log stream");
+}
+
+prefix_ void RegisterStatisticsLogger::consoleCreate(senf::StatisticsBase & stats,
+ unsigned rank,
+ std::string const & prefix)
+{
+ stats.output(rank).connect(senf::StatisticsLogger(prefix),
+ "senf::StatisticsLogger(\"" + prefix + "\")");
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "StatisticsTargets.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2009
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief StatisticsTargets inline non-template implementation */
+
+#include "StatisticsTargets.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::detail::StatisticsLoggerRegistry
+
+prefix_ void senf::detail::StatisticsLoggerRegistry::add(AddFn fn)
+{
+ adders_.push_back(fn);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+prefix_ std::auto_ptr< senf::detail::StatisticsLogger<void,void,void> >
+senf::StatisticsLogger(std::string const & label)
+{
+ return std::auto_ptr< detail::StatisticsLogger<void,void,void> >(
+ new detail::StatisticsLogger<void,void,void>(label));
+}
+
+///////////////////////////////cci.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2009
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief StatisticsTargets non-inline template implementation */
+
+#include "StatisticsTargets.ih"
+
+// Custom includes
+
+#define prefix_
+///////////////////////////////ct.p////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::detail::StatisticsLogger
+
+template <class Stream, class Area, class Level>
+prefix_ void senf::detail::StatisticsLogger<Stream,Area,Level>::operator()(float min,
+ float avg,
+ float max)
+{
+ SENF_LOG_TPL((StatisticsStream)(Stream)(Area)(Level)(label << min << " " << avg << " " << max));
+}
+
+///////////////////////////////ct.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2009
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief StatisticsTargets inline template implementation */
+
+#include "StatisticsTargets.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::detail::StatisticsLogger
+
+template <class Stream, class Area, class Level>
+prefix_ senf::detail::StatisticsLogger<Stream,Area,Level>::
+StatisticsLogger(std::string const & label_)
+ : label (label_.empty() ? "" : label_ + " ")
+{}
+
+///////////////////////////////////////////////////////////////////////////
+
+template <class Stream>
+prefix_ std::auto_ptr< senf::detail::StatisticsLogger<Stream,void,void> >
+senf::StatisticsLogger(std::string const & label)
+{
+ return std::auto_ptr< detail::StatisticsLogger<Stream,void,void> >(
+ new detail::StatisticsLogger<Stream,void,void>(label));
+}
+
+template <class Stream, class Area>
+prefix_ std::auto_ptr< senf::detail::StatisticsLogger<Stream,Area,void> >
+senf::StatisticsLogger(std::string const & label)
+{
+ return std::auto_ptr< detail::StatisticsLogger<Stream,Area,void> >(
+ new detail::StatisticsLogger<Stream,Area,void>(label));
+}
+
+template <class Stream, class Area, class Level>
+prefix_ std::auto_ptr< senf::detail::StatisticsLogger<Stream,Area,Level> >
+senf::StatisticsLogger(std::string const & label)
+{
+ return std::auto_ptr< detail::StatisticsLogger<Stream,Area,Level> >(
+ new detail::StatisticsLogger<Stream,Area,Level>(label));
+}
+
+///////////////////////////////cti.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2009
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief StatisticsTargets public header */
+
+#ifndef HH_SENF_PPI_Utils_StatisticsTargets_
+#define HH_SENF_PPI_Utils_StatisticsTargets_ 1
+
+// Custom includes
+#include <string>
+#include "Logger/Logger.hh"
+
+//#include "StatisticsTargets.mpp"
+#include "StatisticsTargets.ih"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+
+#ifdef DOXYGEN
+ /** \brief Logging stream for statistics messages
+ \ingroup senf_statistics
+ */
+ typedef unspecified StatisticsStream;
+#else
+ SENF_LOG_DEFINE_STREAM(StatisticsStream,
+ senf::log::MESSAGE, senf::log::MESSAGE, senf::log::MESSAGE);
+#endif
+
+#ifdef DOXYGEN
+
+ /** \brief Send statistics to SENF log
+
+ This statistics target will send all statistics values to the SENF log. The template
+ parameters optionally specify the stream, area and/or level to send the messages to. An
+ optional \a label string may be specified which will be added as prefix to all log entries.
+
+ The log stream defaults to senf::StatisticsStream, the level defaults to
+ senf::log::MESSAGE and the are defaults to senf::log::DefaultArea.
+
+ \code
+ // Connect with default parameters
+ stats.output(2u).connect()
+
+ // Send statistics messages to the debug stream at default level (MESSAGE)
+ // Place them in the MyStatistics area. Add 'stat1' prefix to each log message
+ SENF_LOG_DEF_AREA(MyStatistics);
+ stats.output(2u).connect<senf::log::Debug, MyStatistics>("stat1");
+ \endcode
+
+ \ingroup senf_statistics
+ */
+ template <class A1=void, class A2=void, class A3=void>
+ std::auto_ptr< unspecified > StatisticsLogger(std::string const & label="")
+
+#else
+
+ std::auto_ptr< detail::StatisticsLogger<void,void,void> > StatisticsLogger(
+ std::string const & label="");
+
+ template <class Stream>
+ std::auto_ptr< detail::StatisticsLogger<Stream,void,void> > StatisticsLogger(
+ std::string const & label="");
+
+ template <class Stream, class Area>
+ std::auto_ptr< detail::StatisticsLogger<Stream,Area,void> > StatisticsLogger(
+ std::string const & label="");
+
+ template <class Stream, class Area, class Level>
+ std::auto_ptr< detail::StatisticsLogger<Stream,Area,Level> > StatisticsLogger(
+ std::string const & label="");
+
+#endif
+
+}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#include "StatisticsTargets.cci"
+#include "StatisticsTargets.ct"
+#include "StatisticsTargets.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2009
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief StatisticsTargets internal header */
+
+#ifndef IH_SENF_Utils_StatisticsTargets_
+#define IH_SENF_Utils_StatisticsTargets_ 1
+
+// Custom includes
+#include <string>
+#include <boost/utility.hpp>
+#include <senf/Utils/singleton.hh>
+
+///////////////////////////////ih.p////////////////////////////////////////
+
+namespace senf {
+
+ namespace console { class DirectoryNode; }
+
+ class StatisticsBase;
+
+namespace detail {
+
+ class StatisticsLoggerRegistry
+ : public senf::singleton<StatisticsLoggerRegistry>
+ {
+ public:
+ typedef void (*AddFn)(senf::StatisticsBase &, unsigned,
+ senf::console::DirectoryNode &);
+
+ using senf::singleton<StatisticsLoggerRegistry>::instance;
+ using senf::singleton<StatisticsLoggerRegistry>::alive;
+
+ void add(AddFn fn);
+ void apply(senf::StatisticsBase & stats, unsigned rank,
+ senf::console::DirectoryNode & dir);
+
+ private:
+ typedef std::vector<AddFn> Adders;
+ Adders adders_;
+ };
+
+ template <class Stream=void, class Area=void, class Level=void>
+ struct StatisticsLogger
+ : boost::noncopyable
+ {
+ StatisticsLogger(std::string const & label_);
+ void operator()(float min, float avg, float max);
+
+ std::string label;
+ };
+
+}}
+
+///////////////////////////////ih.e////////////////////////////////////////
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End: