LogCabin
|
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