use crate::Backend;
#[derive(Debug, Clone)]
pub struct StressTestConfig {
pub cycles_per_backend: u32,
pub input_sizes: Vec<usize>,
pub backends: Vec<Backend>,
pub thresholds: StressThresholds,
pub master_seed: u64,
}
impl Default for StressTestConfig {
fn default() -> Self {
Self {
cycles_per_backend: 100,
input_sizes: vec![100, 1_000, 10_000, 100_000, 1_000_000],
backends: vec![Backend::Scalar, Backend::AVX2],
thresholds: StressThresholds::default(),
master_seed: 42,
}
}
}
impl StressTestConfig {
#[must_use]
pub fn new(master_seed: u64) -> Self {
Self { master_seed, ..Default::default() }
}
#[must_use]
pub const fn with_cycles(mut self, cycles: u32) -> Self {
self.cycles_per_backend = cycles;
self
}
#[must_use]
pub fn with_input_sizes(mut self, sizes: Vec<usize>) -> Self {
self.input_sizes = sizes;
self
}
#[must_use]
pub fn with_backends(mut self, backends: Vec<Backend>) -> Self {
self.backends = backends;
self
}
#[must_use]
pub fn with_thresholds(mut self, thresholds: StressThresholds) -> Self {
self.thresholds = thresholds;
self
}
#[must_use]
pub fn total_tests(&self) -> usize {
self.backends.len() * self.input_sizes.len() * self.cycles_per_backend as usize
}
}
#[derive(Debug, Clone)]
pub struct StressThresholds {
pub max_op_time_ms: u64,
pub max_memory_bytes: usize,
pub max_timing_variance: f64,
pub max_failure_rate: f64,
}
impl Default for StressThresholds {
fn default() -> Self {
Self {
max_op_time_ms: 1000, max_memory_bytes: 256 * 1024 * 1024, max_timing_variance: 0.5, max_failure_rate: 0.0, }
}
}
impl StressThresholds {
#[must_use]
pub const fn strict() -> Self {
Self {
max_op_time_ms: 100,
max_memory_bytes: 64 * 1024 * 1024,
max_timing_variance: 0.2,
max_failure_rate: 0.0,
}
}
const RELAXED_MAX_OP_TIME_MS: u64 = 5000;
#[must_use]
pub const fn relaxed() -> Self {
Self {
max_op_time_ms: Self::RELAXED_MAX_OP_TIME_MS,
max_memory_bytes: 512 * 1024 * 1024,
max_timing_variance: 1.0,
max_failure_rate: 0.01,
}
}
}
#[derive(Debug, Clone)]
pub struct StressResult {
pub backend: Backend,
pub input_size: usize,
pub cycles_completed: u32,
pub tests_passed: u32,
pub tests_failed: u32,
pub mean_op_time_ms: f64,
pub max_op_time_ms: u64,
pub timing_variance: f64,
pub anomalies: Vec<StressAnomaly>,
}
impl StressResult {
#[must_use]
pub fn passed(&self) -> bool {
self.tests_failed == 0 && self.anomalies.is_empty()
}
#[must_use]
pub fn pass_rate(&self) -> f64 {
let total = self.tests_passed + self.tests_failed;
if total == 0 {
1.0
} else {
self.tests_passed as f64 / total as f64
}
}
}
#[derive(Debug, Clone)]
pub struct StressAnomaly {
pub cycle: u32,
pub kind: StressAnomalyKind,
pub description: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StressAnomalyKind {
SlowOperation,
HighMemory,
TestFailure,
TimingSpike,
NonDeterministic,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_stress_test_config_default() {
let config = StressTestConfig::default();
assert_eq!(config.cycles_per_backend, 100);
assert_eq!(config.input_sizes.len(), 5);
assert_eq!(config.backends.len(), 2);
assert_eq!(config.master_seed, 42);
}
#[test]
fn test_stress_test_config_builder() {
let config = StressTestConfig::new(123)
.with_cycles(50)
.with_input_sizes(vec![100, 1000])
.with_backends(vec![Backend::Scalar])
.with_thresholds(StressThresholds::strict());
assert_eq!(config.master_seed, 123);
assert_eq!(config.cycles_per_backend, 50);
assert_eq!(config.input_sizes.len(), 2);
assert_eq!(config.backends.len(), 1);
}
#[test]
fn test_stress_test_config_total_tests() {
let config = StressTestConfig::default()
.with_cycles(10)
.with_input_sizes(vec![100, 1000, 10000])
.with_backends(vec![Backend::Scalar, Backend::AVX2]);
assert_eq!(config.total_tests(), 60);
}
#[test]
fn test_stress_thresholds_default() {
let thresholds = StressThresholds::default();
assert_eq!(thresholds.max_op_time_ms, 1000);
assert_eq!(thresholds.max_memory_bytes, 256 * 1024 * 1024);
assert!((thresholds.max_timing_variance - 0.5).abs() < 0.001);
assert_eq!(thresholds.max_failure_rate, 0.0);
}
#[test]
fn test_stress_thresholds_strict() {
let thresholds = StressThresholds::strict();
assert_eq!(thresholds.max_op_time_ms, 100);
assert_eq!(thresholds.max_memory_bytes, 64 * 1024 * 1024);
assert!((thresholds.max_timing_variance - 0.2).abs() < 0.001);
}
#[test]
fn test_stress_thresholds_relaxed() {
let thresholds = StressThresholds::relaxed();
assert_eq!(thresholds.max_op_time_ms, 5000);
assert_eq!(thresholds.max_memory_bytes, 512 * 1024 * 1024);
assert!((thresholds.max_timing_variance - 1.0).abs() < 0.001);
}
#[test]
fn test_stress_result_passed() {
let result = StressResult {
backend: Backend::Scalar,
input_size: 1000,
cycles_completed: 10,
tests_passed: 100,
tests_failed: 0,
mean_op_time_ms: 50.0,
max_op_time_ms: 100,
timing_variance: 0.1,
anomalies: vec![],
};
assert!(result.passed());
assert_eq!(result.pass_rate(), 1.0);
}
#[test]
fn test_stress_result_failed() {
let result = StressResult {
backend: Backend::AVX2,
input_size: 10000,
cycles_completed: 10,
tests_passed: 95,
tests_failed: 5,
mean_op_time_ms: 100.0,
max_op_time_ms: 500,
timing_variance: 0.3,
anomalies: vec![],
};
assert!(!result.passed()); assert!((result.pass_rate() - 0.95).abs() < 0.001);
}
#[test]
fn test_stress_result_with_anomaly() {
let result = StressResult {
backend: Backend::Scalar,
input_size: 1000,
cycles_completed: 10,
tests_passed: 100,
tests_failed: 0,
mean_op_time_ms: 50.0,
max_op_time_ms: 100,
timing_variance: 0.1,
anomalies: vec![StressAnomaly {
cycle: 5,
kind: StressAnomalyKind::SlowOperation,
description: "Operation took 200ms".to_string(),
}],
};
assert!(!result.passed()); }
#[test]
fn test_stress_anomaly_kinds() {
assert_eq!(StressAnomalyKind::SlowOperation, StressAnomalyKind::SlowOperation);
assert_ne!(StressAnomalyKind::SlowOperation, StressAnomalyKind::TestFailure);
let _ = StressAnomalyKind::SlowOperation;
let _ = StressAnomalyKind::HighMemory;
let _ = StressAnomalyKind::TestFailure;
let _ = StressAnomalyKind::TimingSpike;
let _ = StressAnomalyKind::NonDeterministic;
}
#[test]
fn test_stress_result_zero_tests() {
let result = StressResult {
backend: Backend::Scalar,
input_size: 0,
cycles_completed: 0,
tests_passed: 0,
tests_failed: 0,
mean_op_time_ms: 0.0,
max_op_time_ms: 0,
timing_variance: 0.0,
anomalies: vec![],
};
assert!(result.passed());
assert_eq!(result.pass_rate(), 1.0);
}
}