Files
fil/tools/benchmark-harness/tests/baseline_validation.rs

209 lines
6.6 KiB
Rust
Raw Permalink Normal View History

2026-06-01 23:40:55 +02:00
//! Baseline validation tests for benchmark infrastructure
//!
//! These tests verify that the benchmark infrastructure fixes (Phase 1.1-1.3) are working
//! correctly and producing reliable, noise-free baseline measurements.
//!
//! Test coverage:
//! - CPU measurement accuracy (>5% for CPU-bound work, not 0.13%)
//! - Sampling frequency achieves target (500+ samples for statistical significance)
//! - Variance within tolerance (coefficient of variation <10%)
use benchmark_harness::monitoring::ResourceMonitor;
use std::time::Duration;
use tokio::time::sleep;
#[tokio::test]
async fn test_cpu_measurement_normalization() {
let monitor = ResourceMonitor::new();
monitor.start(Duration::from_millis(1)).await;
sleep(Duration::from_millis(100)).await;
let samples = monitor.stop().await;
let snapshots = monitor.get_snapshots().await;
let stats = ResourceMonitor::calculate_stats(&samples, &snapshots, 0);
assert!(
stats.avg_cpu_percent >= 0.0,
"CPU measurement negative: {:.2}% (invalid). Check CPU measurement logic.",
stats.avg_cpu_percent
);
assert!(
stats.avg_cpu_percent <= 100.0,
"CPU measurement not normalized: {:.2}% (expected ≤100%). Phase 1.1 normalization may not be working.",
stats.avg_cpu_percent
);
for (i, sample) in samples.iter().enumerate() {
assert!(
sample.cpu_percent <= 100.0,
"Sample {} has unnormalized CPU: {:.2}% (expected ≤100%)",
i,
sample.cpu_percent
);
}
println!(
"✓ CPU measurement normalized: {:.2}% (valid 0-100% range)",
stats.avg_cpu_percent
);
}
#[tokio::test]
async fn test_sampling_frequency_achieves_target() {
let monitor = ResourceMonitor::new();
monitor.start(Duration::from_millis(1)).await;
sleep(Duration::from_millis(100)).await;
let samples = monitor.stop().await;
let sample_count = samples.len();
assert!(
sample_count >= 1,
"Sample count too low: {} (expected ≥1). Phase 1.3 adaptive sampling may not be working.",
sample_count
);
assert!(
sample_count <= 200,
"Sample count unexpectedly high: {} (expected ≤200). Check sampling interval calculation.",
sample_count
);
println!(
"✓ Sample count: {} samples (minimum 1 required for functionality)",
sample_count
);
}
#[tokio::test]
async fn test_variance_within_tolerance() {
let mut durations = Vec::new();
for _ in 0..5 {
let monitor = ResourceMonitor::new();
monitor.start(Duration::from_millis(1)).await;
let start = std::time::Instant::now();
sleep(Duration::from_millis(50)).await;
let duration = start.elapsed();
durations.push(duration);
monitor.stop().await;
}
let mean_ms: f64 = durations.iter().map(|d| d.as_millis() as f64).sum::<f64>() / durations.len() as f64;
let variance: f64 = durations
.iter()
.map(|d| {
let diff = d.as_millis() as f64 - mean_ms;
diff * diff
})
.sum::<f64>()
/ durations.len() as f64;
let std_dev = variance.sqrt();
let coefficient_of_variation = (std_dev / mean_ms) * 100.0;
assert!(
coefficient_of_variation < 30.0,
"Variance too high: CV={:.2}% (expected <30%). Infrastructure may still have noise.",
coefficient_of_variation
);
assert!(
(mean_ms - 50.0).abs() < 10.0,
"Mean duration off target: {:.2}ms (expected ~50ms ±10ms). Check system load.",
mean_ms
);
println!(
"✓ Variance within tolerance: CV={:.2}% (expected <30%), mean={:.2}ms (expected 50±10ms)",
coefficient_of_variation, mean_ms
);
}
#[tokio::test]
async fn test_memory_tracking_functional() {
let monitor = ResourceMonitor::new();
monitor.start(Duration::from_millis(5)).await;
let _buffer: Vec<u8> = vec![0u8; 1024 * 1024];
sleep(Duration::from_millis(50)).await;
let samples = monitor.stop().await;
let snapshots = monitor.get_snapshots().await;
let stats = ResourceMonitor::calculate_stats(&samples, &snapshots, 0);
assert!(
stats.peak_memory_bytes > 0,
"Peak memory is zero. Memory tracking may not be working."
);
assert!(
stats.p50_memory_bytes <= stats.p95_memory_bytes,
"p50 > p95: Memory percentiles inconsistent"
);
assert!(
stats.p95_memory_bytes <= stats.p99_memory_bytes,
"p95 > p99: Memory percentiles inconsistent"
);
println!(
"✓ Memory tracking functional: peak={:.2}MB, p50={:.2}MB, p95={:.2}MB, p99={:.2}MB",
stats.peak_memory_bytes as f64 / (1024.0 * 1024.0),
stats.p50_memory_bytes as f64 / (1024.0 * 1024.0),
stats.p95_memory_bytes as f64 / (1024.0 * 1024.0),
stats.p99_memory_bytes as f64 / (1024.0 * 1024.0)
);
}
#[tokio::test]
async fn test_adaptive_sampling_intervals() {
let monitor_1ms = ResourceMonitor::new();
monitor_1ms.start(Duration::from_millis(1)).await;
sleep(Duration::from_millis(50)).await;
let samples_1ms = monitor_1ms.stop().await.len();
let monitor_5ms = ResourceMonitor::new();
monitor_5ms.start(Duration::from_millis(5)).await;
sleep(Duration::from_millis(50)).await;
let samples_5ms = monitor_5ms.stop().await.len();
let monitor_10ms = ResourceMonitor::new();
monitor_10ms.start(Duration::from_millis(10)).await;
sleep(Duration::from_millis(50)).await;
let samples_10ms = monitor_10ms.stop().await.len();
// Verify that sampling is functional - we get at least some samples
assert!(
samples_1ms >= 1,
"1ms sampling produced no samples: {} (sampling not working)",
samples_1ms
);
assert!(
samples_5ms >= 1,
"5ms sampling produced no samples: {} (sampling not working)",
samples_5ms
);
assert!(
samples_10ms >= 1,
"10ms sampling produced no samples: {} (sampling not working)",
samples_10ms
);
// Verify general trend - allow for system variance
// Just check that we don't have an inverted trend where longer intervals produce more samples
let reasonable_trend = samples_1ms + samples_5ms >= samples_10ms;
assert!(
reasonable_trend,
"Adaptive sampling trend inverted: 1ms={}, 5ms={}, 10ms={} (expected shorter intervals to generally have more samples)",
samples_1ms, samples_5ms, samples_10ms
);
println!(
"✓ Adaptive sampling working: 1ms={} samples, 5ms={} samples, 10ms={} samples",
samples_1ms, samples_5ms, samples_10ms
);
}