slow5lib 0.1.0

Rust re-implementation of slow5lib: read and write SLOW5/BLOW5 nanopore sequencing files
Documentation
/// Sequential read throughput benchmarks.
///
/// Each benchmark opens a file, iterates every record to completion,
/// and accumulates the total sample count. This exercises:
///   - file open + header parse
///   - I/O (BufReader reads)
///   - block decompression (zstd / zlib / none)
///   - signal decompression (SVB-ZD / none)
///
/// Run:
///   cargo bench --bench throughput
///   cargo bench --bench throughput -- sequential_five_reads
use std::time::{Duration, Instant};

use criterion::{BenchmarkId, Criterion, Throughput, black_box, criterion_group, criterion_main};
use slow5lib::Slow5Reader;

const FIVE_READS_ZSTD: &str = "tests/data/five_reads.blow5";
const FIVE_READS_NONE: &str = "tests/data/five_reads_nocompress.blow5";
const FIVE_READS_SLOW5: &str = "tests/data/five_reads.slow5";
const SMALL_BLOW5: &str = "tests/data/small.blow5";

/// Iterate all five reads from each format variant and count total samples.
///
/// Fast benchmark: ~167 K samples * 5 reads = ~835 K samples per iteration.
/// Useful for comparing format overhead (text vs binary, compressed vs not).
fn bench_sequential_five(c: &mut Criterion) {
    let cases: &[(&str, &str)] = &[
        ("blow5_zstd_svbzd", FIVE_READS_ZSTD),
        ("blow5_none_none", FIVE_READS_NONE),
        ("slow5_text", FIVE_READS_SLOW5),
    ];

    let mut group = c.benchmark_group("sequential_five_reads");

    for (name, path) in cases {
        group.bench_with_input(BenchmarkId::from_parameter(name), path, |b, path| {
            b.iter(|| {
                let mut reader = Slow5Reader::open(black_box(*path)).expect("open");
                let mut total = 0usize;
                for rec in reader.records() {
                    total += rec.expect("record ok").raw_signal.len();
                }
                black_box(total)
            });
        });
    }

    group.finish();
}

/// Sequential throughput over the full large BLOW5 file (zstd + SVB-ZD).
///
/// Measures end-to-end read rate in bytes/sec. Uses fewer samples
/// because each iteration reads ~705 MB.
fn bench_sequential_large(c: &mut Criterion) {
    let file_bytes = std::fs::metadata(SMALL_BLOW5).map(|m| m.len()).unwrap_or(0);

    let mut group = c.benchmark_group("sequential_large");
    group.sample_size(10);
    group.measurement_time(Duration::from_secs(120));
    group.throughput(Throughput::Bytes(file_bytes));

    group.bench_function("blow5_zstd_svbzd", |b| {
        b.iter_custom(|iters| {
            let mut total = Duration::ZERO;
            for _ in 0..iters {
                let mut reader = Slow5Reader::open(SMALL_BLOW5).expect("open");
                let t0 = Instant::now();
                let mut samples = 0usize;
                for rec in reader.records() {
                    samples += rec.expect("record ok").raw_signal.len();
                }
                total += t0.elapsed();
                black_box(samples);
            }
            total
        });
    });

    group.finish();
}

criterion_group!(benches, bench_sequential_five, bench_sequential_large);
criterion_main!(benches);