1use alloc::vec::Vec;
27
28#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
30pub struct Counter(u64);
31
32impl Counter {
33 pub const fn new() -> Counter {
34 Counter(0)
35 }
36 pub fn inc(&mut self) {
37 self.0 = self.0.saturating_add(1);
38 }
39 pub fn add(&mut self, n: u64) {
40 self.0 = self.0.saturating_add(n);
41 }
42 pub fn get(&self) -> u64 {
43 self.0
44 }
45}
46
47#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
49pub struct Gauge {
50 v: i64,
51 max: i64,
52}
53
54impl Gauge {
55 pub const fn new() -> Gauge {
56 Gauge { v: 0, max: 0 }
57 }
58 pub fn set(&mut self, v: i64) {
59 self.v = v;
60 self.max = self.max.max(v);
61 }
62 pub fn add(&mut self, d: i64) {
63 self.set(self.v.saturating_add(d));
64 }
65 pub fn get(&self) -> i64 {
66 self.v
67 }
68 pub fn max(&self) -> i64 {
69 self.max
70 }
71}
72
73pub const HIST_BITS: u8 = 5;
75
76fn bucket_of(b: u32, v: u64) -> usize {
78 let sub = 1u64 << b;
79 if v < sub {
80 return v as usize;
81 }
82 let e = 63 - v.leading_zeros();
83 let s = (v >> (e - b)) - sub;
84 (((e - b + 1) as usize) << b) | s as usize
85}
86
87fn bucket_range(b: u32, i: usize) -> (u64, u64) {
89 let sub = 1usize << b;
90 if i < sub {
91 return (i as u64, 1);
92 }
93 let k = (i >> b) as u32;
94 let s = (i & (sub - 1)) as u64;
95 (((1u64 << b) + s) << (k - 1), 1u64 << (k - 1))
96}
97
98fn estimate(b: u32, i: usize, min: u64, max: u64) -> u64 {
100 let (lo, w) = bucket_range(b, i);
101 (lo + (w - 1) / 2).clamp(min, max)
102}
103
104fn rank(pm: u32, n: u64) -> u64 {
106 let r = (pm.min(1000) as u128 * n as u128).div_ceil(1000) as u64;
107 r.clamp(1, n)
108}
109
110#[derive(Clone, Debug, PartialEq, Eq)]
112pub struct Hist {
113 bits: u8,
114 counts: Vec<u64>,
115 n: u64,
116 sum: u128,
117 min: u64,
118 max: u64,
119}
120
121impl Default for Hist {
122 fn default() -> Hist {
123 Hist::new()
124 }
125}
126
127impl Hist {
128 pub fn new() -> Hist {
129 Hist::with_bits(HIST_BITS)
130 }
131 pub fn with_bits(bits: u8) -> Hist {
133 Hist { bits: bits.clamp(1, 8), counts: Vec::new(), n: 0, sum: 0, min: u64::MAX, max: 0 }
134 }
135 pub fn bits(&self) -> u8 {
136 self.bits
137 }
138 pub fn bucket(&self, v: u64) -> usize {
140 bucket_of(self.bits as u32, v)
141 }
142 pub fn range(&self, i: usize) -> (u64, u64) {
144 bucket_range(self.bits as u32, i)
145 }
146 pub fn record(&mut self, v: u64) {
147 self.record_n(v, 1);
148 }
149 pub fn record_n(&mut self, v: u64, n: u64) {
150 if n == 0 {
151 return;
152 }
153 let i = self.bucket(v);
154 if self.counts.len() <= i {
155 self.counts.resize(i + 1, 0);
156 }
157 self.counts[i] = self.counts[i].saturating_add(n);
158 self.n = self.n.saturating_add(n);
159 self.sum = self.sum.saturating_add(v as u128 * n as u128);
160 self.min = self.min.min(v);
161 self.max = self.max.max(v);
162 }
163 pub fn count(&self) -> u64 {
164 self.n
165 }
166 pub fn sum(&self) -> u128 {
167 self.sum
168 }
169 pub fn min(&self) -> Option<u64> {
170 if self.n == 0 { None } else { Some(self.min) }
171 }
172 pub fn max(&self) -> Option<u64> {
173 if self.n == 0 { None } else { Some(self.max) }
174 }
175 pub fn mean(&self) -> Option<u64> {
177 if self.n == 0 { None } else { Some((self.sum / self.n as u128) as u64) }
178 }
179 pub fn quantile(&self, per_mille: u32) -> Option<u64> {
181 if self.n == 0 {
182 return None;
183 }
184 let r = rank(per_mille, self.n);
185 if r == self.n {
186 return Some(self.max);
187 }
188 if r == 1 {
189 return Some(self.min);
190 }
191 let mut cum = 0;
192 for (i, &c) in self.counts.iter().enumerate() {
193 cum += c;
194 if cum >= r {
195 return Some(estimate(self.bits as u32, i, self.min, self.max));
196 }
197 }
198 Some(self.max)
199 }
200 pub fn p50(&self) -> Option<u64> {
201 self.quantile(500)
202 }
203 pub fn p95(&self) -> Option<u64> {
204 self.quantile(950)
205 }
206 pub fn p99(&self) -> Option<u64> {
207 self.quantile(990)
208 }
209 pub fn merge(&mut self, o: &Hist) -> bool {
211 if o.bits != self.bits {
212 return false;
213 }
214 if self.counts.len() < o.counts.len() {
215 self.counts.resize(o.counts.len(), 0);
216 }
217 for (i, &c) in o.counts.iter().enumerate() {
218 self.counts[i] = self.counts[i].saturating_add(c);
219 }
220 self.n = self.n.saturating_add(o.n);
221 self.sum = self.sum.saturating_add(o.sum);
222 self.min = self.min.min(o.min);
223 self.max = self.max.max(o.max);
224 true
225 }
226 pub fn clear(&mut self) {
227 *self = Hist::with_bits(self.bits);
228 }
229 pub fn buckets(&self) -> Vec<(u64, u64, u64)> {
231 self.counts.iter().enumerate().filter(|(_, c)| **c > 0).map(|(i, &c)| {
232 let (lo, w) = self.range(i);
233 (lo, w, c)
234 }).collect()
235 }
236}
237
238#[derive(Clone, Debug, PartialEq, Eq)]
240struct Slot {
241 idx: u64,
243 n: u64,
244 sum: u128,
245 min: u64,
246 max: u64,
247 cells: Vec<(u16, u32)>,
249}
250
251impl Slot {
252 fn empty() -> Slot {
253 Slot { idx: u64::MAX, n: 0, sum: 0, min: u64::MAX, max: 0, cells: Vec::new() }
254 }
255 fn reset(&mut self, idx: u64) {
256 *self = Slot { idx, cells: core::mem::take(&mut self.cells), ..Slot::empty() };
257 self.cells.clear();
258 }
259 fn add(&mut self, bucket: usize, v: u64, n: u32) {
260 let b = bucket as u16;
261 match self.cells.binary_search_by_key(&b, |c| c.0) {
262 Ok(i) => self.cells[i].1 = self.cells[i].1.saturating_add(n),
263 Err(i) => self.cells.insert(i, (b, n)),
264 }
265 self.n = self.n.saturating_add(n as u64);
266 self.sum = self.sum.saturating_add(v as u128 * n as u128);
267 self.min = self.min.min(v);
268 self.max = self.max.max(v);
269 }
270}
271
272fn add_slot(h: &mut Hist, s: &Slot) {
274 for &(b, c) in &s.cells {
275 let i = b as usize;
276 if h.counts.len() <= i {
277 h.counts.resize(i + 1, 0);
278 }
279 h.counts[i] = h.counts[i].saturating_add(c as u64);
280 }
281 h.n = h.n.saturating_add(s.n);
282 h.sum = h.sum.saturating_add(s.sum);
283 h.min = h.min.min(s.min);
284 h.max = h.max.max(s.max);
285}
286
287#[derive(Clone, Debug, PartialEq, Eq)]
289pub struct Window {
290 span: u64,
291 bits: u8,
292 ring: Vec<Slot>,
294 len: usize,
295 head: u64,
297}
298
299impl Window {
300 pub fn new(slots: usize, span: u64) -> Window {
302 Window::with_bits(slots, span, HIST_BITS)
303 }
304 pub fn with_bits(slots: usize, span: u64, bits: u8) -> Window {
305 Window { span: span.max(1), bits: bits.clamp(1, 8), ring: Vec::new(), len: slots.max(1), head: 0 }
306 }
307 pub fn slots(&self) -> usize {
308 self.len
309 }
310 pub fn bytes(&self) -> usize {
312 self.ring.capacity() * core::mem::size_of::<Slot>() + self.ring.iter().map(|s| s.cells.capacity() * core::mem::size_of::<(u16, u32)>()).sum::<usize>()
313 }
314 pub fn span(&self) -> u64 {
315 self.span
316 }
317 pub fn record(&mut self, t: u64, v: u64) -> bool {
320 self.record_n(t, v, 1)
321 }
322 pub fn record_n(&mut self, t: u64, v: u64, n: u32) -> bool {
323 let i = t / self.span;
324 let len = self.len as u64;
325 if i == u64::MAX {
326 return false; }
328 if i > self.head {
329 self.head = i;
330 }
331 if i.saturating_add(len) <= self.head || n == 0 {
332 return false;
333 }
334 let bucket = bucket_of(self.bits as u32, v);
335 if self.ring.is_empty() {
336 self.ring = alloc::vec![Slot::empty(); self.len];
337 }
338 let s = &mut self.ring[(i % len) as usize];
339 if s.idx != i {
340 s.reset(i);
341 }
342 s.add(bucket, v, n);
343 true
344 }
345 fn live(&self, t: u64) -> impl Iterator<Item = &Slot> {
347 let now = t / self.span;
348 let len = self.len as u64;
349 self.ring.iter().filter(move |s| s.idx != u64::MAX && s.idx <= now && s.idx.saturating_add(len) > now)
350 }
351 pub fn hist(&self, t: u64) -> Hist {
353 let mut h = Hist::with_bits(self.bits);
354 for s in self.live(t) {
355 add_slot(&mut h, s);
356 }
357 h
358 }
359 pub fn hist_between(&self, from: u64, to: u64) -> Hist {
362 let mut h = Hist::with_bits(self.bits);
363 let len = self.len as u64;
364 let (a, b) = (from.div_ceil(self.span), to.div_ceil(self.span));
365 for i in a.max(b.saturating_sub(len))..b {
367 if let Some(s) = self.ring.get((i % len) as usize)
368 && s.idx == i
369 {
370 add_slot(&mut h, s);
371 }
372 }
373 h
374 }
375 pub fn count(&self, t: u64) -> u64 {
376 self.live(t).map(|s| s.n).sum()
377 }
378 pub fn sum(&self, t: u64) -> u128 {
379 self.live(t).map(|s| s.sum).sum()
380 }
381 pub fn mean(&self, t: u64) -> Option<u64> {
382 let n = self.count(t);
383 if n == 0 { None } else { Some((self.sum(t) / n as u128) as u64) }
384 }
385 pub fn min(&self, t: u64) -> Option<u64> {
386 self.live(t).filter(|s| s.n > 0).map(|s| s.min).min()
387 }
388 pub fn max(&self, t: u64) -> Option<u64> {
389 self.live(t).filter(|s| s.n > 0).map(|s| s.max).max()
390 }
391 pub fn quantile(&self, t: u64, per_mille: u32) -> Option<u64> {
392 self.hist(t).quantile(per_mille)
393 }
394 pub fn p50(&self, t: u64) -> Option<u64> {
395 self.quantile(t, 500)
396 }
397 pub fn p95(&self, t: u64) -> Option<u64> {
398 self.quantile(t, 950)
399 }
400 pub fn p99(&self, t: u64) -> Option<u64> {
401 self.quantile(t, 990)
402 }
403 pub fn per_slot(&self, t: u64, per_mille: u32) -> Vec<(u64, u64, Option<u64>)> {
406 let now = t / self.span;
407 let len = self.len as u64;
408 let first = now.saturating_sub(len - 1);
409 (first..=now)
410 .map(|i| {
411 let Some(s) = self.ring.get((i % len) as usize).filter(|s| s.idx == i && s.n > 0) else {
412 return (i * self.span, 0, None);
413 };
414 let r = rank(per_mille, s.n);
415 let mut cum = 0u64;
416 let mut v = if r == 1 { s.min } else { s.max };
417 for &(b, c) in s.cells.iter().filter(|_| r > 1 && r < s.n) {
418 cum += c as u64;
419 if cum >= r {
420 v = estimate(self.bits as u32, b as usize, s.min, s.max);
421 break;
422 }
423 }
424 (i * self.span, s.n, Some(v))
425 })
426 .collect()
427 }
428}