fix(ci): address PR #35 review comments
- Document non-blocking receive contract in perf_bench.rs docstring, confirming no TCP deadlock race (Hoshe #1, critical) - Make shadowcast parser order-independent — flush on new config header instead of requiring Recursive after Symmetric (Hoshe #2) - Fix p95 calculation: use floor(0.95*(N-1)) nearest-rank instead of ceil(0.95*N)-1 which was off-by-one at N=50 (Hoshe #4) - Error on --compare when no baseline file exists (Hoshe #5) - Add D-031 10tps assumption comment to TICK_BUDGET_US (Tyre #1) - Strengthen snapshot assertion: require warmup + half measurement window instead of warmup + 1 (Tyre #2) - Regenerate baseline with corrected p95 (356µs, was 526µs) Hoshe #3 (.PHONY) was already addressed — perf-baseline is in the .PHONY declaration on Makefile line 10. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -55,6 +55,12 @@ fn read_rss_kb() -> Option<u64> {
|
||||
/// Boots the server with production content, runs WARMUP_TICKS to stabilize,
|
||||
/// then measures MEASURE_TICKS of app.update() wall-clock time. Reports entity
|
||||
/// counts from observer snapshots and process RSS.
|
||||
///
|
||||
/// Protocol contract: BridgePlugin uses non-blocking receive (WouldBlock →
|
||||
/// empty input vec), so the server always advances even if the client hasn't
|
||||
/// sent input yet. The server sends a snapshot each tick; the client blocks
|
||||
/// on read until one arrives, then responds with (empty) input. No deadlock
|
||||
/// possible — see TcpBridge::receive_inputs and send_snapshot in bridge/tcp.rs.
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn perf_tick_timing() {
|
||||
@@ -145,12 +151,16 @@ fn perf_tick_timing() {
|
||||
}
|
||||
}
|
||||
|
||||
// Must have received enough data past warmup for meaningful results
|
||||
// Must have received enough measured snapshots for meaningful results.
|
||||
// Require all warmup ticks plus at least half the measurement window.
|
||||
let min_snapshots = WARMUP_TICKS + MEASURE_TICKS / 2;
|
||||
assert!(
|
||||
entity_counts.len() > WARMUP_TICKS,
|
||||
"Only received {} snapshots, need at least {} (warmup) + 1",
|
||||
entity_counts.len() >= min_snapshots,
|
||||
"Only received {} snapshots, need at least {} ({} warmup + {} measured)",
|
||||
entity_counts.len(),
|
||||
WARMUP_TICKS
|
||||
min_snapshots,
|
||||
WARMUP_TICKS,
|
||||
MEASURE_TICKS / 2
|
||||
);
|
||||
|
||||
drop(reader);
|
||||
@@ -174,7 +184,8 @@ fn perf_tick_timing() {
|
||||
|
||||
let mut sorted = measured_us.clone();
|
||||
sorted.sort();
|
||||
let p95_idx = ((sorted.len() as f64 * 0.95).ceil() as usize).saturating_sub(1);
|
||||
// Nearest-rank p95: index = floor(0.95 * (N-1)) for 0-based indexing.
|
||||
let p95_idx = ((sorted.len() - 1) as f64 * 0.95).floor() as usize;
|
||||
let p95 = sorted[p95_idx.min(sorted.len() - 1)];
|
||||
|
||||
let entity_counts_measured: Vec<usize> =
|
||||
|
||||
Reference in New Issue
Block a user