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