moved statistics classes from NetEmu to SENF
tho [Mon, 30 Mar 2009 12:02:14 +0000 (12:02 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1177 270642c3-0616-0410-b53a-bc976706d245

15 files changed:
PPI/RateAnalyzer.cc [new file with mode: 0644]
PPI/RateAnalyzer.hh [new file with mode: 0644]
PPI/RateAnalyzer.test.cc [new file with mode: 0644]
Utils/Mainpage.dox
Utils/Statistics.cc [new file with mode: 0644]
Utils/Statistics.cci [new file with mode: 0644]
Utils/Statistics.cti [new file with mode: 0644]
Utils/Statistics.hh [new file with mode: 0644]
Utils/Statistics.test.cc [new file with mode: 0644]
Utils/StatisticsTargets.cc [new file with mode: 0644]
Utils/StatisticsTargets.cci [new file with mode: 0644]
Utils/StatisticsTargets.ct [new file with mode: 0644]
Utils/StatisticsTargets.cti [new file with mode: 0644]
Utils/StatisticsTargets.hh [new file with mode: 0644]
Utils/StatisticsTargets.ih [new file with mode: 0644]

diff --git a/PPI/RateAnalyzer.cc b/PPI/RateAnalyzer.cc
new file mode 100644 (file)
index 0000000..3b84d7a
--- /dev/null
@@ -0,0 +1,80 @@
+// $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:
diff --git a/PPI/RateAnalyzer.hh b/PPI/RateAnalyzer.hh
new file mode 100644 (file)
index 0000000..ed85b33
--- /dev/null
@@ -0,0 +1,121 @@
+// $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:
diff --git a/PPI/RateAnalyzer.test.cc b/PPI/RateAnalyzer.test.cc
new file mode 100644 (file)
index 0000000..110c929
--- /dev/null
@@ -0,0 +1,112 @@
+// $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:
index 1adfc8e..6e2c7f8 100644 (file)
@@ -94,6 +94,8 @@ namespace senf {
     <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>
 
diff --git a/Utils/Statistics.cc b/Utils/Statistics.cc
new file mode 100644 (file)
index 0000000..0b6ab8f
--- /dev/null
@@ -0,0 +1,293 @@
+// $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:
diff --git a/Utils/Statistics.cci b/Utils/Statistics.cci
new file mode 100644 (file)
index 0000000..1f109db
--- /dev/null
@@ -0,0 +1,192 @@
+// $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:
diff --git a/Utils/Statistics.cti b/Utils/Statistics.cti
new file mode 100644 (file)
index 0000000..d34b9ba
--- /dev/null
@@ -0,0 +1,100 @@
+// $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:
diff --git a/Utils/Statistics.hh b/Utils/Statistics.hh
new file mode 100644 (file)
index 0000000..6409ab1
--- /dev/null
@@ -0,0 +1,497 @@
+// $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:
diff --git a/Utils/Statistics.test.cc b/Utils/Statistics.test.cc
new file mode 100644 (file)
index 0000000..99c31e3
--- /dev/null
@@ -0,0 +1,181 @@
+// $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:
diff --git a/Utils/StatisticsTargets.cc b/Utils/StatisticsTargets.cc
new file mode 100644 (file)
index 0000000..a131e36
--- /dev/null
@@ -0,0 +1,111 @@
+// $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:
diff --git a/Utils/StatisticsTargets.cci b/Utils/StatisticsTargets.cci
new file mode 100644 (file)
index 0000000..b42e9e8
--- /dev/null
@@ -0,0 +1,62 @@
+// $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:
diff --git a/Utils/StatisticsTargets.ct b/Utils/StatisticsTargets.ct
new file mode 100644 (file)
index 0000000..9bb386a
--- /dev/null
@@ -0,0 +1,56 @@
+// $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:
diff --git a/Utils/StatisticsTargets.cti b/Utils/StatisticsTargets.cti
new file mode 100644 (file)
index 0000000..922578e
--- /dev/null
@@ -0,0 +1,80 @@
+// $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:
diff --git a/Utils/StatisticsTargets.hh b/Utils/StatisticsTargets.hh
new file mode 100644 (file)
index 0000000..93a2180
--- /dev/null
@@ -0,0 +1,111 @@
+// $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:
diff --git a/Utils/StatisticsTargets.ih b/Utils/StatisticsTargets.ih
new file mode 100644 (file)
index 0000000..54c5d00
--- /dev/null
@@ -0,0 +1,87 @@
+// $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: