4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at
9 // http://senf.berlios.de/license.html
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on,
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
15 // Software distributed under the License is distributed on an "AS IS" basis,
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17 // for the specific language governing rights and limitations under the License.
19 // The Original Code is Fraunhofer FOKUS code.
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V.
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
26 // Stefan Bund <g0dil@berlios.de>
29 \brief Statistics non-inline non-template implementation */
31 #include "Statistics.hh"
32 //#include "Statistics.ih"
38 #include <senf/Utils/Format.hh>
39 #include <senf/Utils/Console/STLSupport.hh>
40 #include "StatisticsTargets.hh"
42 //#include "Statistics.mpp"
44 //-/////////////////////////////////////////////////////////////////////////////////////////////////
46 //-/////////////////////////////////////////////////////////////////////////////////////////////////
47 // senf::StatisticsBase
49 prefix_ void senf::StatisticsBase::enter(unsigned n, float min, float avg, float max, float dev)
55 for (unsigned i (0); i < n; ++i)
57 Children::iterator i (children_.begin());
58 Children::iterator const i_end (children_.end());
59 for (; i != i_end; ++i)
60 i->second.enter(n, min_, avg_, max_, dev_);
63 prefix_ senf::Collector & senf::StatisticsBase::operator[](unsigned rank)
65 Children::iterator i (children_.find(rank));
66 if (i == children_.end())
67 throw InvalidRankException();
71 prefix_ senf::Collector const & senf::StatisticsBase::operator[](unsigned rank)
74 Children::const_iterator i (children_.find(rank));
75 if (i == children_.end())
76 throw InvalidRankException();
80 prefix_ senf::Collector & senf::StatisticsBase::collect(unsigned rank)
82 std::pair<Children::iterator, bool> state (
83 children_.insert(std::make_pair(rank, Collector(this, rank))) );
85 throw DuplicateRankException();
86 return state.first->second;
89 prefix_ senf::StatisticsBase::OutputProxy<senf::StatisticsBase>
90 senf::StatisticsBase::output(unsigned n)
92 OutputMap::iterator i (outputs_.find(n));
93 if (i == outputs_.end()) {
94 i = outputs_.insert(std::make_pair(n, OutputEntry(n))).first;
96 nm << "output" << path() << ":" << n;
97 base().dir.node().add(nm.str(), i->second.dir);
98 detail::StatisticsLoggerRegistry::instance().apply(*this, n, i->second.dir);
100 if (n > maxQueueLen_)
102 return OutputProxy<StatisticsBase>(this, &(i->second));
105 prefix_ void senf::StatisticsBase::consoleList(unsigned level, std::ostream & os)
108 namespace fmt = senf::format;
110 os << boost::format("%s%-5d%|15t| %12.5g %19.5g %12.5g\n")
111 % std::string(2*level,' ') % rank()
112 % fmt::eng(min()).setw() % fmt::eng(avg(),dev()).setw() % fmt::eng(max()).setw();
114 OutputMap::const_iterator i (outputs_.begin());
115 OutputMap::const_iterator i_end (outputs_.end());
116 for (; i != i_end; ++i)
117 os << boost::format(" %3d %12.5g %19.5g %12.5g\n")
119 % fmt::eng(i->second.min).setw()
120 % fmt::eng(i->second.avg, i->second.dev).setw()
121 % fmt::eng(i->second.max).setw();
124 Children::const_iterator i (children_.begin());
125 Children::const_iterator const i_end (children_.end());
126 for (; i != i_end; ++i)
127 i->second.consoleList(level+1, os);
131 prefix_ void senf::StatisticsBase::generateOutput()
133 queue_.push_front(QueueEntry(min_, avg_, max_, dev_));
134 while (queue_.size() > maxQueueLen_)
137 OutputMap::iterator i (outputs_.begin());
138 OutputMap::iterator const i_end (outputs_.end());
139 for (; i != i_end; ++i) {
140 i->second.min = i->second.avg = i->second.max = i->second.dev = 0.0f;
141 Queue::const_iterator j (queue_.begin());
142 Queue::const_iterator const j_end (queue_.end());
144 for (; n < i->second.n && j != j_end; ++n, ++j) {
145 i->second.min += j->min;
146 i->second.avg += j->avg;
147 i->second.max += j->max;
148 i->second.dev += j->dev;
154 i->second.signal(i->second.min, i->second.avg, i->second.max, i->second.dev);
158 //-/////////////////////////////////////////////////////////////////////////////////////////////////
159 // senf::StatisticsBase::OutputEntry
161 prefix_ void senf::StatisticsBase::OutputEntry::consoleList(std::ostream & os)
163 for (boost::ptr_vector<TargetBase>::iterator i (targets_.begin());
164 i != targets_.end(); ++i)
165 if (! i->label.empty())
166 os << i->label << "\n";
169 //-/////////////////////////////////////////////////////////////////////////////////////////////////
172 prefix_ senf::Statistics::Statistics()
173 #ifndef SENF_DISABLE_CONSOLE
177 #ifndef SENF_DISABLE_CONSOLE
178 namespace fty = console::factory;
180 dir.add("list", fty::Command(&Statistics::consoleList, this)
181 .doc("List statistics collection intervals and current values.\n"
184 " RANK Number of values collected. Since the statistics collectors form\n"
185 " a tree, the value is indented according to it's tree location.\n"
186 " WIN Size of output average window.\n"
187 " MIN Last entered minimum value.\n"
188 " AVG Last entered average value.\n"
189 " DEV Standard deviation of average value over the collector rank.\n"
190 " MAX Last entered maximum value.") );
191 dir.add("collect", fty::Command(&Statistics::consoleCollect, this)
192 .doc("Add statistics collection groups. The argument gives a sequence of collector\n"
193 "ranks each building on the preceding collector:\n"
195 " $ collect (10 60 60)\n"
197 "Will start by collecting every 10 values together to a new value. 60 of such\n"
198 "combined values will be collected together in the next step again followed by\n"
199 "a collection of 60 values. If the statistics is entered with a frequency of\n"
200 "10 values per second, this will provide combined statistics over the second,\n"
201 "minutes and hours ranges.\n"
203 "You may call collect multiple times. Any missing collection ranks will be\n"
205 .arg("ranks","chain of collector ranks") );
206 dir.add("output", fty::Command(&Statistics::consoleOutput, this)
207 .doc("Generate statistics output. This statement will add an additional output\n"
208 "generator. This generator will be attached to the collector specified by\n"
209 "the {rank} parameter. This parameter is a chain of successive rank values\n"
210 "which specifies the exact collector to use. If the collector does not\n"
211 "exist, it will be created (this is like automatically calling 'collect'\n"
212 "with {rank} as argument).\n"
214 "If the output is to be sent somewhere it must be connected to a statistics\n"
217 "The output may optionally be built using a sliding average over the last\n"
222 "will output the basic statistics value each time a new value is entered.\n"
224 " $ output (10 60) 5\n"
226 "Assuming that new data values are entered 10 times per second, this command\n"
227 "will generate output once every minute. The value will be the average over\n"
228 "the last 5 minutes.")
229 .arg("rank","Rank chain selecting the value to generate output for")
230 .arg("window","Optional size of sliding average window",
231 console::kw::default_value = 1u) );
235 prefix_ void senf::Statistics::consoleList(std::ostream & os)
237 os << "RANK WIN MIN AVG MAX\n";
238 StatisticsBase::consoleList(0, os);
241 prefix_ void senf::Statistics::consoleCollect(std::vector<unsigned> & ranks)
243 StatisticsBase * stats (this);
244 std::vector<unsigned>::const_iterator i (ranks.begin());
245 std::vector<unsigned>::const_iterator const i_end (ranks.end());
248 for (; i != i_end; ++i)
249 stats = &(*stats)[*i];
251 catch (InvalidRankException &) {}
253 for (; i != i_end; ++i)
254 stats = & (stats->collect(*i));
258 prefix_ boost::shared_ptr<senf::console::DirectoryNode>
259 senf::Statistics::consoleOutput(std::vector<unsigned> & ranks, unsigned window)
261 StatisticsBase * stats (this);
262 std::vector<unsigned>::const_iterator i (ranks.begin());
263 std::vector<unsigned>::const_iterator const i_end (ranks.end());
266 for (; i != i_end; ++i)
267 stats = &(*stats)[*i];
269 catch (InvalidRankException &) {}
271 for (; i != i_end; ++i)
272 stats = & (stats->collect(*i));
274 return stats->output(window).dir().node().thisptr();
277 prefix_ senf::Statistics & senf::Statistics::v_base()
282 prefix_ std::string senf::Statistics::v_path()
288 //-/////////////////////////////////////////////////////////////////////////////////////////////////
291 prefix_ void senf::Collector::enter(unsigned n, float min, float avg, float max, float dev)
293 if (min < accMin_) accMin_ = min;
294 if (max > accMax_) accMax_ = max;
296 if (i_ + n >= rank_) {
297 accSum_ += (rank_-i_)*avg;
298 accSumSq_ += (rank_-i_)*(rank_-i_)*(avg*avg + dev*dev);
299 float accAvg (accSum_ / rank_);
300 float accDev (std::sqrt(std::max(0.0f,accSumSq_ / rank_ - accAvg*accAvg)));
301 StatisticsBase::enter(1, accMin_, accAvg, accMax_, accDev);
310 std::div_t d (std::div(int(n), int(rank_)));
311 StatisticsBase::enter(d.quot, min, avg, max, dev);
318 accSumSq_ += n*n*(avg*avg+dev*dev);
320 if (min < accMin_) accMin_ = min;
321 if (max > accMax_) accMax_ = max;
325 prefix_ senf::Statistics & senf::Collector::v_base()
327 return owner_->base();
330 prefix_ std::string senf::Collector::v_path()
333 return owner_->path() + "-" + senf::str(rank_);
336 //-/////////////////////////////////////////////////////////////////////////////////////////////////
338 //#include "Statistics.mpp"
344 // comment-column: 40
345 // c-file-style: "senf"
346 // indent-tabs-mode: nil
347 // ispell-local-dictionary: "american"
348 // compile-command: "scons -u test"