-
Notifications
You must be signed in to change notification settings - Fork 67
perf(a2a3/tmr): shrink dispatch cold-write cost on the sync_start drain #1328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
ChaoWao
merged 2 commits into
hw-native-sys:main
from
ChaoWao:perf/tmr-dispatch-drain-cold-writes
Jul 11, 2026
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
91 changes: 91 additions & 0 deletions
91
docs/investigations/2026-07-aicore-fills-all-args-ready-path.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| # AICore-side arg materialization for ALL dispatches (not just the gated path) | ||
|
|
||
| **Date**: 2026-07-11 | ||
| **Verdict**: measured and rejected for the ready path — making the AICore | ||
| fill its own `args[]` for **every** task adds **~1.0 µs to each task's | ||
| setup** (`receive → start`), on the critical path, because a ready task has | ||
| no idle doorbell gate to hide the fill behind. Offloading is only a win on | ||
| the `not_ready` (early-dispatch) path, where the AICore is already spinning | ||
| at the gate and absorbs the fill for free. The shipped design keeps the | ||
| AICPU filling `args[]` for ready tasks and offloads only gated ones. | ||
|
|
||
| ## Question | ||
|
|
||
| The tmr dispatch handoff writes the kernel `args[]` (tensor GM pointers + | ||
| scalar values) into the per-core `PTO2DispatchPayload` on the AICPU. For | ||
| gated (`not_ready` / early-dispatch) tasks we already offload that fill to | ||
| the AICore — it does it during its doorbell wait, off the AICPU dispatch | ||
| path (see the folded-gate `src_payload` design in the dispatch cold-write | ||
| PR). | ||
|
|
||
| Natural follow-on: why not offload the fill for **all** tasks and take the | ||
| `args[]` write off the AICPU entirely? What does that cost the AICore? | ||
|
|
||
| ## What was tried | ||
|
|
||
| An experiment build (not merged) that: | ||
|
|
||
| - Adds a separate `gated` flag to `PTO2DispatchPayload` — with all tasks | ||
| filling from source, `src_payload` is always non-zero and can no longer | ||
| double as the gate flag (the shipped design folds `not_ready` into | ||
| `src_payload == 0`). | ||
| - AICPU `build_payload` writes only `src_payload = &PTO2TaskPayload` and | ||
| `gated`, and **never** fills `args[]`. | ||
| - AICore `aicore_executor` fills `args[0..num_args)` from `src_payload` for | ||
| **every** task (moved out of the gate branch), then gates only when | ||
| `gated`. | ||
|
|
||
| Measured `paged_attention_unroll` (`--enable-l2-swimlane`, 1024 AICore | ||
| tasks, a2a3 silicon) and read each task's AICore setup — | ||
| `receive_to_start_cycles` from `l2_swimlane_records.json::aicore_tasks` | ||
| (50 MHz → 20 ns/cycle). | ||
|
|
||
| ## Result | ||
|
|
||
| | build | AICore setup (`receive → start`) | | ||
| | ----- | -------------------------------- | | ||
| | baseline (AICPU fills args) | mean **349 ns** / p50 320 ns | | ||
| | experiment (AICore fills **all**) | mean **1356 ns** / p50 1340 ns | | ||
| | **delta** | **+~1.0 µs/task (+50 cycles, ~4×)** | | ||
|
|
||
| Correctness held (`paged_attention_unroll` passes), so the AICore fill is | ||
| functionally equivalent — it just costs ~1 µs. The fill is AICore GM work: | ||
| after the per-task whole-cache `dcci(ENTIRE_DATA_CACHE)`, the first reads of | ||
| the source `PTO2TaskPayload` (counts, scalars) miss to HBM, then the loop | ||
| computes `&tensors[i]` and writes `args[]` — all on a core whose GM-access | ||
| latency is high. On the **ready** path there is no doorbell wait to overlap | ||
| it with, so the whole ~1 µs lands on the `receive → start` setup. | ||
|
|
||
| ## Why the shipped design offloads only the gated path | ||
|
|
||
| - **Gated (`not_ready`) tasks are staged before their producer completes**; | ||
| the AICore then spins at the doorbell gate. The ~1 µs fill runs inside | ||
| that otherwise-idle wait → net ~zero, and it takes the `args[]` write off | ||
| the AICPU dispatch path (the win we wanted). | ||
| - **Ready tasks execute on pickup** — no gate, no idle window. Offloading | ||
| the fill there is a straight +~1 µs/task regression on the AICore | ||
| critical path. For an AICore-bound workload (e.g. `paged_attention`, | ||
| 1024 tasks) that is a large, unhideable cost. | ||
|
|
||
| So the asymmetry is intrinsic: offload where there is idle time to spend | ||
| (gated), keep it on the AICPU where the AICore would otherwise stall | ||
| (ready). | ||
|
|
||
| ## When to reconsider | ||
|
|
||
| - If a future protocol gives ready tasks an idle window between pickup and | ||
| the point their inputs are guaranteed visible (today the kernel's input | ||
| `dcci` runs right after ACK), the fill could hide there — re-measure. | ||
| - If the AICPU dispatch path becomes the proven end-to-end bottleneck for a | ||
| ready-dominated workload AND the AICore has spare setup budget (setup ≪ | ||
| the WAIT/exec time), the trade could flip — but weigh against the ~1 µs | ||
| measured here, and note it scales with per-task arg count. | ||
|
|
||
| ## References | ||
|
|
||
| - Dispatch cold-write PR (folded-gate `src_payload`, AICore fill on the | ||
| gated path, init prefill, deferred-slab-at-completion, prefetch): | ||
| hw-native-sys/simpler#1328. | ||
| - [2026-07 — L2 swimlane AICore switch-overhead](2026-07-aicore-swimlane-switch-overhead-and-ack-gate.md) | ||
| — the baseline ~0.28–0.35 µs AICore setup (`payload dcci + ACK`) this | ||
| experiment adds onto. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.