github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/bench/tools/aisloader/stats/statsdplus.go (about) 1 // Package stats provides various structs for collecting stats 2 /* 3 * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 4 */ 5 package stats 6 7 import ( 8 "time" 9 10 "github.com/NVIDIA/aistore/stats/statsd" 11 ) 12 13 const ( 14 get = "get" 15 put = "put" 16 getConfig = "getconfig" 17 throughput = "throughput" 18 latency = "latency" 19 latencyProxy = "latency.proxy" 20 latencyProxyConn = "latency.proxyconn" 21 minLatency = "minlatency" 22 maxLatency = "maxlatency" 23 pending = "pending" 24 count = "count" 25 ) 26 27 type ( 28 BaseMetricAgg struct { 29 name string 30 start time.Time // time current stats started 31 cnt int64 // total # of requests 32 } 33 MetricAgg struct { 34 MetricLatAgg 35 bytes int64 // total bytes by all requests 36 errs int64 // number of failed requests 37 pending int64 38 } 39 MetricLatAgg struct { 40 BaseMetricAgg 41 latency time.Duration // Accumulated request latency 42 43 // self maintained fields 44 minLatency time.Duration 45 maxLatency time.Duration 46 } 47 MetricConfigAgg struct { 48 BaseMetricAgg 49 latency time.Duration 50 minLatency time.Duration 51 maxLatency time.Duration 52 proxyLatency time.Duration 53 minProxyLatency time.Duration 54 maxProxyLatency time.Duration 55 proxyConnLatency time.Duration 56 minProxyConnLatency time.Duration 57 maxProxyConnLatency time.Duration 58 } 59 MetricLatsAgg struct { 60 metrics map[string]*MetricLatAgg 61 } 62 Metrics struct { 63 Put MetricAgg 64 Get MetricAgg 65 Config MetricConfigAgg 66 PutLat MetricLatsAgg 67 GetLat MetricLatsAgg 68 } 69 ) 70 71 func NewStatsdMetrics(start time.Time) Metrics { 72 m := Metrics{} 73 m.Get.start = start 74 m.Put.start = start 75 m.Config.start = start 76 return m 77 } 78 79 func (ma *MetricAgg) Add(size int64, lat time.Duration) { 80 ma.cnt++ 81 ma.latency += lat 82 ma.bytes += size 83 ma.minLatency = min(ma.minLatency, lat) 84 ma.maxLatency = max(ma.maxLatency, lat) 85 } 86 87 func (ma *MetricAgg) AddPending(pending int64) { 88 ma.pending += pending 89 } 90 91 func (ma *MetricAgg) AddErr() { 92 ma.errs++ 93 } 94 95 func (ma *MetricAgg) AvgLatency() float64 { 96 if ma.cnt == 0 { 97 return 0 98 } 99 return float64(ma.latency/time.Millisecond) / float64(ma.cnt) 100 } 101 102 func (ma *MetricAgg) Throughput(end time.Time) int64 { 103 if ma.cnt == 0 { 104 return 0 105 } 106 if end == ma.start { 107 return 0 108 } 109 110 return int64(float64(ma.bytes) / end.Sub(ma.start).Seconds()) 111 } 112 113 func (mgs *MetricLatsAgg) Add(name string, lat time.Duration) { 114 if mgs.metrics == nil { 115 mgs.metrics = make(map[string]*MetricLatAgg) 116 } 117 118 if val, ok := mgs.metrics[name]; !ok { 119 mgs.metrics[name] = &MetricLatAgg{ 120 BaseMetricAgg: BaseMetricAgg{ 121 start: time.Now(), 122 cnt: 1, 123 name: name, 124 }, 125 126 latency: lat, 127 minLatency: lat, 128 maxLatency: lat, 129 } 130 } else { 131 val.cnt++ 132 val.latency += lat 133 val.maxLatency = max(val.maxLatency, lat) 134 val.minLatency = min(val.minLatency, lat) 135 } 136 } 137 138 func (mcg *MetricConfigAgg) Add(lat, _, _ time.Duration) { 139 mcg.cnt++ 140 141 mcg.latency += lat 142 mcg.minLatency = min(mcg.minLatency, lat) 143 mcg.maxLatency = max(mcg.maxLatency, lat) 144 145 mcg.proxyLatency += lat 146 mcg.minProxyLatency = min(mcg.minProxyLatency, lat) 147 mcg.maxProxyLatency = max(mcg.maxProxyLatency, lat) 148 149 mcg.proxyConnLatency += lat 150 mcg.minProxyConnLatency = min(mcg.minProxyConnLatency, lat) 151 mcg.maxProxyConnLatency = max(mcg.maxProxyConnLatency, lat) 152 } 153 154 func (ma *MetricAgg) Send(c *statsd.Client, mType string, general []statsd.Metric, genAggCnt int64) { 155 endTime := time.Now() 156 c.Send(mType, 1, statsd.Metric{ 157 Type: statsd.Counter, 158 Name: count, 159 Value: ma.cnt, 160 }) 161 // don't send anything when cnt == 0 -> no data aggregated 162 if ma.cnt > 0 { 163 c.Send(mType, ma.cnt, statsd.Metric{ 164 Type: statsd.Gauge, 165 Name: pending, 166 Value: ma.pending / ma.cnt, 167 }) 168 c.Send(mType, ma.cnt, 169 statsd.Metric{ 170 Type: statsd.Timer, 171 Name: latency, 172 Value: ma.AvgLatency(), 173 }, 174 statsd.Metric{ 175 Type: statsd.Timer, 176 Name: minLatency, 177 Value: float64(ma.minLatency / time.Millisecond), 178 }, 179 statsd.Metric{ 180 Type: statsd.Timer, 181 Name: maxLatency, 182 Value: float64(ma.maxLatency / time.Millisecond), 183 }, 184 ) 185 c.Send(mType, ma.cnt, statsd.Metric{ 186 Type: statsd.Gauge, 187 Name: throughput, 188 Value: ma.Throughput(endTime), 189 }) 190 } 191 if len(general) != 0 && genAggCnt > 0 { 192 c.Send(mType, genAggCnt, general...) 193 } 194 } 195 196 func (mcg *MetricConfigAgg) Send(c *statsd.Client) { 197 // don't send anything when cnt == 0 -> no data aggregated 198 if mcg.cnt == 0 { 199 return 200 } 201 c.Send(getConfig, 1, 202 statsd.Metric{ 203 Type: statsd.Counter, 204 Name: count, 205 Value: mcg.cnt, 206 }) 207 c.Send(getConfig, mcg.cnt, 208 statsd.Metric{ 209 Type: statsd.Timer, 210 Name: latency, 211 Value: float64(mcg.latency/time.Millisecond) / float64(mcg.cnt), 212 }, 213 statsd.Metric{ 214 Type: statsd.Timer, 215 Name: latencyProxyConn, 216 Value: float64(mcg.proxyConnLatency/time.Millisecond) / float64(mcg.cnt), 217 }, 218 statsd.Metric{ 219 Type: statsd.Timer, 220 Name: latencyProxy, 221 Value: float64(mcg.proxyLatency/time.Millisecond) / float64(mcg.cnt), 222 }, 223 ) 224 } 225 226 func (m *Metrics) SendAll(c *statsd.Client) { 227 var ( 228 aggCntGet, aggCntPut int64 229 generalMetricsGet = make([]statsd.Metric, 0, len(m.GetLat.metrics)) 230 generalMetricsPut = make([]statsd.Metric, 0, len(m.PutLat.metrics)) 231 ) 232 for _, m := range m.GetLat.metrics { 233 generalMetricsGet = append(generalMetricsGet, statsd.Metric{ 234 Type: statsd.Timer, 235 Name: m.name, 236 Value: float64(m.latency/time.Millisecond) / float64(m.cnt), 237 }) 238 // m.cnt is the same for all aggregated metrics 239 aggCntGet = m.cnt 240 } 241 for _, m := range m.PutLat.metrics { 242 generalMetricsPut = append(generalMetricsPut, statsd.Metric{ 243 Type: statsd.Timer, 244 Name: m.name, 245 Value: float64(m.latency/time.Millisecond) / float64(m.cnt), 246 }) 247 // m.cnt is the same for all aggregated metrics 248 aggCntPut = m.cnt 249 } 250 251 m.Get.Send(c, get, generalMetricsGet, aggCntGet) 252 m.Put.Send(c, put, generalMetricsPut, aggCntPut) 253 254 m.Config.Send(c) 255 } 256 257 func ResetMetricsGauges(c *statsd.Client) { 258 c.Send(get, 1, 259 statsd.Metric{ 260 Type: statsd.Gauge, 261 Name: throughput, 262 Value: 0, 263 }, statsd.Metric{ 264 Type: statsd.Gauge, 265 Name: pending, 266 Value: 0, 267 }) 268 269 c.Send(put, 1, 270 statsd.Metric{ 271 Type: statsd.Gauge, 272 Name: throughput, 273 Value: 0, 274 }, statsd.Metric{ 275 Type: statsd.Gauge, 276 Name: pending, 277 Value: 0, 278 }) 279 }