#stress-testing #benchmark #performance-testing #performance

bin+lib cntryl-stress

Lightweight benchmark runner for single-shot and duration-based stress tests

6 releases

new 0.2.1 Apr 7, 2026
0.2.0 Feb 18, 2026
0.1.3 Dec 30, 2025

#261 in Profiling

37 downloads per month

Apache-2.0

95KB
2K SLoC

cntryl-stress

A lightweight benchmark runner for system-level stress tests.

Unlike Criterion (which uses statistical sampling), this crate is designed for expensive operations where each iteration matters: disk I/O, network calls, database transactions, compaction, recovery, etc. It supports both single-shot measurements and duration-bounded throughput loops.

The easiest way to write stress tests is with the #[stress_test] attribute:

use cntryl_stress::{stress_test, StressContext};

#[stress_test]
fn write_1mb_file(ctx: &mut StressContext) {
    let data = vec![0u8; 1024 * 1024];
    ctx.set_bytes(data.len() as u64);
    
    ctx.measure(|| {
        std::fs::write("/tmp/test", &data).unwrap();
    });
    
    std::fs::remove_file("/tmp/test").ok();
}

#[stress_test]
fn database_insert(ctx: &mut StressContext) {
    let db = setup_database();
    ctx.measure(|| {
        db.insert("key", "value");
    });
}

#[stress_test]
fn database_throughput(ctx: &mut StressContext) {
    use std::time::Duration;

    let db = setup_database();
    let iterations = ctx.measure_for(Duration::from_secs(3), || {
        db.insert("key", "value");
    });
    ctx.set_elements(iterations as u64);
}

// Generate main function
cntryl_stress::stress_main!();

Then run with:

cargo stress                          # Run all stress tests
cargo stress --workload "database*"   # Run matching tests
cargo stress --workload "*insert*"    # Glob patterns supported

Manual Runner Style

For more control, use the BenchRunner directly:

use cntryl_stress::{BenchRunner, StressContext};

let mut runner = BenchRunner::new("my_suite");

runner.run("expensive_operation", |ctx| {
    let data = prepare_data();
    ctx.measure(|| {
        expensive_operation(&data);
    });
    cleanup(&data);
});

runner.finish();

fn prepare_data() -> Vec<u8> { vec![0; 1024] }
fn expensive_operation(_: &[u8]) {}
fn cleanup(_: &[u8]) {}

Features

  • Single-shot measurements — no statistical sampling overhead
  • Duration-bounded measurements — sustain work for a wall-clock budget
  • Glob filtering — run subsets with --workload "pattern*"

Dependencies

~1.3–2.5MB
~46K SLoC