Skip to main content

mobench_sdk/
metrics.rs

1//! Custom benchmark metrics captured alongside the timed samples.
2//!
3//! The timing harness deliberately owns the clock. Benchmark functions can
4//! record small scalar outputs, such as serialized proof length, and the
5//! native JSON ABI attaches them to the report after timing has completed.
6
7use {
8    serde::Serialize,
9    std::{cell::RefCell, collections::BTreeMap},
10};
11
12/// Additional scalar metrics emitted by one native benchmark run.
13#[derive(Debug, Default, Serialize)]
14pub struct CustomMetrics {
15    /// One value per warmup or measured invocation, in execution order.
16    pub sample_u64: BTreeMap<String, Vec<u64>>,
17    /// Run-wide values such as a deduplicated proving-payload size.
18    pub run_u64: BTreeMap<String, u64>,
19}
20
21thread_local! {
22    static CUSTOM_METRICS: RefCell<CustomMetrics> =
23        RefCell::new(CustomMetrics::default());
24}
25
26/// Records an unsigned scalar for the current benchmark invocation.
27///
28/// Values are retained in invocation order, including warmups. Recording uses
29/// thread-local storage so it does not acquire a process-wide lock. Call this
30/// near the end of the benchmark function after producing the measured output.
31pub fn record_sample_u64(name: impl Into<String>, value: u64) {
32    CUSTOM_METRICS.with(|metrics| {
33        metrics
34            .borrow_mut()
35            .sample_u64
36            .entry(name.into())
37            .or_default()
38            .push(value);
39    });
40}
41
42/// Records or replaces an unsigned run-wide scalar.
43///
44/// This is intended for setup code that runs outside the measured region.
45pub fn record_run_u64(name: impl Into<String>, value: u64) {
46    CUSTOM_METRICS.with(|metrics| {
47        metrics.borrow_mut().run_u64.insert(name.into(), value);
48    });
49}
50
51#[cfg(feature = "registry")]
52pub(crate) fn clear() {
53    CUSTOM_METRICS.with(|metrics| {
54        *metrics.borrow_mut() = CustomMetrics::default();
55    });
56}
57
58#[cfg(feature = "registry")]
59pub(crate) fn take() -> CustomMetrics {
60    CUSTOM_METRICS.with(|metrics| std::mem::take(&mut *metrics.borrow_mut()))
61}
62
63impl CustomMetrics {
64    #[cfg(feature = "registry")]
65    pub(crate) fn is_empty(&self) -> bool {
66        self.sample_u64.is_empty() && self.run_u64.is_empty()
67    }
68}