//////////////////////////////////////////////////////////////////////////////// /// @brief utilities for round robin figures /// /// @file /// /// DISCLAIMER /// /// Copyright 2004-2012 triagens GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author Dr. Frank Celler /// @author Copyright 2010-2012, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #ifndef TRIAGENS_BASICS_ROUND_ROBIN_FIGURES_H #define TRIAGENS_BASICS_ROUND_ROBIN_FIGURES_H 1 #include "Basics/Common.h" #include #include "Basics/Mutex.h" #include "Basics/MutexLocker.h" #include "Variant/VariantArray.h" #include "Variant/VariantDouble.h" #include "Variant/VariantUInt32.h" #include "Variant/VariantUInt64.h" #include "Variant/VariantVector.h" // ----------------------------------------------------------------------------- // --SECTION-- public macros // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @addtogroup Utilities /// @{ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @brief macro to define a new counter //////////////////////////////////////////////////////////////////////////////// #define RRF_COUNTER(S, n) \ struct n ## Accessor { \ static triagens::basics::RrfCounter& access (S& s) { \ return s.n; \ } \ static triagens::basics::RrfCounter const& access (S const& s) { \ return s.n; \ } \ }; \ \ triagens::basics::RrfCounter n //////////////////////////////////////////////////////////////////////////////// /// @brief macro to define a new continuous //////////////////////////////////////////////////////////////////////////////// #define RRF_CONTINUOUS(S, n) \ struct n ## Accessor { \ static triagens::basics::RrfContinuous& access (S& s) { \ return s.n; \ } \ static triagens::basics::RrfContinuous const& access (S const& s) { \ return s.n; \ } \ }; \ \ triagens::basics::RrfContinuous n //////////////////////////////////////////////////////////////////////////////// /// @brief macro to define a new figure /// /// The figures contains the sum of the values and the count. //////////////////////////////////////////////////////////////////////////////// #define RRF_FIGURE(S, n) \ struct n ## Accessor { \ static triagens::basics::RrfFigure& access (S& s) { \ return s.n; \ } \ static triagens::basics::RrfFigure const& access (S const& s) { \ return s.n; \ } \ }; \ \ triagens::basics::RrfFigure n //////////////////////////////////////////////////////////////////////////////// /// @brief macro to define a new set of figures /// /// The figures contains the sum of the values and the count. //////////////////////////////////////////////////////////////////////////////// #define RRF_FIGURES(S, N, n) \ struct n ## Accessor { \ static triagens::basics::RrfFigures& access (S& s) { \ return s.n; \ } \ static triagens::basics::RrfFigures const& access (S const& s) { \ return s.n; \ } \ }; \ \ triagens::basics::RrfFigures n //////////////////////////////////////////////////////////////////////////////// /// @brief macro to define a new distribution /// /// The distributions contains the sum of the values, the sum of the /// squares, the count, and minimum and maximum. //////////////////////////////////////////////////////////////////////////////// #define RRF_DISTRIBUTION(S, n, a) \ struct n ## Cuts_s { \ static std::vector cuts () { \ triagens::basics::RrfVector g; g << a; return g._value; \ } \ }; \ \ struct n ## Accessor { \ static triagens::basics::RrfDistribution& access (S& s) { \ return s.n; \ } \ static triagens::basics::RrfDistribution const& access (S const& s) { \ return s.n; \ } \ }; \ \ triagens::basics::RrfDistribution n //////////////////////////////////////////////////////////////////////////////// /// @brief macro to define a new set of distributions /// /// The distributions contains the sum of the values, the sum of the /// squares, the count, and minimum and maximum. //////////////////////////////////////////////////////////////////////////////// #define RRF_DISTRIBUTIONS(S, N, n, a) \ struct n ## Cuts_s { \ static std::vector cuts () { \ triagens::basics::RrfVector g; g << a; return g._value; \ } \ }; \ \ struct n ## Accessor { \ static triagens::basics::RrfDistributions& access (S& s) { \ return s.n; \ } \ }; \ \ triagens::basics::RrfDistributions n //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// namespace triagens { namespace basics { // ----------------------------------------------------------------------------- // --SECTION-- public types // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @addtogroup Utilities /// @{ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @brief vector generator //////////////////////////////////////////////////////////////////////////////// struct RrfVector { RrfVector () : _value() { } RrfVector& operator<< (double v) { _value.push_back(v); return *this; } std::vector _value; }; //////////////////////////////////////////////////////////////////////////////// /// @brief a simple counter //////////////////////////////////////////////////////////////////////////////// struct RrfCounter { RrfCounter() : _count(0) { } RrfCounter& operator= (RrfCounter const&) { _count = 0; return *this; } int32_t _count; }; //////////////////////////////////////////////////////////////////////////////// /// @brief a simple continuous counter //////////////////////////////////////////////////////////////////////////////// struct RrfContinuous { RrfContinuous() : _count(0) { } RrfContinuous& operator= (RrfContinuous const& that) { if (this == &that) { _count = 0; } else { _count = that._count; } return *this; } int32_t _count; }; //////////////////////////////////////////////////////////////////////////////// /// @brief a figure with count //////////////////////////////////////////////////////////////////////////////// struct RrfFigure { RrfFigure() : _count(0), _sum(0.0) { } RrfFigure& operator= (RrfFigure const&) { _count = 0; _sum = 0.0; return *this; } int32_t _count; double _sum; }; //////////////////////////////////////////////////////////////////////////////// /// @brief a figure with count //////////////////////////////////////////////////////////////////////////////// template struct RrfFigures { RrfFigures() { for (size_t i = 0; i < N; ++i) { _count[i] = 0; _sum[i] = 0.0; } } RrfFigures& operator= (RrfFigures const&) { for (size_t i = 0; i < N; ++i) { _count[i] = 0; _sum[i] = 0.0; } return *this; } uint32_t _count[N]; double _sum[N]; }; //////////////////////////////////////////////////////////////////////////////// /// @brief a distribution with count, min, max, mean, and variance //////////////////////////////////////////////////////////////////////////////// template struct RrfDistribution { RrfDistribution() : _count(0), _sum(0.0), _squares(0.0), _minimum(HUGE_VAL), _maximum(-HUGE_VAL), _cuts(C::cuts()), _counts() { _counts.resize(_cuts.size() + 1); } RrfDistribution& operator= (RrfDistribution const&) { _count = 0; _sum = 0.0; _squares = 0.0; _minimum = HUGE_VAL; _maximum = -HUGE_VAL; return *this; } uint32_t _count; double _sum; double _squares; double _minimum; double _maximum; std::vector _cuts; std::vector _counts; }; //////////////////////////////////////////////////////////////////////////////// /// @brief many distributions with count, min, max, mean, and variance //////////////////////////////////////////////////////////////////////////////// template struct RrfDistributions { RrfDistributions() : _cuts(C::cuts()) { for (size_t i = 0; i < N; ++i) { _counts[i].resize(_cuts.size() + 1); _sum[i] = 0.0; _squares[i] = 0.0; _minimum[i] = HUGE_VAL; _maximum[i] = -HUGE_VAL; } } RrfDistributions& operator= (RrfDistributions const&) { for (size_t i = 0; i < N; ++i) { _sum[i] = 0.0; _squares[i] = 0.0; _minimum[i] = HUGE_VAL; _maximum[i] = -HUGE_VAL; } return *this; } uint32_t _count[N]; double _sum[N]; double _squares[N]; double _minimum[N]; double _maximum[N]; std::vector _cuts; std::vector _counts[N]; }; //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @addtogroup Utilities /// @{ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @brief generates a variant representation for the distribution //////////////////////////////////////////////////////////////////////////////// template void RRF_GenerateVariantDistribution (VariantArray* result, STAT const& s, std::string const& name, bool showMinimum, bool showMaximum, bool showDeviation) { VariantArray* values = new VariantArray(); result->add(name, values); VariantVector* cuts = new VariantVector(); values->add("cuts", cuts); // generate the cuts std::vector const& vv = ACC::access(s)._cuts; for (std::vector::const_iterator k = vv.begin(); k != vv.end(); ++k) { cuts->add(new VariantDouble(*k)); } // generate the distribution values uint32_t count = ACC::access(s)._count; double sum = ACC::access(s)._sum; double squares = ACC::access(s)._squares; VariantUInt32* valCount = new VariantUInt32(count); values->add("count", valCount); VariantDouble* valMean = new VariantDouble(count == 0 ? 0.0 : (sum / count)); values->add("mean", valMean); double w = 0; if (1 < count) { try { w = sqrt(squares - sum * sum / count) / (count - 1); } catch (...) { } } if (showDeviation) { VariantDouble* valDeviation = new VariantDouble(w); values->add("deviation", valDeviation); } if (showMinimum) { VariantDouble* valMin = new VariantDouble(ACC::access(s)._minimum); values->add("min", valMin); } if (showMaximum) { VariantDouble* valMax = new VariantDouble(ACC::access(s)._maximum); values->add("max", valMax); } VariantVector* dists = new VariantVector(); values->add("distribution", dists); for (vector::const_iterator m = ACC::access(s)._counts.begin(); m != ACC::access(s)._counts.end(); ++m) { dists->add(new VariantUInt32(*m)); } } //////////////////////////////////////////////////////////////////////////////// /// @brief generates a variant representation for the distributions //////////////////////////////////////////////////////////////////////////////// template void RRF_GenerateVariantDistribution (VariantArray* result, typename std::vector const& v, std::string const& name, bool showMinimum, bool showMaximum, bool showDeviation) { VariantArray* values = new VariantArray(); result->add(name, values); VariantVector* cuts = new VariantVector(); values->add("cuts", cuts); if (! v.empty()) { // generate the cuts { STAT const& s = *(v.begin()); std::vector const& vv = ACC::access(s)._cuts; for (std::vector::const_iterator k = vv.begin(); k != vv.end(); ++k) { cuts->add(new VariantDouble(*k)); } } // generate the distribution values VariantVector* vecCount = new VariantVector(); values->add("count", vecCount); VariantVector* vecMean = new VariantVector(); values->add("mean", vecMean); VariantVector* vecMin = 0; if (showMinimum) { vecMin = new VariantVector(); values->add("min", vecMin); } VariantVector* vecMax = 0; if (showMaximum) { vecMax = new VariantVector(); values->add("max", vecMax); } VariantVector* vecDeviation = 0; if (showDeviation) { vecDeviation = new VariantVector(); values->add("deviation", vecDeviation); } VariantVector* vecDistribution = new VariantVector(); values->add("distribution", vecDistribution); for (typename std::vector::const_iterator j = v.begin(); j != v.end(); ++j) { STAT const& s = *j; uint32_t count = ACC::access(s)._count; double sum = ACC::access(s)._sum; double squares = ACC::access(s)._squares; vecCount->add(new VariantUInt32(count)); vecMean->add(new VariantDouble(count == 0 ? 0.0 : (sum / count))); if (showDeviation) { double w = 0; if (1 < count) { try { w = sqrt(squares - sum * sum / count) / (count - 1); } catch (...) { } } vecDeviation->add(new VariantDouble(w)); } if (showMinimum) { vecMin->add(new VariantDouble(ACC::access(s)._minimum)); } if (showMaximum) { vecMax->add(new VariantDouble(ACC::access(s)._maximum)); } VariantVector* dists = new VariantVector(); vecDistribution->add(dists); for (vector::const_iterator m = ACC::access(s)._counts.begin(); m != ACC::access(s)._counts.end(); ++m) { dists->add(new VariantUInt32(*m)); } } } } //////////////////////////////////////////////////////////////////////////////// /// @brief generates a variant representation for the counter //////////////////////////////////////////////////////////////////////////////// template void RRF_GenerateVariantCounter (VariantArray* result, STAT const& s, std::string const& name, double resolution) { VariantArray* values = new VariantArray(); result->add(name, values); // generate the continuous figure uint32_t count = ACC::access(s)._count; values->add("count", new VariantUInt32(count)); values->add("perSecond", new VariantDouble(count / resolution)); } //////////////////////////////////////////////////////////////////////////////// /// @brief generates a variant representation for the counter //////////////////////////////////////////////////////////////////////////////// template void RRF_GenerateVariantCounter (VariantArray* result, typename std::vector const& v, std::string const& name, double resolution) { VariantArray* values = new VariantArray(); result->add(name, values); if (! v.empty()) { // generate the continuous figures VariantVector* vecCount = new VariantVector(); values->add("count", vecCount); VariantVector* vecSecond = new VariantVector(); values->add("perSecond", vecSecond); for (typename std::vector::const_iterator j = v.begin(); j != v.end(); ++j) { STAT const& s = *j; uint32_t count = ACC::access(s)._count; vecCount->add(new VariantUInt32(count)); vecSecond->add(new VariantDouble(count / resolution)); } } } //////////////////////////////////////////////////////////////////////////////// /// @brief generates a variant representation for the continuous figures //////////////////////////////////////////////////////////////////////////////// template void RRF_GenerateVariantContinuous (VariantArray* result, STAT const& s, std::string const& name) { VariantArray* values = new VariantArray(); result->add(name, values); // generate the continuous figure uint32_t count = ACC::access(s)._count; VariantUInt32* valCount = new VariantUInt32(count); values->add("count", valCount); } //////////////////////////////////////////////////////////////////////////////// /// @brief generates a variant representation for the continuous figures //////////////////////////////////////////////////////////////////////////////// template void RRF_GenerateVariantContinuous (VariantArray* result, typename std::vector const& v, std::string const& name) { VariantArray* values = new VariantArray(); result->add(name, values); if (! v.empty()) { // generate the continuous figures VariantVector* vecCount = new VariantVector(); values->add("count", vecCount); for (typename std::vector::const_iterator j = v.begin(); j != v.end(); ++j) { STAT const& s = *j; uint32_t count = ACC::access(s)._count; vecCount->add(new VariantUInt32(count)); } } } //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// // ----------------------------------------------------------------------------- // --SECTION-- class RoundRobinFigures // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @addtogroup Utilities /// @{ //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @brief utilities for round robin distributions //////////////////////////////////////////////////////////////////////////////// template class RoundRobinFigures { //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// // ----------------------------------------------------------------------------- // --SECTION-- constructors and destructors // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @addtogroup Utilities /// @{ //////////////////////////////////////////////////////////////////////////////// public: //////////////////////////////////////////////////////////////////////////////// /// @brief constructor //////////////////////////////////////////////////////////////////////////////// RoundRobinFigures () : _current(0), _accessLock() { for (size_t i = 0; i < N; ++i) { _buffer[i] = S(); _start[i] = 0; } time_t now = time(0); _current = (now / P) % N; _start[_current] = (now / P) * P; } //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// // ----------------------------------------------------------------------------- // --SECTION-- public methods // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @addtogroup Utilities /// @{ //////////////////////////////////////////////////////////////////////////////// public: //////////////////////////////////////////////////////////////////////////////// /// @brief increments a counter //////////////////////////////////////////////////////////////////////////////// template void incCounter () { MUTEX_LOCKER(_accessLock); checkTime(); S& s = _buffer[_current]; C::access(s)._count += 1; } //////////////////////////////////////////////////////////////////////////////// /// @brief decrements a counter //////////////////////////////////////////////////////////////////////////////// template void decCounter () { MUTEX_LOCKER(_accessLock); checkTime(); S& s = _buffer[_current]; C::access(s)._count -= 1; } //////////////////////////////////////////////////////////////////////////////// /// @brief generate a new figure //////////////////////////////////////////////////////////////////////////////// template void addFigure (double value) { MUTEX_LOCKER(_accessLock); checkTime(); S& s = _buffer[_current]; F::access(s)._count += 1; F::access(s)._sum += value; } //////////////////////////////////////////////////////////////////////////////// /// @brief generate a new figure //////////////////////////////////////////////////////////////////////////////// template void addFigure (size_t pos, double value) { MUTEX_LOCKER(_accessLock); checkTime(); S& s = _buffer[_current]; F::access(s)._count[pos] += 1; F::access(s)._sum[pos] += value; } //////////////////////////////////////////////////////////////////////////////// /// @brief generate a new distribution //////////////////////////////////////////////////////////////////////////////// template void addDistribution (double value) { MUTEX_LOCKER(_accessLock); checkTime(); S& s = _buffer[_current]; F::access(s)._count += 1; F::access(s)._sum += value; F::access(s)._squares += double(value * value); if (F::access(s)._minimum > value) { F::access(s)._minimum = value; } if (F::access(s)._maximum < value) { F::access(s)._maximum = value; } typename std::vector::const_iterator i = F::access(s)._cuts.begin(); std::vector::iterator j = F::access(s)._counts.begin(); for(; i != F::access(s)._cuts.end(); ++i, ++j) { if (value < *i) { (*j)++; return; } } (*j)++; } //////////////////////////////////////////////////////////////////////////////// /// @brief generate a new distribution //////////////////////////////////////////////////////////////////////////////// template void addDistribution (size_t pos, double value) { MUTEX_LOCKER(_accessLock); checkTime(); S& s = _buffer[_current]; F::access(s)._count[pos] += 1; F::access(s)._sum[pos] += value; F::access(s)._squares[pos] += double(value * value); if (F::access(s)._minimum[pos] > value) { F::access(s)._minimum[pos] = value; } if (F::access(s)._maximum[pos] < value) { F::access(s)._maximum[pos] = value; } typename std::vector::const_iterator i = F::access(s)._cuts.begin(); std::vector::iterator j = F::access(s)._counts[pos].begin(); for(; i != F::access(s)._cuts.end(); ++i, ++j) { if (value < *i) { (*j)++; return; } } (*j)++; } //////////////////////////////////////////////////////////////////////////////// /// @brief returns the list of distributions //////////////////////////////////////////////////////////////////////////////// std::vector values (size_t n = N) { std::vector result; MUTEX_LOCKER(_accessLock); checkTime(); if (n >= N) { n = N; } size_t j = (_current + N - n + 1) % N; for (size_t i = 0; i < n; ++i) { result.push_back(_buffer[j]); j = (j + 1) % N; } return result; } //////////////////////////////////////////////////////////////////////////////// /// @brief returns the list of distributions and times //////////////////////////////////////////////////////////////////////////////// std::vector values (vector& times, size_t n = N) { std::vector result; MUTEX_LOCKER(_accessLock); checkTime(); if (n >= N) { n = N; } times.clear(); size_t j = (_current + N - n + 1) % N; for (size_t i = 0; i < n; ++i) { result.push_back(_buffer[j]); times.push_back(_start[j]); j = (j + 1) % N; } return result; } //////////////////////////////////////////////////////////////////////////////// /// @brief returns the resolution //////////////////////////////////////////////////////////////////////////////// size_t getResolution () const { return P; } //////////////////////////////////////////////////////////////////////////////// /// @brief returns the length //////////////////////////////////////////////////////////////////////////////// size_t getLength () const { return N; } //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// // ----------------------------------------------------------------------------- // --SECTION-- protected methods // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @addtogroup Utilities /// @{ //////////////////////////////////////////////////////////////////////////////// protected: //////////////////////////////////////////////////////////////////////////////// /// @brief checks if we have to use a new time intervall //////////////////////////////////////////////////////////////////////////////// void checkTime () { time_t now = time(0); size_t p1 = now / P; size_t p2 = _start[_current] / P; if (p1 == p2) { return; } S save = _buffer[_current]; for (size_t p = max(p2, p1 - N) + 1; p <= p1; ++p) { _current = p % N; _buffer[_current] = save; _start[_current] = p * P; } } //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// // ----------------------------------------------------------------------------- // --SECTION-- private variables // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @addtogroup Utilities /// @{ //////////////////////////////////////////////////////////////////////////////// private: //////////////////////////////////////////////////////////////////////////////// /// @brief staticstics ring-buffer //////////////////////////////////////////////////////////////////////////////// S _buffer[N]; //////////////////////////////////////////////////////////////////////////////// /// @brief time buffer //////////////////////////////////////////////////////////////////////////////// time_t _start[N]; //////////////////////////////////////////////////////////////////////////////// /// @brief current position //////////////////////////////////////////////////////////////////////////////// size_t _current; //////////////////////////////////////////////////////////////////////////////// /// @brief access lock //////////////////////////////////////////////////////////////////////////////// Mutex _accessLock; }; } } //////////////////////////////////////////////////////////////////////////////// /// @} //////////////////////////////////////////////////////////////////////////////// #endif // Local Variables: // mode: outline-minor // outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" // End: