//! Serialization and data transformation performance benchmarks //! //! This benchmark suite measures the performance of protobuf serialization, //! JSON conversion, and data transformation operations used in FXT. //! //! ============================================================================ //! TEMPORARILY DISABLED - Missing protobuf definitions //! ============================================================================ //! //! This benchmark file references protobuf types that don't exist in trading.proto: //! - `Order` (standalone message) - proto only has OrderUpdateEvent and order fields in responses //! - `ListOrdersResponse` - not defined in proto //! - `OrderUpdate` - proto has OrderUpdateEvent instead //! - `MetricValue` - proto has Metric instead //! //! TODO: Fix this benchmark by either: //! 1. Adding the missing proto message definitions to fxt/proto/trading.proto //! 2. Rewriting benchmarks to use existing proto types (GetOrderStatusResponse, OrderUpdateEvent, Metric) //! 3. Creating separate benchmark-specific proto messages //! //! Related files: //! - fxt/proto/trading.proto - contains actual protobuf definitions //! - fxt/build.rs - compiles proto files to Rust code //! //! See Wave 36 - Agent 1 for context //! ============================================================================ #![allow(unused_crate_dependencies)] #![allow(clippy::doc_markdown)] // DISABLED: use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; // DISABLED: use prost::Message; // DISABLED: use std::collections::HashMap; // DISABLED: use std::time::Duration; // DISABLED: use fxt::proto::trading::*; /* /// Benchmark protobuf serialization fn bench_protobuf_serialization(c: &mut Criterion) { let mut group = c.benchmark_group("protobuf_serialization"); // Order serialization let order = Order { order_id: "ORDER_123456".to_string(), symbol: "AAPL".to_string(), side: OrderSide::Buy as i32, order_type: OrderType::Market as i32, quantity: 100.0, price: 150.0, status: OrderStatus::New as i32, filled_quantity: 0.0, remaining_quantity: 100.0, average_price: 0.0, created_time_unix_nanos: 1640995200000000000, updated_time_unix_nanos: 1640995200000000000, }; group.bench_function("order_encode", |b| { b.iter(|| { let mut buf = Vec::new(); black_box(&order).encode(&mut buf).unwrap(); black_box(buf) }) }); let encoded_order = { let mut buf = Vec::new(); order.encode(&mut buf).unwrap(); buf }; group.bench_function("order_decode", |b| { b.iter(|| { let decoded = Order::decode(black_box(encoded_order.as_slice())).unwrap(); black_box(decoded) }) }); // Position serialization let position = Position { symbol: "AAPL".to_string(), quantity: 100.0, market_price: 150.0, market_value: 15000.0, average_cost: 140.0, unrealized_pnl: 1000.0, realized_pnl: 0.0, }; group.bench_function("position_encode", |b| { b.iter(|| { let mut buf = Vec::new(); black_box(&position).encode(&mut buf).unwrap(); black_box(buf) }) }); let encoded_position = { let mut buf = Vec::new(); position.encode(&mut buf).unwrap(); buf }; group.bench_function("position_decode", |b| { b.iter(|| { let decoded = Position::decode(black_box(encoded_position.as_slice())).unwrap(); black_box(decoded) }) }); group.finish(); } /// Benchmark JSON serialization fn bench_json_serialization(c: &mut Criterion) { let mut group = c.benchmark_group("json_serialization"); // Create test data structures let submit_order_request = SubmitOrderRequest { symbol: "AAPL".to_string(), side: OrderSide::Buy as i32, order_type: OrderType::Market as i32, quantity: 100.0, price: Some(150.0), }; group.bench_function("submit_order_request_to_json", |b| { b.iter(|| { let json = serde_json::to_string(black_box(&submit_order_request)).unwrap(); black_box(json) }) }); let json_string = serde_json::to_string(&submit_order_request).unwrap(); group.bench_function("submit_order_request_from_json", |b| { b.iter(|| { let request: SubmitOrderRequest = serde_json::from_str(black_box(&json_string)).unwrap(); black_box(request) }) }); // Metrics serialization let metrics_response = GetMetricsResponse { metrics: vec![ MetricValue { name: "latency_p99".to_string(), value: 0.025, unit: "seconds".to_string(), labels: HashMap::from([ ("service".to_string(), "trading".to_string()), ("environment".to_string(), "production".to_string()), ]), timestamp_unix_nanos: 1640995200000000000, }, MetricValue { name: "orders_per_second".to_string(), value: 150.0, unit: "ops/sec".to_string(), labels: HashMap::from([("service".to_string(), "trading".to_string())]), timestamp_unix_nanos: 1640995200000000000, }, ], }; group.bench_function("metrics_response_to_json", |b| { b.iter(|| { let json = serde_json::to_string(black_box(&metrics_response)).unwrap(); black_box(json) }) }); let metrics_json = serde_json::to_string(&metrics_response).unwrap(); group.bench_function("metrics_response_from_json", |b| { b.iter(|| { let response: GetMetricsResponse = serde_json::from_str(black_box(&metrics_json)).unwrap(); black_box(response) }) }); group.finish(); } /// Benchmark data transformation operations fn bench_data_transformations(c: &mut Criterion) { let mut group = c.benchmark_group("data_transformations"); // Order list transformation let orders: Vec = (0..1000) .map(|i| Order { order_id: format!("ORDER_{:06}", i), symbol: "AAPL".to_string(), side: if i % 2 == 0 { OrderSide::Buy } else { OrderSide::Sell } as i32, order_type: OrderType::Market as i32, quantity: 100.0, price: 150.0 + (i as f64 * 0.01), status: if i % 3 == 0 { OrderStatus::Filled } else { OrderStatus::New } as i32, filled_quantity: if i % 3 == 0 { 100.0 } else { 0.0 }, remaining_quantity: if i % 3 == 0 { 0.0 } else { 100.0 }, average_price: if i % 3 == 0 { 150.0 + (i as f64 * 0.01) } else { 0.0 }, created_time_unix_nanos: 1640995200000000000 + (i as i64 * 1000000), updated_time_unix_nanos: 1640995200000000000 + (i as i64 * 1000000), }) .collect(); group.bench_function("filter_filled_orders", |b| { b.iter(|| { let filled_orders: Vec<&Order> = black_box(&orders) .iter() .filter(|o| o.status == OrderStatus::Filled as i32) .collect(); black_box(filled_orders) }) }); group.bench_function("calculate_total_quantity", |b| { b.iter(|| { let total: f64 = black_box(&orders).iter().map(|o| o.quantity).sum(); black_box(total) }) }); group.bench_function("group_orders_by_symbol", |b| { b.iter(|| { let mut grouped: HashMap> = HashMap::new(); for order in black_box(&orders) { grouped .entry(order.symbol.clone()) .or_insert_with(Vec::new) .push(order); } black_box(grouped) }) }); group.finish(); } /// Benchmark large data structure serialization fn bench_large_data_structures(c: &mut Criterion) { let mut group = c.benchmark_group("large_data_structures"); group.measurement_time(Duration::from_secs(10)); let sizes = vec![100, 1000, 5000, 10000]; for size in sizes { // Create large order list let orders: Vec = (0..size) .map(|i| Order { order_id: format!("ORDER_{:06}", i), symbol: format!("SYM{}", i % 100), // 100 different symbols side: if i % 2 == 0 { OrderSide::Buy } else { OrderSide::Sell } as i32, order_type: OrderType::Market as i32, quantity: 100.0 + (i as f64), price: 100.0 + (i as f64 * 0.01), status: OrderStatus::New as i32, filled_quantity: 0.0, remaining_quantity: 100.0 + (i as f64), average_price: 0.0, created_time_unix_nanos: 1640995200000000000 + (i as i64 * 1000), updated_time_unix_nanos: 1640995200000000000 + (i as i64 * 1000), }) .collect(); let list_response = ListOrdersResponse { orders: orders.clone(), }; group.bench_with_input( BenchmarkId::new("protobuf_encode_large", size), &list_response, |b, response: &ListOrdersResponse| { b.iter(|| { let mut buf = Vec::new(); black_box(response).encode(&mut buf).unwrap(); black_box(buf) }) }, ); let encoded = { let mut buf = Vec::new(); list_response.encode(&mut buf).unwrap(); buf }; group.bench_with_input( BenchmarkId::new("protobuf_decode_large", size), &encoded, |b, data| { b.iter(|| { let decoded = ListOrdersResponse::decode(black_box(data.as_slice())).unwrap(); black_box(decoded) }) }, ); group.bench_with_input( BenchmarkId::new("json_encode_large", size), &list_response, |b, response| { b.iter(|| { let json = serde_json::to_string(black_box(response)).unwrap(); black_box(json) }) }, ); let json_data = serde_json::to_string(&list_response).unwrap(); group.bench_with_input( BenchmarkId::new("json_decode_large", size), &json_data, |b, data| { b.iter(|| { let decoded: ListOrdersResponse = serde_json::from_str(black_box(data)).unwrap(); black_box(decoded) }) }, ); } group.finish(); } /// Benchmark streaming data serialization fn bench_streaming_serialization(c: &mut Criterion) { let mut group = c.benchmark_group("streaming_serialization"); // Order updates stream let order_updates: Vec = (0..100) .map(|i| OrderUpdate { order_id: format!("ORDER_{:06}", i), symbol: "AAPL".to_string(), status: if i % 3 == 0 { OrderStatus::Filled } else { OrderStatus::PartiallyFilled } as i32, filled_quantity: (i as f64) * 10.0, timestamp_unix_nanos: 1640995200000000000 + (i as i64 * 1000000), }) .collect(); group.bench_function("order_updates_batch_encode", |b| { b.iter(|| { let mut encoded_updates = Vec::new(); for update in black_box(&order_updates) { let mut buf = Vec::new(); update.encode(&mut buf).unwrap(); encoded_updates.push(buf); } black_box(encoded_updates) }) }); // Metrics stream let metric_updates: Vec = (0..100) .map(|i| MetricValue { name: format!("metric_{}", i % 10), value: (i as f64) * 1.5, unit: "count".to_string(), labels: HashMap::from([ ("instance".to_string(), format!("server_{}", i % 5)), ("environment".to_string(), "production".to_string()), ]), timestamp_unix_nanos: 1640995200000000000 + (i as i64 * 100000), }) .collect(); group.bench_function("metrics_stream_encode", |b| { b.iter(|| { let mut encoded_metrics = Vec::new(); for metric in black_box(&metric_updates) { let mut buf = Vec::new(); metric.encode(&mut buf).unwrap(); encoded_metrics.push(buf); } black_box(encoded_metrics) }) }); group.finish(); } /// Benchmark memory efficiency fn bench_memory_efficiency(c: &mut Criterion) { let mut group = c.benchmark_group("memory_efficiency"); // Compare different serialization formats let order = Order { order_id: "ORDER_123456".to_string(), symbol: "AAPL".to_string(), side: OrderSide::Buy as i32, order_type: OrderType::Market as i32, quantity: 100.0, price: 150.0, status: OrderStatus::New as i32, filled_quantity: 0.0, remaining_quantity: 100.0, average_price: 0.0, created_time_unix_nanos: 1640995200000000000, updated_time_unix_nanos: 1640995200000000000, }; group.bench_function("protobuf_size_efficiency", |b| { b.iter(|| { let mut buf = Vec::new(); black_box(&order).encode(&mut buf).unwrap(); let size = buf.len(); black_box((buf, size)) }) }); group.bench_function("json_size_efficiency", |b| { b.iter(|| { let json = serde_json::to_string(black_box(&order)).unwrap(); let size = json.len(); black_box((json, size)) }) }); group.bench_function("json_compact_size_efficiency", |b| { b.iter(|| { let json = serde_json::to_vec(black_box(&order)).unwrap(); let size = json.len(); black_box((json, size)) }) }); group.finish(); } /// Benchmark concurrent serialization fn bench_concurrent_serialization(c: &mut Criterion) { use tokio::runtime::Runtime; let rt = Runtime::new().unwrap(); let mut group = c.benchmark_group("concurrent_serialization"); group.measurement_time(Duration::from_secs(10)); let thread_counts = vec![1, 2, 4, 8]; for thread_count in thread_counts { group.bench_with_input( BenchmarkId::new("parallel_order_encoding", thread_count), &thread_count, |b, &tc| { b.to_async(&rt).iter(|| async move { let orders: Vec = (0..100) .map(|i| Order { order_id: format!("ORDER_{:06}", i), symbol: "AAPL".to_string(), side: OrderSide::Buy as i32, order_type: OrderType::Market as i32, quantity: 100.0, price: 150.0, status: OrderStatus::New as i32, filled_quantity: 0.0, remaining_quantity: 100.0, average_price: 0.0, created_time_unix_nanos: 1640995200000000000, updated_time_unix_nanos: 1640995200000000000, }) .collect(); let chunk_size = orders.len() / tc; let tasks = orders.chunks(chunk_size).map(|chunk| { let chunk = chunk.to_vec(); tokio::spawn(async move { let mut encoded = Vec::new(); for order in chunk { let mut buf = Vec::new(); order.encode(&mut buf).unwrap(); encoded.push(buf); } encoded }) }); let results = futures::future::join_all(tasks).await; black_box(results); }) }, ); } group.finish(); } criterion_group!( benches, bench_protobuf_serialization, bench_json_serialization, bench_data_transformations, bench_large_data_structures, bench_streaming_serialization, bench_memory_efficiency, bench_concurrent_serialization ); criterion_main!(benches); */ // Placeholder to keep file valid fn main() { println!("Benchmark disabled - see file header for details"); }