1 #ifndef BENCHMARK_STAT_H_ 2 #define BENCHMARK_STAT_H_ 3 4 #include <cmath> 5 #include <limits> 6 #include <ostream> 7 #include <type_traits> 8 9 namespace benchmark { 10 11 template <typename VType, typename NumType> 12 class Stat1; 13 14 template <typename VType, typename NumType> 15 class Stat1MinMax; 16 17 typedef Stat1<float, int64_t> Stat1_f; 18 typedef Stat1<double, int64_t> Stat1_d; 19 typedef Stat1MinMax<float, int64_t> Stat1MinMax_f; 20 typedef Stat1MinMax<double, int64_t> Stat1MinMax_d; 21 22 template <typename VType> 23 class Vector2; 24 template <typename VType> 25 class Vector3; 26 template <typename VType> 27 class Vector4; 28 29 template <typename VType, typename NumType> 30 class Stat1 { 31 public: 32 typedef Stat1<VType, NumType> Self; 33 Stat1()34 Stat1() { Clear(); } 35 // Create a sample of value dat and weight 1 Stat1(const VType & dat)36 explicit Stat1(const VType &dat) { 37 sum_ = dat; 38 sum_squares_ = Sqr(dat); 39 numsamples_ = 1; 40 } 41 // Create statistics for all the samples between begin (included) 42 // and end(excluded) Stat1(const VType * begin,const VType * end)43 explicit Stat1(const VType *begin, const VType *end) { 44 Clear(); 45 for (const VType *item = begin; item < end; ++item) { 46 (*this) += Stat1(*item); 47 } 48 } 49 // Create a sample of value dat and weight w Stat1(const VType & dat,const NumType & w)50 Stat1(const VType &dat, const NumType &w) { 51 sum_ = w * dat; 52 sum_squares_ = w * Sqr(dat); 53 numsamples_ = w; 54 } 55 // Copy operator Stat1(const Self & stat)56 Stat1(const Self &stat) { 57 sum_ = stat.sum_; 58 sum_squares_ = stat.sum_squares_; 59 numsamples_ = stat.numsamples_; 60 } 61 Clear()62 void Clear() { 63 numsamples_ = NumType(); 64 sum_squares_ = sum_ = VType(); 65 } 66 67 Self &operator=(const Self &stat) { 68 sum_ = stat.sum_; 69 sum_squares_ = stat.sum_squares_; 70 numsamples_ = stat.numsamples_; 71 return (*this); 72 } 73 // Merge statistics from two sample sets. 74 Self &operator+=(const Self &stat) { 75 sum_ += stat.sum_; 76 sum_squares_ += stat.sum_squares_; 77 numsamples_ += stat.numsamples_; 78 return (*this); 79 } 80 // The operation opposite to += 81 Self &operator-=(const Self &stat) { 82 sum_ -= stat.sum_; 83 sum_squares_ -= stat.sum_squares_; 84 numsamples_ -= stat.numsamples_; 85 return (*this); 86 } 87 // Multiply the weight of the set of samples by a factor k 88 Self &operator*=(const VType &k) { 89 sum_ *= k; 90 sum_squares_ *= k; 91 numsamples_ *= k; 92 return (*this); 93 } 94 95 // Merge statistics from two sample sets. 96 Self operator+(const Self &stat) const { return Self(*this) += stat; } 97 98 // The operation opposite to + 99 Self operator-(const Self &stat) const { return Self(*this) -= stat; } 100 101 // Multiply the weight of the set of samples by a factor k 102 Self operator*(const VType &k) const { return Self(*this) *= k; } 103 104 // Return the total weight of this sample set numSamples()105 NumType numSamples() const { return numsamples_; } 106 107 // Return the sum of this sample set Sum()108 VType Sum() const { return sum_; } 109 110 // Return the mean of this sample set Mean()111 VType Mean() const { 112 if (numsamples_ == 0) return VType(); 113 return sum_ * (1.0 / numsamples_); 114 } 115 116 // Return the mean of this sample set and compute the standard deviation at 117 // the same time. Mean(VType * stddev)118 VType Mean(VType *stddev) const { 119 if (numsamples_ == 0) return VType(); 120 VType mean = sum_ * (1.0 / numsamples_); 121 if (stddev) { 122 VType avg_squares = sum_squares_ * (1.0 / numsamples_); 123 *stddev = Sqrt(avg_squares - Sqr(mean)); 124 } 125 return mean; 126 } 127 128 // Return the standard deviation of the sample set StdDev()129 VType StdDev() const { 130 if (numsamples_ == 0) return VType(); 131 VType mean = Mean(); 132 VType avg_squares = sum_squares_ * (1.0 / numsamples_); 133 return Sqrt(avg_squares - Sqr(mean)); 134 } 135 136 private: 137 static_assert(std::is_integral<NumType>::value && 138 !std::is_same<NumType, bool>::value, 139 "NumType must be an integral type that is not bool."); 140 // Let i be the index of the samples provided (using +=) 141 // and weight[i],value[i] be the data of sample #i 142 // then the variables have the following meaning: 143 NumType numsamples_; // sum of weight[i]; 144 VType sum_; // sum of weight[i]*value[i]; 145 VType sum_squares_; // sum of weight[i]*value[i]^2; 146 147 // Template function used to square a number. 148 // For a vector we square all components 149 template <typename SType> Sqr(const SType & dat)150 static inline SType Sqr(const SType &dat) { 151 return dat * dat; 152 } 153 154 template <typename SType> Sqr(const Vector2<SType> & dat)155 static inline Vector2<SType> Sqr(const Vector2<SType> &dat) { 156 return dat.MulComponents(dat); 157 } 158 159 template <typename SType> Sqr(const Vector3<SType> & dat)160 static inline Vector3<SType> Sqr(const Vector3<SType> &dat) { 161 return dat.MulComponents(dat); 162 } 163 164 template <typename SType> Sqr(const Vector4<SType> & dat)165 static inline Vector4<SType> Sqr(const Vector4<SType> &dat) { 166 return dat.MulComponents(dat); 167 } 168 169 // Template function used to take the square root of a number. 170 // For a vector we square all components 171 template <typename SType> Sqrt(const SType & dat)172 static inline SType Sqrt(const SType &dat) { 173 // Avoid NaN due to imprecision in the calculations 174 if (dat < 0) return 0; 175 return sqrt(dat); 176 } 177 178 template <typename SType> Sqrt(const Vector2<SType> & dat)179 static inline Vector2<SType> Sqrt(const Vector2<SType> &dat) { 180 // Avoid NaN due to imprecision in the calculations 181 return Max(dat, Vector2<SType>()).Sqrt(); 182 } 183 184 template <typename SType> Sqrt(const Vector3<SType> & dat)185 static inline Vector3<SType> Sqrt(const Vector3<SType> &dat) { 186 // Avoid NaN due to imprecision in the calculations 187 return Max(dat, Vector3<SType>()).Sqrt(); 188 } 189 190 template <typename SType> Sqrt(const Vector4<SType> & dat)191 static inline Vector4<SType> Sqrt(const Vector4<SType> &dat) { 192 // Avoid NaN due to imprecision in the calculations 193 return Max(dat, Vector4<SType>()).Sqrt(); 194 } 195 }; 196 197 // Useful printing function 198 template <typename VType, typename NumType> 199 std::ostream &operator<<(std::ostream &out, const Stat1<VType, NumType> &s) { 200 out << "{ avg = " << s.Mean() << " std = " << s.StdDev() 201 << " nsamples = " << s.NumSamples() << "}"; 202 return out; 203 } 204 205 // Stat1MinMax: same as Stat1, but it also 206 // keeps the Min and Max values; the "-" 207 // operator is disabled because it cannot be implemented 208 // efficiently 209 template <typename VType, typename NumType> 210 class Stat1MinMax : public Stat1<VType, NumType> { 211 public: 212 typedef Stat1MinMax<VType, NumType> Self; 213 Stat1MinMax()214 Stat1MinMax() { Clear(); } 215 // Create a sample of value dat and weight 1 Stat1MinMax(const VType & dat)216 explicit Stat1MinMax(const VType &dat) : Stat1<VType, NumType>(dat) { 217 max_ = dat; 218 min_ = dat; 219 } 220 // Create statistics for all the samples between begin (included) 221 // and end(excluded) Stat1MinMax(const VType * begin,const VType * end)222 explicit Stat1MinMax(const VType *begin, const VType *end) { 223 Clear(); 224 for (const VType *item = begin; item < end; ++item) { 225 (*this) += Stat1MinMax(*item); 226 } 227 } 228 // Create a sample of value dat and weight w Stat1MinMax(const VType & dat,const NumType & w)229 Stat1MinMax(const VType &dat, const NumType &w) 230 : Stat1<VType, NumType>(dat, w) { 231 max_ = dat; 232 min_ = dat; 233 } 234 // Copy operator Stat1MinMax(const Self & stat)235 Stat1MinMax(const Self &stat) : Stat1<VType, NumType>(stat) { 236 max_ = stat.max_; 237 min_ = stat.min_; 238 } 239 Clear()240 void Clear() { 241 Stat1<VType, NumType>::Clear(); 242 if (std::numeric_limits<VType>::has_infinity) { 243 min_ = std::numeric_limits<VType>::infinity(); 244 max_ = -std::numeric_limits<VType>::infinity(); 245 } else { 246 min_ = std::numeric_limits<VType>::max(); 247 max_ = std::numeric_limits<VType>::min(); 248 } 249 } 250 251 Self &operator=(const Self &stat) { 252 this->Stat1<VType, NumType>::operator=(stat); 253 max_ = stat.max_; 254 min_ = stat.min_; 255 return (*this); 256 } 257 // Merge statistics from two sample sets. 258 Self &operator+=(const Self &stat) { 259 this->Stat1<VType, NumType>::operator+=(stat); 260 if (stat.max_ > max_) max_ = stat.max_; 261 if (stat.min_ < min_) min_ = stat.min_; 262 return (*this); 263 } 264 // Multiply the weight of the set of samples by a factor k 265 Self &operator*=(const VType &stat) { 266 this->Stat1<VType, NumType>::operator*=(stat); 267 return (*this); 268 } 269 // Merge statistics from two sample sets. 270 Self operator+(const Self &stat) const { return Self(*this) += stat; } 271 // Multiply the weight of the set of samples by a factor k 272 Self operator*(const VType &k) const { return Self(*this) *= k; } 273 274 // Return the maximal value in this sample set Max()275 VType Max() const { return max_; } 276 // Return the minimal value in this sample set Min()277 VType Min() const { return min_; } 278 279 private: 280 // The - operation makes no sense with Min/Max 281 // unless we keep the full list of values (but we don't) 282 // make it private, and let it undefined so nobody can call it 283 Self &operator-=(const Self &stat); // senseless. let it undefined. 284 285 // The operation opposite to - 286 Self operator-(const Self &stat) const; // senseless. let it undefined. 287 288 // Let i be the index of the samples provided (using +=) 289 // and weight[i],value[i] be the data of sample #i 290 // then the variables have the following meaning: 291 VType max_; // max of value[i] 292 VType min_; // min of value[i] 293 }; 294 295 // Useful printing function 296 template <typename VType, typename NumType> 297 std::ostream &operator<<(std::ostream &out, 298 const Stat1MinMax<VType, NumType> &s) { 299 out << "{ avg = " << s.Mean() << " std = " << s.StdDev() 300 << " nsamples = " << s.NumSamples() << " min = " << s.Min() 301 << " max = " << s.Max() << "}"; 302 return out; 303 } 304 } // end namespace benchmark 305 306 #endif // BENCHMARK_STAT_H_ 307