use std::hint::black_box;
use std::sync::OnceLock;
use std::sync::atomic::{AtomicU64, Ordering};
use std::thread;
use std::time::Duration;
use criterion::{criterion_group, criterion_main, Criterion};
use subetha_cxc::SharedAsyncPointer;
static UNIQUE_SUFFIX: AtomicU64 = AtomicU64::new(0);
fn tmp_path(name: &str) -> std::path::PathBuf {
let mut p = std::env::temp_dir();
let pid = std::process::id();
p.push(format!("subetha-async-bench-{name}-{pid}.bin"));
p
}
fn unique_tmp_path(prefix: &str) -> std::path::PathBuf {
let n = UNIQUE_SUFFIX.fetch_add(1, Ordering::Relaxed);
let pid = std::process::id();
let mut p = std::env::temp_dir();
p.push(format!("subetha-async-bench-{prefix}-{pid}-{n}.bin"));
p
}
fn resolved_peek(c: &mut Criterion) {
let p = tmp_path("resolved-peek");
let sap: SharedAsyncPointer<u64> = SharedAsyncPointer::create(&p).unwrap();
sap.set_resolved(12345);
c.bench_function("shared_async.resolved_peek/mmf", |b| {
b.iter(|| black_box(sap.try_get()));
});
let lock: OnceLock<u64> = OnceLock::new();
lock.set(12345).unwrap();
c.bench_function("shared_async.resolved_peek/oncelock", |b| {
b.iter(|| black_box(lock.get().copied()));
});
std::fs::remove_file(&p).ok();
}
fn lazy_first_compute(c: &mut Criterion) {
c.bench_function("shared_async.lazy_first_compute/mmf", |b| {
b.iter_with_setup(
|| {
let p = unique_tmp_path("lazy");
let sap: SharedAsyncPointer<u64> =
SharedAsyncPointer::create(&p).unwrap();
(sap, p)
},
|(sap, path)| {
let v = sap.get_or_lazy(|| black_box(99u64));
black_box(v);
drop(sap);
std::fs::remove_file(&path).ok();
},
);
});
c.bench_function("shared_async.lazy_first_compute/oncelock", |b| {
b.iter_with_setup(
OnceLock::<u64>::new,
|lock| {
let v = *lock.get_or_init(|| black_box(99u64));
black_box(v);
},
);
});
}
fn speculative_hedging(c: &mut Criterion) {
c.bench_function("shared_async.speculative_2_hedged/mmf", |b| {
b.iter_with_setup(
|| {
let p = unique_tmp_path("spec2");
let sap: SharedAsyncPointer<u64> =
SharedAsyncPointer::create(&p).unwrap();
(sap, p)
},
|(sap, path)| {
let v = sap.get_or_speculative_with([
Box::new(|| {
thread::sleep(Duration::from_millis(20));
999u64
}) as Box<dyn FnOnce() -> u64 + Send>,
Box::new(|| {
thread::sleep(Duration::from_millis(2));
100u64
}) as Box<dyn FnOnce() -> u64 + Send>,
]);
black_box(v);
drop(sap);
std::fs::remove_file(&path).ok();
},
);
});
c.bench_function("shared_async.speculative_2_hedged/sequential_slow", |b| {
b.iter(|| {
thread::sleep(Duration::from_millis(20));
black_box(999u64);
});
});
c.bench_function("shared_async.speculative_2_hedged/sequential_fast", |b| {
b.iter(|| {
thread::sleep(Duration::from_millis(2));
black_box(100u64);
});
});
}
fn speculative_overhead(c: &mut Criterion) {
c.bench_function("shared_async.speculative_4_same/mmf", |b| {
b.iter_with_setup(
|| {
let p = unique_tmp_path("spec4");
let sap: SharedAsyncPointer<u64> =
SharedAsyncPointer::create(&p).unwrap();
(sap, p)
},
|(sap, path)| {
let v = sap.get_or_speculative(4, || {
thread::sleep(Duration::from_millis(2));
42u64
});
black_box(v);
drop(sap);
std::fs::remove_file(&path).ok();
},
);
});
c.bench_function("shared_async.speculative_4_same/lazy_single", |b| {
b.iter_with_setup(
|| {
let p = unique_tmp_path("lazy1");
let sap: SharedAsyncPointer<u64> =
SharedAsyncPointer::create(&p).unwrap();
(sap, p)
},
|(sap, path)| {
let v = sap.get_or_lazy(|| {
thread::sleep(Duration::from_millis(2));
42u64
});
black_box(v);
drop(sap);
std::fs::remove_file(&path).ok();
},
);
});
}
criterion_group!(
benches,
resolved_peek,
lazy_first_compute,
speculative_hedging,
speculative_overhead,
);
criterion_main!(benches);