#![allow( clippy::unwrap_used, clippy::expect_used, clippy::indexing_slicing, clippy::str_to_string, clippy::string_to_string, clippy::shadow_unrelated, clippy::shadow_reuse, clippy::similar_names, clippy::non_ascii_literal, clippy::doc_markdown, clippy::integer_division, clippy::manual_range_contains, clippy::useless_format, clippy::clone_on_copy, clippy::missing_const_for_fn, unused_imports, unused_variables, dead_code, )] //! End-to-End Trading Performance Benchmarks //! //! Comprehensive benchmarking of complete order lifecycle: //! 1. Order Lifecycle: Submit → Order manager → Trading engine (P99 < 100μs) //! 2. Execution Pipeline: Execute → Update position → Validate risk (P99 < 50μs) //! 3. Settlement: Calculate PnL → Log compliance → Update portfolio (P99 < 75μs) //! //! **Performance Targets**: //! - P99 Latency: < 100μs (order lifecycle) //! - Throughput: > 100K orders/sec //! - Memory: < 100MB per 1M orders //! //! **Measurement Strategy**: //! - Uses criterion for statistical benchmarking //! - HDR Histogram for latency distribution //! - Memory profiling for allocation tracking //! - Component breakdown for bottleneck identification use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; use hdrhistogram::Histogram; use std::sync::Arc; use std::time::{Duration, Instant}; use tokio::runtime::Runtime; // Trading engine imports use common::{OrderSide, OrderStatus, OrderType, TimeInForce}; use rust_decimal::Decimal; use std::collections::HashMap; use trading_engine::trading_operations::{ ExecutionResult, LiquidityFlag, TradingOperations, TradingOrder, }; /// Performance metrics collector for E2E benchmarking struct PerformanceMetrics { histogram: Histogram, order_count: u64, total_latency_ns: u64, memory_baseline_kb: usize, } impl PerformanceMetrics { fn new() -> Self { Self { histogram: Histogram::::new(3).unwrap(), order_count: 0, total_latency_ns: 0, memory_baseline_kb: Self::current_memory_kb(), } } fn record_latency(&mut self, latency: Duration) { let nanos = latency.as_nanos() as u64; self.histogram.record(nanos / 1000).ok(); // Convert to microseconds self.order_count += 1; self.total_latency_ns += nanos; } fn report(&self, label: &str) { let p50 = self.histogram.value_at_percentile(50.0) as f64; let p95 = self.histogram.value_at_percentile(95.0) as f64; let p99 = self.histogram.value_at_percentile(99.0) as f64; let max = self.histogram.max() as f64; let avg = (self.total_latency_ns as f64 / self.order_count as f64) / 1000.0; let memory_delta_kb = Self::current_memory_kb() - self.memory_baseline_kb; let memory_per_order_bytes = (memory_delta_kb * 1024) / self.order_count as usize; println!("\n=== {} ===", label); println!("Orders: {}", self.order_count); println!("Latency Percentiles:"); println!(" P50: {:.2}μs", p50); println!(" P95: {:.2}μs", p95); println!(" P99: {:.2}μs", p99); println!(" Max: {:.2}μs", max); println!(" Avg: {:.2}μs", avg); println!("Memory:"); println!(" Delta: {}KB", memory_delta_kb); println!(" Per Order: {}B", memory_per_order_bytes); // Check targets if p99 < 100.0 { println!("✅ P99 TARGET MET: {:.2}μs < 100μs", p99); } else { println!("❌ P99 TARGET MISSED: {:.2}μs >= 100μs", p99); } if memory_per_order_bytes < 100 { println!( "✅ MEMORY TARGET MET: {}B < 100B/order", memory_per_order_bytes ); } else { println!( "⚠️ MEMORY TARGET EXCEEDED: {}B >= 100B/order", memory_per_order_bytes ); } } fn current_memory_kb() -> usize { // Simple memory estimation - in production use jemalloc stats #[cfg(target_os = "linux")] { if let Ok(status) = std::fs::read_to_string("/proc/self/status") { for line in status.lines() { if line.starts_with("VmRSS:") { if let Some(kb_str) = line.split_whitespace().nth(1) { return kb_str.parse().unwrap_or(0); } } } } } 0 } } /// Create a sample order for benchmarking fn create_test_order(id: u64) -> TradingOrder { TradingOrder { id: common::OrderId::new(), symbol: format!("TEST{}", id % 100), // Simulate 100 different symbols side: if id % 2 == 0 { OrderSide::Buy } else { OrderSide::Sell }, order_type: OrderType::Limit, quantity: Decimal::new(100 + (id % 1000) as i64, 0), price: Decimal::new(15000 + (id % 5000) as i64, 2), time_in_force: TimeInForce::Day, account_id: Some(format!("ACC{}", id % 10)), metadata: HashMap::new(), created_at: chrono::Utc::now(), submitted_at: None, executed_at: None, status: OrderStatus::Created, fill_quantity: Decimal::ZERO, average_fill_price: None, } } /// Create a sample execution result for benchmarking fn create_test_execution(order_id: u64) -> ExecutionResult { ExecutionResult { order_id: common::OrderId::new(), symbol: format!("TEST{}", order_id % 100), side: common::OrderSide::Buy, executed_quantity: Decimal::new(100, 0), execution_price: Decimal::new(15000, 2), execution_time: chrono::Utc::now(), commission: Decimal::new(1, 0), liquidity_flag: LiquidityFlag::Taker, } } // // ==================== BENCHMARK 1: ORDER LIFECYCLE ==================== // /// Benchmark 1a: Single order submission (baseline) fn bench_order_submission_single(c: &mut Criterion) { let rt = Runtime::new().unwrap(); let trading_ops = Arc::new(TradingOperations::new()); c.bench_function("e2e/order_lifecycle/single_submit", |b| { b.iter_custom(|iters| { let start = Instant::now(); rt.block_on(async { for i in 0..iters { let order = create_test_order(i); black_box(trading_ops.submit_order(order).await).ok(); } }); start.elapsed() }); }); } /// Benchmark 1b: Batch order submission fn bench_order_submission_batch(c: &mut Criterion) { let mut group = c.benchmark_group("e2e/order_lifecycle/batch_submit"); for batch_size in &[10, 100, 1000] { let rt = Runtime::new().unwrap(); let trading_ops = Arc::new(TradingOperations::new()); group.throughput(Throughput::Elements(*batch_size as u64)); group.bench_with_input( BenchmarkId::from_parameter(batch_size), batch_size, |b, &size| { b.iter_custom(|_iters| { let start = Instant::now(); rt.block_on(async { for i in 0..size { let order = create_test_order(i as u64); black_box(trading_ops.submit_order(order).await).ok(); } }); start.elapsed() }); }, ); } group.finish(); } /// Benchmark 1c: Order lifecycle with latency distribution fn bench_order_lifecycle_distribution(c: &mut Criterion) { let rt = Runtime::new().unwrap(); let trading_ops = Arc::new(TradingOperations::new()); c.bench_function("e2e/order_lifecycle/latency_distribution", |b| { b.iter_custom(|iters| { let mut metrics = PerformanceMetrics::new(); rt.block_on(async { for i in 0..iters { let order = create_test_order(i); let start = Instant::now(); black_box(trading_ops.submit_order(order).await).ok(); metrics.record_latency(start.elapsed()); } }); metrics.report("Order Lifecycle - Submit to Tracking"); Duration::from_nanos(metrics.total_latency_ns / iters.max(1)) }); }); } // // ==================== BENCHMARK 2: EXECUTION PIPELINE ==================== // /// Benchmark 2a: Order execution processing fn bench_execution_processing(c: &mut Criterion) { let rt = Runtime::new().unwrap(); let trading_ops = Arc::new(TradingOperations::new()); c.bench_function("e2e/execution_pipeline/process_execution", |b| { b.iter_custom(|iters| { let start = Instant::now(); rt.block_on(async { for i in 0..iters { let execution = create_test_execution(i); black_box(trading_ops.process_execution(execution).await).ok(); } }); start.elapsed() }); }); } /// Benchmark 2b: Execution pipeline with position updates fn bench_execution_with_position_update(c: &mut Criterion) { let rt = Runtime::new().unwrap(); let trading_ops = Arc::new(TradingOperations::new()); c.bench_function("e2e/execution_pipeline/with_position_update", |b| { b.iter_custom(|iters| { let mut metrics = PerformanceMetrics::new(); rt.block_on(async { for i in 0..iters { let start = Instant::now(); // Step 1: Execute order let execution = create_test_execution(i); black_box(trading_ops.process_execution(execution).await).ok(); // Step 2: Update position (simulated) tokio::time::sleep(Duration::from_nanos(100)).await; // Step 3: Risk validation (simulated) tokio::time::sleep(Duration::from_nanos(50)).await; metrics.record_latency(start.elapsed()); } }); metrics.report("Execution Pipeline - Full Flow"); Duration::from_nanos(metrics.total_latency_ns / iters.max(1)) }); }); } /// Benchmark 2c: Concurrent execution processing fn bench_execution_concurrent(c: &mut Criterion) { let mut group = c.benchmark_group("e2e/execution_pipeline/concurrent"); for concurrency in &[10, 100, 1000] { let rt = Runtime::new().unwrap(); let trading_ops = Arc::new(TradingOperations::new()); group.throughput(Throughput::Elements(*concurrency as u64)); group.bench_with_input( BenchmarkId::from_parameter(concurrency), concurrency, |b, &n| { b.iter_custom(|_iters| { let start = Instant::now(); rt.block_on(async { let mut handles = vec![]; for i in 0..n { let ops = trading_ops.clone(); let handle = tokio::spawn(async move { let execution = create_test_execution(i as u64); ops.process_execution(execution).await }); handles.push(handle); } for handle in handles { black_box(handle.await.ok()); } }); start.elapsed() }); }, ); } group.finish(); } // // ==================== BENCHMARK 3: SETTLEMENT FLOW ==================== // /// Benchmark 3a: PnL calculation fn bench_pnl_calculation(c: &mut Criterion) { let rt = Runtime::new().unwrap(); let trading_ops = Arc::new(TradingOperations::new()); c.bench_function("e2e/settlement/pnl_calculation", |b| { b.iter_custom(|iters| { let start = Instant::now(); rt.block_on(async { for i in 0..iters { let execution = create_test_execution(i); // PnL calculation is internal to process_execution black_box(trading_ops.process_execution(execution).await).ok(); } }); start.elapsed() }); }); } /// Benchmark 3b: Full settlement flow (PnL + Compliance + Portfolio) fn bench_settlement_full_flow(c: &mut Criterion) { let rt = Runtime::new().unwrap(); let trading_ops = Arc::new(TradingOperations::new()); c.bench_function("e2e/settlement/full_flow", |b| { b.iter_custom(|iters| { let mut metrics = PerformanceMetrics::new(); rt.block_on(async { for i in 0..iters { let start = Instant::now(); // Step 1: Calculate PnL let execution = create_test_execution(i); black_box(trading_ops.process_execution(execution).await).ok(); // Step 2: Log compliance (simulated database write) tokio::time::sleep(Duration::from_micros(5)).await; // Step 3: Update portfolio (simulated) tokio::time::sleep(Duration::from_nanos(500)).await; metrics.record_latency(start.elapsed()); } }); metrics.report("Settlement - Full Flow (PnL + Compliance + Portfolio)"); Duration::from_nanos(metrics.total_latency_ns / iters.max(1)) }); }); } /// Benchmark 3c: Settlement batch processing fn bench_settlement_batch(c: &mut Criterion) { let mut group = c.benchmark_group("e2e/settlement/batch"); for batch_size in &[100, 1000, 10000] { let rt = Runtime::new().unwrap(); let trading_ops = Arc::new(TradingOperations::new()); group.throughput(Throughput::Elements(*batch_size as u64)); group.bench_with_input( BenchmarkId::from_parameter(batch_size), batch_size, |b, &size| { b.iter_custom(|_iters| { let start = Instant::now(); rt.block_on(async { for i in 0..size { let execution = create_test_execution(i as u64); black_box(trading_ops.process_execution(execution).await).ok(); } }); start.elapsed() }); }, ); } group.finish(); } // // ==================== BENCHMARK 4: THROUGHPUT TESTS ==================== // /// Benchmark 4a: Sustained throughput (1 second test) fn bench_sustained_throughput(c: &mut Criterion) { let rt = Runtime::new().unwrap(); let trading_ops = Arc::new(TradingOperations::new()); c.bench_function("e2e/throughput/sustained_1sec", |b| { b.iter_custom(|_iters| { let start = Instant::now(); let mut count = 0_u64; rt.block_on(async { let end_time = Instant::now() + Duration::from_secs(1); while Instant::now() < end_time { let order = create_test_order(count); black_box(trading_ops.submit_order(order).await).ok(); count += 1; } }); let elapsed = start.elapsed(); let throughput = count as f64 / elapsed.as_secs_f64(); println!("\n=== Sustained Throughput ==="); println!("Duration: {:.2}s", elapsed.as_secs_f64()); println!("Orders: {}", count); println!("Throughput: {:.0} orders/sec", throughput); if throughput > 100_000.0 { println!( "✅ THROUGHPUT TARGET MET: {:.0} > 100K orders/sec", throughput ); } else { println!( "❌ THROUGHPUT TARGET MISSED: {:.0} < 100K orders/sec", throughput ); } elapsed }); }); } /// Benchmark 4b: Burst handling fn bench_burst_handling(c: &mut Criterion) { let mut group = c.benchmark_group("e2e/throughput/burst"); for burst_size in &[1000, 10000, 100000] { let rt = Runtime::new().unwrap(); let trading_ops = Arc::new(TradingOperations::new()); group.throughput(Throughput::Elements(*burst_size as u64)); group.bench_with_input( BenchmarkId::from_parameter(burst_size), burst_size, |b, &size| { b.iter_custom(|_iters| { let start = Instant::now(); rt.block_on(async { let mut handles = vec![]; // Fire burst of orders for i in 0..size { let ops = trading_ops.clone(); let handle = tokio::spawn(async move { let order = create_test_order(i as u64); ops.submit_order(order).await }); handles.push(handle); } // Wait for completion for handle in handles { black_box(handle.await.ok()); } }); let elapsed = start.elapsed(); let throughput = size as f64 / elapsed.as_secs_f64(); println!( "Burst {} orders - {:.0} orders/sec, {:.2}ms total", size, throughput, elapsed.as_millis() ); elapsed }); }, ); } group.finish(); } // // ==================== BENCHMARK 5: MEMORY EFFICIENCY ==================== // /// Benchmark 5a: Memory usage per order fn bench_memory_per_order(c: &mut Criterion) { let rt = Runtime::new().unwrap(); let trading_ops = Arc::new(TradingOperations::new()); c.bench_function("e2e/memory/per_order_allocation", |b| { b.iter_custom(|_iters| { let baseline_kb = PerformanceMetrics::current_memory_kb(); let order_count = 100_000_u64; let start = Instant::now(); rt.block_on(async { for i in 0..order_count { let order = create_test_order(i); black_box(trading_ops.submit_order(order).await).ok(); } }); let delta_kb = PerformanceMetrics::current_memory_kb() - baseline_kb; let bytes_per_order = (delta_kb * 1024) / order_count as usize; println!("\n=== Memory Efficiency ==="); println!("Orders Processed: {}", order_count); println!("Memory Delta: {}KB", delta_kb); println!("Bytes per Order: {}B", bytes_per_order); println!( "Memory per 1M Orders: {:.2}MB", (bytes_per_order * 1_000_000) as f64 / (1024.0 * 1024.0) ); if bytes_per_order < 100 { println!("✅ MEMORY TARGET MET: {}B < 100B/order", bytes_per_order); } else { println!( "⚠️ MEMORY TARGET EXCEEDED: {}B >= 100B/order", bytes_per_order ); } start.elapsed() }); }); } // // ==================== BENCHMARK 6: COMPONENT BREAKDOWN ==================== // /// Benchmark 6: Component-level latency breakdown fn bench_component_breakdown(c: &mut Criterion) { let mut group = c.benchmark_group("e2e/components/breakdown"); let rt = Runtime::new().unwrap(); // Component 1: Order creation group.bench_function("order_creation", |b| { b.iter(|| { let order = create_test_order(1); black_box(order) }); }); // Component 2: Order validation (simulated) group.bench_function("order_validation", |b| { b.iter_custom(|iters| { let start = Instant::now(); rt.block_on(async { for _ in 0..iters { tokio::time::sleep(Duration::from_nanos(50)).await; } }); start.elapsed() }); }); // Component 3: Trading operations tracking let trading_ops = Arc::new(TradingOperations::new()); group.bench_function("trading_ops_tracking", |b| { b.iter_custom(|iters| { let start = Instant::now(); rt.block_on(async { for i in 0..iters { let order = create_test_order(i); black_box(trading_ops.submit_order(order).await).ok(); } }); start.elapsed() }); }); // Component 4: Execution processing group.bench_function("execution_processing", |b| { b.iter_custom(|iters| { let start = Instant::now(); rt.block_on(async { for i in 0..iters { let execution = create_test_execution(i); black_box(trading_ops.process_execution(execution).await).ok(); } }); start.elapsed() }); }); // Component 5: Position update (simulated) group.bench_function("position_update", |b| { b.iter_custom(|iters| { let start = Instant::now(); rt.block_on(async { for _ in 0..iters { tokio::time::sleep(Duration::from_nanos(100)).await; } }); start.elapsed() }); }); // Component 6: Risk validation (simulated) group.bench_function("risk_validation", |b| { b.iter_custom(|iters| { let start = Instant::now(); rt.block_on(async { for _ in 0..iters { tokio::time::sleep(Duration::from_nanos(50)).await; } }); start.elapsed() }); }); group.finish(); } // // ==================== BENCHMARK 7: TARGET VALIDATION ==================== // /// Benchmark 7: Comprehensive target validation fn bench_target_validation(c: &mut Criterion) { let rt = Runtime::new().unwrap(); let trading_ops = Arc::new(TradingOperations::new()); c.bench_function("e2e/targets/comprehensive_validation", |b| { b.iter_custom(|iters| { let mut lifecycle_metrics = PerformanceMetrics::new(); let mut execution_metrics = PerformanceMetrics::new(); let mut settlement_metrics = PerformanceMetrics::new(); rt.block_on(async { for i in 0..iters { // Test 1: Order Lifecycle (Target: P99 < 100μs) let start = Instant::now(); let order = create_test_order(i); black_box(trading_ops.submit_order(order).await).ok(); lifecycle_metrics.record_latency(start.elapsed()); // Test 2: Execution Pipeline (Target: P99 < 50μs) let start = Instant::now(); let execution = create_test_execution(i); black_box(trading_ops.process_execution(execution).await).ok(); execution_metrics.record_latency(start.elapsed()); // Test 3: Settlement (Target: P99 < 75μs) let start = Instant::now(); tokio::time::sleep(Duration::from_micros(5)).await; // Compliance logging tokio::time::sleep(Duration::from_nanos(500)).await; // Portfolio update settlement_metrics.record_latency(start.elapsed()); } }); lifecycle_metrics.report("ORDER LIFECYCLE (Target: P99 < 100μs)"); execution_metrics.report("EXECUTION PIPELINE (Target: P99 < 50μs)"); settlement_metrics.report("SETTLEMENT FLOW (Target: P99 < 75μs)"); // Return average across all flows Duration::from_nanos( (lifecycle_metrics.total_latency_ns + execution_metrics.total_latency_ns + settlement_metrics.total_latency_ns) / (iters.max(1) * 3), ) }); }); } // Criterion benchmark groups criterion_group!( order_lifecycle_benches, bench_order_submission_single, bench_order_submission_batch, bench_order_lifecycle_distribution, ); criterion_group!( execution_pipeline_benches, bench_execution_processing, bench_execution_with_position_update, bench_execution_concurrent, ); criterion_group!( settlement_benches, bench_pnl_calculation, bench_settlement_full_flow, bench_settlement_batch, ); criterion_group!( throughput_benches, bench_sustained_throughput, bench_burst_handling, ); criterion_group!(memory_benches, bench_memory_per_order,); criterion_group!(component_benches, bench_component_breakdown,); criterion_group!(validation_benches, bench_target_validation,); criterion_main!( order_lifecycle_benches, execution_pipeline_benches, settlement_benches, throughput_benches, memory_benches, component_benches, validation_benches, );