Performance benchmarks for engineers who need trustworthy artifacts, not just timing numbers.
cntryl-stress is an opinionated Rust benchmarking framework for performance
engineering loops. It keeps benchmark authoring low ceremony while producing
structured artifacts, diagnostics, and gates that can support real optimization
decisions.
The core question is simple: can this benchmark row be trusted?
cntryl-stress helps answer that by recording raw samples, deriving summaries
from measured samples only, preserving correctness counters, and calling out
common benchmark-shape mistakes such as uncounted batch work, invalid timing,
high variance, setup-dominated measurements, and missing allocation tracking.
- Small benchmark bodies that read like tests.
- Deterministic fixtures with setup outside measured work.
- Named measurements and stable row identifiers.
- Logical operation counts for batch and throughput work.
- Machine-readable JSON artifacts under
target/stress. - Human output that prioritizes value, variance, allocations, and fixes.
- Release gates based on correctness, budgets, diagnostics, quality, and baseline comparisons.
Use cntryl-stress when benchmark output needs to feed an engineering
workflow:
- Day-to-day optimization loops.
- CI performance gates.
- Baseline refresh decisions.
- Release-quality benchmark reports.
- Subsystem, integration, throughput, saturation, or soak-style workloads.
- Allocation-aware hot-path and parser/constructor benchmarks.
cntryl-stress is public tooling, but it is intentionally not neutral. It has
opinions about benchmark shape because those opinions make performance work
easier to repeat and harder to misread.
Do not reach for cntryl-stress first when you only need a quick one-off
timing, rich statistical plotting for an isolated function, or a fully custom
benchmarking policy. It works best when you want conventions, JSON artifacts,
and actionable diagnostics more than a blank-slate benchmark harness.
cntryl-stress organizes benchmarks by intent rather than by raw size:
- Tier 1: Hot paths and microbenchmarks.
- Tier 2: Subsystem operations.
- Tier 3: System behavior.
- Tier 4: Integration workloads.
- Tier 5: Saturation and scaling scenarios.
- Tier 6: Soak and endurance runs.
Each tier uses the same authoring API and reporting model, but the default timing shape changes to match the expected workload: micro timing for Tier 1, fixed operations for Tier 2, and fixed-duration windows for Tiers 3 through 6.
cntryl-stress keeps the dependencies that directly support the benchmark
authoring and reporting experience.
serdeandserde_jsonare core dependencies because JSON artifacts, baselines, schema validation, and machine-readable output are part of the stable workflow.linkmekeeps#[stress]benchmarks automatically registered without asking users to maintain manual benchmark lists.fs2serializes same-suite artifact publishers; durable transaction state lets the next publisher recover an interrupted generation before writing.cntryl-stress-macrosand its proc-macro stack power the macro-first API, including async benchmark support and benchmark metadata.clap,anyhow,syn, andtomlare limited to the optionalclifeature used by thecargo stresswrapper, so ordinary benchmark builds do not compile that discovery and configuration-receipt graph.
[dev-dependencies]
cntryl-stress = "0.3"
[[bench]]
name = "storage_stress"
path = "benches/storage_stress.rs"
harness = falseuse cntryl_stress::{black_box, stress, stress_main, StressContext};
use std::collections::BTreeMap;
cntryl_stress::stress_allocator!();
#[stress(tier = 1, max_allocs_per_op = 0, max_bytes_per_op = 0)]
fn parse_route_hot_path(ctx: &mut StressContext) {
let route = b"tenant-a.queue.primary.region-east-1.message-handler-v2.delivery-attempt-000042.customer-enterprise";
ctx.measure("route hash", || {
let mut hash = 5381_u64;
for byte in black_box(route) {
hash = hash.wrapping_mul(33).wrapping_add(u64::from(*byte));
}
black_box(hash)
});
}
#[stress(tier = 2, metadata(component = "index"))]
fn insert_index_entry(ctx: &mut StressContext) {
let initial_entries = 256_u64;
ctx.parameter("initial_entries", initial_entries);
ctx.benchmark("index insert")
.operations_per_sample(256)
.measure_with_setup(
|| {
(0..initial_entries)
.map(|key| (key, key.rotate_left(5)))
.collect::<BTreeMap<_, _>>()
},
|mut index| {
index.insert(initial_entries, initial_entries.rotate_left(5));
black_box(index)
},
);
}
stress_main!();Allocation tracking uses process-wide allocator counters. Keep unrelated background work quiescent while enforcing per-operation allocation budgets; allocations performed by workload-owned threads are intentionally included.
cargo bench --bench storage_stress
cargo bench --bench storage_stress -- --workload 'parse_route_hot_path'The optional cargo stress wrapper is feature-gated so ordinary benchmark builds do not compile its CLI dependency graph:
cargo install cntryl-stress --features cli
cargo stress
cargo stress --bench storage_stress --profile release --save-baseline
cargo stress --bench storage_stress --baseline latest--workload filters the registered benchmark set before execution. It matches
the display name, Rust function name, module path, module_path::function_name,
and module_path::display_name.
cargo bench --bench storage_stress -- --list
cargo bench --bench storage_stress -- --workload 'parse_route_hot_path'
cargo bench --bench storage_stress -- --workload 'queue::writer::*'Selection is strict. When no row matches, stress exits unsuccessfully and
prints close registered candidates. A misspelled filter can never produce a
successful empty run. In workspace runs, cargo stress probes every selected
bench target, skips only targets with no local match, and runs every target that
does match; selection fails only when the pattern matches nowhere.
Wrapper discovery parses each declared Cargo bench source and attributes its
entrypoint to that package's declared cntryl-stress dependency. Qualified
calls, dependency renames, and direct, renamed, grouped, or glob imports of
stress_main! are supported. The entrypoint must be an unconditional top-level
invocation; nested, conditional, generated, or unattributed lookalikes are
rejected with the inspected source and supported forms instead of being run as
an unrelated executable.
tier = 1..6describes benchmark scope:- Tier 1: hot path
- Tier 2: subsystem
- Tier 3: system
- Tier 4: integration
- Tier 5: saturation/scaling
- Tier 6: soak/endurance
- Use
smokefor a quick correctness-focused diagnostic run. - The
defaultprofile is the normal day-to-day run: useful per-tier signal without paying the exhaustive lab cost. - Use
labfor deeper exploratory runs with more samples and longer sample windows. - Use
releasefor the trustworthy release-quality gate: quality enforcement and regression enforcement when a baseline is supplied. - JSON artifacts use
schema_version: "cntryl-stress.v2". STRESS_RUN_IDis copied into run metadata when present;cargo stresscreates one shared run id for all child benchmark binaries unless the caller already supplied one.- Raw
Samplerows are the source of truth; summaries, diagnostics, quality, and comparisons are derived from measured samples only. - Warmup and cooldown samples are retained in JSON and excluded from summary statistics and baseline comparison.
- Tier drives benchmark mode: Tier 1 uses micro timing, Tier 2 uses fixed operations, and Tiers 3-6 use fixed duration.
mode = "..."is not public API; choose#[stress(tier = 1..6)].- Human console output is one table per suite. Bench-shape, result, and diagnostic issues are grouped after the table with concrete fixes.
- Tier 1 logical-outcome rows mark
ns_per_op_basis = logical_completed_operationso baseline tools can treat changed ns/op semantics as a baseline refresh event, not as a performance regression. metadata(row_class = "construction" | "parsing" | "allocation")marks allocation-oriented rows so allocation diagnostics are advisory unless an explicit allocation budget fails.
Tier 1 rows below 5 ns/op are invalid by default because dead-code elimination or measurement overhead can dominate them; rows below 15 ns/op receive a warning. Vary inputs and accumulate an observable output first. Only after an explicit anti-DCE review, opt in with the exact attribute syntax:
#[stress(tier = 1, metadata(validated_micro = "true"))]Pick the tier first, then use the matching timing shape. The detailed copy-paste guide is in the benchmark recipes.
| Tier | Scope | Recipe |
|---|---|---|
| 1 | Hot path | measure, or measure_with_setup for consumed input |
| 2 | Subsystem operation | Single-operation timing; measure_outcome for batches |
| 3 | System throughput | measure_outcome plus LogicalUnit::new("record") |
| 4 | Integration throughput | Observed measure_outcome or record_external_outcome |
| 5 | Saturation/scaling | Observed outcomes across a real scale or load sweep |
| 6 | Soak/endurance | Observed outcomes across the declared soak duration |
Tier 5 and Tier 6 describe evidence, not merely code shape. A real Tier 5 suite
must exercise a scale/load sweep long enough to locate sustained saturation. A
real Tier 6 suite must run a representative workload across its declared soak
window and observe correctness and resource drift. Mark short synthetic shape
examples with role = "diagnostic"; the repository demos do this explicitly.
Use measure for repeatable, non-destructive single operations:
#[stress(tier = 1)]
fn parse_document_header(ctx: &mut StressContext) {
let document = load_document();
ctx.parameter("payload_size", document.len());
ctx.measure("parse header", || parse_header(&document));
}Use measure_with_setup when an operation consumes or mutates input. The setup
closure creates fresh input outside the timed interval, and the measured output
is dropped outside it:
#[stress(tier = 2)]
fn sort_records(ctx: &mut StressContext) {
let input = (0_u64..1024).rev().collect::<Vec<_>>();
ctx.parameter("record_count", input.len());
ctx.measure_with_setup("sort records", || input.clone(), |mut records| {
records.sort_unstable();
black_box(records)
});
}Benchmark functions may return Result<(), E> where E: Display, or
StressResult. Prefer ? to panicking when fixture or benchmark-level setup
can fail:
#[stress(tier = 2)]
fn parse_checked_counter(ctx: &mut StressContext) -> Result<(), std::num::ParseIntError> {
let value = ctx.measure_result("parse counter", || "42".parse::<u64>())?;
black_box(value);
Ok(())
}measure_result and measure_result_with_setup stop on the first Err and
record the calls actually attempted, completed, and failed. The general
measure and measure_with_setup methods are for infallible work: repeated
modes retain only the final closure value, so passing a Result to them can
hide an earlier error.
For gate-worthy batch or throughput work, name the logical operation and return the counters actually observed by the workload:
use cntryl_stress::{LogicalUnit, OperationOutcome};
#[stress(tier = 3)]
fn project_records(ctx: &mut StressContext) {
let records = (0_u64..512).collect::<Vec<_>>();
let outcome = ctx.measure_outcome(
"project records",
LogicalUnit::new("record"),
|| {
let mut completed = 0_u64;
for record in &records {
black_box(record.rotate_left(7));
completed += 1;
}
OperationOutcome::new(records.len() as u64, completed)
},
);
black_box(outcome);
}Use record_external_outcome when another harness owns both timing and
correctness observation:
#[stress(tier = 4)]
fn external_round_trip(ctx: &mut StressContext) {
let report = run_external_harness();
let outcome = OperationOutcome::new(report.attempted, report.completed)
.failures(report.failures)
.timeouts(report.timeouts);
ctx.record_external_outcome(
"round trip",
report.duration,
LogicalUnit::new("request"),
outcome,
);
}Async benchmarks can also be fallible:
#[stress(tier = 2)]
async fn async_lookup(ctx: &mut StressContext) -> Result<(), &'static str> {
let value = ctx
.measure_result_async("lookup", || async {
Ok::<_, &'static str>(black_box(42_u64))
})
.await?;
black_box(value);
Ok(())
}measure_batch("name", n, ...) is a legacy convenience that infers all n
operations succeeded. It is unsuitable when partial failure, timeout, drop,
duplicate, or validation failure is possible. The same caveat applies to
record_external("name", duration, n). Gate-worthy batch and external rows
must use LogicalUnit with measure_outcome or record_external_outcome.
Use the builder path when one row needs local run-shape overrides:
ctx.benchmark("large fanout")
.samples(20)
.warmup(2)
.parameter("client_count", client_count)
.measure_outcome(LogicalUnit::new("request"), || run_fanout_once());Every named row emitted by one #[stress] function must use the same
samples, warmup, and cooldown overrides. Split differently shaped rows
into separate functions; otherwise extra invocations would create work that
cannot be represented honestly in every row.
Useful context methods:
ctx.parameter("client_count", 16);
ctx.metadata("scenario", "fanout");
ctx.record_latency(duration);
ctx.measure("name", || work());
ctx.measure_result("name", || fallible_work())?;
ctx.measure_with_setup("name", setup, |input| work(input));
ctx.measure_result_with_setup("name", setup, |input| fallible_work(input))?;
ctx.measure_outcome("name", LogicalUnit::new("request"), || observed_work());
ctx.measure_outcome_with_setup("name", LogicalUnit::new("request"), setup, |input| observed_work(input));
ctx.measure_async("name", || async { work().await }).await;
ctx.measure_result_async("name", || async { fallible_work().await }).await?;
ctx.measure_result_async_with_setup("name", setup, |input| async move { fallible_work(input).await }).await?;
ctx.measure_threaded("name", || work());
ctx.measure_pipeline("name", || work());
ctx.measure_io("name", || work());
ctx.record_external_outcome("name", duration, LogicalUnit::new("request"), outcome);For a fast Tier 2 operation, use
ctx.benchmark("name").operations_per_sample(n) to batch enough independent
operations for a stable sample while retaining per-operation metrics.
Fallible builder rows use the matching explicit method, for example
.operations_per_sample(n).measure_result(...) or
.measure_result_with_setup(...); they stop before a later success can hide
the first error.
#[stress]
#[stress(tier = 1)]
#[stress(tier = 4)]
#[stress(tier = 1, max_ns_per_op = 250, max_regression_pct = 5)]
#[stress(max_allocs_per_op = 0, max_bytes_per_op = 0, max_rsd_pct = 10)]
#[stress(name = "custom_name", ignore)]
#[stress(tier = 5, role = "diagnostic")]
#[stress(metadata(component = "queue", scenario = "fanout"))]
#[stress(metadata(row_class = "parsing"))]Tiers are defined as 1 through 6. role = "gate" is the default. Use
role = "diagnostic" or role = "experimental" for rows that should not
create authoritative suite obligations. The macro rejects invalid tiers,
roles, attributes, and function signatures; benchmark functions take exactly
one &mut StressContext and return (), Result<(), E>, or StressResult.
Release and explicit quality/regression policies still require the selected
row set to contain at least one gate row. A filter that selects only
diagnostic or experimental rows therefore fails that policy rather than
vacuously passing a release gate; use default, smoke, or lab for a
diagnostic-only selection.
| Profile | Default Samples | Gate Behavior |
|---|---|---|
default |
5 measured, 1 warmup | Fails correctness, budgets, and invalid evidence; reports merely noisy rows |
smoke |
1 measured, 0 warmup | Explicit diagnostic override; correctness-focused, no quality/regression failure |
lab |
30 measured, 2 warmup, 1 cooldown | Exhaustive exploration; fails correctness, budgets, and invalid evidence |
release |
10 measured, 1 warmup | Fails correctness, quality below acceptable, and meaningful regressions |
Quality classes:
authoritative: at least 10 measured samples and RSD <= 5%acceptable: at least 5 measured samples and RSD <= 10%noisy: correctness passed but sample count or variance is weakuntrustworthy: too few samples, zero completed ops, invalid timing, or correctness failure
Baseline regressions are meaningful only when the primary metric moves past threshold and 95% confidence intervals do not overlap.
Benchmark budgets fail the run when exceeded. Diagnostics are structured on each summary with code, severity, reason, evidence, and suggestions.
Command-line arguments override STRESS_* environment variables, which override the trustworthy defaults.
| Variable | Description |
|---|---|
STRESS_PROFILE |
Optional profile override: default, smoke, lab, or release |
STRESS_SAMPLES |
Measured samples per benchmark |
STRESS_WARMUP_SAMPLES |
Warmup samples |
STRESS_COOLDOWN_SAMPLES |
Cooldown samples |
STRESS_FILTER |
Benchmark name/module glob; an unmatched selection is fatal |
STRESS_TIER |
Exact tier filter, 1 through 6 |
STRESS_TIMEOUT_SECS |
Positive per-benchmark deadline in seconds |
STRESS_OUTPUT_DIR |
Artifact output directory |
STRESS_JSON |
Emit machine-readable JSON to stdout instead of the console table |
STRESS_INCLUDE_IGNORED |
Include ignored benchmarks |
STRESS_BASELINE |
Baseline stress artifact |
STRESS_BASELINE_DIR |
Baseline directory for latest and --save-baseline conventions |
STRESS_SAVE_BASELINE |
Save a passed run under the baseline directory |
STRESS_THRESHOLD |
Regression threshold as a fraction (0.05 means 5%) |
STRESS_GIT_SHA |
Git SHA override |
STRESS_SAMPLE_DURATION_MS |
Fixed-duration sample budget |
STRESS_OPERATIONS_PER_SAMPLE |
Fixed-operations sample size |
STRESS_MICRO_SAMPLE_DURATION_MS |
Micro sample target duration |
STRESS_RUN_ID |
Run generation identity copied into artifact metadata |
STRESS_BUILD_INPUT_IDENTITY |
Advanced direct-run identity for non-default feature/target builds; the wrapper sets this automatically |
STRESS_FAIL_ON_ISSUES |
Fail on warning-or-error diagnostics |
STRESS_DENY_DIAGNOSTICS |
Fail on diagnostics at info, warning, or error |
STRESS_CONSOLE_NAMES |
Human console name mode: compact or full |
STRESS_PROGRESS |
Enable or disable stderr progress for human output |
Harness options:
cargo bench --bench storage_stress -- --tier 3 --workload '*fanout*'
cargo bench --bench storage_stress -- --samples 10 --warmup-samples 1
cargo bench --bench storage_stress -- --timeout-secs 300
cargo bench --bench storage_stress -- --operations-per-sample 64 --sample-duration-ms 500
cargo bench --bench storage_stress -- --profile release --save-baseline
cargo bench --bench storage_stress -- --baseline latest --threshold 0.05
cargo bench --bench storage_stress -- --print-configPrefer the Cargo wrapper's explicit percentage-points spelling:
cargo stress --bench storage_stress --timeout-secs 300
cargo stress --bench storage_stress --operations-per-sample 64 --sample-duration-ms 500
cargo stress --baseline latest --threshold-percent 5An explicit baseline file applies to exactly one benchmark target, so select it
with --bench (and --package when needed). Use --baseline latest for a
multi-target or workspace run: the wrapper resolves each suite independently.
Direct runs resolve and save latest under
{baseline_dir}/{latest|timestamp}/{suite}.json; wrapper runs add the package
namespace under
{baseline_dir}/{package}/{latest|timestamp}/{suite}.json to prevent packages
with the same bench name from overwriting each other.
Do not use the current output artifact
{output_dir}/{suite}/latest.json as an explicit baseline: that path is
overwritten by the run being evaluated and is rejected before measurement.
Keep accepted evidence under --baseline-dir, create it with
--save-baseline, and select it with --baseline latest.
Saving is strict: the run gate must pass, at least one intended gate row must be
present, and every intended gate must retain gate trust with acceptable-or-better
quality. Smoke, noisy, invalid, and diagnostic-only runs are rejected before
either the timestamped or latest baseline is changed.
The main artifacts are published first, followed by a requested baseline. Only
then does the run emit its final human result or single JSON stdout receipt. A
publication failure is recorded in metadata.reporter_errors, evaluates as
ArtifactFailed, and exits unsuccessfully. An earlier run-gate failure skips
baseline publication and remains the reported gate.
Baseline comparisons require known, matching CPU, logical core count, operating system and architecture, allocator, build profile/input identity, Rust compiler, and tool version. A missing or changed identity rejects the comparison with a baseline refresh explanation instead of treating unlike environments as evidence.
The wrapper also accepts Cargo-native --features, --all-features,
--no-default-features, --target <TRIPLE>, and --target-dir. Target
selection is forwarded to metadata, build, and execution, so Cargo's
target.<triple>.runner configuration is honored. Repeatable
--cargo-arg <ARG> accepts only Cargo's non-resolution-changing controls:
locked/offline/frozen mode, jobs, verbosity/quiet, color, timings, and
ignore-rust-version. Each value is one exact argument and is never shell-split;
scope, profile, feature, target, config, unstable, and positional escapes are
rejected.
Build profile, feature mode/list, target, and conservative Rust/Cargo build-input
receipts are recorded as compatibility identity so unlike binaries cannot
silently share a baseline. The ambient receipt covers Rust flags, active DEV or
BENCH/RELEASE profile overrides, compiler and wrapper selection, build target
and incremental controls, plus target-specific Rust flags, linker, and runner.
The config-input receipt covers the workspace-root manifest's [profile]
section and relevant build, target, profile, unstable, and material
env inputs from Cargo config files consulted from the working-directory
hierarchy and Cargo home, including recursively included configs. It is
intentionally conservative: a tracked source change can require a baseline
refresh even when another Cargo source overrides it. Source roles, variable
names, and deterministic value fingerprints are recorded; absolute config
paths, raw values, secrets, unrelated sections/variables, and inactive ambient
profile overrides are not. The wrapper derives this identity automatically. If
you invoke cargo bench directly with non-default build inputs, set the same stable
STRESS_BUILD_INPUT_IDENTITY for baseline creation and comparison; for direct
artifacts intended for later wrapper comparison, prefer creating them through
cargo stress so the identity is canonical.
This is a fail-closed compatibility guard, not proof that two binaries are
semantically identical; requiring an extra baseline refresh is preferred to
comparing builds whose relevant inputs are unknown.
The benchmark binary parser is strict: unknown flags, missing values, malformed
CLI or STRESS_* values, invalid profiles, and unmatched workload selections
fail the command. This prevents a typo from weakening policy or producing a
plausible-looking successful run. Wrapper child output is consolidated after
each binary completes; it does not currently stream live progress.
Console output:
cargo bench --bench storage_stress
cargo bench --bench storage_stress -- --jsoncargo bench --bench ... uses one console format: one simple benchmark table per suite with benchmark, measurement, value, p50, p95, p99, rsd, trust, and mode columns. Suite-local issues appear directly after a table only when a row needs attention, and the run ends with one result: line. Use --json only for machine-readable stdout.
Direct cargo bench runs write under target/stress/{suite}/. The Cargo
wrapper keeps the same canonical suite and benchmark IDs, but avoids package
collisions by writing under target/stress/{package}/{suite}/:
{timestamp}.jsonandlatest.json{timestamp}.txtandlatest.txt{timestamp}.mdandlatest.md
All six files are staged and synced before publication. A durable transaction
manifest distinguishes a commit in progress from a fully committed generation.
Detected failures roll back immediately, restoring the previous latest set
and removing the new timestamp set. If the process stops mid-publication, the
next same-suite publisher acquires the advisory lock and rolls back uncommitted
state before writing; committed cleanup debris is removed without discarding
the completed generation. A rollback failure remains fatal and preserves the
transaction state for diagnosis.
Same-suite publishers serialize through the persistent hidden
.artifact-publication.lock; its operating-system lock is released when the
process exits. Run history uses collision-resistant epoch/PID/sequence stems and
is create-only, so an unexpected timestamp collision fails instead of
overwriting evidence. The lock and transient .artifact-transaction.* or
.artifact-committed.* directories are coordination and recovery state, not
public artifacts.
Programmatic suite names are portable path components: ASCII letters, digits,
., -, and _ only. The wrapper also rejects Cargo targets such as
same-name and same_name when they would canonicalize to the same suite.
The JSON artifact contains tool version, run profile, environment, benchmark specs, raw samples, summaries, diagnostics, quality, and comparisons. Unknown environment fields are explicit "unknown" or null.
The checked-in cntryl-stress.v2 JSON Schema
is also available to Rust tooling as
cntryl_stress::artifact::ARTIFACT_JSON_SCHEMA.
Freshness-sensitive report tooling should group artifacts by metadata.run_id
when present. Older artifacts without run ids can still be consumed, but mixed
latest.json files from widely separated runs should be treated as stale.
Common benchmark files use root imports such as stress, stress_main,
black_box, StressContext, LogicalUnit, OperationOutcome, StressError,
StressResult, BenchmarkRole, StressRunner, StressRunnerConfig,
StressRunnerOptions, and RunProfile.
Advanced imports moved out of the crate root. Run artifacts and schema types are
under cntryl_stress::artifact, reporters and console formatting helpers are
under cntryl_stress::reporting, and run gate helpers are under
cntryl_stress::runner.
- Rename
#[stress_test]functions to#[stress]. - Register each benchmark target with
harness = falseand end its source file withcntryl_stress::stress_main!(). - Replace inferred-success batch/external gates with
LogicalUnitplusmeasure_outcomeorrecord_external_outcomeand observedOperationOutcomecounters. - Replace fallible closures passed to
measure,measure_with_setup, ormeasure_asyncwithmeasure_result,measure_result_with_setup, ormeasure_result_asyncso repeated calls cannot hide an earlier error. - Fix scripts that depended on ignored arguments or successful empty filters: 0.3 rejects unknown or malformed flags and treats unmatched selections as failures.
- Refresh baselines. Current artifacts use schema v2 and current logical-unit, correctness, and summary semantics; old artifacts are not an apples-to-apples regression baseline.
use cntryl_stress::{black_box, StressRunner, StressRunnerConfig};
let config = StressRunnerConfig::new().filter("parse");
let mut runner = StressRunner::with_config("storage", config);
runner.run("parse_counter", |ctx| -> Result<(), std::num::ParseIntError> {
let value = ctx.measure_result("parse counter", || "42".parse::<u64>())?;
black_box(value);
Ok(())
});
let run = runner.finish();cargo fmt --all -- --check
cargo clippy --locked --workspace --all-targets --all-features -- -D warnings -D clippy::pedantic
cargo test --locked --workspace --all-targets --all-features
RUSTDOCFLAGS="-D warnings" cargo doc --locked --workspace --all-features --no-depsApache License 2.0. See the repository LICENSE.