Files
foxhunt/tests/e2e/tests/performance_validation_tests.rs
jgrusewski eb5fe84e22 🔥 COMPILATION SUCCESS: Complete resolution of all 543+ compilation errors
ARCHITECTURAL ACHIEVEMENTS:
 Zero compilation errors across entire workspace
 Complete elimination of circular dependencies
 Proper configuration architecture with centralized config crate
 Fixed all type mismatches and missing fields
 Restored proper crate structure (config at root level)

MAJOR FIXES:
- Fixed 19 critical data crate compilation errors
- Resolved configuration struct field mismatches
- Fixed enum variant naming (CSV → Csv)
- Corrected type conversions (FromPrimitive, compression types)
- Fixed HashMap key types (u32 vs usize)
- Resolved TLOBProcessor constructor issues

WORKSPACE STATUS:
- All services compile successfully
- Trading Service:  Ready
- Backtesting Service:  Ready
- ML Training Service:  Ready
- TLI Client:  Ready

Only documentation warnings remain (3,316 warnings to be addressed)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-29 10:59:34 +02:00

746 lines
28 KiB
Rust

use std::collections::VecDeque;
use std::sync::Arc;
use tokio::time::{timeout, Duration};
use trading_engine::{
infrastructure::{PerformanceAnalyzer, ResourceMonitor, ThroughputMonitor},
lockfree::{AtomicCounter, RingBuffer},
prelude::*,
simd::SimdProcessor,
timing::{HardwareTimestamp, LatencyTracker, PrecisionTimer},
trading::{OrderManager, PositionManager},
types::{PerformanceMetrics, Price, Quantity, Symbol},
};
/// Comprehensive performance validation and benchmarking tests
pub struct PerformanceValidationTests {
latency_tracker: Arc<LatencyTracker>,
throughput_monitor: Arc<ThroughputMonitor>,
resource_monitor: Arc<ResourceMonitor>,
performance_analyzer: Arc<PerformanceAnalyzer>,
order_manager: Arc<OrderManager>,
position_manager: Arc<PositionManager>,
simd_processor: Arc<SimdProcessor>,
ring_buffer: Arc<RingBuffer<u64>>,
}
impl PerformanceValidationTests {
pub async fn new() -> Result<Self> {
let config = load_test_config().await?;
let latency_tracker = Arc::new(LatencyTracker::new());
let throughput_monitor = Arc::new(ThroughputMonitor::new());
let resource_monitor = Arc::new(ResourceMonitor::new());
let performance_analyzer = Arc::new(PerformanceAnalyzer::new(config.clone()));
let order_manager = Arc::new(OrderManager::new(config.clone()).await?);
let position_manager = Arc::new(PositionManager::new(config.clone()).await?);
let simd_processor = Arc::new(SimdProcessor::new());
let ring_buffer = Arc::new(RingBuffer::new(65536)); // 64k entries
Ok(Self {
latency_tracker,
throughput_monitor,
resource_monitor,
performance_analyzer,
order_manager,
position_manager,
simd_processor,
ring_buffer,
})
}
/// Test 1: Critical path sub-50μs latency validation
/// Steps: 12 comprehensive latency measurement phases
pub async fn test_critical_path_latency_validation(&self) -> Result<WorkflowTestResult> {
let mut result = WorkflowTestResult::new("Critical Path Latency Validation");
// Step 1: Hardware timing calibration
result.add_step("Hardware Timing Calibration").await;
let calibration_start = HardwareTimestamp::now();
let calibration_samples: Vec<u64> = (0..10000)
.map(|_| {
let start = HardwareTimestamp::now();
std::hint::black_box(42); // Prevent optimization
start.elapsed_nanos()
})
.collect();
let calibration_time = calibration_start.elapsed_nanos();
let min_resolution = calibration_samples
.iter()
.filter(|&&x| x > 0)
.min()
.unwrap_or(&1);
let avg_resolution =
calibration_samples.iter().sum::<u64>() as f64 / calibration_samples.len() as f64;
assert!(
*min_resolution <= 50,
"Hardware timing resolution should be ≤50ns, got {}ns",
min_resolution
);
result.add_metric("hardware_resolution_ns", *min_resolution as f64);
result.add_metric("avg_resolution_ns", avg_resolution);
result.add_metric("calibration_time_ns", calibration_time as f64);
// Step 2: RDTSC precision measurement
result.add_step("RDTSC Precision Measurement").await;
let rdtsc_samples: Vec<u64> = (0..1000)
.map(|_| {
let start = HardwareTimestamp::rdtsc_start();
// Minimal operation to measure
let _dummy = 1u64.wrapping_add(2);
HardwareTimestamp::rdtsc_end(start)
})
.collect();
let rdtsc_p50 = percentile(&rdtsc_samples, 50.0);
let rdtsc_p95 = percentile(&rdtsc_samples, 95.0);
let rdtsc_p99 = percentile(&rdtsc_samples, 99.0);
assert!(
rdtsc_p95 <= 100,
"RDTSC P95 should be ≤100ns, got {}ns",
rdtsc_p95
);
result.add_metric("rdtsc_p50_ns", rdtsc_p50 as f64);
result.add_metric("rdtsc_p95_ns", rdtsc_p95 as f64);
result.add_metric("rdtsc_p99_ns", rdtsc_p99 as f64);
// Step 3: Order creation latency measurement
result.add_step("Order Creation Latency").await;
let order_creation_samples: Vec<u64> = (0..10000)
.map(|i| {
let start = HardwareTimestamp::now();
let _order = Order::new(
OrderId::from_u64(i as u64),
Symbol::new("EURUSD"),
OrderType::Market,
OrderSide::Buy,
Quantity::from(100_000),
None,
);
start.elapsed_nanos()
})
.collect();
let creation_p50 = percentile(&order_creation_samples, 50.0);
let creation_p95 = percentile(&order_creation_samples, 95.0);
let creation_p99 = percentile(&order_creation_samples, 99.0);
assert!(
creation_p95 <= 5_000,
"Order creation P95 should be ≤5μs, got {}ns",
creation_p95
);
result.add_metric("order_creation_p50_ns", creation_p50 as f64);
result.add_metric("order_creation_p95_ns", creation_p95 as f64);
// Step 4: Risk validation latency
result.add_step("Risk Validation Latency").await;
let symbol = Symbol::new("EURUSD");
let test_order = Order::new(
OrderId::new(),
symbol.clone(),
OrderType::Market,
OrderSide::Buy,
Quantity::from(100_000),
None,
)?;
let risk_samples: Vec<u64> = {
let mut samples = Vec::with_capacity(1000);
for _ in 0..1000 {
let start = HardwareTimestamp::now();
let _risk_result = self.order_manager.validate_risk_fast(&test_order).await;
let elapsed = start.elapsed_nanos();
samples.push(elapsed);
}
samples
};
let risk_p50 = percentile(&risk_samples, 50.0);
let risk_p95 = percentile(&risk_samples, 95.0);
assert!(
risk_p95 <= 10_000,
"Risk validation P95 should be ≤10μs, got {}ns",
risk_p95
);
result.add_metric("risk_validation_p50_ns", risk_p50 as f64);
result.add_metric("risk_validation_p95_ns", risk_p95 as f64);
// Step 5: Position update latency
result.add_step("Position Update Latency").await;
let position_samples: Vec<u64> = {
let mut samples = Vec::with_capacity(1000);
for i in 0..1000 {
let start = HardwareTimestamp::now();
let _result = self
.position_manager
.update_position_atomic(&symbol, Quantity::from(i as i64 * 100))
.await;
let elapsed = start.elapsed_nanos();
samples.push(elapsed);
}
samples
};
let position_p50 = percentile(&position_samples, 50.0);
let position_p95 = percentile(&position_samples, 95.0);
assert!(
position_p95 <= 8_000,
"Position update P95 should be ≤8μs, got {}ns",
position_p95
);
result.add_metric("position_update_p50_ns", position_p50 as f64);
result.add_metric("position_update_p95_ns", position_p95 as f64);
// Step 6: Lock-free data structure performance
result.add_step("Lock-free Structure Performance").await;
let lockfree_samples: Vec<u64> = (0..10000)
.map(|i| {
let start = HardwareTimestamp::now();
let success = self.ring_buffer.try_push(i);
let elapsed = start.elapsed_nanos();
assert!(success, "Ring buffer push should succeed");
elapsed
})
.collect();
let lockfree_p50 = percentile(&lockfree_samples, 50.0);
let lockfree_p95 = percentile(&lockfree_samples, 95.0);
assert!(
lockfree_p95 <= 500,
"Lock-free push P95 should be ≤500ns, got {}ns",
lockfree_p95
);
result.add_metric("lockfree_push_p50_ns", lockfree_p50 as f64);
result.add_metric("lockfree_push_p95_ns", lockfree_p95 as f64);
// Step 7: SIMD operation performance
result.add_step("SIMD Operation Performance").await;
let simd_data: Vec<f64> = (0..1000).map(|i| i as f64 * 1.1).collect();
let simd_samples: Vec<u64> = (0..1000)
.map(|_| {
let start = HardwareTimestamp::now();
let _result = self.simd_processor.vectorized_multiply(&simd_data, 2.0);
start.elapsed_nanos()
})
.collect();
let simd_p50 = percentile(&simd_samples, 50.0);
let simd_p95 = percentile(&simd_samples, 95.0);
assert!(
simd_p95 <= 2_000,
"SIMD operation P95 should be ≤2μs, got {}ns",
simd_p95
);
result.add_metric("simd_operation_p50_ns", simd_p50 as f64);
result.add_metric("simd_operation_p95_ns", simd_p95 as f64);
// Step 8: End-to-end critical path measurement
result.add_step("End-to-End Critical Path").await;
let e2e_samples: Vec<u64> = {
let mut samples = Vec::with_capacity(1000);
for i in 0..1000 {
let start = HardwareTimestamp::now();
// Critical path: Order creation -> Risk check -> Position update -> Submit
let order = Order::new(
OrderId::from_u64(10000 + i as u64),
symbol.clone(),
OrderType::Market,
OrderSide::Buy,
Quantity::from(100_000),
None,
)?;
let _risk_check = self.order_manager.validate_risk_fast(&order).await;
let _position_update = self
.position_manager
.update_position_atomic(&symbol, Quantity::from(100_000))
.await;
let _submission = self.order_manager.submit_order_fast(order).await;
let elapsed = start.elapsed_nanos();
samples.push(elapsed);
}
Result::<Vec<u64>>::Ok(samples)
}?;
let e2e_p50 = percentile(&e2e_samples, 50.0);
let e2e_p95 = percentile(&e2e_samples, 95.0);
let e2e_p99 = percentile(&e2e_samples, 99.0);
// THE CRITICAL REQUIREMENT: Sub-50μs end-to-end
assert!(
e2e_p95 < 50_000,
"End-to-end critical path too slow: P95={}ns > 50μs",
e2e_p95
);
result.add_metric("e2e_critical_p50_ns", e2e_p50 as f64);
result.add_metric("e2e_critical_p95_ns", e2e_p95 as f64);
result.add_metric("e2e_critical_p99_ns", e2e_p99 as f64);
// Step 9: Jitter analysis
result.add_step("Jitter Analysis").await;
let jitter_samples: Vec<u64> = e2e_samples
.windows(2)
.map(|pair| (pair[1] as i64 - pair[0] as i64).abs() as u64)
.collect();
let jitter_p95 = percentile(&jitter_samples, 95.0);
let jitter_max = jitter_samples.iter().max().unwrap_or(&0);
assert!(
jitter_p95 < 10_000,
"Jitter P95 should be <10μs, got {}ns",
jitter_p95
);
result.add_metric("jitter_p95_ns", jitter_p95 as f64);
result.add_metric("jitter_max_ns", *jitter_max as f64);
// Step 10: Temperature and throttling monitoring
result.add_step("Thermal Performance").await;
let thermal_metrics = self.resource_monitor.get_thermal_metrics().await?;
assert!(
thermal_metrics.cpu_temperature_celsius < 80.0,
"CPU temperature too high: {}°C",
thermal_metrics.cpu_temperature_celsius
);
assert!(
!thermal_metrics.is_throttling,
"CPU should not be throttling"
);
result.add_metric("cpu_temperature", thermal_metrics.cpu_temperature_celsius);
// Step 11: Cache performance analysis
result.add_step("Cache Performance Analysis").await;
let cache_metrics = self.resource_monitor.get_cache_metrics().await?;
assert!(
cache_metrics.l1_hit_rate > 0.95,
"L1 cache hit rate should be >95%"
);
assert!(
cache_metrics.l2_hit_rate > 0.90,
"L2 cache hit rate should be >90%"
);
result.add_metric("l1_hit_rate", cache_metrics.l1_hit_rate);
result.add_metric("l2_hit_rate", cache_metrics.l2_hit_rate);
// Step 12: Sustained performance validation
result.add_step("Sustained Performance").await;
let sustained_start = HardwareTimestamp::now();
let mut sustained_samples = Vec::with_capacity(10000);
// Run for 10 seconds at high frequency
let test_duration = Duration::from_secs(10);
let test_end = sustained_start.add_duration(test_duration);
while HardwareTimestamp::now() < test_end {
let sample_start = HardwareTimestamp::now();
let order = Order::new(
OrderId::new(),
symbol.clone(),
OrderType::Market,
OrderSide::Buy,
Quantity::from(100_000),
None,
)?;
let _risk_check = self.order_manager.validate_risk_fast(&order).await;
let elapsed = sample_start.elapsed_nanos();
sustained_samples.push(elapsed);
}
let sustained_p95 = percentile(&sustained_samples, 95.0);
let sustained_degradation = (sustained_p95 as f64 / e2e_p95 as f64) - 1.0;
assert!(
sustained_degradation < 0.20,
"Sustained performance degradation should be <20%, got {:.1}%",
sustained_degradation * 100.0
);
result.add_metric("sustained_samples", sustained_samples.len() as f64);
result.add_metric("sustained_p95_ns", sustained_p95 as f64);
result.add_metric("performance_degradation", sustained_degradation);
result.mark_success();
Ok(result)
}
/// Test 2: Throughput and scalability benchmarks
/// Steps: 10 comprehensive throughput measurement phases
pub async fn test_throughput_scalability_benchmarks(&self) -> Result<WorkflowTestResult> {
let mut result = WorkflowTestResult::new("Throughput Scalability Benchmarks");
// Step 1: Single-threaded baseline throughput
result.add_step("Single-threaded Baseline").await;
let single_thread_start = HardwareTimestamp::now();
let mut operations_completed = 0u64;
let test_duration = Duration::from_secs(5);
let end_time = single_thread_start.add_duration(test_duration);
while HardwareTimestamp::now() < end_time {
let order = Order::new(
OrderId::from_u64(operations_completed),
Symbol::new("EURUSD"),
OrderType::Market,
OrderSide::Buy,
Quantity::from(100_000),
None,
)?;
let _validation = self.order_manager.validate_risk_fast(&order).await;
operations_completed += 1;
}
let actual_duration = single_thread_start.elapsed_nanos() as f64 / 1_000_000_000.0;
let single_thread_ops_per_sec = operations_completed as f64 / actual_duration;
assert!(
single_thread_ops_per_sec > 100_000.0,
"Single-thread should exceed 100k ops/sec, got {:.0}",
single_thread_ops_per_sec
);
result.add_metric("single_thread_ops_per_sec", single_thread_ops_per_sec);
result.add_metric("single_thread_total_ops", operations_completed as f64);
// Step 2: Multi-threaded throughput scaling
result.add_step("Multi-threaded Scaling").await;
let thread_counts = vec![2, 4, 8, 16];
let mut scaling_results = Vec::new();
for thread_count in thread_counts {
let mt_start = HardwareTimestamp::now();
let operations_per_thread = Arc::new(AtomicCounter::new());
let handles: Vec<_> = (0..thread_count)
.map(|thread_id| {
let counter = operations_per_thread.clone();
let order_manager = self.order_manager.clone();
tokio::spawn(async move {
let thread_start = HardwareTimestamp::now();
let thread_duration = Duration::from_secs(3);
let thread_end = thread_start.add_duration(thread_duration);
let mut local_ops = 0u64;
while HardwareTimestamp::now() < thread_end {
let order = Order::new(
OrderId::from_u64((thread_id as u64) << 32 | local_ops),
Symbol::new("EURUSD"),
OrderType::Market,
OrderSide::Buy,
Quantity::from(100_000),
None,
)?;
let _validation = order_manager.validate_risk_fast(&order).await;
local_ops += 1;
}
counter.add(local_ops);
Result::<u64>::Ok(local_ops)
})
})
.collect();
let thread_results = futures::future::join_all(handles).await;
let mt_duration = mt_start.elapsed_nanos() as f64 / 1_000_000_000.0;
let total_mt_ops = operations_per_thread.get();
let mt_ops_per_sec = total_mt_ops as f64 / mt_duration;
scaling_results.push((thread_count, mt_ops_per_sec));
// Validate scaling efficiency
let scaling_efficiency =
mt_ops_per_sec / (single_thread_ops_per_sec * thread_count as f64);
result.add_metric(
&format!("mt_{}_threads_ops_per_sec", thread_count),
mt_ops_per_sec,
);
result.add_metric(
&format!("mt_{}_threads_efficiency", thread_count),
scaling_efficiency,
);
// Should maintain at least 70% efficiency up to 8 threads
if thread_count <= 8 {
assert!(
scaling_efficiency > 0.70,
"Scaling efficiency for {} threads too low: {:.1}%",
thread_count,
scaling_efficiency * 100.0
);
}
}
// Step 3: Memory bandwidth saturation test
result.add_step("Memory Bandwidth Saturation").await;
let memory_test_data: Vec<f64> = (0..1_000_000).map(|i| i as f64 * 1.1).collect();
let memory_start = HardwareTimestamp::now();
let memory_operations = 1000;
for _ in 0..memory_operations {
let _result = self.simd_processor.vectorized_sum(&memory_test_data);
}
let memory_duration = memory_start.elapsed_nanos() as f64 / 1_000_000.0; // ms
let memory_bandwidth_gbps = (memory_test_data.len() * 8 * memory_operations) as f64
/ 1_000_000_000.0
/ (memory_duration / 1000.0);
result.add_metric("memory_bandwidth_gbps", memory_bandwidth_gbps);
assert!(
memory_bandwidth_gbps > 10.0,
"Memory bandwidth should exceed 10 GB/s"
);
// Step 4: Queue depth and batching optimization
result.add_step("Queue Depth Optimization").await;
let batch_sizes = vec![1, 8, 32, 128, 512];
let mut batch_results = Vec::new();
for batch_size in batch_sizes {
let batch_start = HardwareTimestamp::now();
let total_batches = 1000;
for batch_idx in 0..total_batches {
let mut batch_orders = Vec::with_capacity(batch_size);
for i in 0..batch_size {
let order = Order::new(
OrderId::from_u64((batch_idx * batch_size + i) as u64),
Symbol::new("EURUSD"),
OrderType::Market,
OrderSide::Buy,
Quantity::from(100_000),
None,
)?;
batch_orders.push(order);
}
let _batch_result = self.order_manager.validate_risk_batch(&batch_orders).await;
}
let batch_duration = batch_start.elapsed_nanos() as f64 / 1_000_000_000.0;
let batch_ops_per_sec = (total_batches * batch_size) as f64 / batch_duration;
batch_results.push((batch_size, batch_ops_per_sec));
result.add_metric(
&format!("batch_size_{}_ops_per_sec", batch_size),
batch_ops_per_sec,
);
}
// Find optimal batch size
let optimal_batch = batch_results
.iter()
.max_by(|a, b| a.1.partial_cmp(&b.1).unwrap())
.unwrap();
result.add_metric("optimal_batch_size", optimal_batch.0 as f64);
result.add_metric("optimal_batch_ops_per_sec", optimal_batch.1);
// Step 5: Network I/O throughput simulation
result.add_step("Network I/O Throughput").await;
let network_start = HardwareTimestamp::now();
let message_count = 100_000;
let message_size = 256; // bytes
for i in 0..message_count {
let message = vec![0u8; message_size];
let _serialized = self.order_manager.serialize_order_message(&message).await;
}
let network_duration = network_start.elapsed_nanos() as f64 / 1_000_000_000.0;
let network_messages_per_sec = message_count as f64 / network_duration;
let network_mbps = (message_count * message_size) as f64 / 1_000_000.0 / network_duration;
result.add_metric("network_messages_per_sec", network_messages_per_sec);
result.add_metric("network_throughput_mbps", network_mbps);
assert!(
network_messages_per_sec > 50_000.0,
"Network message rate should exceed 50k/sec"
);
// Step 6: Database write throughput
result.add_step("Database Write Throughput").await;
let db_start = HardwareTimestamp::now();
let db_writes = 10_000;
for i in 0..db_writes {
let trade_record = create_test_trade_record(i);
let _db_result = self.order_manager.persist_trade_record(&trade_record).await;
}
let db_duration = db_start.elapsed_nanos() as f64 / 1_000_000_000.0;
let db_writes_per_sec = db_writes as f64 / db_duration;
result.add_metric("db_writes_per_sec", db_writes_per_sec);
assert!(
db_writes_per_sec > 5_000.0,
"Database writes should exceed 5k/sec"
);
// Step 7: CPU utilization under load
result.add_step("CPU Utilization Analysis").await;
let cpu_start = HardwareTimestamp::now();
let baseline_cpu = self.resource_monitor.get_cpu_usage().await?;
// Generate high load
let high_load_duration = Duration::from_secs(5);
let load_end = cpu_start.add_duration(high_load_duration);
let _load_task = tokio::spawn(async move {
while HardwareTimestamp::now() < load_end {
// Simulate trading workload
let _computation = (0..1000).map(|x| x * x).sum::<i32>();
}
});
tokio::time::sleep(Duration::from_secs(2)).await;
let load_cpu = self.resource_monitor.get_cpu_usage().await?;
let cpu_utilization = load_cpu.user_percent + load_cpu.system_percent;
result.add_metric("cpu_utilization_percent", cpu_utilization);
result.add_metric("cpu_user_percent", load_cpu.user_percent);
result.add_metric("cpu_system_percent", load_cpu.system_percent);
assert!(
cpu_utilization < 90.0,
"CPU utilization should stay below 90%"
);
// Step 8: Memory allocation and GC pressure
result.add_step("Memory Allocation Analysis").await;
let memory_start = self.resource_monitor.get_memory_usage().await?;
// Allocate and deallocate memory to test pressure
let allocation_cycles = 1000;
for _ in 0..allocation_cycles {
let large_allocation: Vec<u64> = (0..10_000).collect();
std::hint::black_box(&large_allocation); // Prevent optimization
}
let memory_end = self.resource_monitor.get_memory_usage().await?;
let memory_growth = memory_end.used_mb - memory_start.used_mb;
result.add_metric("memory_growth_mb", memory_growth);
result.add_metric("memory_utilization_percent", memory_end.utilization_percent);
// Memory growth should be reasonable (not a major leak)
assert!(
memory_growth < 100.0,
"Memory growth should be <100MB for test workload"
);
// Step 9: I/O wait and disk performance
result.add_step("I/O Performance Analysis").await;
let io_metrics = self.resource_monitor.get_io_metrics().await?;
result.add_metric("disk_read_mbps", io_metrics.read_mbps);
result.add_metric("disk_write_mbps", io_metrics.write_mbps);
result.add_metric("io_wait_percent", io_metrics.io_wait_percent);
assert!(io_metrics.io_wait_percent < 20.0, "I/O wait should be <20%");
// Step 10: Overall system performance score
result.add_step("System Performance Score").await;
let perf_score = self
.performance_analyzer
.calculate_overall_score(
single_thread_ops_per_sec,
optimal_batch.1,
network_messages_per_sec,
db_writes_per_sec,
)
.await?;
result.add_metric("overall_performance_score", perf_score.total_score);
result.add_metric("latency_score", perf_score.latency_score);
result.add_metric("throughput_score", perf_score.throughput_score);
result.add_metric(
"resource_efficiency_score",
perf_score.resource_efficiency_score,
);
assert!(
perf_score.total_score > 85.0,
"Overall performance score should exceed 85/100"
);
result.mark_success();
Ok(result)
}
}
// Helper functions for performance testing
fn percentile(samples: &[u64], percentile: f64) -> u64 {
if samples.is_empty() {
return 0;
}
let mut sorted = samples.to_vec();
sorted.sort_unstable();
let index = ((percentile / 100.0) * (sorted.len() - 1) as f64) as usize;
sorted[index]
}
fn create_test_trade_record(id: u64) -> TradeRecord {
TradeRecord {
trade_id: TradeId::from_u64(id),
symbol: Symbol::new("EURUSD"),
quantity: Quantity::from(100_000),
price: Price::from_f64(1.1050).unwrap(),
side: OrderSide::Buy,
timestamp: HardwareTimestamp::now(),
venue: "TEST_VENUE".to_string(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_critical_path_latency_integration() {
let test_suite = PerformanceValidationTests::new().await.unwrap();
let result = test_suite
.test_critical_path_latency_validation()
.await
.unwrap();
assert!(result.success, "Critical path latency test failed");
assert!(result.steps.len() == 12, "Should have 12 steps");
// Verify critical performance requirements
let e2e_p95 = result.metrics.get("e2e_critical_p95_ns").unwrap();
assert!(
*e2e_p95 < 50_000.0,
"End-to-end P95 latency requirement failed"
);
}
#[tokio::test]
async fn test_throughput_benchmarks_integration() {
let test_suite = PerformanceValidationTests::new().await.unwrap();
let result = test_suite
.test_throughput_scalability_benchmarks()
.await
.unwrap();
assert!(result.success, "Throughput benchmarks test failed");
assert!(result.steps.len() == 10, "Should have 10 steps");
// Verify throughput requirements
let single_thread_ops = result.metrics.get("single_thread_ops_per_sec").unwrap();
assert!(
*single_thread_ops > 100_000.0,
"Single-thread throughput requirement failed"
);
}
}