Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

mikronova/modgunn

.nornir/engine-benchmarks.md

Engine A vs Engine B — HEAVY benchmark

Head-to-head of the two swappable advisory-matching strategies behind engine::AdvisoryEngine: Engine A (linear scan) vs Engine B (inverted index). Same verdicts (asserted equal every run); the question is cost. The rationale is in .nornir/engine-reasoning.md; the harness is benches/engine_ab.rs.

Method

export CARGO_TARGET_DIR=/mnt/work4t/cargo-target/modgunn-engine
cargo bench --features scan --bench engine_ab

Machine

resource value
cores (full parallelism) 12 (the base tables) · 32 on oden · 16 on t14s
system memory 61 GiB total (~42 GiB free at run) · t14s: 46 GiB
target dir /mnt/work4t (fast PCIe4 disk, per disk-layout law)
build profile bench (optimized)

Results

Point 1 — artifact-scaled (1 M-artifact fleet, mid-size db)

advisories=25 000 packages=3 000 artifacts=1 000 000 cores=12

engine build (s) scan (s) verdicts/s µs/verdict peak RSS
A linear 0.0000 31.174 32 078 31.174 291 MiB
B indexed 0.0053 0.160 6 260 387 0.160 291 MiB

Identical findings: 1 667 658 (A == B). B index buckets: 10 477. Winner: Engine B — 195×.

Point 1 · re-run on oden (32-core) — 2026-07-26

advisories=25 000 packages=3 000 artifacts=1 000 000 cores=32 · host oden, box uptime 12:19

engine build (s) scan (s) verdicts/s µs/verdict peak RSS
A linear 0.0000 8.115 123 225 8.115 305 MiB
B indexed 0.0037 0.057 17 525 920 0.057 305 MiB

Identical findings: 1 667 658 (A == B — the same count as the 12-core run on the same SplitMix64 corpus: a cross-machine large-scale equivalence confirmation). B index buckets: 10 477. Winner: Engine B — 142×. Absolute B throughput ~2.8× the 12-core box (faster CPU + more cores); the A/B ratio is lower (142× vs 195×) because Engine A's linear scan parallelizes across 32 cores better than the already-saturated index, narrowing the gap while both get faster.

Point 1 · re-run on t14s (16-core) — 2026-07-27

oden is powered off, so Point 1 was re-run on t14s (16 CPUs / 46 GB). A new host is a NEW row — never a merge into the oden or 12-core tables above, and no number here is restated from either.

advisories=25 000 packages=3 000 artifacts=1 000 000 cores=16 · host t14s, box uptime 0,58 before → 17,67 after (16 gatling workers on 16 cores; no foreign process present on either side)

engine build (s) scan (s) verdicts/s µs/verdict peak RSS
A linear 0.0000 64.288 15 555 64.288 302 MiB
B indexed 0.0094 0.177 5 643 647 0.177 302 MiB

Identical findings: 1 667 658 (A == B) — byte-identical to BOTH the 12-core and the oden runs on the same SplitMix64 corpus, a third-machine confirmation of the A/B equivalence assertion. B index buckets: 10 477. Winner: Engine B — 362.8×.

Reproducibility. A second clean-start run (uptime 0,68 → 18,63) gave A 66.602 s / B 0.205 s / 325.2× — A within 3.5 %, B within 15 %, which is the expected spread for a 0.2-second measurement. It is cited as corroboration only, not as the row, because a foreign build appeared on the box near its end. Engine B's sub-second scan is inherently the noise-sensitive number here; Engine A's ~65 s is the stable one.

Two earlier runs on this host were REJECTED, not published. Both picked up a foreign rustc build partway through (load on a 16-core box: 1,12 → 37,17 and 0,67 → 45,24) and disagreed with each other by 30 % on scan time — they measured contention, not the engine. They are recorded here as discarded so the published row above cannot be confused with them:

rejected run uptime before → after A scan (s) B scan (s) speedup
⛔ 1 1,12 → 37,17 61.457 0.505 121.7×
⛔ 2 0,67 → 45,24 58.167 0.623 93.3×

Note how badly contention distorts the ratio specifically: Engine A's 60-second linear scan barely notices a competing build, while Engine B's 0.2-second indexed scan is stretched 3×. A shared box makes the A/B speedup look 3–4× worse than it is — which is exactly why a contended run must never be published as a host row.

Point 2 — db-scaled (large advisory corpus, higher index memory)

advisories=200 000 packages=80 000 artifacts=300 000 cores=12

engine build (s) scan (s) verdicts/s µs/verdict peak RSS
A linear 0.0000 173.615 1 728 578.718 213 MiB
B indexed 0.1393 0.054 5 554 512 0.180 213 MiB

Identical findings: 359 906 (A == B). B index buckets: 148 915. Winner: Engine B — 3 214×.

Reading it

Verdict

Use Engine A for the lean per-artifact gate (tiny db, one artifact — the index never pays off). Use Engine B for every fleet / warehouse scan over the real CVE-warehouse corpus: modgunn warehouse scan --engine b. Above ~10⁴ advisories it is one-to-three orders of magnitude faster for identical output.


Manifest ingest — HEAVY parse-throughput benchmark

Pure-Rust, zero-shell parse of each ecosystem's manifest/lockfile into the shared sbom::SbomComponent model — the ingest side of manifests.rs. The question is raw parse throughput (components/sec), not a match. Harness: benches/manifest_parse.rs.

Method

export CARGO_TARGET_DIR=/mnt/work4t/cargo-target/modgunn
cargo bench --features manifests --bench manifest_parse
# tunables: MODGUNN_BENCH_DEPS (default 50 000), MODGUNN_BENCH_REPEATS (default 5)

Machine

host=loki cores=12 build profile=bench (optimized) target dir=/mnt/work4t (PCIe4)

Results

deps_per_manifest=50 000 repeats=5 cores=12

ecosystem format components best (s) throughput (comp/s) input
cargo Cargo.lock 50 000 0.0659 759 008 2.5 MiB
pip requirements.txt 50 000 0.0053 9 449 922 0.9 MiB
npm package-lock.json 50 000 0.0271 1 845 357 3.4 MiB
maven pom.xml 50 000 0.0234 2 134 820 5.7 MiB
go go.sum 50 000 0.0090 5 566 602 2.0 MiB
gem Gemfile.lock 50 000 0.0036 13 967 214 1.1 MiB

Total: 300 000 components across six ecosystems; peak RSS 88 MiB.

Reading it