LogCabin
Core/RollingStat.cc
Go to the documentation of this file.
00001 /* Copyright (c) 2015 Diego Ongaro
00002  *
00003  * Permission to use, copy, modify, and distribute this software for any
00004  * purpose with or without fee is hereby granted, provided that the above
00005  * copyright notice and this permission notice appear in all copies.
00006  *
00007  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
00008  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00009  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
00010  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00011  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00012  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00013  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00014  */
00015 
00016 #include <cmath>
00017 
00018 #include "build/Protocol/ServerStats.pb.h"
00019 #include "Core/RollingStat.h"
00020 #include "Core/StringUtil.h"
00021 
00022 namespace LogCabin {
00023 namespace Core {
00024 
00025 RollingStat::RollingStat()
00026     : count(0)
00027     , ewma2(0)
00028     , ewma4(0)
00029     , exceptionalCount(0)
00030     , last(0)
00031     , lastExceptional()
00032     , max(0)
00033     , min(0)
00034     , sum(0)
00035     , sumSquares(0)
00036 {
00037 }
00038 
00039 RollingStat::~RollingStat()
00040 {
00041 }
00042 
00043 double
00044 RollingStat::getAverage() const
00045 {
00046     if (count == 0)
00047         return 0.0;
00048     return double(sum) / double(count);
00049 }
00050 
00051 uint64_t
00052 RollingStat::getCount() const
00053 {
00054     return count;
00055 }
00056 
00057 double
00058 RollingStat::getEWMA2() const
00059 {
00060     return ewma2;
00061 }
00062 
00063 double
00064 RollingStat::getEWMA4() const
00065 {
00066     return ewma4;
00067 }
00068 
00069 uint64_t
00070 RollingStat::getExceptionalCount() const
00071 {
00072     return exceptionalCount;
00073 }
00074 
00075 std::vector<std::pair<RollingStat::TimePoint, uint64_t>>
00076 RollingStat::getLastExceptional() const
00077 {
00078     std::vector<std::pair<RollingStat::TimePoint, uint64_t>> ret;
00079     ret.insert(ret.begin(), lastExceptional.begin(), lastExceptional.end());
00080     return ret;
00081 }
00082 
00083 uint64_t
00084 RollingStat::getLast() const
00085 {
00086     return last;
00087 }
00088 
00089 uint64_t
00090 RollingStat::getMin() const
00091 {
00092     return min;
00093 }
00094 
00095 uint64_t
00096 RollingStat::getMax() const
00097 {
00098     return max;
00099 }
00100 
00101 uint64_t
00102 RollingStat::getSum() const
00103 {
00104     return sum;
00105 }
00106 
00107 double
00108 RollingStat::getStdDev() const
00109 {
00110     if (count == 0)
00111         return 0.0;
00112     return (sqrt(double(count) * double(sumSquares) - double(sum * sum)) /
00113             double(count));
00114 }
00115 
00116 void
00117 RollingStat::noteExceptional(TimePoint when, uint64_t value)
00118 {
00119     ++exceptionalCount;
00120     if (lastExceptional.size() == 5)
00121         lastExceptional.pop_back();
00122     lastExceptional.emplace_front(when, value);
00123 }
00124 
00125 void
00126 RollingStat::push(uint64_t value)
00127 {
00128     ++count;
00129 
00130     if (count == 1)
00131         ewma2 = double(value);
00132     else
00133         ewma2 = 0.5 * double(value) + 0.5 * ewma2;
00134 
00135     if (count == 1)
00136         ewma4 = double(value);
00137     else
00138         ewma4 = 0.25 * double(value) + 0.75 * ewma4;
00139 
00140     last = value;
00141 
00142     if (value > max)
00143         max = value;
00144 
00145     if (value < min || count == 1)
00146         min = value;
00147 
00148     sum += value;
00149 
00150     sumSquares += value * value;
00151 }
00152 
00153 void
00154 RollingStat::updateProtoBuf(Protocol::RollingStat& message) const
00155 {
00156     message.set_count(getCount());
00157     if (getCount() > 0) {
00158         message.set_average(getAverage());
00159         message.set_ewma2(getEWMA2());
00160         message.set_ewma4(getEWMA4());
00161         message.set_last(getLast());
00162         message.set_min(getMin());
00163         message.set_max(getMax());
00164         message.set_sum(getSum());
00165         message.set_stddev(getStdDev());
00166     }
00167     message.set_exceptional_count(getExceptionalCount());
00168     Core::Time::SteadyTimeConverter timeConverter;
00169     for (auto it = lastExceptional.begin();
00170          it != lastExceptional.end();
00171          ++it) {
00172         Protocol::RollingStat::Exceptional& e =
00173             *message.add_last_exceptional();
00174         e.set_when(timeConverter.unixNanos(it->first));
00175         e.set_value(it->second);
00176     }
00177 }
00178 
00179 std::ostream&
00180 operator<<(std::ostream& os, const RollingStat& stat)
00181 {
00182     os << "count: " << stat.getCount() << std::endl;
00183     if (stat.getCount() > 0) {
00184         os << "average: " << stat.getAverage() << std::endl;
00185         os << "EWMA-2: " << stat.getEWMA2() << std::endl;
00186         os << "EWMA-4: " << stat.getEWMA4() << std::endl;
00187         os << "last: " << stat.getLast() << std::endl;
00188         os << "min: " << stat.getMin() << std::endl;
00189         os << "max: " << stat.getMax() << std::endl;
00190         os << "sum: " << stat.getSum() << std::endl;
00191         os << "stddev: " << stat.getStdDev() << std::endl;
00192     }
00193     os << "exceptional: " << stat.getExceptionalCount() << std::endl;
00194     if (!stat.lastExceptional.empty()) {
00195         os << "Last " << stat.lastExceptional.size() << " exceptional values:"
00196            << std::endl;
00197         Core::Time::SteadyTimeConverter timeConverter;
00198         for (auto it = stat.lastExceptional.begin();
00199              it != stat.lastExceptional.end();
00200              ++it) {
00201             int64_t nanos = timeConverter.unixNanos(it->first);
00202             os << it->second
00203                << " at "
00204                << Core::StringUtil::format("%ld.%09ld",
00205                                            nanos / 1000000000U,
00206                                            nanos % 1000000000U)
00207                << std::endl;
00208         }
00209     }
00210     return os;
00211 }
00212 
00213 } // namespace LogCabin::Core
00214 } // namespace LogCabin
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines