Skip to content

perf(semantics): decide a member's root restatement once per symbol - #1368

Merged
HuiJun merged 1 commit into
developfrom
perf/memoize-root-restatement
Oct 22, 2026
Merged

HuiJun merged 1 commit into
developfrom
perf/memoize-root-restatement

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What and why

Model.restatesRoot answers whether a member redefines or subsets one of the frame roots (Anything::self, Occurrence::timeSlices, incomingTransfers, …) or the coordinate frame's featuring reference. FrameFeature asks it for every member of every type whose shape is computed, and each call walked the member's redefinition/subsetting chain and built the qualified name of every feature on it (symbols.FQNOf per visited symbol). The answer depends only on the member, so a model instantiating many types that share their library members (the tests/perf synthetic model: 1 000 part definitions over the same Objects/Occurrences members) paid the walk 1 000 times per member.

The cost became visible when an item's nested actions were counted among its ownedPerformances (#1310): the 0.11.0 performance measurement of develop against v0.10.1 has Instantiate at 2.51 M → 6.34 M allocations, of which 3.82 M → 4.94 M is that merge, and the profile puts the growth under ShapeFeatures → FrameFeature → restatesRoot (strings.Builder.grow 617 k → 1 570 k, restatesAny 1.05 M → 2.19 M cumulative).

The change keeps the answer per symbol on the model, in two tables (restatesFrameRoot, restatesReferenceRoot) journaled with the symbol's document as the other per-symbol memos (allRedefined, redefClosure) are, and only when the resolver frame settled (a walk cut short by a guard is not memoized — the same rule as AllRedefinedFeatures). restatesRoot now takes a rootSet naming which root set is asked about; its four callers are unchanged otherwise.

Six interleaved rounds on a quiet machine, develop (5db0f74) | this branch | #1369 | both (benchstat, allocations exact, p = 0.002 on every moved row):

benchmark allocs/op B/op time
tests/perf Instantiate 6.338 M | 4.224 M | 5.012 M | 2.219 M 425 | 338 | 389 | 207 MiB 1.52 | 1.03 | 1.44 | 0.73 s
tests/perf BatchSatisfy 8.301 M | 5.672 M | 6.965 M | 4.336 M 602 | 492 | 565 | 456 MiB 2.18 | 1.53 | 2.02 | 1.42 s
tests/perf FeaturesOf 6.450 M | 3.683 M | 5.030 M | 2.263 M 413 | 298 | 376 | 261 MiB 1.29 | 0.70 | 1.22 | 0.67 s
tests/perf GRPCVerifyConstraint 14.67 k on all — ~
tests/stressmodel Satisfy/32 42.03 k | 42.03 k | 40.04 k | 40.04 k — ~

v0.10.1: Instantiate 2.509 M, BatchSatisfy 4.301 M, FeaturesOf 4.130 M — with both fixes the first and third are below the previous release (the memo also serves the shapes 0.10.1 computed once per type) and the second is at parity. GRPCVerifyConstraint's growth at #1310 (10.69 k → 14.67 k) is that change's own work (a run begun per nested performance) and is not touched here; the stress constellation's Satisfy rows have few types and gain nothing from this memo (their remainder over v0.10.1 is #1276/#1319's wider type set, as the record states).

How it was verified

  • TestRootRestatementIsDecidedOncePerSymbol (new): a repeated restatesRoot/NamesFeaturingReference query allocates nothing and answers as the first did; on develop the NamesFeaturingReference row allocates 1 per query.
  • go build ./..., go vet ./..., gofmt -l . clean; go test of internal/semantic/..., internal/exec/runtime, internal/check/..., internal/frontend/lsp, internal/frontend/grpc, tests/model, tests/resolve green.

Checklist

  • make test and make lint pass locally (the packages above; full suite in CI)
  • Tests added or updated for the change
  • Documentation extended where it already covers the surface (the 0.11.0 performance record names this fix in its correction)
  • Changelog entry added as changes/unreleased/memoize-root-restatement.fixed.md
  • baselines regenerated and make docs-counts run if a gate count moved (none moved)
  • No internal work-item labels in the body, docs, or changelog

Link to Devin session: https://nasa-jpl-demo.devinenterprise.com/sessions/cf22d7a746814d20b2f0eaf11682fef9
Open in Devin Desktop: https://nasa-jpl-demo.devinenterprise.com/desktop/session/cf22d7a746814d20b2f0eaf11682fef9?variant=devin
Requested by: @HuiJun


Devin Review

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

@devin-ai-integration
devin-ai-integration Bot marked this pull request as ready for review October 21, 2026 22:37
@HuiJun
HuiJun merged commit f63911f into develop Oct 22, 2026
51 checks passed
@HuiJun
HuiJun deleted the perf/memoize-root-restatement branch October 22, 2026 00:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant