use std::hint::black_box;
use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
use gladius::math::{Accuracy, Consistency, Ipm, Wpm};
fn benchmark_wpm_calculations(c: &mut Criterion) {
let mut group = c.benchmark_group("wpm_calculations");
let test_cases = vec![
(100, 5, 2, 1.0), (1000, 50, 20, 10.0), (10000, 500, 200, 100.0), ];
for (characters, errors, corrections, minutes) in test_cases {
group.bench_with_input(
BenchmarkId::new(
"calculate",
format!("{}chars_{}min", characters, minutes as u32),
),
&(characters, errors, corrections, minutes),
|b, &(characters, errors, corrections, minutes)| {
b.iter(|| {
Wpm::calculate(
black_box(characters),
black_box(errors),
black_box(corrections),
black_box(minutes),
)
})
},
);
}
group.finish();
}
fn benchmark_ipm_calculations(c: &mut Criterion) {
let mut group = c.benchmark_group("ipm_calculations");
let test_cases = vec![
(100, 120, 1.0), (1000, 1200, 10.0), (10000, 12000, 100.0), ];
for (actual_inputs, raw_inputs, minutes) in test_cases {
group.bench_with_input(
BenchmarkId::new(
"calculate",
format!("{}inputs_{}min", actual_inputs, minutes as u32),
),
&(actual_inputs, raw_inputs, minutes),
|b, &(actual_inputs, raw_inputs, minutes)| {
b.iter(|| {
Ipm::calculate(
black_box(actual_inputs),
black_box(raw_inputs),
black_box(minutes),
)
})
},
);
}
group.finish();
}
fn benchmark_accuracy_calculations(c: &mut Criterion) {
let mut group = c.benchmark_group("accuracy_calculations");
let test_cases = vec![
(100, 5, 2), (1000, 50, 20), (10000, 500, 200), ];
for (input_len, total_errors, total_corrections) in test_cases {
group.bench_with_input(
BenchmarkId::new("calculate", format!("{}chars", input_len)),
&(input_len, total_errors, total_corrections),
|b, &(input_len, total_errors, total_corrections)| {
b.iter(|| {
Accuracy::calculate(
black_box(input_len),
black_box(total_errors),
black_box(total_corrections),
)
})
},
);
}
group.finish();
}
fn benchmark_consistency_calculations(c: &mut Criterion) {
let mut group = c.benchmark_group("consistency_calculations");
let test_sizes = vec![10, 100, 1000];
for size in test_sizes {
let mut measurements = Vec::with_capacity(size);
let base_wpm = 50.0;
for i in 0..size {
let variation = (i as f64 * 0.1).sin() * 5.0; measurements.push(Wpm {
raw: base_wpm + variation,
corrected: base_wpm + variation - 2.0,
actual: base_wpm + variation - 3.0,
});
}
group.bench_with_input(
BenchmarkId::new("calculate", format!("{}measurements", size)),
&measurements,
|b, measurements| b.iter(|| Consistency::calculate(black_box(measurements))),
);
}
group.finish();
}
fn benchmark_consistency_std_dev_algorithms(c: &mut Criterion) {
let mut group = c.benchmark_group("consistency_std_dev");
let sizes = vec![10, 100, 1000, 10000];
for size in sizes {
let values: Vec<f64> = (0..size)
.map(|i| 50.0 + (i as f64 * 0.1).sin() * 5.0)
.collect();
group.bench_with_input(
BenchmarkId::new("welfords_algorithm", size),
&values,
|b, values| b.iter(|| calculate_std_dev_welford(black_box(values))),
);
group.bench_with_input(
BenchmarkId::new("naive_two_pass", size),
&values,
|b, values| b.iter(|| calculate_std_dev_naive(black_box(values))),
);
}
group.finish();
}
fn calculate_std_dev_welford(values: &[f64]) -> f64 {
if values.len() <= 1 {
return 0.0;
}
let mut mean = 0.0;
let mut m2 = 0.0;
for (i, &value) in values.iter().enumerate() {
let delta = value - mean;
mean += delta / (i + 1) as f64;
let delta2 = value - mean;
m2 += delta * delta2;
}
let variance = m2 / values.len() as f64;
variance.sqrt()
}
fn calculate_std_dev_naive(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(|&x| (x - mean).powi(2)).sum::<f64>() / values.len() as f64;
variance.sqrt()
}
criterion_group!(
benches,
benchmark_wpm_calculations,
benchmark_ipm_calculations,
benchmark_accuracy_calculations,
benchmark_consistency_calculations,
benchmark_consistency_std_dev_algorithms
);
criterion_main!(benches);