1/* @title: Stat series */
2#pragma once
3#include <stdatomic.h>
4#include <stddef.h>
5#include <stdint.h>
6#include <string.h>
7#include <sync/spinlock.h>
8
9/*
10 * Generic time-bucketed statistics series.
11 *
12 * Subsystems can embed one or more struct stat_series to track
13 * short-term rates (e.g., allocations/sec, frees/sec, requests/sec, etc).
14 *
15 * Each bucket represents a fixed-duration window
16 * The current bucket advances as time passes
17 */
18
19struct stat_bucket {
20 struct stat_series *parent;
21 atomic_size_t count; /* count for this bucket */
22 atomic_size_t sum; /* optional aggregate */
23 void *private; /* private, per subsystem */
24};
25typedef size_t (*stat_series_callback)(struct stat_bucket *bucket);
26
27struct stat_series {
28 stat_series_callback bucket_reset; /* to call upon bucket reset */
29 struct stat_bucket *buckets; /* ringbuffer */
30 uint32_t nbuckets; /* how many buckets */
31 _Atomic uint32_t current; /* current bucket idx */
32 time_t bucket_us; /* duration for each bucket */
33 _Atomic uint64_t last_update_us; /* last time we advanced */
34 void *private; /* private, per subsystem */
35 struct spinlock lock;
36};
37
38struct stat_series *stat_series_create(uint32_t nbuckets, time_t bucket_us,
39 stat_series_callback bucket_reset,
40 void *private);
41
42void stat_series_init(struct stat_series *s, struct stat_bucket *buckets,
43 uint32_t nbuckets, time_t bucket_us,
44 stat_series_callback bucket_reset, void *private);
45void stat_series_reset(struct stat_series *s);
46void stat_series_record(struct stat_series *s, size_t value,
47 stat_series_callback callback);
48
49void stat_series_advance(struct stat_series *s, time_t now_us);
50
51#define stat_series_for_each(series, iter) \
52 for (uint32_t __i = 0; \
53 (iter = &((series)->buckets[__i]), __i < (series)->nbuckets); __i++)
54
55#define STAT_SERIES_DEFINE(name, n, bucket_us) \
56 static struct stat_bucket name##_buckets[(n)] = {0}; \
57 static struct stat_series name = { \
58 .buckets = name##_buckets, \
59 .nbuckets = (n), \
60 .bucket_us = (bucket_us), \
61 };
62
63#define STAT_SERIES_CUR_BUCKET(s) (&(s)->buckets[(s)->current])
64