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