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

nordisk/nornir

.nornir/scip-bench.md

SCIP bench — ours (in-process ra-ingest) vs rust-analyzer scip

A small, controlled head-to-head: nornir's in-process resolved-index builder (--features ra-ingest) against the external rust-analyzer scip CLI, with the external binary pinned to the same rust-analyzer cut so the comparison isolates approach from version. Companion to scip-resolved-knowledge.md (the design) and callgraph-perf.md.

TL;DR

Setup

Results

metric OURS — in-process ra-ingest THEIRS — rust-analyzer scip (pinned 0.0.337)
wall clock 0.11–0.13 s 1.37–1.42 s
peak RSS 55 MB 508 MB
occurrences 135 (41 def, 94 ref) 268 (64 def, 204 ref)
intermediate artifact none → warehouse row a 26 KB index.scip file
resolution engine rust-analyzer on salsa (ra_ap_* libs) rust-analyzer on salsa (the binary)

Drift check: the stable-1.95.0 (2026-04-14) binary produced the same 268 (64 def, 204 ref) as the pinned 0.0.337 cut → version drift contributed nothing to the gap.

RE-MEASURED 2026-09-07 (t14s, 16 cores, 46 GB) — the flip's evidence

Re-run because the numbers above were about to be used to justify turning ra-ingest on for the dwarves-server build (dwarves 1b6e731), and a doc figure is not evidence. Different external binary: the rustup rust-analyzer component for stable 1.97.1 (2026-07-14), not the 2026-06-15 cut ra_ap_* 0.0.337 was published from — so this run does NOT have the original's zero-drift property, and its own drift check is the one above. Fixture: an equivalent 120-LOC, zero-dependency 3-module crate (git-committed). Both roads driven through the SAME release nornir binary (--in-process vs --subprocess), best of 3, warm, box otherwise idle.

metric OURS — --in-process THEIRS — --subprocess
wall clock 0.13–0.14 s 1.83–2.22 s (2.01 s end-to-end incl. parse)
peak RSS ~96 MB ~572 MB
occurrences 98 (38 def, 60 ref) 238 (60 def, 178 ref)

≈14× faster, ≈6× leaner. The order-of-magnitude claim REPRODUCES. The RSS ratio is lower than the original's 9× only because OURS is measured here through the fat default+ra-ingest release binary (423 MB, viz linked in), which starts heavier than the original's build.

Full nornir — and the one claim that did NOT reproduce

metric OURS — --in-process THEIRS — rust-analyzer scip
wall clock 43.7 s 607.5 s (10.1 min) + 0.26 s to parse
peak RSS 7.55 GB 12.67 GB
rows 198 466 (123 107 def, 75 359 ref) 428 694 (58 486 def, 370 208 ref)
artifact none → warehouse a 41 MB index.scip

OURS beat its own documented 63.5 s (43.7 s here). But THEIRS did not fail — the "19 minutes AND IT FAILED" line elsewhere in these docs did not reproduce on this box: the external run exited 0 in 10.1 minutes, having printed 2 019 ERROR Encountered enclosing definition with no name lines on the way. Treat that failure as an oden-specific observation, not a property of the subprocess road. That matters for the flip: the shell-out is a fallback that WORKS, which is part of why it was kept rather than deleted (the other part being that it is the only producer of real SCIP monikers — see scip-resolved-knowledge.md).

Note the def/ref inversion at scale: OURS finds ~2× the definitions (it walks file_structure over every workspace file) and ~5× fewer references (workspace- only goto_definition, locals dropped). Subset-by-intent, in both directions.

Why the counts differ — and why that's correct

The 135-vs-268 gap is intentional, not a miss:

Both resolve the same named defs/refs via the same engine; OURS's output is a subset by intent, not a lower-fidelity approximation.

"Can we output the same?"

What OURS buys beyond the numbers

Caveats

Reproduce

# (2026-09-07 form: one binary, two flags — `--subprocess` forces the shell-out
#  road even in a build that links the in-process engine, as does
#  NORNIR_SCIP_SUBPROCESS=1.)
#   nornir --workspace <ws> scip ingest scipcrate --in-process --no-save
#   nornir --workspace <ws> scip ingest scipcrate --subprocess  --no-save

# 1. build nornir with the in-process engine (target off the T9 SSD)
export CARGO_TARGET_DIR=/home/rickard/nornir-target
cargo build --release --features ra-ingest --bin nornir

# 2. a tiny git-committed crate in a workspace with a one-line nornir.toml:
#    <ws>/nornir.toml   ->   [repo.scipcrate]
#    <ws>/scipcrate/    ->   Cargo.toml + src/*.rs   (git init && commit)

# 3. pin the external binary to the matching cut
curl -sL https://github.com/rust-lang/rust-analyzer/releases/download/2026-06-15/\
rust-analyzer-x86_64-unknown-linux-gnu.gz | gunzip > ra-pinned && chmod +x ra-pinned

# 4. OURS (in-process)
nornir --workspace . scip ingest scipcrate --in-process --no-save     # 3 runs

# 5. THEIRS (pinned) → parse for comparable counts
./ra-pinned scip <ws>/scipcrate --output index.scip                    # 3 runs
nornir --workspace . scip ingest scipcrate --index index.scip --no-save