Repository navigation
perf(repl): collect referenced roots only when a reference is unresolved - #1624
Conversation
resolveReferences walked every submission's text twice (ImportedRoots and ReferencedRoots, both reflection walks over the whole tree) before checking whether anything was unresolved; undeclaredRoots then filtered every root out when nothing was. Gather the unresolved subjects first, return when there are none, and collect the referenced roots only when the imports answered nothing. A differential test asserts the cost no longer grows with the text. Co-Authored-By: jason.han <hanhuijun@gmail.com>
|
I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".
|
|
Local gates on head 3ef59e1 (go1.27.3): The failing "From the tree" check ( |
|
The one red check on this head, |
What and why
Since the resolve-first dependency search landed (#1528,
fix/resolve-first-dependency-search),Session.resolveReferenceswalked every submission's text twice before checking whether anything was unresolved:project.ImportedRootsandproject.ReferencedRootsare both reflection walks (ast.Inspect) over the whole tree, andundeclaredRootsthen filtered every root out when the submission had no unresolved reference. On a 1 000-element model load that was 14 130 allocations and about 14 % of the wall time per load.The method now gathers the unresolved subjects first and returns when there are none, collects the imported roots only then, and the referenced roots only when the imports answered nothing (the branch that already needed them). Behaviour with an unresolved import or qualified name is unchanged; the existing on-demand loading tests in
workspace_test.gocover it.Measured (
BenchmarkLoadModel/elements=1000,internal/frontend/repl, go1.27.3, same machine, single 10× run; the six-round benchstat table follows in a comment):ddf4df000)ddfbb9446)The remaining sec/op gap to v0.11.0 is the reflection walker's per-field type lookups (fixed separately by
perf/ast-inspect-field-plan); the B/op residual (+4.6 %) is theTypedByspans and stdlib snapshot growth of #1478, which this PR does not touch.How it was verified
TestResolvingNothingDoesNotWalkTheText(new):testing.AllocsPerRunofresolveReferencesover 50 vs 100 fully resolved packages must not grow; fails on develop (the walk scales with the text), passes here.go build ./...,go vet ./...,gofmt -l .empty,python3 scripts/changelog.py check.go test -count=1 ./internal/frontend/repl ./internal/frontend/lsp ./tests/perf,go test -count=1 -race ./internal/frontend/repl(results pasted in a comment when complete).Overlap with open PRs
Touches
internal/frontend/repl/workspace.goonly; none of the openfix/sonar-*PRs (#1606internal/exec/runtime, #1610 internal packages) edits that file. Re-checked at push time: noperf/*branch or PR on the remote.Checklist
make testandmake lintpass locally (touched packages; see above)changes/unreleased/resolve-first-lazy-roots.changed.md