use arcweight::optimization::prefetch::prefetch_cache_line;
use arcweight::prelude::*;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use std::hint::black_box;
use std::time::Duration;
fn create_large_fst(states: usize) -> VectorFst<TropicalWeight> {
let mut fst = VectorFst::new();
let mut state_ids = Vec::new();
for _ in 0..states {
state_ids.push(fst.add_state());
}
fst.set_start(state_ids[0]);
fst.set_final(state_ids[states - 1], TropicalWeight::one());
for i in 0..states - 1 {
for j in 0..5 {
fst.add_arc(
state_ids[i],
Arc::new(
(j + 1) as u32,
(j + 1) as u32,
TropicalWeight::new((j + 1) as f32),
state_ids[i + 1],
),
);
}
}
fst
}
pub fn bench_sequential_traversal_prefetch(c: &mut Criterion) {
let mut group = c.benchmark_group("sequential_traversal_prefetch");
group.measurement_time(Duration::from_secs(10));
for states in [1000, 5000, 10000, 50000].iter() {
let fst = create_large_fst(*states);
let state_list: Vec<u32> = fst.states().collect();
group.bench_with_input(
BenchmarkId::new("without_prefetch", states),
states,
|b, _| {
b.iter(|| {
let mut sum = TropicalWeight::zero();
for &state in &state_list {
for arc in fst.arcs(state) {
sum = sum.plus(&arc.weight);
}
}
black_box(sum);
})
},
);
group.bench_with_input(BenchmarkId::new("with_prefetch", states), states, |b, _| {
b.iter(|| {
let mut sum = TropicalWeight::zero();
for (i, &state) in state_list.iter().enumerate() {
if i + 4 < state_list.len() {
prefetch_cache_line(&state_list[i + 4]);
}
for arc in fst.arcs(state) {
sum = sum.plus(&arc.weight);
}
}
black_box(sum);
})
});
}
group.finish();
}
pub fn bench_random_access_prefetch(c: &mut Criterion) {
let mut group = c.benchmark_group("random_access_prefetch");
group.measurement_time(Duration::from_secs(10));
for states in [1000, 5000, 10000].iter() {
let fst = create_large_fst(*states);
let mut access_pattern: Vec<u32> = fst.states().collect();
for i in 0..access_pattern.len() {
let j = (i * 7919 + 1234567) % access_pattern.len();
access_pattern.swap(i, j);
}
group.bench_with_input(
BenchmarkId::new("random_no_prefetch", states),
states,
|b, _| {
b.iter(|| {
let mut sum = TropicalWeight::zero();
for &state in &access_pattern {
for arc in fst.arcs(state) {
sum = sum.plus(&arc.weight);
}
}
black_box(sum);
})
},
);
}
group.finish();
}
criterion_group!(
benches,
bench_sequential_traversal_prefetch,
bench_random_access_prefetch
);
criterion_main!(benches);