github.com/MikyChow/arbitrum-go-ethereum@v0.0.0-20230306102812-078da49636de/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 // Samples maintain a statistically-significant selection of values from 14 // a stream. 15 type Sample interface { 16 Clear() 17 Count() int64 18 Max() int64 19 Mean() float64 20 Min() int64 21 Percentile(float64) float64 22 Percentiles([]float64) []float64 23 Size() int 24 Snapshot() Sample 25 StdDev() float64 26 Sum() int64 27 Update(int64) 28 Values() []int64 29 Variance() float64 30 } 31 32 func NewBoundedHistogramSample() Sample { 33 return NewSlidingTimeWindowArraySample(time.Minute * 1) 34 } 35 36 // ExpDecaySample is an exponentially-decaying sample using a forward-decaying 37 // priority reservoir. See Cormode et al's "Forward Decay: A Practical Time 38 // Decay Model for Streaming Systems". 39 // 40 // <http://dimacs.rutgers.edu/~graham/pubs/papers/fwddecay.pdf> 41 type ExpDecaySample struct { 42 alpha float64 43 count int64 44 mutex sync.Mutex 45 reservoirSize int 46 t0, t1 time.Time 47 values *expDecaySampleHeap 48 } 49 50 // NewExpDecaySample constructs a new exponentially-decaying sample with the 51 // given reservoir size and alpha. 52 func NewExpDecaySample(reservoirSize int, alpha float64) Sample { 53 if !Enabled { 54 return NilSample{} 55 } 56 s := &ExpDecaySample{ 57 alpha: alpha, 58 reservoirSize: reservoirSize, 59 t0: time.Now(), 60 values: newExpDecaySampleHeap(reservoirSize), 61 } 62 s.t1 = s.t0.Add(rescaleThreshold) 63 return s 64 } 65 66 // Clear clears all samples. 67 func (s *ExpDecaySample) Clear() { 68 s.mutex.Lock() 69 defer s.mutex.Unlock() 70 s.count = 0 71 s.t0 = time.Now() 72 s.t1 = s.t0.Add(rescaleThreshold) 73 s.values.Clear() 74 } 75 76 // Count returns the number of samples recorded, which may exceed the 77 // reservoir size. 78 func (s *ExpDecaySample) Count() int64 { 79 s.mutex.Lock() 80 defer s.mutex.Unlock() 81 return s.count 82 } 83 84 // Max returns the maximum value in the sample, which may not be the maximum 85 // value ever to be part of the sample. 86 func (s *ExpDecaySample) Max() int64 { 87 return SampleMax(s.Values()) 88 } 89 90 // Mean returns the mean of the values in the sample. 91 func (s *ExpDecaySample) Mean() float64 { 92 return SampleMean(s.Values()) 93 } 94 95 // Min returns the minimum value in the sample, which may not be the minimum 96 // value ever to be part of the sample. 97 func (s *ExpDecaySample) Min() int64 { 98 return SampleMin(s.Values()) 99 } 100 101 // Percentile returns an arbitrary percentile of values in the sample. 102 func (s *ExpDecaySample) Percentile(p float64) float64 { 103 return SamplePercentile(s.Values(), p) 104 } 105 106 // Percentiles returns a slice of arbitrary percentiles of values in the 107 // sample. 108 func (s *ExpDecaySample) Percentiles(ps []float64) []float64 { 109 return SamplePercentiles(s.Values(), ps) 110 } 111 112 // Size returns the size of the sample, which is at most the reservoir size. 113 func (s *ExpDecaySample) Size() int { 114 s.mutex.Lock() 115 defer s.mutex.Unlock() 116 return s.values.Size() 117 } 118 119 // Snapshot returns a read-only copy of the sample. 120 func (s *ExpDecaySample) Snapshot() Sample { 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 &SampleSnapshot{ 129 count: s.count, 130 values: values, 131 } 132 } 133 134 // StdDev returns the standard deviation of the values in the sample. 135 func (s *ExpDecaySample) StdDev() float64 { 136 return SampleStdDev(s.Values()) 137 } 138 139 // Sum returns the sum of the values in the sample. 140 func (s *ExpDecaySample) Sum() int64 { 141 return SampleSum(s.Values()) 142 } 143 144 // Update samples a new value. 145 func (s *ExpDecaySample) Update(v int64) { 146 s.update(time.Now(), v) 147 } 148 149 // Values returns a copy of the values in the sample. 150 func (s *ExpDecaySample) Values() []int64 { 151 s.mutex.Lock() 152 defer s.mutex.Unlock() 153 vals := s.values.Values() 154 values := make([]int64, len(vals)) 155 for i, v := range vals { 156 values[i] = v.v 157 } 158 return values 159 } 160 161 // Variance returns the variance of the values in the sample. 162 func (s *ExpDecaySample) Variance() float64 { 163 return SampleVariance(s.Values()) 164 } 165 166 // update samples a new value at a particular timestamp. This is a method all 167 // its own to facilitate testing. 168 func (s *ExpDecaySample) update(t time.Time, v int64) { 169 s.mutex.Lock() 170 defer s.mutex.Unlock() 171 s.count++ 172 if s.values.Size() == s.reservoirSize { 173 s.values.Pop() 174 } 175 s.values.Push(expDecaySample{ 176 k: math.Exp(t.Sub(s.t0).Seconds()*s.alpha) / rand.Float64(), 177 v: v, 178 }) 179 if t.After(s.t1) { 180 values := s.values.Values() 181 t0 := s.t0 182 s.values.Clear() 183 s.t0 = t 184 s.t1 = s.t0.Add(rescaleThreshold) 185 for _, v := range values { 186 v.k = v.k * math.Exp(-s.alpha*s.t0.Sub(t0).Seconds()) 187 s.values.Push(v) 188 } 189 } 190 } 191 192 // NilSample is a no-op Sample. 193 type NilSample struct{} 194 195 // Clear is a no-op. 196 func (NilSample) Clear() {} 197 198 // Count is a no-op. 199 func (NilSample) Count() int64 { return 0 } 200 201 // Max is a no-op. 202 func (NilSample) Max() int64 { return 0 } 203 204 // Mean is a no-op. 205 func (NilSample) Mean() float64 { return 0.0 } 206 207 // Min is a no-op. 208 func (NilSample) Min() int64 { return 0 } 209 210 // Percentile is a no-op. 211 func (NilSample) Percentile(p float64) float64 { return 0.0 } 212 213 // Percentiles is a no-op. 214 func (NilSample) Percentiles(ps []float64) []float64 { 215 return make([]float64, len(ps)) 216 } 217 218 // Size is a no-op. 219 func (NilSample) Size() int { return 0 } 220 221 // Sample is a no-op. 222 func (NilSample) Snapshot() Sample { return NilSample{} } 223 224 // StdDev is a no-op. 225 func (NilSample) StdDev() float64 { return 0.0 } 226 227 // Sum is a no-op. 228 func (NilSample) Sum() int64 { return 0 } 229 230 // Update is a no-op. 231 func (NilSample) Update(v int64) {} 232 233 // Values is a no-op. 234 func (NilSample) Values() []int64 { return []int64{} } 235 236 // Variance is a no-op. 237 func (NilSample) Variance() float64 { return 0.0 } 238 239 // SampleMax returns the maximum value of the slice of int64. 240 func SampleMax(values []int64) int64 { 241 if len(values) == 0 { 242 return 0 243 } 244 var max int64 = math.MinInt64 245 for _, v := range values { 246 if max < v { 247 max = v 248 } 249 } 250 return max 251 } 252 253 // SampleMean returns the mean value of the slice of int64. 254 func SampleMean(values []int64) float64 { 255 if len(values) == 0 { 256 return 0.0 257 } 258 return float64(SampleSum(values)) / float64(len(values)) 259 } 260 261 // SampleMin returns the minimum value of the slice of int64. 262 func SampleMin(values []int64) int64 { 263 if len(values) == 0 { 264 return 0 265 } 266 var min int64 = math.MaxInt64 267 for _, v := range values { 268 if min > v { 269 min = v 270 } 271 } 272 return min 273 } 274 275 // SamplePercentiles returns an arbitrary percentile of the slice of int64. 276 func SamplePercentile(values int64Slice, p float64) float64 { 277 return SamplePercentiles(values, []float64{p})[0] 278 } 279 280 // SamplePercentiles returns a slice of arbitrary percentiles of the slice of 281 // int64. 282 func SamplePercentiles(values int64Slice, ps []float64) []float64 { 283 scores := make([]float64, len(ps)) 284 size := len(values) 285 if size > 0 { 286 sort.Sort(values) 287 for i, p := range ps { 288 pos := p * float64(size+1) 289 if pos < 1.0 { 290 scores[i] = float64(values[0]) 291 } else if pos >= float64(size) { 292 scores[i] = float64(values[size-1]) 293 } else { 294 lower := float64(values[int(pos)-1]) 295 upper := float64(values[int(pos)]) 296 scores[i] = lower + (pos-math.Floor(pos))*(upper-lower) 297 } 298 } 299 } 300 return scores 301 } 302 303 // SampleSnapshot is a read-only copy of another Sample. 304 type SampleSnapshot struct { 305 count int64 306 values []int64 307 } 308 309 func NewSampleSnapshot(count int64, values []int64) *SampleSnapshot { 310 return &SampleSnapshot{ 311 count: count, 312 values: values, 313 } 314 } 315 316 // Clear panics. 317 func (*SampleSnapshot) Clear() { 318 panic("Clear called on a SampleSnapshot") 319 } 320 321 // Count returns the count of inputs at the time the snapshot was taken. 322 func (s *SampleSnapshot) Count() int64 { return s.count } 323 324 // Max returns the maximal value at the time the snapshot was taken. 325 func (s *SampleSnapshot) Max() int64 { return SampleMax(s.values) } 326 327 // Mean returns the mean value at the time the snapshot was taken. 328 func (s *SampleSnapshot) Mean() float64 { return SampleMean(s.values) } 329 330 // Min returns the minimal value at the time the snapshot was taken. 331 func (s *SampleSnapshot) Min() int64 { return SampleMin(s.values) } 332 333 // Percentile returns an arbitrary percentile of values at the time the 334 // snapshot was taken. 335 func (s *SampleSnapshot) Percentile(p float64) float64 { 336 return SamplePercentile(s.values, p) 337 } 338 339 // Percentiles returns a slice of arbitrary percentiles of values at the time 340 // the snapshot was taken. 341 func (s *SampleSnapshot) Percentiles(ps []float64) []float64 { 342 return SamplePercentiles(s.values, ps) 343 } 344 345 // Size returns the size of the sample at the time the snapshot was taken. 346 func (s *SampleSnapshot) Size() int { return len(s.values) } 347 348 // Snapshot returns the snapshot. 349 func (s *SampleSnapshot) Snapshot() Sample { return s } 350 351 // StdDev returns the standard deviation of values at the time the snapshot was 352 // taken. 353 func (s *SampleSnapshot) StdDev() float64 { return SampleStdDev(s.values) } 354 355 // Sum returns the sum of values at the time the snapshot was taken. 356 func (s *SampleSnapshot) Sum() int64 { return SampleSum(s.values) } 357 358 // Update panics. 359 func (*SampleSnapshot) Update(int64) { 360 panic("Update called on a SampleSnapshot") 361 } 362 363 // Values returns a copy of the values in the sample. 364 func (s *SampleSnapshot) Values() []int64 { 365 values := make([]int64, len(s.values)) 366 copy(values, s.values) 367 return values 368 } 369 370 // Variance returns the variance of values at the time the snapshot was taken. 371 func (s *SampleSnapshot) Variance() float64 { return SampleVariance(s.values) } 372 373 // SampleStdDev returns the standard deviation of the slice of int64. 374 func SampleStdDev(values []int64) float64 { 375 return math.Sqrt(SampleVariance(values)) 376 } 377 378 // SampleSum returns the sum of the slice of int64. 379 func SampleSum(values []int64) int64 { 380 var sum int64 381 for _, v := range values { 382 sum += v 383 } 384 return sum 385 } 386 387 // SampleVariance returns the variance of the slice of int64. 388 func SampleVariance(values []int64) float64 { 389 if len(values) == 0 { 390 return 0.0 391 } 392 m := SampleMean(values) 393 var sum float64 394 for _, v := range values { 395 d := float64(v) - m 396 sum += d * d 397 } 398 return sum / float64(len(values)) 399 } 400 401 // A uniform sample using Vitter's Algorithm R. 402 // 403 // <http://www.cs.umd.edu/~samir/498/vitter.pdf> 404 type UniformSample struct { 405 count int64 406 mutex sync.Mutex 407 reservoirSize int 408 values []int64 409 } 410 411 // NewUniformSample constructs a new uniform sample with the given reservoir 412 // size. 413 func NewUniformSample(reservoirSize int) Sample { 414 if !Enabled { 415 return NilSample{} 416 } 417 return &UniformSample{ 418 reservoirSize: reservoirSize, 419 values: make([]int64, 0, reservoirSize), 420 } 421 } 422 423 // Clear clears all samples. 424 func (s *UniformSample) Clear() { 425 s.mutex.Lock() 426 defer s.mutex.Unlock() 427 s.count = 0 428 s.values = make([]int64, 0, s.reservoirSize) 429 } 430 431 // Count returns the number of samples recorded, which may exceed the 432 // reservoir size. 433 func (s *UniformSample) Count() int64 { 434 s.mutex.Lock() 435 defer s.mutex.Unlock() 436 return s.count 437 } 438 439 // Max returns the maximum value in the sample, which may not be the maximum 440 // value ever to be part of the sample. 441 func (s *UniformSample) Max() int64 { 442 s.mutex.Lock() 443 defer s.mutex.Unlock() 444 return SampleMax(s.values) 445 } 446 447 // Mean returns the mean of the values in the sample. 448 func (s *UniformSample) Mean() float64 { 449 s.mutex.Lock() 450 defer s.mutex.Unlock() 451 return SampleMean(s.values) 452 } 453 454 // Min returns the minimum value in the sample, which may not be the minimum 455 // value ever to be part of the sample. 456 func (s *UniformSample) Min() int64 { 457 s.mutex.Lock() 458 defer s.mutex.Unlock() 459 return SampleMin(s.values) 460 } 461 462 // Percentile returns an arbitrary percentile of values in the sample. 463 func (s *UniformSample) Percentile(p float64) float64 { 464 s.mutex.Lock() 465 defer s.mutex.Unlock() 466 return SamplePercentile(s.values, p) 467 } 468 469 // Percentiles returns a slice of arbitrary percentiles of values in the 470 // sample. 471 func (s *UniformSample) Percentiles(ps []float64) []float64 { 472 s.mutex.Lock() 473 defer s.mutex.Unlock() 474 return SamplePercentiles(s.values, ps) 475 } 476 477 // Size returns the size of the sample, which is at most the reservoir size. 478 func (s *UniformSample) Size() int { 479 s.mutex.Lock() 480 defer s.mutex.Unlock() 481 return len(s.values) 482 } 483 484 // Snapshot returns a read-only copy of the sample. 485 func (s *UniformSample) Snapshot() Sample { 486 s.mutex.Lock() 487 defer s.mutex.Unlock() 488 values := make([]int64, len(s.values)) 489 copy(values, s.values) 490 return &SampleSnapshot{ 491 count: s.count, 492 values: values, 493 } 494 } 495 496 // StdDev returns the standard deviation of the values in the sample. 497 func (s *UniformSample) StdDev() float64 { 498 s.mutex.Lock() 499 defer s.mutex.Unlock() 500 return SampleStdDev(s.values) 501 } 502 503 // Sum returns the sum of the values in the sample. 504 func (s *UniformSample) Sum() int64 { 505 s.mutex.Lock() 506 defer s.mutex.Unlock() 507 return SampleSum(s.values) 508 } 509 510 // Update samples a new value. 511 func (s *UniformSample) Update(v int64) { 512 s.mutex.Lock() 513 defer s.mutex.Unlock() 514 s.count++ 515 if len(s.values) < s.reservoirSize { 516 s.values = append(s.values, v) 517 } else { 518 r := rand.Int63n(s.count) 519 if r < int64(len(s.values)) { 520 s.values[int(r)] = v 521 } 522 } 523 } 524 525 // Values returns a copy of the values in the sample. 526 func (s *UniformSample) Values() []int64 { 527 s.mutex.Lock() 528 defer s.mutex.Unlock() 529 values := make([]int64, len(s.values)) 530 copy(values, s.values) 531 return values 532 } 533 534 // Variance returns the variance of the values in the sample. 535 func (s *UniformSample) Variance() float64 { 536 s.mutex.Lock() 537 defer s.mutex.Unlock() 538 return SampleVariance(s.values) 539 } 540 541 // expDecaySample represents an individual sample in a heap. 542 type expDecaySample struct { 543 k float64 544 v int64 545 } 546 547 func newExpDecaySampleHeap(reservoirSize int) *expDecaySampleHeap { 548 return &expDecaySampleHeap{make([]expDecaySample, 0, reservoirSize)} 549 } 550 551 // expDecaySampleHeap is a min-heap of expDecaySamples. 552 // The internal implementation is copied from the standard library's container/heap 553 type expDecaySampleHeap struct { 554 s []expDecaySample 555 } 556 557 func (h *expDecaySampleHeap) Clear() { 558 h.s = h.s[:0] 559 } 560 561 func (h *expDecaySampleHeap) Push(s expDecaySample) { 562 n := len(h.s) 563 h.s = h.s[0 : n+1] 564 h.s[n] = s 565 h.up(n) 566 } 567 568 func (h *expDecaySampleHeap) Pop() expDecaySample { 569 n := len(h.s) - 1 570 h.s[0], h.s[n] = h.s[n], h.s[0] 571 h.down(0, n) 572 573 n = len(h.s) 574 s := h.s[n-1] 575 h.s = h.s[0 : n-1] 576 return s 577 } 578 579 func (h *expDecaySampleHeap) Size() int { 580 return len(h.s) 581 } 582 583 func (h *expDecaySampleHeap) Values() []expDecaySample { 584 return h.s 585 } 586 587 func (h *expDecaySampleHeap) up(j int) { 588 for { 589 i := (j - 1) / 2 // parent 590 if i == j || !(h.s[j].k < h.s[i].k) { 591 break 592 } 593 h.s[i], h.s[j] = h.s[j], h.s[i] 594 j = i 595 } 596 } 597 598 func (h *expDecaySampleHeap) down(i, n int) { 599 for { 600 j1 := 2*i + 1 601 if j1 >= n || j1 < 0 { // j1 < 0 after int overflow 602 break 603 } 604 j := j1 // left child 605 if j2 := j1 + 1; j2 < n && !(h.s[j1].k < h.s[j2].k) { 606 j = j2 // = 2*i + 2 // right child 607 } 608 if !(h.s[j].k < h.s[i].k) { 609 break 610 } 611 h.s[i], h.s[j] = h.s[j], h.s[i] 612 i = j 613 } 614 } 615 616 // SlidingTimeWindowArraySample is ported from Coda Hale's dropwizard library 617 // <https://github.com/dropwizard/metrics/pull/1139> 618 // A reservoir implementation backed by a sliding window that stores only the 619 // measurements made in the last given window of time 620 type SlidingTimeWindowArraySample struct { 621 startTick int64 622 measurements *ChunkedAssociativeArray 623 window int64 624 count int64 625 lastTick int64 626 mutex sync.Mutex 627 } 628 629 const ( 630 // SlidingTimeWindowCollisionBuffer allow this many duplicate ticks 631 // before overwriting measurements 632 SlidingTimeWindowCollisionBuffer = 256 633 634 // SlidingTimeWindowTrimThreshold is number of updates between trimming data 635 SlidingTimeWindowTrimThreshold = 256 636 637 // SlidingTimeWindowClearBufferTicks is the number of ticks to keep past the 638 // requested trim 639 SlidingTimeWindowClearBufferTicks = int64(time.Hour/time.Nanosecond) * 640 SlidingTimeWindowCollisionBuffer 641 ) 642 643 // NewSlidingTimeWindowArraySample creates new object with given window of time 644 func NewSlidingTimeWindowArraySample(window time.Duration) Sample { 645 if !Enabled { 646 return NilSample{} 647 } 648 return &SlidingTimeWindowArraySample{ 649 startTick: time.Now().UnixNano(), 650 measurements: NewChunkedAssociativeArray(ChunkedAssociativeArrayDefaultChunkSize), 651 window: window.Nanoseconds() * SlidingTimeWindowCollisionBuffer, 652 } 653 } 654 655 // Clear clears all samples. 656 func (s *SlidingTimeWindowArraySample) Clear() { 657 s.mutex.Lock() 658 defer s.mutex.Unlock() 659 s.count = 0 660 s.measurements.Clear() 661 } 662 663 // Count returns the number of samples recorded, which may exceed the 664 // reservoir size. 665 func (s *SlidingTimeWindowArraySample) Count() int64 { 666 s.mutex.Lock() 667 defer s.mutex.Unlock() 668 return s.count 669 } 670 671 // Max returns the maximum value in the sample, which may not be the maximum 672 // value ever to be part of the sample. 673 func (s *SlidingTimeWindowArraySample) Max() int64 { 674 s.mutex.Lock() 675 defer s.mutex.Unlock() 676 s.trim() 677 return SampleMax(s.measurements.Values()) 678 } 679 680 // Mean returns the mean of the values in the sample. 681 func (s *SlidingTimeWindowArraySample) Mean() float64 { 682 s.mutex.Lock() 683 defer s.mutex.Unlock() 684 s.trim() 685 return SampleMean(s.measurements.Values()) 686 } 687 688 // Min returns the minimum value in the sample, which may not be the minimum 689 // value ever to be part of the sample. 690 func (s *SlidingTimeWindowArraySample) Min() int64 { 691 s.mutex.Lock() 692 defer s.mutex.Unlock() 693 s.trim() 694 return SampleMin(s.measurements.Values()) 695 } 696 697 // Percentile returns an arbitrary percentile of values in the sample. 698 func (s *SlidingTimeWindowArraySample) Percentile(p float64) float64 { 699 s.mutex.Lock() 700 defer s.mutex.Unlock() 701 s.trim() 702 return SamplePercentile(s.measurements.Values(), p) 703 } 704 705 // Percentiles returns a slice of arbitrary percentiles of values in the 706 // sample. 707 func (s *SlidingTimeWindowArraySample) Percentiles(ps []float64) []float64 { 708 s.mutex.Lock() 709 defer s.mutex.Unlock() 710 s.trim() 711 return SamplePercentiles(s.measurements.Values(), ps) 712 } 713 714 // Size returns the size of the sample, which is at most the reservoir size. 715 func (s *SlidingTimeWindowArraySample) Size() int { 716 s.mutex.Lock() 717 defer s.mutex.Unlock() 718 s.trim() 719 return s.measurements.Size() 720 } 721 722 // trim requires s.mutex to already be acquired 723 func (s *SlidingTimeWindowArraySample) trim() { 724 now := s.getTick() 725 windowStart := now - s.window 726 windowEnd := now + SlidingTimeWindowClearBufferTicks 727 if windowStart < windowEnd { 728 s.measurements.Trim(windowStart, windowEnd) 729 } else { 730 // long overflow handling that can only happen 1 year after class loading 731 s.measurements.Clear() 732 } 733 } 734 735 // getTick requires s.mutex to already be acquired 736 func (s *SlidingTimeWindowArraySample) getTick() int64 { 737 oldTick := s.lastTick 738 tick := (time.Now().UnixNano() - s.startTick) * SlidingTimeWindowCollisionBuffer 739 var newTick int64 740 if tick-oldTick > 0 { 741 newTick = tick 742 } else { 743 newTick = oldTick + 1 744 } 745 s.lastTick = newTick 746 return newTick 747 } 748 749 // Snapshot returns a read-only copy of the sample. 750 func (s *SlidingTimeWindowArraySample) Snapshot() Sample { 751 s.mutex.Lock() 752 defer s.mutex.Unlock() 753 s.trim() 754 origValues := s.measurements.Values() 755 values := make([]int64, len(origValues)) 756 copy(values, origValues) 757 return &SampleSnapshot{ 758 count: s.count, 759 values: values, 760 } 761 } 762 763 // StdDev returns the standard deviation of the values in the sample. 764 func (s *SlidingTimeWindowArraySample) StdDev() float64 { 765 s.mutex.Lock() 766 defer s.mutex.Unlock() 767 s.trim() 768 return SampleStdDev(s.measurements.Values()) 769 } 770 771 // Sum returns the sum of the values in the sample. 772 func (s *SlidingTimeWindowArraySample) Sum() int64 { 773 s.mutex.Lock() 774 defer s.mutex.Unlock() 775 s.trim() 776 return SampleSum(s.measurements.Values()) 777 } 778 779 // Update samples a new value. 780 func (s *SlidingTimeWindowArraySample) Update(v int64) { 781 s.mutex.Lock() 782 defer s.mutex.Unlock() 783 var newTick int64 784 s.count += 1 785 if s.count%SlidingTimeWindowTrimThreshold == 0 { 786 s.trim() 787 } 788 newTick = s.getTick() 789 longOverflow := newTick < s.lastTick 790 if longOverflow { 791 s.measurements.Clear() 792 } 793 s.measurements.Put(newTick, v) 794 } 795 796 // Values returns a copy of the values in the sample. 797 func (s *SlidingTimeWindowArraySample) Values() []int64 { 798 s.mutex.Lock() 799 defer s.mutex.Unlock() 800 s.trim() 801 origValues := s.measurements.Values() 802 values := make([]int64, len(origValues)) 803 copy(values, origValues) 804 return values 805 } 806 807 // Variance returns the variance of the values in the sample. 808 func (s *SlidingTimeWindowArraySample) Variance() float64 { 809 s.mutex.Lock() 810 defer s.mutex.Unlock() 811 s.trim() 812 return SampleVariance(s.measurements.Values()) 813 } 814 815 type int64Slice []int64 816 817 func (p int64Slice) Len() int { return len(p) } 818 func (p int64Slice) Less(i, j int) bool { return p[i] < p[j] } 819 func (p int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }