Files
rustytorch/crates/data/rtx-data-validation/benches/validation_benchmarks.rs
T
2026-03-04 00:08:42 +00:00

480 lines
15 KiB
Rust

//! 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<DataRecord> {
(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("[email protected]".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<f64> = (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<f64> = (0..1000)
.map(|i| i as f64 + rand::random::<f64>() * 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<Vec<f64>> = (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);