Skip to main content

waterui_preview_protocol/
bench.rs

1//! Benchmark report wire format shared by `waterui-testing` and the `water` CLI.
2//!
3//! `#[waterui::bench]` tests run under `cargo nextest`; in full-run mode each
4//! bench serializes one [`BenchReport`] JSON file into the directory named by
5//! [`BENCH_REPORT_DIR_ENV`]. `water bench` sets the environment, runs nextest,
6//! and deserializes the same types, so field renames break the build instead of
7//! silently desynchronizing the two halves.
8
9use serde::{Deserialize, Serialize};
10
11/// Environment variable selecting the recorded frame count per measurement.
12///
13/// Setting any of the three run-shape variables switches benches from smoke
14/// mode into a full measurement run.
15pub const BENCH_SAMPLES_ENV: &str = "WATERUI_BENCH_SAMPLES";
16/// Environment variable selecting the unrecorded warmup frame count.
17pub const BENCH_WARMUPS_ENV: &str = "WATERUI_BENCH_WARMUPS";
18/// Environment variable selecting the independent measurement repetitions.
19pub const BENCH_REPETITIONS_ENV: &str = "WATERUI_BENCH_REPETITIONS";
20/// Environment variable naming the directory that receives one
21/// [`BenchReport`] JSON file per executed bench in full-run mode.
22pub const BENCH_REPORT_DIR_ENV: &str = "WATERUI_BENCH_REPORT_DIR";
23
24/// Environment variable capping every bench's p95 frame-time budget, in microseconds.
25pub const BENCH_MAX_P95_US_ENV: &str = "WATERUI_BENCH_MAX_P95_US";
26/// Environment variable capping every bench's mean frame-time budget, in microseconds.
27pub const BENCH_MAX_MEAN_US_ENV: &str = "WATERUI_BENCH_MAX_MEAN_US";
28/// Environment variable capping every bench's rebuild-ratio budget.
29pub const BENCH_MAX_REBUILD_RATIO_ENV: &str = "WATERUI_BENCH_MAX_REBUILD_RATIO";
30/// Environment variable capping every bench's compositor scene-layer budget.
31pub const BENCH_MAX_SCENE_LAYERS_ENV: &str = "WATERUI_BENCH_MAX_SCENE_LAYERS";
32/// Environment variable capping every bench's embedded GPU-surface-layer budget.
33pub const BENCH_MAX_GPU_SURFACE_LAYERS_ENV: &str = "WATERUI_BENCH_MAX_GPU_SURFACE_LAYERS";
34/// Environment variable capping every bench's Vello clip-layer budget.
35pub const BENCH_MAX_CLIP_LAYERS_ENV: &str = "WATERUI_BENCH_MAX_CLIP_LAYERS";
36
37/// File name of one bench's report inside the report directory.
38#[must_use]
39pub fn bench_report_file_name(crate_name: &str, bench_name: &str) -> String {
40    format!("{crate_name}__{bench_name}.json")
41}
42
43/// One executed bench: its identity, run shape, budgets, and measurements.
44#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct BenchReport {
46    /// Package that declared the bench.
47    pub crate_name: String,
48    /// Bench function name (without the `waterui_bench_` prefix).
49    pub bench_name: String,
50    /// Run shape the measurements were recorded with.
51    pub config: BenchRunConfig,
52    /// Effective budgets the run was judged against (attribute budgets merged
53    /// with environment caps), echoed so reporters can show headroom.
54    pub budgets: BenchBudgets,
55    /// Recorded measurements in insertion order.
56    pub measurements: Vec<PerfMeasurement>,
57}
58
59/// Frame-run shape of one bench execution.
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
61pub struct BenchRunConfig {
62    /// Unrecorded frames run before sampling.
63    pub warmups: u32,
64    /// Recorded frames per measurement.
65    pub samples: u32,
66    /// Independent measurement repetitions.
67    pub repetitions: u32,
68}
69
70/// Optional per-metric ceilings applied to every measurement a bench records.
71#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize)]
72pub struct BenchBudgets {
73    /// Maximum allowed 95th-percentile frame time, in microseconds.
74    pub max_p95_us: Option<u64>,
75    /// Maximum allowed mean frame time, in microseconds.
76    pub max_mean_us: Option<u64>,
77    /// Maximum allowed share of sampled frames that rebuilt (0.0..=1.0).
78    pub max_rebuild_ratio: Option<f64>,
79    /// Maximum allowed compositor scene layers submitted by one frame.
80    pub max_scene_layers: Option<u64>,
81    /// Maximum allowed embedded GPU surface layers submitted by one frame.
82    pub max_gpu_surface_layers: Option<u64>,
83    /// Maximum allowed Vello clip layers pushed by one frame.
84    pub max_clip_layers: Option<u64>,
85}
86
87/// Aggregated statistics of one perf measurement.
88#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct PerfMeasurement {
90    /// Scenario name.
91    pub name: String,
92    /// Recorded sample count.
93    pub samples: u64,
94    /// Mean frame time in microseconds.
95    pub mean_us: u64,
96    /// Median frame time in microseconds.
97    pub median_us: u64,
98    /// 95th-percentile frame time in microseconds.
99    pub p95_us: u64,
100    /// Minimum frame time in microseconds.
101    pub min_us: u64,
102    /// Maximum frame time in microseconds.
103    pub max_us: u64,
104    /// Frames that performed a structural rebuild.
105    pub rebuilt_frames: u64,
106    /// Frames that rendered.
107    pub rendered_frames: u64,
108    /// Frames that did no work.
109    pub idle_frames: u64,
110    /// Mean frame time of rendered frames in microseconds.
111    pub rendered_mean_us: u64,
112    /// 95th-percentile frame time of rendered frames in microseconds.
113    pub rendered_p95_us: u64,
114    /// Maximum frame time of rendered frames in microseconds.
115    pub rendered_max_us: u64,
116    /// Frames exceeding the 120 fps budget.
117    pub missed_120fps_frames: u64,
118    /// Frames exceeding the 60 fps budget.
119    pub missed_60fps_frames: u64,
120    /// Measurement-cache hits across the run.
121    pub measurement_cache_hits: u64,
122    /// Measurement-cache misses across the run.
123    pub measurement_cache_misses: u64,
124    /// Compositor scene layers submitted.
125    pub scene_layers: u64,
126    /// Vello scene layers submitted.
127    pub vello_scene_layers: u64,
128    /// GPU surface layers submitted.
129    pub gpu_surface_layers: u64,
130    /// Clip layers pushed.
131    pub clip_layers: u64,
132    /// Maximum clip depth reached.
133    pub max_clip_depth: u64,
134    /// Applied filter count.
135    pub applied_filter_count: u64,
136    /// Applied filter capture time in microseconds.
137    pub applied_filter_capture_us: u64,
138    /// Applied filter effect time in microseconds.
139    pub applied_filter_effect_us: u64,
140    /// Frame phase aggregates.
141    pub phases: PerfPhases,
142    /// Per-frame samples.
143    pub frames: Vec<PerfFrame>,
144}
145
146/// Frame phase aggregates of a perf measurement.
147#[derive(Debug, Clone, Default, Serialize, Deserialize)]
148pub struct PerfPhases {
149    /// Mean rebuild phase time in microseconds.
150    pub rebuild_mean_us: u64,
151    /// 95th-percentile rebuild phase time in microseconds.
152    pub rebuild_p95_us: u64,
153    /// Mean content-build phase time in microseconds.
154    pub build_content_mean_us: u64,
155    /// 95th-percentile content-build phase time in microseconds.
156    pub build_content_p95_us: u64,
157    /// Mean scene-dispatch phase time in microseconds.
158    pub scene_dispatch_mean_us: u64,
159    /// 95th-percentile scene-dispatch phase time in microseconds.
160    pub scene_dispatch_p95_us: u64,
161    /// Mean scene-finish phase time in microseconds.
162    pub scene_finish_mean_us: u64,
163    /// 95th-percentile scene-finish phase time in microseconds.
164    pub scene_finish_p95_us: u64,
165    /// Mean render phase time in microseconds.
166    pub render_mean_us: u64,
167    /// 95th-percentile render phase time in microseconds.
168    pub render_p95_us: u64,
169    /// Mean animation phase time in microseconds.
170    pub animation_mean_us: u64,
171    /// Mean input phase time in microseconds.
172    pub input_mean_us: u64,
173}
174
175/// One recorded perf frame.
176#[derive(Debug, Clone, Serialize, Deserialize)]
177pub struct PerfFrame {
178    /// Frame index within the measurement.
179    pub index: u64,
180    /// Total frame time in microseconds.
181    pub total_us: u64,
182    /// Rebuild phase time in microseconds.
183    pub rebuild_us: u64,
184    /// Content-build phase time in microseconds.
185    pub build_content_us: u64,
186    /// Scene-dispatch phase time in microseconds.
187    pub scene_dispatch_us: u64,
188    /// Scene-finish phase time in microseconds.
189    pub scene_finish_us: u64,
190    /// Render phase time in microseconds.
191    pub render_us: u64,
192    /// Surface acquire time in microseconds.
193    pub acquire_us: u64,
194    /// Present time in microseconds.
195    pub present_us: u64,
196    /// Animation phase time in microseconds.
197    pub animation_us: u64,
198    /// Input phase time in microseconds.
199    pub input_us: u64,
200    /// Executor drain time before the frame in microseconds.
201    pub executor_before_us: u64,
202    /// Executor drain time after the frame in microseconds.
203    pub executor_after_us: u64,
204    /// Whether the frame performed a structural rebuild.
205    pub rebuilt: bool,
206    /// Whether the frame rendered.
207    pub rendered: bool,
208    /// Whether the frame captured a snapshot.
209    pub captured_snapshot: bool,
210    /// Process CPU usage in percent.
211    pub cpu_percent: f64,
212    /// Process memory footprint in bytes.
213    pub memory_bytes: u64,
214    /// GPU frame time (acquire + render + present) in microseconds.
215    pub gpu_frame_us: u64,
216    /// Measurement-cache hits this frame.
217    pub measurement_cache_hits: u64,
218    /// Measurement-cache misses this frame.
219    pub measurement_cache_misses: u64,
220    /// Compositor scene layers this frame.
221    pub scene_layers: u64,
222    /// Vello scene layers this frame.
223    pub vello_scene_layers: u64,
224    /// GPU surface layers this frame.
225    pub gpu_surface_layers: u64,
226    /// Clip layers pushed this frame.
227    pub clip_layers: u64,
228    /// Maximum clip depth this frame.
229    pub max_clip_depth: u64,
230    /// Applied filter count this frame.
231    pub applied_filter_count: u64,
232    /// Applied filter capture time this frame in microseconds.
233    pub applied_filter_capture_us: u64,
234    /// Applied filter effect time this frame in microseconds.
235    pub applied_filter_effect_us: u64,
236}