1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! The bench gate's *smoke test*.
//!
//! # What this test exists to do
//!
//! The committed bench baselines in `docs/benchmarks.md` are the
//! numbers the CI gate compares against. The gate itself is the
//! `bench` CI job; the smoke test this file carries is the
//! cheapest way to prove the gate is wired up at all.
//!
//! Specifically: this test measures the same shape of work the
//! `decode` bench measures (`tools/call` envelope decode) on a
//! hot loop, asserts the per-iteration cost is comfortably
//! under the bench baseline (5× the median), and would fail if
//! a regression made the per-iteration cost 5× worse. The
//! threshold is 5× rather than 1× so the test is stable across
//! CI machines, OSes, and kernel scheduling quirks; the
//! *actual* gate is 1.1× (the `>10% regression` rule in
//! `docs/benchmarks.md`), and the smoke test's looser
//! threshold is what makes a "the gate is working" failure
//! visible without the gate being so tight it flakes on
//! Monday.
//!
//! # What this test is not
//!
//! It is not a bench. The full `cargo bench` run is the source
//! of the committed baseline; this test only asserts the
//! baseline is *plausible* (a single decode is not 5× slower
//! than the median). The actual regression gate lives in
//! `.github/workflows/ci.yml`'s `bench` job, not here.
use Instant;
/// The frame the bench measures; the same envelope the
/// `decode_tools_call` bench exercises. The text is the exact
/// bytes the bench hands the decoder, so a change to the
/// test's text would invalidate the comparison.
///
/// # Why a raw string
///
/// The decoder is the boundary; the test is a
/// throughput measurement, and a hand-written
/// `serde_json::json!()` macro would re-serialise through
/// `serde_json::Value` and add a small but non-zero
/// amount of work the bench does not. The raw
/// string keeps the bytes identical to what a
/// real client would send.
const TOOLS_CALL_FRAME: &str = r#"{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"add","arguments":{"a":2,"b":3}}}"#;
/// The committed baseline for `decode_tools_call` in
/// `docs/benchmarks.md` (median, 1.98.1, aarch64).
///
/// The smoke test runs in *dev* mode (no release profile,
/// no opt-level=3), and the dev/release cost ratio on
/// this code is ~15×. The 5× multiplier on top of the
/// committed release-mode number, plus a 100 ns padding
/// to absorb OS / kernel / cache variation across the
/// three CI runners, lands the threshold at:
/// 200 ns (committed) * 5 (gate margin) * 15 (dev/release) + 100 ns
/// which is what the assertion below compares against.
/// A future commit that makes the decoder 5× slower
/// shows up here as a 5× regression against the
/// committed baseline, not against the dev-mode
/// smoke-test cost, so the test's threshold is
/// anchored to the *bench's* number rather than to
/// the test's own measurement.
const BASELINE_NS: u128 = 200;
const DEV_RELEASE_RATIO: u128 = 15;
const PAD_NS: u128 = 100;
/// How many iterations the smoke test runs. The number
/// is large enough that the elapsed wall time dwarfs
/// the per-iteration timing overhead (a `Instant::now()`
/// is ~25 ns on Linux) and small enough that the
/// test finishes in well under a second.
///
/// 100 000 iterations is the same order of magnitude
/// the divan bench uses, and a smoke test that
/// finishes in under a second is a smoke test a
/// developer will actually leave on.
const ITERATIONS: u64 = 100_000;
/// The smoke test. Runs the decoder on the
/// `tools/call` frame `ITERATIONS` times and asserts
/// the per-iteration cost is below 5× the committed
/// baseline.
///
/// # Errors
///
/// Returns `Err` when the gate would fail — i.e. when
/// the per-iteration cost is above the 5× threshold.
/// The `Err` carries the measured number so a
/// failing run prints "per-iter was N ns, threshold
/// is M ns" rather than just "regression".