github.com/minio/madmin-go/v2@v2.2.1/timings.go (about)

     1  //
     2  // Copyright (c) 2015-2022 MinIO, Inc.
     3  //
     4  // This file is part of MinIO Object Storage stack
     5  //
     6  // This program is free software: you can redistribute it and/or modify
     7  // it under the terms of the GNU Affero General Public License as
     8  // published by the Free Software Foundation, either version 3 of the
     9  // License, or (at your option) any later version.
    10  //
    11  // This program is distributed in the hope that it will be useful,
    12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  // GNU Affero General Public License for more details.
    15  //
    16  // You should have received a copy of the GNU Affero General Public License
    17  // along with this program. If not, see <http://www.gnu.org/licenses/>.
    18  //
    19  
    20  package madmin
    21  
    22  import (
    23  	"math"
    24  	"sort"
    25  	"time"
    26  )
    27  
    28  // Timings captures all latency metrics
    29  type Timings struct {
    30  	Avg     time.Duration `json:"avg"`   // Average duration per sample
    31  	P50     time.Duration `json:"p50"`   // 50th %ile of all the sample durations
    32  	P75     time.Duration `json:"p75"`   // 75th %ile of all the sample durations
    33  	P95     time.Duration `json:"p95"`   // 95th %ile of all the sample durations
    34  	P99     time.Duration `json:"p99"`   // 99th %ile of all the sample durations
    35  	P999    time.Duration `json:"p999"`  // 99.9th %ile of all the sample durations
    36  	Long5p  time.Duration `json:"l5p"`   // Average duration of the longest 5%
    37  	Short5p time.Duration `json:"s5p"`   // Average duration of the shortest 5%
    38  	Max     time.Duration `json:"max"`   // Max duration
    39  	Min     time.Duration `json:"min"`   // Min duration
    40  	StdDev  time.Duration `json:"sdev"`  // Standard deviation among all the sample durations
    41  	Range   time.Duration `json:"range"` // Delta between Max and Min
    42  }
    43  
    44  // Measure - calculate all the latency measurements
    45  func (ts TimeDurations) Measure() Timings {
    46  	if len(ts) == 0 {
    47  		return Timings{
    48  			Avg:     0,
    49  			P50:     0,
    50  			P75:     0,
    51  			P95:     0,
    52  			P99:     0,
    53  			P999:    0,
    54  			Long5p:  0,
    55  			Short5p: 0,
    56  			Min:     0,
    57  			Max:     0,
    58  			Range:   0,
    59  			StdDev:  0,
    60  		}
    61  	}
    62  	sort.Slice(ts, func(i, j int) bool {
    63  		return int64(ts[i]) < int64(ts[j])
    64  	})
    65  	return Timings{
    66  		Avg:     ts.avg(),
    67  		P50:     ts[ts.Len()/2],
    68  		P75:     ts.p(0.75),
    69  		P95:     ts.p(0.95),
    70  		P99:     ts.p(0.99),
    71  		P999:    ts.p(0.999),
    72  		Long5p:  ts.long5p(),
    73  		Short5p: ts.short5p(),
    74  		Min:     ts.min(),
    75  		Max:     ts.max(),
    76  		Range:   ts.srange(),
    77  		StdDev:  ts.stdDev(),
    78  	}
    79  }
    80  
    81  // TimeDurations is time.Duration segments.
    82  type TimeDurations []time.Duration
    83  
    84  func (ts TimeDurations) Len() int { return len(ts) }
    85  
    86  func (ts TimeDurations) avg() time.Duration {
    87  	var total time.Duration
    88  	for _, t := range ts {
    89  		total += t
    90  	}
    91  	return time.Duration(int(total) / ts.Len())
    92  }
    93  
    94  func (ts TimeDurations) p(p float64) time.Duration {
    95  	return ts[int(float64(ts.Len())*p+0.5)-1]
    96  }
    97  
    98  func (ts TimeDurations) stdDev() time.Duration {
    99  	m := ts.avg()
   100  	s := 0.00
   101  
   102  	for _, t := range ts {
   103  		s += math.Pow(float64(m-t), 2)
   104  	}
   105  
   106  	msq := s / float64(ts.Len())
   107  
   108  	return time.Duration(math.Sqrt(msq))
   109  }
   110  
   111  func (ts TimeDurations) long5p() time.Duration {
   112  	set := ts[int(float64(ts.Len())*0.95+0.5):]
   113  
   114  	if len(set) <= 1 {
   115  		return ts[ts.Len()-1]
   116  	}
   117  
   118  	var t time.Duration
   119  	var i int
   120  	for _, n := range set {
   121  		t += n
   122  		i++
   123  	}
   124  
   125  	return time.Duration(int(t) / i)
   126  }
   127  
   128  func (ts TimeDurations) short5p() time.Duration {
   129  	set := ts[:int(float64(ts.Len())*0.05+0.5)]
   130  
   131  	if len(set) <= 1 {
   132  		return ts[0]
   133  	}
   134  
   135  	var t time.Duration
   136  	var i int
   137  	for _, n := range set {
   138  		t += n
   139  		i++
   140  	}
   141  
   142  	return time.Duration(int(t) / i)
   143  }
   144  
   145  func (ts TimeDurations) min() time.Duration {
   146  	return ts[0]
   147  }
   148  
   149  func (ts TimeDurations) max() time.Duration {
   150  	return ts[ts.Len()-1]
   151  }
   152  
   153  func (ts TimeDurations) srange() time.Duration {
   154  	return ts.max() - ts.min()
   155  }