//! Throughput of the streaming superkmer pipeline (`RollingStat`'s hot path: //! minimizer selection + entropy tracking fused in a single pass). //! //! Reference point for the `obikentropy` extraction: the entropy bookkeeping //! that used to live inline in `RollingStat` was pulled out into a composed //! `EntropyTracker`. This benchmark is run before and after that change to //! confirm no regression. use criterion::{Criterion, Throughput, criterion_group, criterion_main}; use obikrope::Rope; use obiskbuilder::SuperKmerIter; const K: usize = 21; const M: usize = 9; const LEVEL_MAX: usize = 6; const THETA: f64 = 0.7; const SEQ_LEN: usize = 200_000; /// Deterministic pseudo-random ACGT sequence — high enough complexity that /// the entropy filter rarely rejects, so the bench stays on the steady-state /// path rather than repeatedly resetting. fn make_sequence(len: usize) -> Vec { let mut state: u64 = 0x9E3779B97F4A7C15; (0..len) .map(|_| { state ^= state << 13; state ^= state >> 7; state ^= state << 17; b"ACGT"[(state % 4) as usize] }) .collect() } fn make_rope(seq: &[u8]) -> Rope { let mut rope = Rope::new(None); rope.push(seq.to_vec()); rope } fn bench_build_superkmers(c: &mut Criterion) { obikseq::set_k(K); obikseq::set_m(M); let seq = make_sequence(SEQ_LEN); let rope = make_rope(&seq); let mut group = c.benchmark_group("build_superkmers"); group.throughput(Throughput::Bytes(SEQ_LEN as u64)); group.bench_function("stream", |b| { b.iter(|| { SuperKmerIter::new(std::hint::black_box(&rope), K, LEVEL_MAX, THETA).count() }); }); group.finish(); } criterion_group!(benches, bench_build_superkmers); criterion_main!(benches);