github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/utilities/metrics/sample.go (about) 1 package metrics 2 3 import ( 4 "math" 5 "math/rand" 6 "sort" 7 "sync" 8 "time" 9 ) 10 11 const rescaleThreshold = time.Hour 12 13 type Sample interface { 14 Clear() 15 Count() int64 16 Max() int64 17 Mean() float64 18 Min() int64 19 Percentile(float64) float64 20 Percentiles([]float64) []float64 21 Size() int 22 Snapshot() Sample 23 StdDev() float64 24 Sum() int64 25 Update(int64) 26 Values() []int64 27 Variance() float64 28 } 29 30 type ExpDecaySample struct { 31 alpha float64 32 count int64 33 mutex sync.Mutex 34 reservoirSize int 35 t0, t1 time.Time 36 values *expDecaySampleHeap 37 } 38 39 func NewExpDecaySample(reservoirSize int, alpha float64) Sample { 40 if !Enabled { 41 return NilSample{} 42 } 43 s := &ExpDecaySample{ 44 alpha: alpha, 45 reservoirSize: reservoirSize, 46 t0: time.Now(), 47 values: newExpDecaySampleHeap(reservoirSize), 48 } 49 s.t1 = s.t0.Add(rescaleThreshold) 50 return s 51 } 52 53 func (s *ExpDecaySample) Clear() { 54 s.mutex.Lock() 55 defer s.mutex.Unlock() 56 s.count = 0 57 s.t0 = time.Now() 58 s.t1 = s.t0.Add(rescaleThreshold) 59 s.values.Clear() 60 } 61 62 func (s *ExpDecaySample) Count() int64 { 63 s.mutex.Lock() 64 defer s.mutex.Unlock() 65 return s.count 66 } 67 68 func (s *ExpDecaySample) Max() int64 { 69 return SampleMax(s.Values()) 70 } 71 72 func (s *ExpDecaySample) Mean() float64 { 73 return SampleMean(s.Values()) 74 } 75 76 func (s *ExpDecaySample) Min() int64 { 77 return SampleMin(s.Values()) 78 } 79 80 func (s *ExpDecaySample) Percentile(p float64) float64 { 81 return SamplePercentile(s.Values(), p) 82 } 83 84 func (s *ExpDecaySample) Percentiles(ps []float64) []float64 { 85 return SamplePercentiles(s.Values(), ps) 86 } 87 88 func (s *ExpDecaySample) Size() int { 89 s.mutex.Lock() 90 defer s.mutex.Unlock() 91 return s.values.Size() 92 } 93 94 func (s *ExpDecaySample) Snapshot() Sample { 95 s.mutex.Lock() 96 defer s.mutex.Unlock() 97 vals := s.values.Values() 98 values := make([]int64, len(vals)) 99 for i, v := range vals { 100 values[i] = v.v 101 } 102 return &SampleSnapshot{ 103 count: s.count, 104 values: values, 105 } 106 } 107 108 func (s *ExpDecaySample) StdDev() float64 { 109 return SampleStdDev(s.Values()) 110 } 111 112 func (s *ExpDecaySample) Sum() int64 { 113 return SampleSum(s.Values()) 114 } 115 116 func (s *ExpDecaySample) Update(v int64) { 117 s.update(time.Now(), v) 118 } 119 120 func (s *ExpDecaySample) Values() []int64 { 121 s.mutex.Lock() 122 defer s.mutex.Unlock() 123 vals := s.values.Values() 124 values := make([]int64, len(vals)) 125 for i, v := range vals { 126 values[i] = v.v 127 } 128 return values 129 } 130 131 func (s *ExpDecaySample) Variance() float64 { 132 return SampleVariance(s.Values()) 133 } 134 135 func (s *ExpDecaySample) update(t time.Time, v int64) { 136 s.mutex.Lock() 137 defer s.mutex.Unlock() 138 s.count++ 139 if s.values.Size() == s.reservoirSize { 140 s.values.Pop() 141 } 142 s.values.Push(expDecaySample{ 143 k: math.Exp(t.Sub(s.t0).Seconds()*s.alpha) / rand.Float64(), 144 v: v, 145 }) 146 if t.After(s.t1) { 147 values := s.values.Values() 148 t0 := s.t0 149 s.values.Clear() 150 s.t0 = t 151 s.t1 = s.t0.Add(rescaleThreshold) 152 for _, v := range values { 153 v.k = v.k * math.Exp(-s.alpha*s.t0.Sub(t0).Seconds()) 154 s.values.Push(v) 155 } 156 } 157 } 158 159 type NilSample struct{} 160 161 func (NilSample) Clear() {} 162 163 func (NilSample) Count() int64 { return 0 } 164 165 func (NilSample) Max() int64 { return 0 } 166 167 func (NilSample) Mean() float64 { return 0.0 } 168 169 func (NilSample) Min() int64 { return 0 } 170 171 func (NilSample) Percentile(p float64) float64 { return 0.0 } 172 173 func (NilSample) Percentiles(ps []float64) []float64 { 174 return make([]float64, len(ps)) 175 } 176 177 func (NilSample) Size() int { return 0 } 178 179 func (NilSample) Snapshot() Sample { return NilSample{} } 180 181 func (NilSample) StdDev() float64 { return 0.0 } 182 183 func (NilSample) Sum() int64 { return 0 } 184 185 func (NilSample) Update(v int64) {} 186 187 func (NilSample) Values() []int64 { return []int64{} } 188 189 func (NilSample) Variance() float64 { return 0.0 } 190 191 func SampleMax(values []int64) int64 { 192 if 0 == len(values) { 193 return 0 194 } 195 var max int64 = math.MinInt64 196 for _, v := range values { 197 if max < v { 198 max = v 199 } 200 } 201 return max 202 } 203 204 func SampleMean(values []int64) float64 { 205 if 0 == len(values) { 206 return 0.0 207 } 208 return float64(SampleSum(values)) / float64(len(values)) 209 } 210 211 func SampleMin(values []int64) int64 { 212 if 0 == len(values) { 213 return 0 214 } 215 var min int64 = math.MaxInt64 216 for _, v := range values { 217 if min > v { 218 min = v 219 } 220 } 221 return min 222 } 223 224 func SamplePercentile(values int64Slice, p float64) float64 { 225 return SamplePercentiles(values, []float64{p})[0] 226 } 227 228 func SamplePercentiles(values int64Slice, ps []float64) []float64 { 229 scores := make([]float64, len(ps)) 230 size := len(values) 231 if size > 0 { 232 sort.Sort(values) 233 for i, p := range ps { 234 pos := p * float64(size+1) 235 if pos < 1.0 { 236 scores[i] = float64(values[0]) 237 } else if pos >= float64(size) { 238 scores[i] = float64(values[size-1]) 239 } else { 240 lower := float64(values[int(pos)-1]) 241 upper := float64(values[int(pos)]) 242 scores[i] = lower + (pos-math.Floor(pos))*(upper-lower) 243 } 244 } 245 } 246 return scores 247 } 248 249 type SampleSnapshot struct { 250 count int64 251 values []int64 252 } 253 254 func NewSampleSnapshot(count int64, values []int64) *SampleSnapshot { 255 return &SampleSnapshot{ 256 count: count, 257 values: values, 258 } 259 } 260 261 func (*SampleSnapshot) Clear() { 262 panic("Clear called on a SampleSnapshot") 263 } 264 265 func (s *SampleSnapshot) Count() int64 { return s.count } 266 267 func (s *SampleSnapshot) Max() int64 { return SampleMax(s.values) } 268 269 func (s *SampleSnapshot) Mean() float64 { return SampleMean(s.values) } 270 271 func (s *SampleSnapshot) Min() int64 { return SampleMin(s.values) } 272 273 func (s *SampleSnapshot) Percentile(p float64) float64 { 274 return SamplePercentile(s.values, p) 275 } 276 277 func (s *SampleSnapshot) Percentiles(ps []float64) []float64 { 278 return SamplePercentiles(s.values, ps) 279 } 280 281 func (s *SampleSnapshot) Size() int { return len(s.values) } 282 283 func (s *SampleSnapshot) Snapshot() Sample { return s } 284 285 func (s *SampleSnapshot) StdDev() float64 { return SampleStdDev(s.values) } 286 287 func (s *SampleSnapshot) Sum() int64 { return SampleSum(s.values) } 288 289 func (*SampleSnapshot) Update(int64) { 290 panic("Update called on a SampleSnapshot") 291 } 292 293 func (s *SampleSnapshot) Values() []int64 { 294 values := make([]int64, len(s.values)) 295 copy(values, s.values) 296 return values 297 } 298 299 func (s *SampleSnapshot) Variance() float64 { return SampleVariance(s.values) } 300 301 func SampleStdDev(values []int64) float64 { 302 return math.Sqrt(SampleVariance(values)) 303 } 304 305 func SampleSum(values []int64) int64 { 306 var sum int64 307 for _, v := range values { 308 sum += v 309 } 310 return sum 311 } 312 313 func SampleVariance(values []int64) float64 { 314 if 0 == len(values) { 315 return 0.0 316 } 317 m := SampleMean(values) 318 var sum float64 319 for _, v := range values { 320 d := float64(v) - m 321 sum += d * d 322 } 323 return sum / float64(len(values)) 324 } 325 326 type UniformSample struct { 327 count int64 328 mutex sync.Mutex 329 reservoirSize int 330 values []int64 331 } 332 333 func NewUniformSample(reservoirSize int) Sample { 334 if !Enabled { 335 return NilSample{} 336 } 337 return &UniformSample{ 338 reservoirSize: reservoirSize, 339 values: make([]int64, 0, reservoirSize), 340 } 341 } 342 343 func (s *UniformSample) Clear() { 344 s.mutex.Lock() 345 defer s.mutex.Unlock() 346 s.count = 0 347 s.values = make([]int64, 0, s.reservoirSize) 348 } 349 350 func (s *UniformSample) Count() int64 { 351 s.mutex.Lock() 352 defer s.mutex.Unlock() 353 return s.count 354 } 355 356 func (s *UniformSample) Max() int64 { 357 s.mutex.Lock() 358 defer s.mutex.Unlock() 359 return SampleMax(s.values) 360 } 361 362 func (s *UniformSample) Mean() float64 { 363 s.mutex.Lock() 364 defer s.mutex.Unlock() 365 return SampleMean(s.values) 366 } 367 368 func (s *UniformSample) Min() int64 { 369 s.mutex.Lock() 370 defer s.mutex.Unlock() 371 return SampleMin(s.values) 372 } 373 374 func (s *UniformSample) Percentile(p float64) float64 { 375 s.mutex.Lock() 376 defer s.mutex.Unlock() 377 return SamplePercentile(s.values, p) 378 } 379 380 func (s *UniformSample) Percentiles(ps []float64) []float64 { 381 s.mutex.Lock() 382 defer s.mutex.Unlock() 383 return SamplePercentiles(s.values, ps) 384 } 385 386 func (s *UniformSample) Size() int { 387 s.mutex.Lock() 388 defer s.mutex.Unlock() 389 return len(s.values) 390 } 391 392 func (s *UniformSample) Snapshot() Sample { 393 s.mutex.Lock() 394 defer s.mutex.Unlock() 395 values := make([]int64, len(s.values)) 396 copy(values, s.values) 397 return &SampleSnapshot{ 398 count: s.count, 399 values: values, 400 } 401 } 402 403 func (s *UniformSample) StdDev() float64 { 404 s.mutex.Lock() 405 defer s.mutex.Unlock() 406 return SampleStdDev(s.values) 407 } 408 409 func (s *UniformSample) Sum() int64 { 410 s.mutex.Lock() 411 defer s.mutex.Unlock() 412 return SampleSum(s.values) 413 } 414 415 func (s *UniformSample) Update(v int64) { 416 s.mutex.Lock() 417 defer s.mutex.Unlock() 418 s.count++ 419 if len(s.values) < s.reservoirSize { 420 s.values = append(s.values, v) 421 } else { 422 r := rand.Int63n(s.count) 423 if r < int64(len(s.values)) { 424 s.values[int(r)] = v 425 } 426 } 427 } 428 429 func (s *UniformSample) Values() []int64 { 430 s.mutex.Lock() 431 defer s.mutex.Unlock() 432 values := make([]int64, len(s.values)) 433 copy(values, s.values) 434 return values 435 } 436 437 func (s *UniformSample) Variance() float64 { 438 s.mutex.Lock() 439 defer s.mutex.Unlock() 440 return SampleVariance(s.values) 441 } 442 443 type expDecaySample struct { 444 k float64 445 v int64 446 } 447 448 func newExpDecaySampleHeap(reservoirSize int) *expDecaySampleHeap { 449 return &expDecaySampleHeap{make([]expDecaySample, 0, reservoirSize)} 450 } 451 452 type expDecaySampleHeap struct { 453 s []expDecaySample 454 } 455 456 func (h *expDecaySampleHeap) Clear() { 457 h.s = h.s[:0] 458 } 459 460 func (h *expDecaySampleHeap) Push(s expDecaySample) { 461 n := len(h.s) 462 h.s = h.s[0 : n+1] 463 h.s[n] = s 464 h.up(n) 465 } 466 467 func (h *expDecaySampleHeap) Pop() expDecaySample { 468 n := len(h.s) - 1 469 h.s[0], h.s[n] = h.s[n], h.s[0] 470 h.down(0, n) 471 472 n = len(h.s) 473 s := h.s[n-1] 474 h.s = h.s[0 : n-1] 475 return s 476 } 477 478 func (h *expDecaySampleHeap) Size() int { 479 return len(h.s) 480 } 481 482 func (h *expDecaySampleHeap) Values() []expDecaySample { 483 return h.s 484 } 485 486 func (h *expDecaySampleHeap) up(j int) { 487 for { 488 i := (j - 1) / 2 489 if i == j || !(h.s[j].k < h.s[i].k) { 490 break 491 } 492 h.s[i], h.s[j] = h.s[j], h.s[i] 493 j = i 494 } 495 } 496 497 func (h *expDecaySampleHeap) down(i, n int) { 498 for { 499 j1 := 2*i + 1 500 if j1 >= n || j1 < 0 { 501 break 502 } 503 j := j1 504 if j2 := j1 + 1; j2 < n && !(h.s[j1].k < h.s[j2].k) { 505 j = j2 506 } 507 if !(h.s[j].k < h.s[i].k) { 508 break 509 } 510 h.s[i], h.s[j] = h.s[j], h.s[i] 511 i = j 512 } 513 } 514 515 type int64Slice []int64 516 517 func (p int64Slice) Len() int { return len(p) } 518 func (p int64Slice) Less(i, j int) bool { return p[i] < p[j] } 519 func (p int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }