Skip to content

perf(runtime): allocate in the binding walks only where a binding can be found - #1742

Merged
HuiJun merged 3 commits into
developfrom
perf/binding-walk-allocs
Oct 30, 2026
Merged

HuiJun merged 3 commits into
developfrom
perf/binding-walk-allocs

Conversation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

What and why

#1508 (resolveBindings climbing a feature read to its owners) and #1512 (bindingWitnesses, siblingSubsetterValues) made the runtime's binding walks correct for owner-declared and sibling bindings, and paid for it on every read whether or not a binding exists: the owner walk spelled out ownerFeature + "." + path at each level, the witness draw built its pool index (witnessDraw + inPool map) before looking at a candidate, the sibling set allocated its taken map before the first value, and unwrappedDeclMembers listed a body's members into a fresh slice each time a body was scanned for a declared feature. In the 0.12.0 candidate that is GRPCVerifyConstraint at 16 301 allocations per constraint against 0.11.0's 14 091 (source rebuilt with the same go1.27.3), and it reaches Instantiate, BatchSatisfy and FeaturesOf.

This branch allocates in those walks only where a binding can be found: the owner walk builds the path only while an owner's types declare a binding (ownersDeclareBindings), the witness draw lives on the stack and indexes its pool on the first candidate (admitsPooled), taken is made on the first sibling value, and bodies are scanned with an iterator (eachUnwrappedDeclMember) instead of a member list. Nothing the walks find changes; the conformance, robustness and gRPC suites are the proof.

Fragment: changes/unreleased/binding-walk-allocs.fixed.md.

How it was verified

A/B, six rounds, benchstat.

Revisions: pre1508 = develop before #1508, m1508 = the #1508 merge, m1512 = the #1512 merge, dev = the 0.12.0 candidate (1c6bb1972), fix1 = this branch on it. Interleaved rounds on one host ("Intel(R) Xeon(R) Processor", 8 CPUs), GOMAXPROCS=8; bytes and allocations are exact, sec/op below is from a machine that was also running the release suite and is reported only where it is flat.

                       │   pre1508    │              m1508              │                m1512               │                dev                 │               fix1
                       │  allocs/op   │  allocs/op    vs base           │  allocs/op    vs base              │  allocs/op    vs base              │  allocs/op   vs base
GRPCVerifyConstraint-8   18.54k ± 0%    18.54k ± 0%   ~ (p=1.000 n=6)     20.76k ± 0%  +12.01% (p=0.002 n=6)   16.30k ± 0%  -12.07% (p=0.002 n=6)   14.89k ± 0%  -19.69% (p=0.002 n=6)
BatchSatisfy-8           4.458M ± 0%    4.458M ± 0%   ~ (p=0.853 n=6)     4.454M ± 0%   -0.09% (p=0.002 n=6)   4.078M ± 0%   -8.53% (p=0.002 n=6)   3.814M ± 0%  -14.45% (p=0.002 n=6)
Instantiate-8            2.315M ± 30%   2.315M ± 30%  ~ (p=0.937 n=6)     2.309M ± 30%  -0.26% (p=0.037 n=6)   2.011M ± 36%  -13.15% (p=0.041 n=6)   1.768M ± 0%  -23.65% (p=0.002 n=6)
FeaturesOf-8             2.271M ± 0%    2.271M ± 0%   ~ (p=0.623 n=6)     2.312M ± 0%   +1.81% (p=0.002 n=6)   2.186M ± 0%   -3.74% (p=0.002 n=6)   2.104M ± 0%   -7.35% (p=0.002 n=6)
                       │     B/op     │     B/op      vs base           │     B/op      vs base              │     B/op      vs base              │     B/op     vs base
GRPCVerifyConstraint-8   1229.7Ki ± 0%  1229.7Ki ± 0%  ~ (p=0.387 n=6)    1626.9Ki ± 0%  +32.30% (p=0.002 n=6)  814.6Ki ± 0%  -33.76% (p=0.002 n=6)   766.8Ki ± 0%  -37.64% (p=0.002 n=6)
BatchSatisfy-8           460.5Mi ± 0%   460.4Mi ± 0%   ~ (p=0.589 n=6)    460.7Mi ± 0%   +0.05% (p=0.002 n=6)   491.1Mi ± 0%   +6.64% (p=0.002 n=6)   481.1Mi ± 0%   +4.48% (p=0.002 n=6)
Instantiate-8            210.0Mi ± 45%  209.9Mi ± 45%  ~ (p=0.589 n=6)    210.5Mi ± 45%  +0.23% (p=0.041 n=6)   240.2Mi ± 40%  +14.40% (p=0.041 n=6)   230.7Mi ± 0%        ~ (p=0.065 n=6)
FeaturesOf-8             262.1Mi ± 0%   262.1Mi ± 0%   ~ (p=0.818 n=6)    266.2Mi ± 0%   +1.56% (p=0.002 n=6)   295.7Mi ± 0%  +12.82% (p=0.002 n=6)   289.7Mi ± 0%  +10.53% (p=0.002 n=6)
                       │    sec/op    │
GRPCVerifyConstraint-8   2.570m ± 25%   2.497m ± 142%  ~ (p=1.000 n=6)    2.822m ± 289%  +9.80% (p=0.041 n=6)   1.662m ± 2%  -35.33% (p=0.002 n=6)   1.676m ± 4%  -34.80% (p=0.002 n=6)

Candidate → this branch: GRPCVerifyConstraint 16 301 → 14 887 allocations (−8.7 %) and 834 KiB → 785 KiB per constraint; BatchSatisfy −6.5 % allocations, −2.0 % bytes; Instantiate −12.1 % allocations, −4.0 % bytes; FeaturesOf −3.7 % allocations, −2.0 % bytes. The other rows of tests/perf, internal/exec/runtime and the tests/stressmodel constellation (Satisfy, FleetInstantiate, FleetSatisfy at 32/128/512 satellites) are unchanged within noise (FleetInstantiate allocations −0.03…−0.13 %, p=0.002). AssignmentLoopStep is not moved by this branch (its bytes are #1514/#1461, their own PR). The warm gRPC row InstantiateWarmModel (tests/grpc) is below.

Residuals, stated plainly: GRPCVerifyConstraint stays 796 allocations per constraint above 0.11.0 (14 887 vs 14 091) — those are the owner and sibling reads #1508/#1512 make correctly and this PR keeps; the BatchSatisfy bytes still +4.5 % over pre-#1508 and FeaturesOf +10.5 % are #1626's subsetting memo, addressed in perf/related-features-memo. No sec/op claim is made here: on this loaded host GRPCVerifyConstraint sec/op is flat between the candidate and this branch (1.66 vs 1.68 ms); the −35 % from pre1508 to dev landed elsewhere in develop. The Instantiate B/op spread (±30–45 % on the older revisions) is the harness's cold first iteration, the same on every revision; the allocation count is the comparable figure.

internal/frontend/grpc, six rounds dev vs fix1 (same host, quiet apart from one A/B):

│ dev-grpc │ fix1-grpc │
                       │              sec/op              │      sec/op       vs base         │
InstantiateWarmModel-8                        221.2µ ± 2%        219.1µ ± 2%  ~ (p=0.065 n=6)

                       │ dev-grpc │ fix1-grpc  │
                       │               B/op               │     B/op      vs base              │
InstantiateWarmModel-8                       125.5Ki ± 1%   117.9Ki ± 0%  -6.01% (p=0.002 n=6)

                       │ dev-grpc │ fix1-grpc │
                       │            allocs/op             │  allocs/op   vs base              │
InstantiateWarmModel-8                        2.155k ± 0%   1.996k ± 0%  -7.35% (p=0.002 n=6)

InstantiateWarmModel 2 155 → 1 996 allocations per instantiation (−7.4 %) and 125.5 → 117.9 KiB; 0.11.0 rebuilt with go1.27.3 is 1 962, so 34 remain — the attribution of that row to the binding walks is confirmed.

Definition of done on this branch:

$ go build ./... && go vet ./... && gofmt -l .      # clean; gofmt prints nothing
$ go test -timeout 45m ./...                         # 124 packages ok, 0 FAIL (PSSM suite and pilot library XMI present, OPENSYSML_REQUIRE_* set)
ok    github.com/Open-MBEE/OpenSysML/cmd/sysml                 606.239s
ok    github.com/Open-MBEE/OpenSysML/internal/exec/runtime     403.277s
ok    github.com/Open-MBEE/OpenSysML/internal/exec/smt         443.188s
ok    github.com/Open-MBEE/OpenSysML/tests/corpus               14.746s
ok    github.com/Open-MBEE/OpenSysML/tests/identity              1.848s
…

(The long cmd/sysml/smt times are the host running a benchmark A/B alongside; the default 10 m per-package timeout is why -timeout 45m.)

Checklist

  • make test and make lint pass locally (go build, go vet, gofmt -l, go test -timeout 45m ./... above)
  • Tests added or updated for the change — none added: the conformance, robustness and gRPC suites pin what the walks find; this changes only when they allocate
  • Documentation extended where it already covers the surface — none covers these internals
  • Changelog entry added as changes/unreleased/binding-walk-allocs.fixed.md
  • baselines regenerated and make docs-counts run if a gate count moved — no gate count moved
  • No internal work-item labels in the body, docs, or changelog

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

devin-ai-integration Bot and others added 2 commits October 30, 2026 00:57
… be found

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…agment

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 marked this pull request as ready for review October 30, 2026 06:36
devin-ai-integration[bot]

This comment was marked as resolved.

…k requires

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@HuiJun
HuiJun merged commit 435991d into develop Oct 30, 2026
30 checks passed
@HuiJun
HuiJun deleted the perf/binding-walk-allocs branch October 30, 2026 12:43
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