use rand::Rng;
use std::error::Error;
use std::time::{Duration, Instant};
use pandrs::optimized::jit::JitCompilable;
#[allow(clippy::result_large_err)]
fn main() -> Result<(), Box<dyn Error>> {
println!("Parallel JIT Execution Example");
println!("==============================");
let size = 20_000_000;
println!("\nBenchmarking with array size: {size}");
let data = generate_random_data(size);
println!("\nSum Operation Comparison:");
let (std_result, std_time) = benchmark_standard_jit(&data);
println!(" Standard JIT sum: {std_result:.6}");
println!(" Standard time: {std_time:?}");
let (simd_result, simd_time) = benchmark_simd_jit(&data);
println!(" SIMD JIT sum: {simd_result:.6}");
println!(" SIMD time: {simd_time:?}");
println!(
" SIMD speedup: {:.2}x",
std_time.as_nanos() as f64 / simd_time.as_nanos() as f64
);
let (par_result, par_time) = benchmark_parallel_jit(&data);
println!(" Parallel JIT sum: {par_result:.6}");
println!(" Parallel time: {par_time:?}");
println!(
" Parallel speedup: {:.2}x",
std_time.as_nanos() as f64 / par_time.as_nanos() as f64
);
benchmark_other_operations(&data);
benchmark_custom_parallel(&data);
benchmark_parallel_config_tuning(&data);
Ok(())
}
fn generate_random_data(size: usize) -> Vec<f64> {
println!("Generating {size} random values...");
let mut rng = rand::rng();
let result = (0..size).map(|_| rng.random_range(0.0..100.0)).collect();
println!("Data generation complete.");
result
}
fn benchmark_standard_jit(data: &[f64]) -> (f64, Duration) {
use pandrs::optimized::jit::jit_f64;
println!("Running standard JIT benchmark...");
let sum_fn = jit_f64("standard_sum", |values: &[f64]| -> f64 {
values.iter().sum()
});
let start = Instant::now();
let result = sum_fn.execute(data);
let duration = start.elapsed();
(result, duration)
}
fn benchmark_simd_jit(data: &[f64]) -> (f64, Duration) {
use pandrs::optimized::jit::simd_sum_f64;
println!("Running SIMD JIT benchmark...");
let start = Instant::now();
let result = simd_sum_f64(data);
let duration = start.elapsed();
(result, duration)
}
fn benchmark_parallel_jit(data: &[f64]) -> (f64, Duration) {
use pandrs::optimized::jit::parallel_sum_f64;
println!("Running parallel JIT benchmark...");
let parallel_sum = parallel_sum_f64(None);
let start = Instant::now();
let result = parallel_sum.execute(data);
let duration = start.elapsed();
(result, duration)
}
fn benchmark_other_operations(data: &[f64]) {
use pandrs::optimized::jit::{
jit_f64, parallel_max_f64, parallel_mean_f64, parallel_min_f64, parallel_std_f64,
};
println!("\nOther Operations Comparison:");
println!("\nMean Operation:");
let mean_fn = jit_f64("standard_mean", |values: &[f64]| -> f64 {
if values.is_empty() {
return 0.0;
}
values.iter().sum::<f64>() / values.len() as f64
});
let start = Instant::now();
let result = mean_fn.execute(data);
let std_time = start.elapsed();
println!(" Standard mean: {result:.6}");
println!(" Standard time: {std_time:?}");
let parallel_mean = parallel_mean_f64(None);
let start = Instant::now();
let result = parallel_mean.execute(data);
let par_time = start.elapsed();
println!(" Parallel mean: {:.6}", result.0);
println!(" Parallel time: {par_time:?}");
println!(
" Speedup: {:.2}x",
std_time.as_nanos() as f64 / par_time.as_nanos() as f64
);
println!("\nStandard Deviation Operation:");
let std_fn = jit_f64("standard_std", |values: &[f64]| -> f64 {
if values.len() <= 1 {
return 0.0;
}
let mean = values.iter().sum::<f64>() / values.len() as f64;
let variance =
values.iter().map(|&v| (v - mean).powi(2)).sum::<f64>() / (values.len() - 1) as f64;
variance.sqrt()
});
let start = Instant::now();
let result = std_fn.execute(data);
let std_time = start.elapsed();
println!(" Standard std: {result:.6}");
println!(" Standard time: {std_time:?}");
let parallel_std = parallel_std_f64(None);
let start = Instant::now();
let result = parallel_std.execute(data);
let par_time = start.elapsed();
println!(" Parallel std: {:.6}", result.0);
println!(" Parallel time: {par_time:?}");
println!(
" Speedup: {:.2}x",
std_time.as_nanos() as f64 / par_time.as_nanos() as f64
);
println!("\nMin/Max Operations:");
let parallel_min = parallel_min_f64(None);
let start = Instant::now();
let min_result = parallel_min.execute(data);
let min_time = start.elapsed();
let parallel_max = parallel_max_f64(None);
let start = Instant::now();
let max_result = parallel_max.execute(data);
let max_time = start.elapsed();
println!(" Min value: {min_result:.6} (computed in {min_time:?})");
println!(" Max value: {max_result:.6} (computed in {max_time:?})");
}
fn benchmark_custom_parallel(data: &[f64]) {
use pandrs::optimized::jit::parallel_custom;
println!("\nCustom Parallel Function:");
let squared_sum = |values: &[f64]| -> f64 { values.iter().map(|x| x * x).sum() };
let reduce_fn = |results: Vec<f64>| -> f64 { results.iter().sum() };
let parallel_squared_sum = parallel_custom(
"parallel_squared_sum",
squared_sum,
squared_sum,
reduce_fn,
None,
);
let start = Instant::now();
let result = parallel_squared_sum.execute(data);
let duration = start.elapsed();
println!(" Result: {result:.6}");
println!(" Time: {duration:?}");
}
fn benchmark_parallel_config_tuning(data: &[f64]) {
use pandrs::optimized::jit::{parallel_sum_f64, ParallelConfig};
println!("\nParallel Configuration Tuning:");
let chunk_sizes = [1000, 10000, 100000, 1000000];
for &chunk_size in &chunk_sizes {
let config = ParallelConfig::new().with_min_chunk_size(chunk_size);
let parallel_sum = parallel_sum_f64(Some(config));
let start = Instant::now();
let _result = parallel_sum.execute(data);
let duration = start.elapsed();
println!(" Chunk size {chunk_size:8}: {duration:?}");
}
let available_threads = num_cpus::get();
println!("\nAvailable CPU cores: {available_threads}");
let thread_counts = [1, 2, 4, available_threads];
for &threads in &thread_counts {
if threads > available_threads {
continue;
}
let config = ParallelConfig::new()
.with_min_chunk_size(100000)
.with_max_threads(threads);
let parallel_sum = parallel_sum_f64(Some(config));
let start = Instant::now();
let _result = parallel_sum.execute(data);
let duration = start.elapsed();
println!(" Threads {threads:8}: {duration:?}");
}
}