On Fri, 2026-09-11 at 14:34 +0200, Tobias Schaffner wrote:
> Add a small primitive that records, per automaton edge, how long the
> monitor dwelled before taking it with a count, a sum and a maximum.
>
> The counters are per-CPU and lock-free, so a monitor's hot path can
> update them without disabling interrupts and without perturbing the latency
> being measured. Keep the state and its entry timestamp in one word so
> nested transitions cannot charge a dwell to the wrong edge.
>
> Signed-off-by: Tobias Schaffner <[email protected]>
> ---
> include/rv/edge_stat.h | 69 ++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 69 insertions(+)
> create mode 100644 include/rv/edge_stat.h
>
> diff --git a/include/rv/edge_stat.h b/include/rv/edge_stat.h
...
> +#define RV_STATE_BITS 8
> +#define RV_STATE_MASK GENMASK(RV_STATE_BITS - 1, 0)
> +#define RV_TS_MASK GENMASK(BITS_PER_LONG - RV_STATE_BITS - 1, 0)
> +
> +#define da_state_of(w) ((unsigned int)((w) & RV_STATE_MASK))
> +#define da_ts_of(w) ((u64)(w) >> RV_STATE_BITS)
> +#define da_state_pack(s, ts) (((((da_state_t)(ts)) & RV_TS_MASK) <<
> RV_STATE_BITS) | \
> + ((da_state_t)(s) & RV_STATE_MASK))
These are barely readable and error prone, can you use FIELD_GET()/FIELD_PREP()?
Thanks,
Gabriele
> +
> +static __always_inline
> +void rv_edge_stat_account(struct rv_edge_stat *s, u64 dwell_ns)
> +{
> + s64 max;
> + int i;
> +
> + local64_inc(&s->count);
> + local64_add(dwell_ns, &s->sum_ns);
> +
> + /* Keep the largest dwell; bound retries if a nested update races us.
> */
> + max = local64_read(&s->max_ns);
> + for (i = 0; dwell_ns > (u64)max; i++) {
> + if (i == MAX_DA_RETRY_RACING_EVENTS) {
> + WARN_ONCE(1, "rv: edge-stat max update exceeded %d
> retries\n",
> + MAX_DA_RETRY_RACING_EVENTS);
> + break;
> + }
> + if (local64_try_cmpxchg(&s->max_ns, &max, dwell_ns))
> + break;
> + }
> +}
> +
> +#endif /* CONFIG_RV_EDGE_STAT */
> +
> +#endif /* _RV_EDGE_STAT_H */