//////////////////////////////////////////////////////////////////////////////// /// @brief utilities for round robin figures /// /// @file /// /// DISCLAIMER /// /// Copyright 2010-2011 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-2011, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #ifndef TRIAGENS_BASICS_ROUND_ROBIN_FIGURES_H #define TRIAGENS_BASICS_ROUND_ROBIN_FIGURES_H 1 #include #include #include #include //////////////////////////////////////////////////////////////////////////////// /// @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; \ } \ }; \ \ 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; \ } \ }; \ \ 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; \ } \ }; \ \ 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; \ } \ }; \ \ 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 vector cuts () { \ triagens::basics::RrfVector g; g << a; return g.value; \ } \ }; \ \ struct n ## Accessor { \ static triagens::basics::RrfDistribution& access (S& 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 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 { //////////////////////////////////////////////////////////////////////////////// /// @brief vector generator //////////////////////////////////////////////////////////////////////////////// struct RrfVector { RrfVector& operator<< (double v) { value.push_back(v); return *this; } 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.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; vector cuts; vector counts; }; //////////////////////////////////////////////////////////////////////////////// /// @brief a distribution 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]; vector cuts; vector counts[N]; }; //////////////////////////////////////////////////////////////////////////////// /// @brief utilities for round robin distributions //////////////////////////////////////////////////////////////////////////////// template class RoundRobinFigures { public: //////////////////////////////////////////////////////////////////////////////// // @brief constructor //////////////////////////////////////////////////////////////////////////////// RoundRobinFigures () { #ifdef TRI_ENABLE_FIGURES 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; #endif } public: //////////////////////////////////////////////////////////////////////////////// // @brief increments a counter //////////////////////////////////////////////////////////////////////////////// template void incCounter () { #ifdef TRI_ENABLE_FIGURES MUTEX_LOCKER(accessLock); checkTime(); S& s = buffer[current]; C::access(s).count += 1; #endif } //////////////////////////////////////////////////////////////////////////////// // @brief decrements a counter //////////////////////////////////////////////////////////////////////////////// template void decCounter () { #ifdef TRI_ENABLE_FIGURES MUTEX_LOCKER(accessLock); checkTime(); S& s = buffer[current]; C::access(s).count -= 1; #endif } //////////////////////////////////////////////////////////////////////////////// // @brief generate a new figure //////////////////////////////////////////////////////////////////////////////// template void addFigure (double value) { #ifdef TRI_ENABLE_FIGURES MUTEX_LOCKER(accessLock); checkTime(); S& s = buffer[current]; F::access(s).count += 1; F::access(s).sum += value; #endif } //////////////////////////////////////////////////////////////////////////////// // @brief generate a new figure //////////////////////////////////////////////////////////////////////////////// template void addFigure (size_t pos, double value) { #ifdef TRI_ENABLE_FIGURES MUTEX_LOCKER(accessLock); checkTime(); S& s = buffer[current]; F::access(s).count[pos] += 1; F::access(s).sum[pos] += value; #endif } //////////////////////////////////////////////////////////////////////////////// // @brief generate a new distribution //////////////////////////////////////////////////////////////////////////////// template void addDistribution (double value) { #ifdef TRI_ENABLE_FIGURES 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 vector::const_iterator i = F::access(s).cuts.begin(); vector::iterator j = F::access(s).counts.begin(); for(; i != F::access(s).cuts.end(); ++i, ++j) { if (value < *i) { (*j)++; return; } } (*j)++; #endif } //////////////////////////////////////////////////////////////////////////////// // @brief generate a new distribution //////////////////////////////////////////////////////////////////////////////// template void addDistribution (size_t pos, double value) { #ifdef TRI_ENABLE_FIGURES 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 vector::const_iterator i = F::access(s).cuts.begin(); vector::iterator j = F::access(s).counts[pos].begin(); for(; i != F::access(s).cuts.end(); ++i, ++j) { if (value < *i) { (*j)++; return; } } (*j)++; #endif } //////////////////////////////////////////////////////////////////////////////// // @brief returns the list of distributions //////////////////////////////////////////////////////////////////////////////// vector values (size_t n = N) { vector result; #ifdef TRI_ENABLE_FIGURES 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; } #endif return result; } //////////////////////////////////////////////////////////////////////////////// // @brief returns the list of distributions and times //////////////////////////////////////////////////////////////////////////////// vector values (vector& times, size_t n = N) { vector result; #ifdef TRI_ENABLE_FIGURES 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; } #endif return result; } protected: //////////////////////////////////////////////////////////////////////////////// // @brief checks if we have to use a new time intervall //////////////////////////////////////////////////////////////////////////////// void checkTime () { #ifdef TRI_ENABLE_FIGURES 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; } #endif } private: #ifdef TRI_ENABLE_FIGURES S buffer[N]; time_t start[N]; size_t current; Mutex accessLock; #endif }; } } #endif