github.com/anycable/anycable-go@v1.5.1/stats/stats.go (about)

     1  // Package stats contains calculation utils for benchmarks
     2  // Based on https://github.com/anycable/websocket-bench/blob/master/benchmark/stat.go
     3  package stats
     4  
     5  import (
     6  	"sort"
     7  	"time"
     8  )
     9  
    10  // RoundToMS returns the number of milliseconds for the given duration
    11  func RoundToMS(d time.Duration) int64 {
    12  	return int64((d + (500 * time.Microsecond)) / time.Millisecond)
    13  }
    14  
    15  // ResAggregate contains duration samples
    16  type ResAggregate struct {
    17  	samples []time.Duration
    18  	sorted  bool
    19  }
    20  
    21  type byAsc []time.Duration
    22  
    23  func (a byAsc) Len() int           { return len(a) }
    24  func (a byAsc) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
    25  func (a byAsc) Less(i, j int) bool { return a[i] < a[j] }
    26  
    27  // Add adds a new sample to the aggregate
    28  func (agg *ResAggregate) Add(rtt time.Duration) {
    29  	agg.samples = append(agg.samples, rtt)
    30  	agg.sorted = false
    31  }
    32  
    33  // Count returns the number of samples
    34  func (agg *ResAggregate) Count() int {
    35  	return len(agg.samples)
    36  }
    37  
    38  // Min returns the min value
    39  func (agg *ResAggregate) Min() time.Duration {
    40  	if agg.Count() == 0 {
    41  		return 0
    42  	}
    43  	agg.sort()
    44  	return agg.samples[0]
    45  }
    46  
    47  // Max returns the max value
    48  func (agg *ResAggregate) Max() time.Duration {
    49  	if agg.Count() == 0 {
    50  		return 0
    51  	}
    52  	agg.sort()
    53  	return agg.samples[len(agg.samples)-1]
    54  }
    55  
    56  // Percentile returns the p-th percentile
    57  func (agg *ResAggregate) Percentile(p int) time.Duration {
    58  	if p <= 0 {
    59  		panic("p must be greater than 0")
    60  	} else if 100 <= p {
    61  		panic("p must be less 100")
    62  	}
    63  
    64  	agg.sort()
    65  
    66  	rank := p * len(agg.samples) / 100
    67  
    68  	if agg.Count() == 0 {
    69  		return 0
    70  	}
    71  
    72  	return agg.samples[rank]
    73  }
    74  
    75  func (agg *ResAggregate) sort() {
    76  	if agg.sorted {
    77  		return
    78  	}
    79  	sort.Sort(byAsc(agg.samples))
    80  	agg.sorted = true
    81  }