use std::time::Duration;
use almost_enough::{DebouncedTimeoutExt, Stop, StopReason, Stopper, TimeoutExt};
#[inline(always)]
fn sub_defilter(buf: &mut [u8]) {
for i in 4..buf.len() {
buf[i] = buf[i].wrapping_add(buf[i - 4]);
}
}
#[inline(always)]
fn light_work(acc: &mut u64) {
for _ in 0..10 {
*acc = acc.wrapping_mul(6364136223846793005).wrapping_add(1);
}
}
#[inline(always)]
fn jittery_work(acc: &mut u64) {
*acc = acc
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
let iters = 2 + ((*acc >> 59) as u32 * 5); for _ in 0..iters {
*acc = acc
.wrapping_mul(2862933555777941757)
.wrapping_add(3037000493);
}
}
const BUF: usize = 256 * 1024;
const CHUNK: usize = 4096;
fn make_buf() -> Vec<u8> {
(0..BUF)
.map(|i| (i.wrapping_mul(0x9E3779B9) >> 24) as u8)
.collect()
}
#[inline(never)]
fn decode(buf: &mut [u8], stop: &dyn Stop) -> Result<(), StopReason> {
for chunk in buf.chunks_mut(CHUNK) {
stop.check()?;
sub_defilter(chunk);
}
Ok(())
}
#[inline(never)]
fn check_10k(stop: &dyn Stop) -> Result<(), StopReason> {
for _ in 0..10_000 {
stop.check()?;
}
Ok(())
}
#[inline(never)]
fn check_10k_light(stop: &dyn Stop) -> Result<u64, StopReason> {
let mut acc = 0u64;
for _ in 0..10_000 {
stop.check()?;
light_work(&mut acc);
}
Ok(acc)
}
#[inline(never)]
fn check_10k_jittery(stop: &dyn Stop) -> Result<u64, StopReason> {
let mut acc = 0x12345678u64;
for _ in 0..10_000 {
stop.check()?;
jittery_work(&mut acc);
}
Ok(acc)
}
fn main() {
let result = zenbench::run(|suite| {
suite.compare("tight_loop_10k", |group| {
group.config().sort_by_speed(true).cache_firewall(false);
group.baseline("WithTimeout");
group.throughput(zenbench::Throughput::Elements(10_000));
group.throughput_unit("checks");
group.bench("WithTimeout", |b| {
let stop = Stopper::new();
let timeout = stop.with_timeout(Duration::from_secs(60));
b.iter(|| check_10k(&timeout))
});
group.bench("DebouncedTimeout", |b| {
let stop = Stopper::new();
let timeout = stop.with_debounced_timeout(Duration::from_secs(60));
for _ in 0..20_000 {
let _ = timeout.check();
}
b.iter(|| check_10k(&timeout))
});
group.bench("Stopper (no timeout)", |b| {
let stop = Stopper::new();
b.iter(|| check_10k(&stop))
});
});
suite.compare("light_work_10k", |group| {
group.config().sort_by_speed(true).cache_firewall(false);
group.baseline("WithTimeout");
group.throughput(zenbench::Throughput::Elements(10_000));
group.throughput_unit("checks");
group.bench("WithTimeout", |b| {
let stop = Stopper::new();
let timeout = stop.with_timeout(Duration::from_secs(60));
b.iter(|| check_10k_light(&timeout))
});
group.bench("DebouncedTimeout", |b| {
let stop = Stopper::new();
let timeout = stop.with_debounced_timeout(Duration::from_secs(60));
for _ in 0..20_000 {
let _ = timeout.check();
}
b.iter(|| check_10k_light(&timeout))
});
group.bench("Stopper (no timeout)", |b| {
let stop = Stopper::new();
b.iter(|| check_10k_light(&stop))
});
});
suite.compare("jittery_work_10k", |group| {
group.config().sort_by_speed(true).cache_firewall(false);
group.baseline("WithTimeout");
group.throughput(zenbench::Throughput::Elements(10_000));
group.throughput_unit("checks");
group.bench("WithTimeout", |b| {
let stop = Stopper::new();
let timeout = stop.with_timeout(Duration::from_secs(60));
b.iter(|| check_10k_jittery(&timeout))
});
group.bench("DebouncedTimeout", |b| {
let stop = Stopper::new();
let timeout = stop.with_debounced_timeout(Duration::from_secs(60));
let mut warmup_acc = 0x12345678u64;
for _ in 0..20_000 {
let _ = timeout.check();
jittery_work(&mut warmup_acc);
}
zenbench::black_box(warmup_acc);
b.iter(|| check_10k_jittery(&timeout))
});
group.bench("Stopper (no timeout)", |b| {
let stop = Stopper::new();
b.iter(|| check_10k_jittery(&stop))
});
});
suite.compare("codec_256kb", |group| {
group.config().sort_by_speed(true).cache_firewall(false);
group.baseline("WithTimeout");
group.throughput(zenbench::Throughput::Bytes(BUF as u64));
group.bench("WithTimeout", |b| {
let stop = Stopper::new();
let timeout = stop.with_timeout(Duration::from_secs(60));
let mut work = make_buf();
b.iter(|| {
let _ = decode(&mut work, &timeout);
zenbench::black_box(&work);
})
});
group.bench("DebouncedTimeout", |b| {
let stop = Stopper::new();
let timeout = stop.with_debounced_timeout(Duration::from_secs(60));
let mut work = make_buf();
for chunk in work.chunks_mut(CHUNK) {
let _ = timeout.check();
zenbench::black_box(chunk);
}
b.iter(|| {
let _ = decode(&mut work, &timeout);
zenbench::black_box(&work);
})
});
group.bench("Stopper (no timeout)", |b| {
let stop = Stopper::new();
let mut work = make_buf();
b.iter(|| {
let _ = decode(&mut work, &stop);
zenbench::black_box(&work);
})
});
});
suite.compare("calibration_warmup", |group| {
group.config().sort_by_speed(true).cache_firewall(false);
group.baseline("WithTimeout");
group.throughput(zenbench::Throughput::Elements(10_000));
group.throughput_unit("checks");
group.bench("WithTimeout", |b| {
let stop = Stopper::new();
let timeout = stop.with_timeout(Duration::from_secs(60));
b.iter(|| check_10k(&timeout))
});
group.bench("DebouncedTimeout (cold)", |b| {
b.iter(|| {
let stop = Stopper::new();
let timeout = stop.with_debounced_timeout(Duration::from_secs(60));
check_10k(&timeout)
})
});
group.bench("DebouncedTimeout (warm)", |b| {
let stop = Stopper::new();
let timeout = stop.with_debounced_timeout(Duration::from_secs(60));
for _ in 0..20_000 {
let _ = timeout.check();
}
b.iter(|| check_10k(&timeout))
});
});
suite.compare("target_interval", |group| {
group.config().sort_by_speed(true).cache_firewall(false);
group.baseline("WithTimeout (always)");
group.throughput(zenbench::Throughput::Elements(10_000));
group.throughput_unit("checks");
group.bench("WithTimeout (always)", |b| {
let stop = Stopper::new();
let timeout = stop.with_timeout(Duration::from_secs(60));
b.iter(|| check_10k(&timeout))
});
for target_us in [10, 50, 100, 500, 1000] {
group.bench(format!("Debounced ({target_us}μs)"), move |b| {
let stop = Stopper::new();
let timeout = stop
.with_debounced_timeout(Duration::from_secs(60))
.with_target_interval(Duration::from_micros(target_us));
for _ in 0..50_000 {
let _ = timeout.check();
}
b.iter(|| check_10k(&timeout))
});
}
});
});
if let Err(e) = result.save("debounced_timeout_results.json") {
eprintln!("Failed to save results: {e}");
}
}