Files
rustytorch/crates/specialized/rtx-science/benches/science_bench.rs
T
2026-03-04 00:08:42 +00:00

453 lines
13 KiB
Rust

//! Comprehensive benchmarks for RTX Science
//!
//! This benchmark suite evaluates the performance of scientific computing
//! operations including PINNs, molecular simulations, and numerical solvers.
use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
use rtx_science::prelude::*;
use rtx_tensor::{Device, Tensor};
use std::time::Duration;
/// PINN training benchmark
fn bench_pinn_training(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut group = c.benchmark_group("PINN Training");
group.measurement_time(Duration::from_secs(10));
for &size in &[32, 64, 128] {
group.throughput(Throughput::Elements(size as u64));
group.bench_with_input(
BenchmarkId::new("heat_equation", size),
&size,
|b, &size| {
b.to_async(&rt)
.iter(|| async { bench_heat_equation_pinn(size).await.unwrap() });
},
);
}
group.finish();
}
/// Molecular property prediction benchmark
fn bench_molecular_prediction(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut group = c.benchmark_group("Molecular Prediction");
for &batch_size in &[16, 32, 64] {
group.bench_with_input(
BenchmarkId::new("gnn_forward", batch_size),
&batch_size,
|b, &batch_size| {
b.to_async(&rt)
.iter(|| async { bench_molecular_gnn(batch_size).await.unwrap() });
},
);
}
group.finish();
}
/// Conservation law validation benchmark
fn bench_conservation_laws(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
c.bench_function("mass_conservation", |b| {
b.to_async(&rt)
.iter(|| async { bench_mass_conservation().await.unwrap() });
});
c.bench_function("energy_conservation", |b| {
b.to_async(&rt)
.iter(|| async { bench_energy_conservation().await.unwrap() });
});
}
/// Scientific computing primitives benchmark
fn bench_scientific_computing(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut group = c.benchmark_group("Scientific Computing");
for &matrix_size in &[256, 512, 1024] {
group.throughput(Throughput::Elements((matrix_size * matrix_size) as u64));
group.bench_with_input(
BenchmarkId::new("matrix_solve", matrix_size),
&matrix_size,
|b, &size| {
b.to_async(&rt)
.iter(|| async { bench_linear_solve(size).await.unwrap() });
},
);
group.bench_with_input(
BenchmarkId::new("fft_transform", matrix_size),
&matrix_size,
|b, &size| {
b.to_async(&rt)
.iter(|| async { bench_fft_transform(size).await.unwrap() });
},
);
}
group.finish();
}
/// GPU vs CPU performance comparison
fn bench_device_comparison(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut group = c.benchmark_group("Device Comparison");
// CPU benchmark
group.bench_function("cpu_pinn", |b| {
b.to_async(&rt).iter(|| async {
let device = Device::cpu();
bench_device_pinn(&device).await.unwrap()
});
});
// GPU benchmark (if available)
if Device::cuda(0).is_ok() {
group.bench_function("gpu_pinn", |b| {
b.to_async(&rt).iter(|| async {
let device = Device::cuda(0).unwrap();
bench_device_pinn(&device).await.unwrap()
});
});
}
group.finish();
}
/// Molecular dataset processing benchmark
fn bench_molecular_datasets(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut group = c.benchmark_group("Molecular Datasets");
group.bench_function("dataset_loading", |b| {
b.to_async(&rt)
.iter(|| async { bench_dataset_loading().await.unwrap() });
});
group.bench_function("feature_extraction", |b| {
b.to_async(&rt)
.iter(|| async { bench_feature_extraction().await.unwrap() });
});
group.finish();
}
/// Benchmark helper functions
async fn bench_heat_equation_pinn(hidden_size: usize) -> Result<f64> {
let device = Device::cpu();
let heat_eq = HeatEquation::new(0.1);
let pinn = PINN::builder()
.device(&device)
.layers(vec![2, hidden_size, hidden_size, 1])
.physics_loss(Box::new(heat_eq))
.build()?;
// Benchmark forward pass
let inputs = vec![(0.5, 0.1), (0.3, 0.2), (0.8, 0.4), (0.1, 0.9)];
let start = std::time::Instant::now();
let _outputs = pinn.predict(&inputs).await?;
let elapsed = start.elapsed().as_secs_f64();
Ok(elapsed)
}
async fn bench_molecular_gnn(batch_size: usize) -> Result<f64> {
let device = Device::cpu();
// Create dummy molecular graphs
let mut molecules = Vec::new();
for i in 0..batch_size {
let mol = Molecule::from_smiles(format!("mol_{}", i), "CCO")?;
molecules.push(mol);
}
// Benchmark feature matrix creation
let start = std::time::Instant::now();
for mol in &molecules {
let _features = mol.to_feature_matrix()?;
}
let elapsed = start.elapsed().as_secs_f64();
Ok(elapsed)
}
async fn bench_mass_conservation() -> Result<f64> {
let device = Device::cpu();
let conservation = MassConservation::new(1e-6);
// Create test data
let coords = Tensor::randn([100, 2], &device)?;
let solution = Variable::new(Tensor::randn([100], &device)?);
let du_dx = Variable::new(Tensor::randn([100], &device)?);
let du_dt = Variable::new(Tensor::randn([100], &device)?);
let start = std::time::Instant::now();
let _loss = conservation
.compute_loss(&coords, &solution, &du_dx, &du_dt)
.await?;
let elapsed = start.elapsed().as_secs_f64();
Ok(elapsed)
}
async fn bench_energy_conservation() -> Result<f64> {
let device = Device::cpu();
let conservation = EnergyConservation::new(0.1, 1e-6);
// Create test data
let coords = Tensor::randn([100, 2], &device)?;
let solution = Variable::new(Tensor::randn([100], &device)?);
let du_dx = Variable::new(Tensor::randn([100], &device)?);
let du_dt = Variable::new(Tensor::randn([100], &device)?);
let start = std::time::Instant::now();
let _loss = conservation
.compute_loss(&coords, &solution, &du_dx, &du_dt)
.await?;
let elapsed = start.elapsed().as_secs_f64();
Ok(elapsed)
}
async fn bench_linear_solve(size: usize) -> Result<f64> {
let device = Device::cpu();
// Create random system Ax = b
let a = Tensor::randn([size, size], &device)?;
let b = Tensor::randn([size], &device)?;
let start = std::time::Instant::now();
// Placeholder for linear solve - would use actual solver
let _x = a.matmul(&Tensor::eye([size, size], &device)?)?;
let elapsed = start.elapsed().as_secs_f64();
Ok(elapsed)
}
async fn bench_fft_transform(size: usize) -> Result<f64> {
let device = Device::cpu();
// Create random signal
let signal = Tensor::randn([size], &device)?;
let start = std::time::Instant::now();
// Placeholder for FFT - would use actual FFT implementation
let _spectrum = signal.multiply(&signal)?;
let elapsed = start.elapsed().as_secs_f64();
Ok(elapsed)
}
async fn bench_device_pinn(device: &Device) -> Result<f64> {
let heat_eq = HeatEquation::new(0.1);
let pinn = PINN::builder()
.device(device)
.layers(vec![2, 64, 64, 1])
.physics_loss(Box::new(heat_eq))
.build()?;
let inputs = vec![(0.5, 0.1); 100]; // Batch of inputs
let start = std::time::Instant::now();
let _outputs = pinn.predict(&inputs).await?;
let elapsed = start.elapsed().as_secs_f64();
Ok(elapsed)
}
async fn bench_dataset_loading() -> Result<f64> {
let start = std::time::Instant::now();
let _dataset = MolecularDataset::load("benchmark_molecules.csv")?;
let elapsed = start.elapsed().as_secs_f64();
Ok(elapsed)
}
async fn bench_feature_extraction() -> Result<f64> {
let dataset = MolecularDataset::load("benchmark_molecules.csv")?;
let start = std::time::Instant::now();
for mol in &dataset.molecules {
let _features = mol.to_feature_matrix()?;
let _adjacency = mol.adjacency_matrix();
let _mw = mol.molecular_weight();
}
let elapsed = start.elapsed().as_secs_f64();
Ok(elapsed)
}
/// Memory usage benchmark
fn bench_memory_usage(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut group = c.benchmark_group("Memory Usage");
group.bench_function("large_tensor_ops", |b| {
b.to_async(&rt)
.iter(|| async { bench_large_tensor_operations().await.unwrap() });
});
group.bench_function("molecular_graph_memory", |b| {
b.to_async(&rt)
.iter(|| async { bench_molecular_graph_memory().await.unwrap() });
});
group.finish();
}
async fn bench_large_tensor_operations() -> Result<f64> {
let device = Device::cpu();
let start = std::time::Instant::now();
// Create large tensors
let a = Tensor::randn([1000, 1000], &device)?;
let b = Tensor::randn([1000, 1000], &device)?;
// Perform operations
let _c = a.matmul(&b)?;
let _d = a.add(&b)?;
let _e = a.multiply(&b)?;
let elapsed = start.elapsed().as_secs_f64();
Ok(elapsed)
}
async fn bench_molecular_graph_memory() -> Result<f64> {
let start = std::time::Instant::now();
// Create large molecular dataset
let mut molecules = Vec::new();
for i in 0..1000 {
let mol = Molecule::from_smiles(
format!("large_mol_{}", i),
"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC",
)?;
molecules.push(mol);
}
// Extract features
for mol in &molecules {
let _features = mol.to_feature_matrix()?;
}
let elapsed = start.elapsed().as_secs_f64();
Ok(elapsed)
}
/// Accuracy vs speed trade-off benchmark
fn bench_accuracy_speed_tradeoff(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut group = c.benchmark_group("Accuracy vs Speed");
for &precision in &["single", "double"] {
group.bench_with_input(
BenchmarkId::new("pinn_precision", precision),
&precision,
|b, &precision| {
b.to_async(&rt)
.iter(|| async { bench_precision_pinn(precision).await.unwrap() });
},
);
}
group.finish();
}
async fn bench_precision_pinn(precision: &str) -> Result<f64> {
let device = match precision {
"single" => Device::cpu(),
"double" => Device::cpu(), // Would use double precision if available
_ => Device::cpu(),
};
let heat_eq = HeatEquation::new(0.1);
let pinn = PINN::builder()
.device(&device)
.layers(vec![2, 64, 64, 1])
.physics_loss(Box::new(heat_eq))
.build()?;
let inputs = vec![(0.5, 0.1); 50];
let start = std::time::Instant::now();
let _outputs = pinn.predict(&inputs).await?;
let elapsed = start.elapsed().as_secs_f64();
Ok(elapsed)
}
/// Parallel scaling benchmark
fn bench_parallel_scaling(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut group = c.benchmark_group("Parallel Scaling");
for &num_threads in &[1, 2, 4, 8] {
group.bench_with_input(
BenchmarkId::new("molecular_parallel", num_threads),
&num_threads,
|b, &num_threads| {
b.to_async(&rt).iter(|| async {
bench_molecular_parallel_processing(num_threads)
.await
.unwrap()
});
},
);
}
group.finish();
}
async fn bench_molecular_parallel_processing(num_threads: usize) -> Result<f64> {
// Set number of threads (placeholder)
std::env::set_var("RAYON_NUM_THREADS", num_threads.to_string());
let start = std::time::Instant::now();
// Create molecules to process in parallel
let molecules: Vec<_> = (0..100)
.map(|i| Molecule::from_smiles(format!("mol_{}", i), "CCCCCCCC").unwrap())
.collect();
// Process in parallel using rayon
use rayon::prelude::*;
let _results: Vec<_> = molecules
.par_iter()
.map(|mol| mol.molecular_weight())
.collect();
let elapsed = start.elapsed().as_secs_f64();
Ok(elapsed)
}
criterion_group!(
benches,
bench_pinn_training,
bench_molecular_prediction,
bench_conservation_laws,
bench_scientific_computing,
bench_device_comparison,
bench_molecular_datasets,
bench_memory_usage,
bench_accuracy_speed_tradeoff,
bench_parallel_scaling
);
criterion_main!(benches);