Skip to content

perf(runtime): resolve flow-control stream state once per lifecycle - #742

Closed
SunSi12138 wants to merge 90 commits into
devfrom
perf/735-resolved-flow-state
Closed

SunSi12138 wants to merge 90 commits into
devfrom
perf/735-resolved-flow-state

Conversation

@SunSi12138

@SunSi12138 SunSi12138 commented Sep 22, 2026 •

Copy link
Copy Markdown
Owner

Refs #735

Status: Draft — two validated footprint reductions, production acceptance not yet passed

Current head: e834d3c28c87ad496989af925515cf21babd308d.
Current tree: 4afb01297ffe8af9b9e27dfcae6663403aaa2c60.
This head adds lazy named-route storage to 2a649a9880589696448e21ce0bd2e67ffd174147 (packed lifecycle flags). Both follow 6ca43ee8e434f2796a9e8d65f49d777d36f52fd2, including dev 0fe26024b114bb6e78411a9b86276086c045d03d.

Production performance acceptance remains blocked. These changes have real allocation-probe results and correctness validation. They do not, by themselves, establish production RPC B/item, NativeAOT short-stream latency or contention acceptance. Do not equate successful collection workflows with #735's joint Go requirements. Keep the issue open and this PR Draft.

Changes in this optimization round

  1. Pack terminal-published, peer-terminal and retirement-claimed into spare, disjoint bits of the existing atomic entry state word. Acquisition count and limit, Close/Detach, cleanup pin and unique ownership remain unchanged.
  2. Default-only requests use the existing inline stream-0 route without allocating the separate nonzero-stream dictionary. Materialize that dictionary only when a nonzero route is published under the existing registry lock. Missing-route operations do not allocate it; named/mixed routes retain their needed map and identities.

The complete receive lease still belongs independently to the route. No entry pool, second state map, smaller negotiated capacity, callback lookup, protocol change or new per-item synchronization was introduced. Previously fixed acquired-DATA credit lifetime, same-key generation, bind rollback and pooled-reference retention rules remain intact.

Relative to 6ca43ee there are two commits and five changed files: one production routing file, two test files and two evidence documents. Existing workflows, deadlines, populations, allocation budgets and acceptance thresholds are unchanged. Temporary preflight workflows/scripts were not promoted into this PR.

Measured allocation — attribution, not E2E

Same probe at each step: one reused stateless dispatcher, no flow callbacks, 2,048 warmups, three repeats of 10,000 Register/Unregister lifecycles. Each adjacent control/candidate comparison ran on the same Linux x64 runner, measuring allocations only around the loop.

Single-route request Original 6ca43ee Packed flags 2a649a9 Packed flags + lazy map Chained reduction
default stream 0 256 / 256 / 256 B 240 / 240 / 240 B 160 / 160 / 160 B 96 B/lifecycle
nonzero stream 7 392 / 392 / 392 B 376 / 376 / 376 B 376 / 376 / 376 B 16 B/lifecycle

The lazy-map change alone saves 80 B/default-only request and adds no allocation to the named-route control. It does not claim that saving for mixed/nonzero requests. The chain comes from two separately retained adjacent comparisons, not a single three-revision timing benchmark.

Do not subtract these values from old RPC measurements to claim a new E2E B/item result. NativeAOT publication below establishes correctness, not a native performance improvement. No microkernel short-flow benefit is claimed: these changes do not alter the controller's separate resolve/debit sequence.

Two self-check rounds before each original-PR submission

Local execution was unavailable, so actual validation ran first on the existing temporary preflight branch with read-only Actions permissions. It verified unchanged shipping sources, built/measured the fixed control, applied a source-blob-pinned candidate only in its disposable checkout and reran checks before this PR was advanced.

First reduction: compact flags

Run 37331620087, artifact 11355220166.
Actions-reported SHA256: 6108ec4ee955ef185769fbc4c4f90f45b7e07a3e0fa23382296fc3de64898074.

Build/engineering: zero warning/error Release builds, changed-file formatting and original maintainability/reference boundaries pass.
Contracts: 11/11 focused cases on control and candidate; complete default and experimental suites each 1972/1972, zero skips; actual JIT and NativeAOT writer self-checks 171/171.

The initial preflight shallow-checkout setup failure is retained; it occurred before compilation. Only history/ancestry validation was repaired, not runtime/tests/measurement thresholds.

Second reduction: lazy named-route map

Run 37335422646, attempt 1, job 111848850430, artifact 11355583391 with 29 evidence files.
Actions-reported SHA256: 5f546e0994b85e4997e76b48513dd69f98f9a49a31110402cb0d4156b31ced63.
Runtime routing blob: a8fa8e890ceaf341a552651fc289c3bddc0b1c4a.
Permanent test blob: 2d06e535fcc4a6b355ed6480179db72ba03f5418.

Build/engineering: zero warning/error builds, formatting and original maintenance/reference gates pass.
Contracts: the intended default-route eager-allocation test fails on unchanged 2a649a9, then 6/6 new cases pass on the lazy candidate; retained flags/allocation 11/11. Full default and experimental suites each 1978/1978, zero skips. Actual JIT and NativeAOT writer self-checks 171/171. Existing evidence-guard Python suites also pass.

The six tests cover absent storage, default/named replacement, missing-named operations, default-only and mixed connection teardown, and concurrent default/nonzero registration. All earlier receive-credit/ABA/rollback/pool-retention regressions remain in the full suites.

Retained correctness fixes

An acquired DATA dispatch pins its receive callback, captured generation and route key through the last release, including synchronous failed-request cleanup and pre-debit/post-debit interleavings. Deferred terminal/cleanup and the existing cleanup pin prevent premature dispatcher reuse while preserving required logical detach. Cleanup failures cannot release an acquisition twice.

Binding is validated before callback mutation/receive-state resolution. Failed rebinding cannot attach ownerless flow state or erase an old route's callback; failed insertion rolls back only the captured unpublished generation. These paths were not changed by the two storage optimizations.

Performance interpretation and remaining blockers

Microkernel: candidate-internal keyed vs resolved ns/item attribution.
Production E2E: pinned dev vs candidate binaries.
B3: isolated writer-ownership research, not the production candidate's E2E result.

Historical integrated 885306c evidence (run 37190672744, artifact 11299511677) showed NativeAOT short-flow ns/item improvement -11.28%, TCP Server1x16 allocation +73.44 B/item, SHM +54.24 B/item, with all three repeats increasing allocation. These were genuine blockers, not overridden by old B3 gains.

Completed 6ca43ee evidence (run 37222858782) also showed short-flow problems: NativeAOT short-flow cost +15.69% vs keyed; TCP Server1x16 -7.51% throughput / +51.07 B/item, SHM -2.98% / +52.77 B/item. These are historical measurements, not claimed measurements of e834d3c.

The new combined head requires its own production E2E/allocation and native timing results. Compact lease metadata, first-DATA resolve/debit overhead and shared connection contention remain separate follow-up work; this round does not declare them fixed.

Current-head CI

New-head runs have started: PR Fast 37336638809, Package Smoke 37336639012, Ready Writer 37336639017, production resolved-state evidence 37336638940. Running jobs are not counted as passed. The independent pre-submit successes above are not presented as the final head's completed CI. Subsequent comments record actual conclusions, including non-gating diagnostic failures and any missing timing population.

Evidence documents:

  • doc/performance/flow-state-route-flags.md
  • doc/performance/flow-state-lazy-route-map.md
  • doc/performance/flow-state-735-integrated-review.md
  • doc/performance/flow-state-735-acceptance.md

Copy link
Copy Markdown
Owner Author

Evidence result on latest dev baseline

This PR was replayed onto:

dev@56c643cd308f294cb03df79d9f1214fb8292affb

and measured as a strict two-point comparison:

baseline  = latest dev
candidate = latest dev + resolved flow-state

Performance run:

35690912084

Flow-control microkernel

Resolved leases clearly remove keyed state-resolution cost in the sequential hot path.

Dynamic PGO ON:

  • long-lived median ns/item improvement: +27.94%
  • send no-wait: +26.21%
  • receive accept: +33.60%
  • receive consume: +10.44%
  • receive accept+consume pair: +30.73%
  • short-stream control: +4.87%

Dynamic PGO OFF:

  • long-lived median ns/item improvement: +20.20%
  • send no-wait: +21.16%
  • receive accept: +18.26%
  • receive consume: +18.22%
  • receive pair: +28.37%
  • short-stream control: +3.72%

However, contention results regress materially:

  • PGO ON receive-pair contention: -86.62%
  • PGO OFF receive-pair contention: -29.87%

The local lookup-elimination mechanism is real, but it does not improve the contended production shape.

Real TCP streaming A/B

Candidate throughput vs latest dev:

Server 100x16B      -1.63%
Server 100x4KiB     -3.08%
Client 100x16B      -1.54%
Client 100x4KiB     -2.43%
Duplex 100x16B      -1.88%
Duplex 100x4KiB     +0.78%

Median throughput delta across the six 100-item scenarios:

-1.75%

So the sequential microkernel win does not translate into an end-to-end TCP streaming win in the current implementation.

Correctness / compatibility status

This PR is also not merge-ready independently of performance:

  • PR Fast has 5 unit-test failures.
  • Four failures involve typed-dispatcher/local-completion credit retirement.
  • Package Smoke rejects the new runtime raw-dispatcher inventory because IResolvedStreamConsumptionAwareDispatcher is newly visible to that inventory check.

Current evidence therefore supports keeping #742 as experimental work rather than merging it in its current form.

This result is specific to #735 flow-control state resolution and is unrelated to #720 struct-Codec specialization work.

@SunSi12138
SunSi12138 marked this pull request as draft October 4, 2026 17:19
Keep receive callbacks, captured generations and route keys alive until every acquired DATA dispatch releases, including the synchronous failed-request cleanup path. Complete mailboxes immediately but defer final receive terminal/cleanup through a single cold-path drain continuation. Preserve immediate logical detach while an atomic cleanup pin prevents pooled-dispatcher reuse before terminal credit publication. Keep final release outside dispatch exception handling so cleanup failures cannot double-release acquisitions.

Bind dispatcher ownership before callback mutation or receive-state resolution. Reject an already-bound pooled dispatcher without attaching ownerless flow state or erasing the original route callback; rollback any captured unpublished generation if later route insertion fails.

Add 30 deterministic tests for before/after debit, plain/compressed PreAdmission DATA, stream 0/nonzero, request/stream/unregister completion, binding rollback, release-before-continuation installation, cleanup exceptions and detached-pool pinning. The first 29 controls fail against the original runtime; final default and disposable experimental UnitTests each pass 1961/1961, zero skipped. Ready-writer self-check passes 171/171. Release builds have zero warnings/errors; formatting, original maintainability and reference-boundary checks pass. Uploaded tree matches the locally validated sources.

Performance acceptance remains BLOCKED: integrated 885306c evidence has NativeAOT short-stream -11.28% and Server1x16 allocation increases. Document the exact artifact and independently measured +48 B/route footprint instead of claiming Go from integrity CI. Local allocation gate has 3/4 passing cases; c1 median is under budget but spread 66.92 exceeds 50 B/op (baseline control passes). NativeAOT local publish is not validated because the offline runtime pack is unavailable. Preserve failures; require fresh CI. No workflow, timeout, population or budget is relaxed. Keep #735 open and #742 Draft.

Copy link
Copy Markdown
Owner Author

Submitted 6ca43ee8e434f2796a9e8d65f49d777d36f52fd2 for the acquired receive-credit loss and bind-failure rollback review items. The 30 deterministic regressions cover before/after debit, plain/compressed PreAdmission, request/stream/unregister retirement, old callback preservation, cleanup failures and detached-pool pinning. New-head remote correctness confirms 1961/1961 UnitTests, 171/171 writer checks and zero warnings/errors. PR Fast #2186 (including allocation gate), Package Smoke #330, NativeAOT and stable JIT also pass; default-socket JIT and both retained stall diagnostics still fail and are not counted as passed.

Performance acceptance remains blocked; this PR remains Draft. The integrated candidate's NativeAOT short-stream -11.28% ns/item improvement and Server1x16 +73.44/+54.24 B/item are retained. A separate 3-repeat route-lifecycle allocation probe confirms a fixed +48 B/route contribution. Correctness fixes and successful evidence collection do not remove these costs. No workflow, threshold, timeout or population was weakened in this increment.

Full fix, two-round self-check and CI/evidence record. The prior Ready/Go conclusion has been withdrawn in the PR body and acceptance document. Production Phase A #73 was still collecting E2E at the last check and is not reported as complete.

…wnership

Move terminal-published, peer-terminal and retirement-claimed flags into disjoint spare bits of the existing DispatcherEntry atomic state word. Keep the original acquisition count/limit, Close/Detach, cleanup pin, captured receive lease and all retirement ordering intact. No new per-item synchronization, pooled entry, callback indirection or state map.

Pre-submit validation ran remotely on a separate disposable preflight checkout because the local executor was unavailable; no uncompiled runtime was pushed to PR 742. Run 37331620087 built and measured unchanged 6ca43ee first, then applied this exact source transformation. Three 10,000-lifecycle repeats: stream0 256/256/256 -> 240/240/240 B/route; stream7 392/392/392 -> 376/376/376. A real 16 B/route reduction in every repeat.

Both review rounds passed: zero-warning/error Release builds, changed-file formatting, original maintainability/reference gates; focused checks 11/11 on control and candidate, complete default and experimental UnitTests each 1972/1972 with zero skips, actual JIT/NativeAOT writer self-checks 171/171. Retain the first preflight shallow-checkout setup failure separately. Promote only runtime change, permanent tests and evidence documentation; no preflight workflow or existing gate modifications.

This is a partial allocation optimization, not production Go. Short-stream E2E allocation, NativeAOT latency and contention still need new comparable evidence. Keep #735 open and #742 Draft.
Keep default stream0 in its existing inline slot and materialize the nonzero route dictionary only when a named stream is published under the existing registry lock. Missing named-route operations do not allocate storage. Preserve mixed-route identities, locks, complete receive leases, acquired-DATA retirement and all bind/terminal rollback rules.

Pre-submit run 37335422646 built unchanged 2a649a9, proved the intended eager-map regression, then applied the exact candidate blob in a disposable remote checkout. Three 10,000-lifecycle repeats show stream0 240/240/240 -> 160/160/160 B/route; stream7 stays 376/376/376. Combined with the preceding flag change, the chained default-only control is 256 -> 240 -> 160 B/route. This is allocation attribution, not RPC throughput or NativeAOT performance acceptance.

Both review rounds passed before advancing the original PR: zero-warning/error builds, original formatting/maintainability/reference gates, six new dictionary tests, eleven retained flag/allocation tests, complete default and experimental UnitTests each 1978/1978 with zero skips, and actual JIT/NativeAOT writer checks 171/171. Source diff hash matches runtime blob a8fa8e8. Keep preflight scripts/workflow off the PR.

No existing performance gate, test population, protocol, window or pool policy is relaxed. Production short-flow allocation/latency and connection contention require fresh comparable evidence. Keep #735 open and #742 Draft.

Copy link
Copy Markdown
Owner Author

Submitted two preflight-validated storage optimizations on this existing PR: 2a649a9880589696448e21ce0bd2e67ffd174147 (compact lifecycle flags), then e834d3c28c87ad496989af925515cf21babd308d (lazy non-default route map).

The chained allocation controls are default-only route 256 -> 240 -> 160 B/lifecycle and named route 392 -> 376 -> 376 B/lifecycle, each value reproduced in all three 10,000-lifecycle repeats of its matched control/candidate run. The latest pre-submit complete default/experimental suites each passed 1978/1978, zero skipped, and actual JIT/NativeAOT writer checks 171/171. The intended eager-map structural regression was first observed on the unchanged control. Existing receive-credit/ABA/bind-rollback/retention regressions and ordinary CI gates remain intact.

Detailed implementation, two review rounds, artifact identities and evidence boundaries.

Still Draft. These are per-lifecycle allocation controls, not new production RPC B/item or throughput results and not a fix for the controller's NativeAOT short-stream initialization overhead. Current-head correctness and NativeAOT evidence jobs have passed; complete production/performance jobs are tracked separately. No previous Ready/Go claim is restored by these partial wins.

SunSi12138 added a commit that referenced this pull request Oct 6, 2026
Source-only snapshot of the candidate tested in preflight 37403642475. Production blobs exactly match that disposable build: StreamManager 699636a and Routing 6892964. Full default and experimental tests pass 1987/1987 and actual JIT/NativeAOT writer controls pass 171/171. Lifecycle allocation falls 16 B for both default and named routes with and without receive callbacks.

Do not promote this candidate to #742: the retained 24-process RPC control shows Server100x16 throughput -6.01% TCP and -8.60% SharedMemory with allocation medians increasing +4.98/+2.30 B/item, despite short-flow allocation improving. This snapshot preserves the failed performance candidate for code-generation attribution; workflow success is not acceptance. No existing PR head, test gate, timeout or workload is changed.
SunSi12138 added a commit that referenced this pull request Oct 6, 2026
Retain the failed unhinted compact source as a separate ancestor/control, not as a PR update. In the disposable candidate only, add an AggressiveInlining hint to the full-lease reconstruction boundary. Capture optimized dispatch code in separate diagnostic processes for unchanged e834, unhinted compact, and the new inline candidate.

Keep the same 24 uninstrumented real-RPC controls, report every launch's allocation and throughput plus CPU medians, and rerun the two engineering/correctness review rounds. The source transform is blob-pinned; all original gates, timeouts, populations, windows and pool rules stay unchanged. Source-only preflight changes remain off #742. No acceptance is claimed from CI success.

Copy link
Copy Markdown
Owner Author

Continued performance work without promoting regressing candidates. The PR remains e834d3c28c87ad496989af925515cf21babd308d, Draft.

The current production evidence now shows lower Server1x16 allocation versus pinned dev (TCP -18.91 B/item, SharedMemory -44.75), but NativeAOT short-flow attribution still regresses -7.36% and PR Fast's c1 allocation spread is 51.576 > 50 B/op. Neither is waived.

Two independently validated compact-route variants each saved another 16 B/lifecycle and passed complete default/experimental tests plus JIT/NativeAOT writer correctness. Their fixed actual-RPC controls did not jointly pass throughput/allocation acceptance, so neither was pushed to this PR.

A third isolated prototype fuses first receive-state resolution, credit debit and generation capture under one controller gate. Actual NativeAOT single-item lifecycle measurements improved from 108.05 to 89.51 ns/item versus separate resolve/accept (+17.16% time improvement), and from 94.48 to 89.51 versus keyed (+5.26%). The 32-active-stream NativeAOT control also improves. PGO ON with one active stream is still 8.16% slower than keyed; it remains a negative control. Full default UnitTests 1987/1987, 9 new contracts in JIT and NativeAOT, a two-failure deliberate negative variant, and all 432 predefined mechanism rows have been verified in preflight 37406519822.

This is warmed-controller candidate-internal attribution, not production RPC integration, cold-route allocation or a contention/Go verdict. Production adoption still needs correct first-frame/callback publication and all previously fixed lifecycle barriers. No original gates, timeouts, windows or populations changed.

Full experiment identities, all outcomes, raw artifacts and remaining integration boundary.

SunSi12138 added a commit that referenced this pull request Oct 6, 2026
…motion

Keep #742 at e834d3c. In disposable checkouts only, apply the exact locally compiled seven-file candidate for first-DATA resolve/debit plus route callback publication. Direct consumption-aware routes defer first receive state; retained PreAdmission mailboxes keep their existing eager contract. Acquired frames pin initialization, the captured generation and deferred retirement. Concurrent first frames wait for callback and first-delivery publication; failed undelivered initialization refunds only the winner's debit. Empty deferred routes cannot complete another generation by key.

Local focused controls pass 25/25, including actual RpcSession/WindowUpdate and two deliberate two-failure mutation groups. An earlier full run passed 2003/2003; final exact-tree revalidation is 2002/2003 with the existing reconnect-policy timer-wait test timing out, retained rather than replaced. Original engineering gates and zero-warning builds pass. The code and test patch SHA256 is 111f6a122b9481f732e319c42ab9f5d6aefddf6b0a845e26cd22b0b9a7440279; multipart transport is checked and expanded to a plain reviewable patch before compilation.

Do not promote: the local fixed 24-process RPC screen shows TCP Server1x16 -12.00% throughput / +14.44% CPU despite lower allocation and positive 100-item medians. A same-binary eager/fused control also retains a short TCP regression. These are negative incremental controls, not Go evidence.

Run independent complete default/experimental correctness, actual generated NativeAOT TCP/SharedMemory smoke, and fixed 24-process RPC screens for each PGO setting. All failures, source hashes and individual reports are retained; workflow success establishes integrity only. No original PR workflow, allocation threshold, socket profile, timeout, population or production default is changed.
SunSi12138 added a commit that referenced this pull request Oct 6, 2026
… smoke

Keep the exact single-await runtime blobs validated by 37434398376. Prepare one identical minimal host for e834d3c and the disposable candidate, retaining the original benchmark service, contracts, transport environment and measured loop. Adapt only result JSON outside the measured interval to source-generated metadata; record every source/harness hash and both native binary identities.

Publish and execute actual NativeAOT binaries, requiring RuntimeFeature.IsDynamicCodeSupported=false. Measure the same short/100-item TCP/SharedMemory server-stream controls in 24 predefined AB/BA/AB processes. Retain all latency, throughput, CPU, allocation and failed outcomes. This is incremental real native RPC evidence, not the full pinned-dev acceptance matrix. The original #742 and its gates remain unchanged and Draft.

Copy link
Copy Markdown
Owner Author

Continued first-receive integration work on the existing preflight branch; the original PR remains e834d3c28c87ad496989af925515cf21babd308d, Draft.

The source-pinned integration is recoverable. New candidate 9ebd60c8 removes a redundant async wrapper by making one completion owner publish first-delivery success and release the acquisition. Followers still wait for actual delivery, and initialization/delivery/cleanup failures preserve their distinct credit ownership. A deterministic control measures pending-first wrapper allocation falling 256 -> 128 B, equal to the unchanged ordinary pending-dispatch path; this is per genuinely suspended first frame, not a blanket RPC saving. Default and experimental full suites each pass 2005/2005, zero skipped; the retained 25 first-receive controls and two new allocation controls pass, as do original engineering gates and writer checks 171/171.

The same runtime completed all 48 fixed JIT RPC processes and, through a minimal identical generated-RPC host on both revisions, 24 actual NativeAOT RPC timing processes. Native timing is now measured rather than inferred from AOT smoke. Runtime/harness hashes, native binary identities, raw reports and negative outcomes are retained.

Do not promote this candidate yet. JIT PGO ON SharedMemory Server100x16 is -1.62% throughput / +4.05 B/item, with all three allocation repetitions increasing; PGO OFF is -3.62% / +4.54 B/item. Native short-flow throughput remains slightly negative (TCP -1.15%, SHM -0.70%), and native SHM allocation medians increase +3.48 B/item short / +0.34 long. These incremental screens compare against e834, not pinned dev, and do not replace the full issue acceptance matrix. Collection success is not Go.

Complete source identities, two-round checks, all JIT/native results, failed tooling builds and artifacts. No original workflow, threshold, timeout, window or population was weakened.

SunSi12138 added a commit that referenced this pull request Oct 6, 2026
Keep the validated single-await runtime unchanged and instrument only both identical benchmark harnesses with two EventSource boundary markers. Pin dotnet-trace 10.0.745401 and TraceEvent 3.2.8; first calibrate inside/outside-window filtering with known allocation types and require no event loss.

Collect 12 fixed allocation-sampling processes: SharedMemory/TCP Server100x16, control e834 versus the exact single-await candidate, three AB/BA/AB repeats. Preserve raw traces, per-process measurements, object-size samples and type-estimate deltas, including every negative outcome. AllocationTick attribution is sampled diagnostic evidence, not exact type counts or a profiled throughput Go decision.

No new runtime optimization is promoted to #742, no production gate is weakened, and no benchmark acceptance population is replaced. The purpose is to identify actual allocating state machines/objects before changing more concurrency code.
SunSi12138 added a commit that referenced this pull request Oct 8, 2026
The latest 0bcc candidate reduces allocation in every screened cell but retains PGO-ON long-flow throughput negatives. Do not conflate that with the cost of either independent change. Reconstruct the verified full candidate, then restore all first-receive/route/controller integration files to published e834 while keeping exactly the pooled SlowMoveNext builder, two single-consumption client wrapper fixes, and their 18 controls.

The five-file isolated candidate builds locally with zero warnings/errors; focused controls pass 18/18 and full default UnitTests pass 1996/1996, zero skipped. Local offline restores disable NuGet audit only on the invocation; CI retains original policies. This temporary preflight requires both original-wrapper and original-builder negative controls, original engineering gates and full default/experimental suites again.

Measure published e834, the exact previously validated fused+pooled candidate, and wait-only isolation on the same fixed three-arm 108-process JIT PGO OFF/ON and actual NativeAOT RPC population. Report all pairwise timing, CPU, allocation and p99 values without retries, removed cells, changed socket/windows or altered acceptance gates. Keep #742 unchanged and Draft pending evidence.
SunSi12138 added a commit that referenced this pull request Oct 11, 2026
Build on fixed PR #742 head e834d3c. Add the existing three-file handoff candidate and 14 real-SendPump regression cases. Keep ordinary/progress budgets, timed flush policy, bounded ordinary/ready selection and buffer ownership through flush and stop.

This is the handoff layer only, not a completed B3 RPC integration or a performance Go claim. No workflow, test population, timeout, allocation threshold or production flow-control default is relaxed. CI has not yet run for this tree.
SunSi12138 added a commit that referenced this pull request Oct 11, 2026
Port just #742's validated lazy nonzero route storage mechanism onto current unmodified dev. Stream 0 keeps its existing inline slot and compare-exchange admission; a missing named route does not allocate storage; the map is created under the existing per-request registry gate only upon first successful named publication. Preserve all route-key semantics, active counts, dispatcher lifetime, and original flow control.

Add six focused actual StreamManager test cases for default-only register/unregister, missing named dispatch/peer completion, mixed named/default routes, connection completion and concurrent registration. This is not the resolved-lease rewrite, packed-flags experiment or B3 scheduler. The prior #742 adjacent probe attributed -80 B/default-only route on its own measured head; independent current-dev allocation and package gates are required before claiming identical deployment savings.

Copy link
Copy Markdown
Owner Author

Post-B3 salvage triage — keep #742 Draft, move proven independent changes out

At maintainer request, the two B3-only WIP PRs #800 and #803 have been closed without merge. #803's genuine generated-RPC JIT loss and repeatable cancellation stress failures remain archived; do not claim its historically positive B3 research evidence is a production improvement. #742 itself remains open Draft and should not be merged wholesale.

Current standalone dev base is f0fee51e77a5a736469bffa837ceb8f31b1f6877, not #742's historical pinned dev baseline. Two focused Draft PRs were prepared against it:

  1. #840: connection-credit conservation. This is an independent pre-existing correctness bug in BOTH old dev and perf(runtime): resolve flow-control stream state once per lifecycle #742: StreamFlowController.ApplyWindowUpdate uses independently clamped stream/connection increments. After abort refunds A's debt, a duplicate/late WindowUpdate(A) can mint connection credit for unrelated B/C and can falsely reject B's valid unsent refund. Minimal repair credits the connection by the effective stream delta under the same existing lock. Test-only red control 33e328fc, then green correction 5bb3b8e3; PR Fast 38157432110 2071/2071 UnitTests, 271/271 Generator.Tests, 77/77 LoadTest.Tests; Package Smoke 38157432134 and CodeQL green. No B3 dependency. This is a correctness fix, not a throughput claim.
  2. #841: lazy nonzero route dictionary. Exact mechanism from perf(runtime): resolve flow-control stream state once per lifecycle #742, ported without its resolved leases. Same-machine current-dev versus standalone candidate attribution run 38157990216: default-only stream 0 208→128 B/lifecycle (-80 B), named stream 7 344→344 B (+0 B). Four balanced dev-A/candidate/dev-B process rounds, 3×10k route lifecycles each. The routing implementation and six dedicated correctness cases passed PR Fast 38157502795, 2065/2065 UnitTests plus other test suites; Package Smoke green. The very latest attribution-only commit is being validated by its own CI. No B3 dependency. This is allocation attribution, not E2E QPS.

Additional proven mechanism in #742, not blindly cherry-pickable: packing three cold lifecycle flags into spare bits of the existing long entry state word reduced 16 B/route in the #742 preflight (run 37331620087), with full correctness/JIT/NativeAOT functional checks. However #742's DispatcherEntry contains its extra resolved-lease retirement and cleanup state, while current dev has a different, smaller int-based entry layout. A new standalone port and independent source-specific allocation/race tests would be required; do not attribute #742's 16 B/route to an unbuilt dev port or mix it into #841's observed -80 B.

Do not salvage as production optimizations without fresh evidence: resolved-state Phase A (mixed E2E, contention/short-flow regression), B3 writer-owned integration (No-Go and closed), first-DATA fused resolve/debit (tombstone-capacity correctness change), retirement OR fusion (model-only, C# not verified), and separate route-lock-object removal (mechanism-only/local measurements, no accepted E2E improvement).

The original #742 receive-lease lifetime/bind rollback fixes are primarily correctness for its new resolved-leasing model; do not assume the original dev has those same failure modes or transplant them unconditionally. The independent dev correctness bug above is tracked in #840.

No original PR, dev production branch, runtime defaults, acceptance thresholds or protocol changes were merged by this triage.

SunSi12138 added a commit that referenced this pull request Oct 11, 2026
…equests (#841)

* perf(runtime): allocate named stream route dictionary only when needed

Port just #742's validated lazy nonzero route storage mechanism onto current unmodified dev. Stream 0 keeps its existing inline slot and compare-exchange admission; a missing named route does not allocate storage; the map is created under the existing per-request registry gate only upon first successful named publication. Preserve all route-key semantics, active counts, dispatcher lifetime, and original flow control.

Add six focused actual StreamManager test cases for default-only register/unregister, missing named dispatch/peer completion, mixed named/default routes, connection completion and concurrent registration. This is not the resolved-lease rewrite, packed-flags experiment or B3 scheduler. The prior #742 adjacent probe attributed -80 B/default-only route on its own measured head; independent current-dev allocation and package gates are required before claiming identical deployment savings.

* fix(runtime): treat missing lazy named routes as absent in terminal-discard cleanup

Current-head PR Fast and Package Smoke on b3af181 fail before tests (CS8602) because RequestDispatchers is a partial class also used by StreamManager.TerminalDrain.cs. Take the named-map reference under the existing per-request lock; return false when the map has never been materialized. This is the same missing-named-route invariant as the earlier lazy storage change. Preserve terminal removal and route identity. No original test, gate, workflow or quota is relaxed.

* test(runtime): measure standalone lazy named-route allocation against pinned dev

PR Fast and Package Smoke 38157502795 / 38157502775 passed on the isolated route-map port. Add an opt-in UnitTests friend-assembly allocation probe that reuses one stateless dispatcher and measures three warmed 10,000-register/unregister lifecycles for default and named routes. The additive workflow copies exactly the same probe source into frozen dev f0fee51 and builds both binaries on one runner, alternating dev-A/candidate/dev-B for 4 rounds, preserving 12 raw process results and A/A controls. The regular tests, performance thresholds, product paths, windows and protocols are unchanged; these numbers attribute per-route allocations only, not RPC QPS.

* test(runtime): use identical camel-case evidence JSON across both measured binaries

The additive route-allocation workflow parser checks stable camel-case provenance fields. Make the shared UnitTests probe explicitly serialize those names rather than relying on the serializer's default Pascal-case anonymous-property names. This affects only the diagnostic artifact format; regular UnitTests, route implementation, allocation thresholds and source comparisons are unchanged.

Copy link
Copy Markdown
Owner Author

Closing this superseded #735 research Draft without merge. The two measured footprint reductions and their evidence remain preserved in this PR/branch, but production RPC throughput, NativeAOT latency, and contention Go gates were not established. The later consolidated architecture audit and No-Go decision are tracked in #852, with follow-up tracked by #735. This closure is not a claim that the underlying optimization is invalid; it means this particular candidate is not a production merge vehicle. No branch or evidence artifacts are deleted.

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.

[Performance / Streaming] Resolve flow-control stream state once instead of per item

1 participant