Performance
These are local reference measurements, not CI thresholds.
Method
- Reference host: kbench, Intel Core i7-6700HQ, 4 cores and 8 threads, 2.6 GHz, Linux x86_64, rustc 1.97.0. The benchmark process was pinned to one CPU.
- Release build with a fixed fixture generator.
cargo bench -p adotenv --bench core --locked -- --sample-size 20 --measurement-time 2- The host was otherwise idle. Wall time is recorded; instruction counts are the stable CPU comparison for cross-library work.
Core workloads
| Workload | 8 entries | 128 entries | 65,536 entries |
|---|---|---|---|
| parse | 6.29 us | 99.8 us | 62.4 ms |
| lookup index build | 136.6 ns | 2.36 us | 3.40 ms |
| indexed get, 64 keys | 195.8 ns | 1.63 us | 1.76 us |
| portability, 4 presets | 62.8 us | 1.09 ms | 745 ms |
| references | 507.6 ns | 7.94 us | 4.64 ms |
| resolve | 7.23 us | 173.9 us | 118.9 ms |
| sort | 3.19 us | 278.6 us | 161.1 ms |
| format normalize | 8.30 us | 135.8 us | 76.7 ms |
| native set | 10.4 us | 102.4 us | 61.7 ms |
| native batch | 8.33 us | 102.9 us | 63.6 ms |
Document::get scans entries. For many lookups, build Document::lookup_index
once. The index uses a compact open-addressed table with an ordered fallback for
collision-heavy input.
Parser memory
One 65,536-entry document with a 1.8 MB source:
- live after parse: 23.6 MB;
- peak parse: 32.0 MB;
- parse plus collected map: 4.6 MB live after the document is dropped.
Retained document memory is dominated by item and token metadata. Values-only loading avoids the document entirely.
Loading memory
One 65,536-entry file on a release build:
| Profile | Peak | Retained |
|---|---|---|
| Default | 47.7 MB | 28.0 MB |
LoadOptions::full | 57.4 MB | 37.7 MB |
| Values only | 11.2 MB | 10.0 MB |
The default keeps values, shared-file origins and raw tokens. Reports add entry, override, repeat and skipped vectors. Values-only loading projects values while parsing and retains no document or provenance.
The default profile now stores value, origin and raw-token data in one record per key. This removes two per-key maps from the retained loader.
Budgets
The comparison harness is the source of these budgets. Reference results are recorded on the kbench host. Run the full check with:
python3 scripts/compare.py --check-budgets
| Profile | Instructions | Peak RSS | Retained RSS |
|---|---|---|---|
| adotenv parse | 260M | not budgeted | 29 MB |
| adotenv parse + values | 400M | 12 MB | 12 MB |
| adotenv parse + map | 335M | not budgeted | 16 MB |
| values-only load | 400M | 13 MB | 11.5 MB |
| default load | 560M | 50 MB | 30 MB |
| full-report load | 750M | 60 MB | 40 MB |
The parse-only binary budget is 500 KB. Wall time is recorded but not enforced because the shared host is too noisy for a hard threshold.
A release blocks above the instruction or memory budget until the regression is fixed or explicitly accepted. A wall-time result between 1.5x and 2x requires a repeat run and an explanation; above 2x blocks the release.
Diff and matrix
For three 65,536-entry files:
- streaming two-file diff with indexed comparison: about 73.3 MB peak and 0.6 s;
- matrix diff with compact incremental rows: about 103.0 MB peak and 0.8 s.
Matrix output retains one row per key because every column is needed. Two-file diff streams candidates and buffers output until all candidates validate.
Comparison with other parsers
The closest comparison is adotenv::parse followed by collecting effective
values. Other crates return maps or load into the environment directly.
Fixture: 65,536 compatible declarations, 1.8 MB source.
| Implementation | Instructions | Live memory | Peak |
|---|---|---|---|
| adotenv parse | 272M | 23.6 MB | 32.0 MB |
| adotenv parse + map | 377M | 4.6 MB | 32.0 MB |
| dotenvy iterator + Vec | 373M | 5.0 MB | 15.7 MB |
| dotenv-compat parse | 307M | 9.5 MB | 18.6 MB |
| dotenv-ng input-only load | 406M | 7.9 MB | 20.4 MB |
| dotenv-parser map | 1,488M | 7.1 MB | 50.1 MB |
adotenv retains more syntax than the other parsers, including spans, items and diagnostics. Values-only loading removes that overhead when it is not needed.
Budget
- CI runs benchmark smoke only.
- Compare repeated runs on the same host and toolchain.
- A 1.5x deviation needs a repeat run and an explanation.
- A 2x deviation blocks a release until it is explained or fixed.
- Update this file when fixtures, compiler major version or methodology change.