Skip to content

perf(runtime): cut TMARB preamble ~72us -> ~9us via report-first + batched handshake#1323

Merged
ChaoWao merged 1 commit into
hw-native-sys:mainfrom
ChaoWao:perf/preamble-reportfirst-batched-handshake
Jul 10, 2026
Merged

perf(runtime): cut TMARB preamble ~72us -> ~9us via report-first + batched handshake#1323
ChaoWao merged 1 commit into
hw-native-sys:mainfrom
ChaoWao:perf/preamble-reportfirst-batched-handshake

Conversation

@ChaoWao

@ChaoWao ChaoWao commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Reworks the AICPU init / AICore handshake to cut the TMARB preamble from ~72µs to ~9µs/step (a2a3 onboard, spmd_paged_attention_highperf s8192, from the device_wall STRACE markers). Applied symmetrically to a2a3 and a5.

  1. Drop the per-round 256KB post_handshake_init memset (~55µs → 0). It zeroed payload_per_core_ + deferred_slab_per_core_ every boot, but prepare_subtask_to_core rewrites every field a slot exposes before the AICore is told to read it, so a prior round's bytes are structurally unreachable.

  2. Report-first AICore handshake (pypto-style), removing the AICPU→AICore round-trip (hs_ready2first ~5µs → ~0.3µs). The AICore publishes {physical_core_id, core_type, aicore_done} on launch without waiting for an aicpu_ready gate; launched before the AICPU, its report is already in GM when the AICPU sweeps. Window-open replaces aicpu_ready as the sync point.

    • task is written per core after aicore_done is observed (else the core's CACHELINE_OUT report flush clobbers it); the core dcci-reads it after window-open.
    • Freshness: the host zeros each worker's aicore_done before launch_aicore_kernel (workers persist across runs in the pooled arena), so the AICPU never opens a window on a stale physical_core_id.
  3. Batch the AICPU's per-core servicing in the handshake sweep (~5µs → ~1.6µs). Report-first means all cores are reported when the AICPU sweeps (single pass), so instead of servicing each core inline (interleaved store-through GM write + posted MMIO STR + barrier, each stalling the next) the sweep runs in phases: collect + prefetch CoreExecState lines → publish all task pointers under one barrier → open all windows back-to-back (pipelined nGnRE STRs) → publish each CoreExecState with a single struct store.

  4. Batch the worker-id list build in post_handshake_init (~3.7µs → ~0.3µs). core_type is read from a compact contiguous array the sweep fills; the aic/aiv lists are built in local buffers and published with two wide memcpys (direct 4-byte stores into the GM members cost ~50ns each, store-through to HBM).

Residual ~9µs is the front-matter (pre_handshake_init, barrier wait, post_handshake_init tail) plus the ~2 MMIO opens/core that cannot move off the AICPU (the AICore cannot self-open its SPR window). Getting below this needs persistent workers, out of scope here.

Testing

  • a2a3 onboard: 20 rounds of spmd_paged_attention_highperf s8192 + 6 examples (spmd_paged_attention_highperf, spmd_multiblock_mix, multi_round_paged_attention, spmd_basic, dummy_task, alternating_matmul_add) pass
  • a5 sim: spmd_multiblock_mix, dummy_task pass
  • a5 onboard: rides CI (dev box is a2a3 silicon)

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cf9a2b89-7895-4695-93fc-5c5699635474

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The A2A3 and A5 runtimes now use a report-first AICPU–AICore handshake. Worker completion flags are reset before launch, register-window setup is batched after AICore reports, compact core metadata supports post-handshake initialization, and dispatch slots no longer receive per-boot clearing.

Changes

AICPU–AICore handshake protocol

Layer / File(s) Summary
Worker launch state reset
src/a2a3/platform/onboard/host/device_runner.cpp, src/a5/platform/onboard/host/device_runner.cpp
aicore_done is cleared for every worker before launching the AICore kernel.
Report-first handshake servicing
src/a2a3/runtime/tensormap_and_ringbuffer/aicore/aicore_executor.cpp, src/a5/runtime/tensormap_and_ringbuffer/aicore/aicore_executor.cpp, src/a2a3/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler_cold_path.cpp, src/a5/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler_cold_path.cpp
AICore reports identity and completion before polling DATA_MAIN_BASE; the scheduler batches task-pointer publication, register-window opening, and CoreExecState updates.
Post-handshake metadata and dispatch initialization
src/a2a3/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler_context.h, src/a5/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler_context.h, src/a2a3/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler_cold_path.cpp, src/a5/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler_cold_path.cpp
Compact core types drive AIC/AIV worker-list construction, while payload and deferred-slab slots are no longer zeroed during initialization.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DeviceRunner
  participant AICoreExecutor
  participant SchedulerContext
  DeviceRunner->>AICoreExecutor: launch with cleared aicore_done
  AICoreExecutor->>SchedulerContext: publish core identity and aicore_done
  SchedulerContext->>SchedulerContext: collect and batch reported cores
  SchedulerContext->>AICoreExecutor: publish task pointer and open register window
  AICoreExecutor->>SchedulerContext: poll DATA_MAIN_BASE and fetch dispatch payload
Loading

Possibly related PRs

Poem

A bunny reset flags before kernels took flight,
Then AICore reported its name in the light.
Windows opened, task pointers hopped through,
Compact core types kept worker lists true.
“Batch the handshake!” sang the rabbit crew.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 56.25% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main performance change: a report-first, batched handshake to reduce TMARB preamble latency.
Description check ✅ Passed The description is directly aligned with the changeset and explains the handshake, batching, and memset removal work.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request implements a "report-first" handshake protocol between the AICore and AICPU across the a2a3 and a5 platforms. Instead of waiting for an AICPU initialization signal, the AICore now immediately reports its physical core ID and core type on launch. The host clears aicore_done before kernel launch to ensure freshness. Additionally, the scheduler's handshake partitioning and core discovery are optimized through batched phases, prefetching, and the use of a compact core-type array to reduce HBM write stalls and eliminate unnecessary zeroing. As there are no review comments provided, I have no additional feedback to offer.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@ChaoWao ChaoWao force-pushed the perf/preamble-reportfirst-batched-handshake branch from 33ad605 to b157389 Compare July 10, 2026 13:47
Reworks the AICPU init / AICore handshake, applied symmetrically to both
arches. Measured on a2a3 onboard (spmd_paged_attention_highperf s8192,
per-step preamble from the device_wall STRACE markers); a5 rides CI.

1. Drop the per-round 256KB post_handshake_init memset (~55us -> 0).
   It zeroed payload_per_core_ + deferred_slab_per_core_ every boot, but
   prepare_subtask_to_core rewrites every field a slot exposes before the
   AICore is told to read it, so a prior round's bytes are structurally
   unreachable.

2. Report-first AICore handshake (pypto-style), removing the AICPU->AICore
   round-trip (hs_ready2first ~5us -> ~0.3us). The AICore publishes
   {physical_core_id, core_type, aicore_done} on launch without waiting for an
   aicpu_ready gate; launched before the AICPU, its report is already in GM
   when the AICPU sweeps. Window-open replaces aicpu_ready as the sync point.
   - task is written per core AFTER aicore_done is observed (else the core's
     CACHELINE_OUT report flush clobbers it); the core dcci-reads it after
     window-open.
   - Freshness: the host zeros each worker's aicore_done before
     launch_aicore_kernel (workers persist across runs in the pooled arena),
     so the AICPU never opens a window on a stale physical_core_id.

3. Batch the AICPU's per-core servicing (the handshake sweep, ~5us -> ~1.6us).
   Report-first means all cores are reported when the AICPU sweeps
   (n_passes==1), so instead of servicing each core inline (interleaved GM
   store-through + posted MMIO STR + barrier, each stalling the next) the sweep
   runs in phases: collect + prefetch CoreExecState lines, publish all task
   pointers under ONE barrier, open all windows back-to-back (pipelined nGnRE
   STRs), then publish each CoreExecState with a single struct store.

4. Batch the worker-id list build in post_handshake_init (~3.7us -> ~0.3us).
   core_type is read from a compact contiguous array the sweep fills; the
   aic/aiv lists are built in local buffers and published with two wide memcpys
   (direct 4-byte stores into the GM members cost ~50ns each, store-through).

Residual ~9us: the front-matter (pre_handshake_init, barrier wait,
post_handshake_init tail) plus the ~2 MMIO opens/core that cannot move off the
AICPU (AICore cannot self-open its SPR window). Getting below this needs
persistent workers, out of scope here.

Validated: a2a3 onboard 20 rounds + 6 examples (paged_attention_highperf,
spmd_multiblock_mix, multi_round_paged_attention, spmd_basic, dummy_task,
alternating_matmul_add) green; a5 sim (spmd_multiblock_mix, dummy_task) green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ChaoWao ChaoWao merged commit 0abbffd into hw-native-sys:main Jul 10, 2026
3 checks passed
@ChaoWao ChaoWao deleted the perf/preamble-reportfirst-batched-handshake branch July 10, 2026 13:54
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