Skip to main content

zenkey_fleet/report/
bench.rs

1//! The bench plane: a measured round-trip, per origin and in aggregate.
2
3use serde::Serialize;
4
5/// One origin's reply-latency distribution in a benchmark (issue #52).
6/// Timed **per reply**, so a fast origin in a fan-out is not charged the
7/// slowest origin's round trip.
8#[derive(Debug, Clone, Serialize)]
9pub struct OriginLatency {
10    pub origin: String,
11    pub replies: usize,
12    pub min_ms: f64,
13    pub p50_ms: f64,
14    pub p95_ms: f64,
15    pub p99_ms: f64,
16    pub max_ms: f64,
17}
18
19/// `zenctl bench rpc` (issue #52).
20#[derive(Debug, Clone, Serialize)]
21pub struct BenchReport {
22    pub key: String,
23    pub requested: usize,
24    pub completed: usize,
25    pub concurrency: usize,
26    /// Error replies (RFC 05 §3) plus calls the GET itself failed.
27    pub errors: usize,
28    /// Calls that drew **zero** replies — counted apart from errors, because
29    /// silence is not a failure and averaging it away would hide it
30    /// (RFC 05 §3.1).
31    pub silent: usize,
32    /// Calls whose task **panicked**: a third population, apart from both
33    /// `errors` and `silent` (#329).
34    ///
35    /// A panicked call answered nothing and measured nothing, and it is not
36    /// news about the fleet — it is news about this tool. Folding it into
37    /// `errors` would blame the producer for a bug here; folding it into
38    /// `silent` would claim an observation nobody made. Dropping it, which is
39    /// what `let Ok(result) = handle.await else { continue }` did, deletes a
40    /// whole population from a report whose other counters exist precisely so
41    /// that a benchmark cannot average a non-answer away (RFC 13 §3 O6).
42    pub panicked: usize,
43    pub elapsed_s: f64,
44    pub calls_per_s: f64,
45    pub origins: Vec<OriginLatency>,
46}