# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.9.7] - 2026-05-18
### Changed
- **`alloc-tracking` backend swapped from `dhat = "0.3"` to
`mod-alloc`'s `dhat_compat` surface.** The public API
(`AllocationStats`, `AllocationStats::snapshot()`, the
`install_global_allocator!()` macro) is unchanged; downstream
callers that use this crate's macro need no edits. Callers that
reach for `dhat::Profiler` or `dhat::HeapStats` directly should
switch to `use mod_alloc::dhat_compat as dhat;` — the surface is
method-for-method compatible (see `MIGRATING_FROM_DHAT.md` in
the mod-alloc repo for the full mapping).
- **`install_global_allocator!` now installs
`mod_alloc::dhat_compat::Alloc`.** Same `#[global_allocator] static`
shape; same DHAT-viewer-compatible JSON output on `Profiler`
drop.
- **`AllocationStats::snapshot()` no longer panics outside a
Profiler scope.** `dhat-rs`'s historical panic on `HeapStats::get()`
without a live Profiler is gone; the snapshot returns zeros if
no global allocator is installed.
### Removed
- **`dhat` dependency dropped.** The transitive
`dhat -> backtrace -> addr2line` chain (which forced Rust 1.85+
through `addr2line 0.25.1`) is no longer pulled in by
`alloc-tracking`.
### Added
- `mod-alloc = { version = "0.9", features = ["dhat-compat"], optional = true }`
as the new `alloc-tracking` backend. MSRV 1.75, pure-Rust, no
FFI, zero runtime deps on the alloc hot path.
### MSRV
- Held at `1.85`. The dhat-side blocker is gone, but the
`dev-report` sibling still requires 1.85; dropping dev-bench's
MSRV to 1.75 waits on a future `dev-report` milestone.
### Migration
No action required for callers that use this crate's
`install_global_allocator!()` macro. Callers that referenced the
`dhat` crate directly in their own code (separate from this
crate's macro expansion) should swap their imports:
```rust
// Before
use dhat;
// After
use mod_alloc::dhat_compat as dhat;
```
Cargo.toml swap is automatic when you bump `dev-bench` to 0.9.7 —
the `alloc-tracking` feature now resolves to `mod-alloc` instead
of `dhat`.
### Notes
- JSON output from the new backend's `Profiler` loads in the same
upstream `dh_view.html` viewer (shipped with Valgrind).
- `dev-bench` does not consume per-call-site backtrace reports;
it only reads `HeapStats` counters. The mod-alloc walker's
shallow-trace gap on stock-std release builds (Windows) does
not affect `alloc-tracking` output.
[0.9.7]: https://github.com/jamesgober/dev-bench/releases/tag/v0.9.7
## [0.9.6] - 2026-05-12
Skip-release to clean up a premature `v0.9.5` GH tag that never reached crates.io. The compiled artifact is the v0.9.4 source plus the `Cargo.lock`-untrack repository-hygiene commit; the version label moves to `0.9.6` so the published version sequence on crates.io stays monotonic after the orphan tag is deleted. No code or behavior change from v0.9.4.
### Changed
- Stopped tracking `Cargo.lock`. Library crates conventionally do not commit lock files — the lock is a snapshot of one resolution and downstream consumers ignore it anyway. Tracking it was generating spurious dirty-tree noise every time a path-dep sibling bumped version. `Cargo.lock` is now in `.gitignore`; `git rm --cached Cargo.lock` retired the tracked copy.
### Notes
- The compiled crate is byte-equivalent to v0.9.4 plus the lock-file untracking.
- v0.9.5 never existed on crates.io. A premature `v0.9.5` GitHub tag/release was created without bumping `Cargo.toml` first; that tag has been deleted as part of this release.
- No new dependencies, no MSRV change.
[0.9.6]: https://github.com/jamesgober/dev-bench/releases/tag/v0.9.6
## [0.9.4] - 2026-05-12
Documentation and SEO pass. No code changes.
### Changed
- README header standardized to match the collection-wide template: Rust logo image, MSRV badge between CI and docs.rs, copyright block at bottom.
- Subtitle now reads `BENCHMARK & REGRESSION DETECTION FOR RUST` (was `PERFORMANCE MEASUREMENT FOR RUST`). More specific and search-tighter.
- Tagline rewritten to lead with the developer outcome (measure, baseline, catch regressions before they ship) instead of the part-of-suite framing.
- `## What it does` no longer leads with the AI-agent framing; the positioning vs. `criterion`/`divan` is more direct.
- `## The dev-* suite` retitled to `The dev-* collection` with the full 14-crate map.
- `Cargo.toml` description rewritten: lists actual feature surface (percentile stats, baselines, threshold gating, CI-gateable verdicts).
- `Cargo.toml` keywords retuned: dropped `verification` and `ai-tools`, added `profiling` and `ci` for crates.io search.
### Added
- "Part of the `dev-*` verification collection" block on the README, under the intro, linking the umbrella `dev-tools` crate.
[0.9.4]: https://github.com/jamesgober/dev-bench/releases/tag/v0.9.4
## [0.9.3] - 2026-05-12
### Added
- `examples/basic_benchmark.rs` — minimal runnable demonstration of the `Benchmark::new` → `iter` → `finish` flow, printing the headline statistics (`mean`, `p50`, `p99`, `ops_per_sec`, `cv`).
### Changed
- CI: `actions/checkout` bumped from `v4` to `v5` (removes Node 20 deprecation warnings).
[0.9.3]: https://github.com/jamesgober/dev-bench/releases/tag/v0.9.3
## [0.9.2] - 2026-05-10
### Added
- `Benchmark::run_for(budget, closure)` — wall-clock-bounded benchmark mode. Runs the closure repeatedly until `budget` elapses, recording one sample per iteration. Pairs naturally with iteration-based `iter` for benchmarks where you want "for N seconds" semantics.
- `BenchmarkResult::histogram(bucket_count)` returning a `Vec<HistogramBin>` with uniform-width bins covering `[min, max]`. Surfaces bimodality, outlier tails, and warmup effects that mean/percentile alone hide.
- New `HistogramBin { lower, upper, count }` type.
[0.9.2]: https://github.com/jamesgober/dev-bench/releases/tag/v0.9.2
## [0.9.1] - 2026-05-09
### Added
- `BenchmarkResult` extra statistics: `min()`, `max()`, `stddev()` (sample, Bessel's correction), `mad()` (median absolute deviation), `p90()`, `p999()`, and a generic `percentile(q)` accessor.
- `install_global_allocator!()` macro (gated by `alloc-tracking`) that expands to the `#[global_allocator] static ALLOC: dhat::Alloc = dhat::Alloc;` declaration users would otherwise have to write themselves. Also re-exports `dhat` privately as `__dhat` for the macro to reference.
### Fixed
- Broken intra-doc link `[`alloc`]` in the crate-level docstring would warn under `cargo doc` when the `alloc-tracking` feature is disabled. The link is now a plain code span.
[0.9.1]: https://github.com/jamesgober/dev-bench/releases/tag/v0.9.1
## [0.9.0] - 2026-05-08
### Added
#### Adoption of dev-report 0.9
- Bumped `dev-report` dep to `0.9`.
- Every non-`Skip` `CheckResult` from `compare_*` now carries the `bench` tag and structured numeric `Evidence`: `mean_ns`, `baseline_ns`, `p50_ns`, `p99_ns`, `cv`, `ops_per_sec`, `samples`, `iterations_recorded`.
- Regression-flagged checks additionally carry the `regression` tag.
#### Throughput
- `BenchmarkResult::ops_per_sec()` returning `iterations_recorded / total_elapsed_seconds`.
- `BenchmarkResult::iterations_recorded` and `total_elapsed` fields.
- `Benchmark::iter_with_count(n, f)` for batched workloads (records ONE sample for `n` ops).
- `Threshold::ThroughputDropPct(pct)` variant.
- `Threshold::throughput_drop_pct` constructor.
#### Variance awareness
- `BenchmarkResult::cv` (coefficient of variation, stddev / mean).
- `CompareOptions` with `min_samples` and `allow_cv_noise_band` controls.
- `BenchmarkResult::compare_with_options(&CompareOptions)`.
- Regressions inside `baseline_ns * cv` are downgraded from `Fail` to `Warn` when `allow_cv_noise_band` is true.
- Skips with detail when `samples.len() < min_samples`.
#### Baseline storage
- `Baseline` struct (serde-roundtrippable: `name`, `mean_ns`, `samples`, `ops_per_sec`).
- `BaselineStore` trait with `load(scope, name)` and `save(scope, baseline)`.
- `JsonFileBaselineStore`: filesystem JSON backend keyed by `(scope, name)`.
- Atomic save via write-temp-rename; tolerant load (returns `Ok(None)` on missing).
- Path sanitization on `scope` and `name` to prevent traversal.
#### Allocation tracking (opt-in)
- `alloc-tracking` feature flag (off by default).
- `dev_bench::alloc::AllocationStats` capturing `total_bytes`, `total_blocks`, `peak_bytes`, `peak_blocks` from `dhat::HeapStats`.
- `AllocationStats::compare_against_baseline` returning a `CheckResult` with `alloc` tag and numeric evidence.
#### Producer trait integration
- `BenchProducer<F>` adapter implementing `dev_report::Producer`.
- `BenchmarkResult::into_report` shortcut producing a single-check finalized `Report`.
### Documentation
- All public items have rustdoc with at least one example.
- REPS.md expanded: §4 (cv, ops_per_sec definitions), §5 (verdict semantics, required evidence), §6 (baseline storage), §7 (allocation tracking), §8 (producer integration).
[0.9.0]: https://github.com/jamesgober/dev-bench/releases/tag/v0.9.0
## [0.1.0] - 2026-05-07
### Added
- Initial crate skeleton.
- `Benchmark` runner with sample collection.
- `BenchmarkResult` with mean, p50, p99 statistics.
- `Threshold::RegressionPct` and `Threshold::RegressionAbsoluteNs`.
- `compare_against_baseline` returning a `dev-report::CheckResult`.
- Smoke tests covering empty, no-baseline, and pass paths.
### Note
This is a name-claim release. Public API will expand significantly
in `0.2.x` and `0.3.x` for throughput, allocation tracking, and
baseline storage.
[Unreleased]: https://github.com/jamesgober/dev-bench/compare/v0.9.3...HEAD
[0.1.0]: https://github.com/jamesgober/dev-bench/releases/tag/v0.1.0