//! Performance benchmarks for rtx-data-validation //! //! This module contains comprehensive benchmarks for all validation operations //! to measure and track performance characteristics. use criterion::{BenchmarkId, Criterion, Throughput, black_box, criterion_group, criterion_main}; use std::collections::HashMap; use std::time::Duration; use tokio::runtime::Runtime; use rtx_data_validation::*; /// Helper function to create sample data for benchmarks fn create_benchmark_record(id: usize) -> DataRecord { let mut fields = HashMap::new(); fields.insert("id".to_string(), DataValue::Int(id as i64)); fields.insert( "name".to_string(), DataValue::String(format!("User {}", id)), ); fields.insert( "email".to_string(), DataValue::String(format!("user{}@example.com", id)), ); fields.insert("age".to_string(), DataValue::Int(25 + (id % 40) as i64)); fields.insert( "score".to_string(), DataValue::Float(50.0 + (id % 50) as f64), ); fields.insert("active".to_string(), DataValue::Bool(id % 2 == 0)); DataRecord { id: format!("record_{}", id), timestamp: chrono::Utc::now(), fields, metadata: HashMap::new(), } } /// Create multiple benchmark records fn create_benchmark_records(count: usize) -> Vec { (0..count).map(create_benchmark_record).collect() } /// Benchmark basic validation engine performance fn benchmark_validation_engine(c: &mut Criterion) { let rt = Runtime::new().unwrap(); // Create engine with various rule configurations let simple_engine = ValidationEngine::builder() .add_rule(ValidationRule::not_null("name")) .build() .expect("Failed to build simple engine"); let complex_engine = ValidationEngine::builder() .with_statistical_validation(true) .add_rule(ValidationRule::not_null("name")) .add_rule(ValidationRule::range("age", 0.0, 120.0)) .add_rule(ValidationRule::email("email")) .add_rule(ValidationRule::range("score", 0.0, 100.0)) .add_rule(ValidationRule::length("name", 2, 100)) .build() .expect("Failed to build complex engine"); let test_record = create_benchmark_record(1); // Benchmark single record validation c.bench_function("validation_single_simple", |b| { b.to_async(&rt) .iter(|| async { black_box(simple_engine.validate(&test_record).await.unwrap()) }) }); c.bench_function("validation_single_complex", |b| { b.to_async(&rt) .iter(|| async { black_box(complex_engine.validate(&test_record).await.unwrap()) }) }); // Benchmark batch validation with different sizes for size in [10, 100, 1000].iter() { let records = create_benchmark_records(*size); c.bench_with_input( BenchmarkId::new("validation_batch_simple", size), &records, |b, records| { b.to_async(&rt).iter(|| async { black_box(simple_engine.validate_batch(records).await.unwrap()) }) }, ); c.bench_with_input( BenchmarkId::new("validation_batch_complex", size), &records, |b, records| { b.to_async(&rt).iter(|| async { black_box(complex_engine.validate_batch(records).await.unwrap()) }) }, ); } } /// Benchmark validation rules performance fn benchmark_validation_rules(c: &mut Criterion) { let test_values = vec![ DataValue::String("test@example.com".to_string()), DataValue::Int(25), DataValue::Float(85.5), DataValue::String("Valid Name".to_string()), ]; // Benchmark individual rule types let not_null_rule = ValidationRule::not_null("test"); let range_rule = ValidationRule::range("test", 0.0, 100.0); let email_rule = ValidationRule::email("test"); let length_rule = ValidationRule::length("test", 2, 100); c.bench_function("rule_not_null", |b| { b.iter(|| { for value in &test_values { black_box(not_null_rule.validate(value)); } }) }); c.bench_function("rule_range", |b| { b.iter(|| { for value in &test_values { black_box(range_rule.validate(value)); } }) }); c.bench_function("rule_email", |b| { b.iter(|| { black_box(email_rule.validate(&test_values[0])); }) }); c.bench_function("rule_length", |b| { b.iter(|| { black_box(length_rule.validate(&test_values[3])); }) }); // Benchmark cross-field validation let cross_field_rule = ValidationRule::cross_field( "field1", "field2", crate::rules::CrossFieldOperation::Greater, ); let mut context = HashMap::new(); context.insert("field2".to_string(), DataValue::Int(20)); c.bench_function("rule_cross_field", |b| { b.iter(|| { black_box(cross_field_rule.validate_with_context(&DataValue::Int(30), &context)); }) }); } /// Benchmark statistical profiling performance fn benchmark_statistical_profiling(c: &mut Criterion) { // Test numerical statistics with different data sizes for size in [100, 1000, 10000].iter() { let values: Vec = (0..*size).map(|i| (i as f64) + (i as f64 * 0.1)).collect(); c.bench_with_input( BenchmarkId::new("numerical_statistics", size), &values, |b, values| b.iter(|| black_box(NumericalStatistics::from_values(values).unwrap())), ); } // Benchmark data profile generation for size in [100, 1000].iter() { let records = create_benchmark_records(*size); c.bench_with_input( BenchmarkId::new("data_profile_generation", size), &records, |b, records| { b.iter(|| { let mut profile = DataProfile::new(); for record in records { profile.add_record(&record.fields).unwrap(); } profile.finalize().unwrap(); black_box(profile) }) }, ); } } /// Benchmark quality scoring performance fn benchmark_quality_scoring(c: &mut Criterion) { for size in [100, 1000, 5000].iter() { let records = create_benchmark_records(*size); c.bench_with_input( BenchmarkId::new("quality_score_calculation", size), &records, |b, records| { b.iter(|| black_box(QualityScore::calculate_for_records(records).unwrap())) }, ); } // Benchmark individual quality dimensions let records = create_benchmark_records(1000); c.bench_function("completeness_scoring", |b| { b.iter(|| { // Simplified completeness calculation let total_fields = records.len() * 6; // 6 fields per record let non_null_fields = records .iter() .flat_map(|r| r.fields.values()) .filter(|v| !v.is_null()) .count(); black_box(non_null_fields as f64 / total_fields as f64) }) }); } /// Benchmark anomaly detection performance fn benchmark_anomaly_detection(c: &mut Criterion) { // Prepare test data let normal_data: Vec = (0..1000) .map(|i| i as f64 + rand::random::() * 10.0) .collect(); let test_values = vec![500.0, 5000.0]; // Normal and anomalous // Benchmark Z-score detection let z_score_detector = ZScoreDetector::new(3.0); c.bench_function("z_score_detection", |b| { b.iter(|| { for &value in &test_values { black_box( z_score_detector .detect("test", value, &normal_data) .unwrap(), ); } }) }); // Benchmark IQR detection let iqr_detector = IQRDetector::new(1.5); c.bench_function("iqr_detection", |b| { b.iter(|| { for &value in &test_values { black_box(iqr_detector.detect("test", value, &normal_data).unwrap()); } }) }); // Benchmark Isolation Forest (simplified) let mut isolation_forest = IsolationForestDetector::new(10, 100, 0.1); let training_data: Vec> = (0..100).map(|i| vec![i as f64]).collect(); isolation_forest.train(&training_data).unwrap(); c.bench_function("isolation_forest_score", |b| { b.iter(|| black_box(isolation_forest.score_multivariate(&[500.0]).unwrap())) }); } /// Benchmark schema operations fn benchmark_schema_operations(c: &mut Criterion) { let mut schema_manager = SchemaManager::new(); // Benchmark schema inference with different data sizes for size in [100, 1000].iter() { let records = create_benchmark_records(*size); c.bench_with_input( BenchmarkId::new("schema_inference", size), &records, |b, records| { b.iter(|| { let mut inference = SchemaInference::new(); black_box( inference .infer_schema("benchmark_schema".to_string(), records) .unwrap(), ) }) }, ); } // Benchmark schema validation let sample_records = create_benchmark_records(10); let schema = schema_manager .infer_schema("test_schema".to_string(), &sample_records) .unwrap(); schema_manager.register_schema(schema).unwrap(); let test_record = create_benchmark_record(1); c.bench_function("schema_validation", |b| { b.iter(|| black_box(schema_manager.validate_record(&test_record).unwrap())) }); } /// Benchmark pipeline performance fn benchmark_pipeline_performance(c: &mut Criterion) { let rt = Runtime::new().unwrap(); // Create pipeline components let engine = std::sync::Arc::new( ValidationEngine::builder() .add_rule(ValidationRule::not_null("name")) .add_rule(ValidationRule::range("age", 0.0, 120.0)) .build() .expect("Failed to build pipeline engine"), ); // Benchmark streaming validation let stream_config = crate::pipeline::StreamConfig::default(); let streaming_validator = crate::pipeline::StreamingValidator::new(engine.clone(), stream_config); c.bench_function("streaming_add_record", |b| { b.to_async(&rt).iter(|| async { let record = create_benchmark_record(1); black_box(streaming_validator.add_record(record).await.unwrap()) }) }); // Benchmark batch validation let batch_config = crate::pipeline::BatchConfig::default(); let batch_validator = crate::pipeline::BatchValidator::new(engine, batch_config); for size in [100, 1000].iter() { let batch_records = create_benchmark_records(*size); c.bench_with_input( BenchmarkId::new("batch_validation", size), &batch_records, |b, records| { b.to_async(&rt).iter(|| async { black_box( batch_validator .process_batch(records.clone()) .await .unwrap(), ) }) }, ); } } /// Benchmark metrics collection fn benchmark_metrics_collection(c: &mut Criterion) { let mut metrics = ValidationMetrics::new(); c.bench_function("metrics_record_validation", |b| { b.iter(|| black_box(metrics.record_validation(Duration::from_millis(100), true))) }); c.bench_function("metrics_record_error", |b| { b.iter(|| black_box(metrics.record_error("test_error", "warning"))) }); c.bench_function("metrics_update_resources", |b| { b.iter(|| black_box(metrics.update_resource_metrics(75.0, 1_000_000, 10))) }); c.bench_function("metrics_calculate_throughput", |b| { b.iter(|| black_box(metrics.calculate_throughput(60.0))) }); // Benchmark metrics with large history let mut large_metrics = ValidationMetrics::new(); for i in 0..10000 { large_metrics.record_validation(Duration::from_millis(50 + i % 100), i % 10 != 0); } c.bench_function("metrics_summary_large", |b| { b.iter(|| black_box(large_metrics.summary())) }); } /// Benchmark throughput with different configurations fn benchmark_throughput_scaling(c: &mut Criterion) { let rt = Runtime::new().unwrap(); // Test different engine configurations let engines = vec![ ( "minimal", ValidationEngine::builder() .add_rule(ValidationRule::not_null("name")) .build() .unwrap(), ), ( "standard", ValidationEngine::builder() .add_rule(ValidationRule::not_null("name")) .add_rule(ValidationRule::range("age", 0.0, 120.0)) .add_rule(ValidationRule::email("email")) .build() .unwrap(), ), ( "comprehensive", ValidationEngine::builder() .with_statistical_validation(true) .add_rule(ValidationRule::not_null("name")) .add_rule(ValidationRule::range("age", 0.0, 120.0)) .add_rule(ValidationRule::email("email")) .add_rule(ValidationRule::range("score", 0.0, 100.0)) .add_rule(ValidationRule::length("name", 2, 100)) .build() .unwrap(), ), ]; // Test different record sizes for (engine_name, engine) in engines { for size in [100, 1000, 10000].iter() { let records = create_benchmark_records(*size); let mut group = c.benchmark_group(format!("throughput_{}_{}", engine_name, size)); group.throughput(Throughput::Elements(*size as u64)); group.bench_function("batch", |b| { b.to_async(&rt) .iter(|| async { black_box(engine.validate_batch(&records).await.unwrap()) }) }); group.finish(); } } } /// Benchmark memory efficiency fn benchmark_memory_efficiency(c: &mut Criterion) { // Test memory usage with different data sizes for size in [1000, 10000, 100000].iter() { let records = create_benchmark_records(*size); c.bench_with_input( BenchmarkId::new("memory_profile_generation", size), &records, |b, records| { b.iter(|| { let mut profile = DataProfile::new(); for record in records { profile.add_record(&record.fields).unwrap(); } // Measure peak memory usage during profile generation black_box(profile) }) }, ); } } criterion_group!( benches, benchmark_validation_engine, benchmark_validation_rules, benchmark_statistical_profiling, benchmark_quality_scoring, benchmark_anomaly_detection, benchmark_schema_operations, benchmark_pipeline_performance, benchmark_metrics_collection, benchmark_throughput_scaling, benchmark_memory_efficiency ); criterion_main!(benches);