feat(a2a3/dispatch): sync_start strict Tier-0 + shared staging order#1319
Conversation
…mal and early dispatch_ready_tasks and try_early_dispatch each carried a hand-mirrored copy of the same occupancy order (MIX strict priority, IDLE before PENDING, cross-thread idle gating). Extract it into one run_staging_order helper parameterized by the per-shape stage callback: normal passes dispatch_shape (pickup, is_ready) and signals stop via entered_drain; early passes early_dispatch_shape (gated) and never stops. Behavior-identical — same order, gates, PMU handling, and progress accounting; the two sources now differ only in the stage callback (is_ready). Verified golden-exact: a2a3sim 13 scene tests, a2a3 onboard 10 scene tests (sync_start family, MIX, starvation, paged-attention, alternating) all pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe scheduler adds per-resource-shape ChangesSync-start scheduler flow
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
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. Comment |
|
Warning Gemini encountered an error creating the review. You can try again by commenting |
2c61182 to
3b5cb55
Compare
…atch Normal-source sync_start cohorts previously rode ready_queues[shape] mixed with regular tasks, so an AIC/AIV sync waited behind regular MIX work — the occupancy order was MIX > C/V with no sync tier. Give sync_start strict priority within the normal source (sync_start > MIX > C/V, idle > pending) by parking ready sync_start cohorts in dedicated per-shape ready_sync_queues[] and draining them as a Tier-0 pass before regular ready work. The Tier-0 pass reuses dispatch_shape unchanged (now parameterized by the queue array): same fits-local inline vs stop-the-world drain decision, per-core MIX placement, and per-task head-start spacing. The regular tier passes ready_queues exactly as before, so regular dispatch is byte-identical. early dispatch already sits strictly after all normal work; its gate now also drains the sync lanes so early never preempts a queued normal sync. Verified: a2a3sim 14 scene tests; a2a3 onboard 9 scene tests + 30x spmd_sync_start_stress (0 failures, no 507018). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…gbuffer hbg's scheduler was a copy of tmr@fb28fd71 and had fallen a full generation behind. This absorbs tmr's post-fork scheduler evolution while preserving hbg's host-orchestration invariants (single ring, no execution-time reclaim, flat Runtime, host-side orchestrator). Absorbed from tmr: - Remove PTO2LocalReadyBuffer local-first dispatch and its local_bufs threading (hw-native-sys#1245); pop/dispatch now take PTO2ReadyQueue* directly. - Ready-claim completion protocol: ready_state / mark_completed / mark_any_subtask_deferred (replaces the any_subtask_deferred bool). - Rename speculative -> early_dispatch and remove the auto-chain (spec_chain_active/depth, PTO2_SPEC_CHAIN_MAX); move allow_early_resolve from payload onto slot_state. - Per-shape early_dispatch_queues[] (was a single queue) + ready_sync_queues[] Tier-0 sync_start staging (hw-native-sys#1319); run_staging_order template; try_early_dispatch / early_dispatch_shape; has_any_free_slot predicates. - MIX subtasks placed per-core instead of uniform cluster placement (hw-native-sys#1308). - Remove the on-device wiring subsystem (PTO2SpscQueue / WiringState / drain_wiring_queue / wire_task, hw-native-sys#1263): the host orchestrator now wires fanout adjacency inline during submit and seeds readiness via the scheduler's push_ready_routed / route_ready_once, with no device-side wiring queue. - Single-round-trip / parallel AICore handshake (hw-native-sys#1279/hw-native-sys#1310): handshake_all_cores -> pre_handshake_init + per-thread handshake_partition + post_handshake_init, with the matching aicpu_executor boot restructure and AICore-worker protocol. - Drop the per-run per-core memset in scheduler init/deinit (hw-native-sys#1212); gate dep_gen init under SIMPLER_DFX; compile out pmu_active when SIMPLER_DFX is off; remove the redundant second completion poll; remove the dead device-orch core transition (handle_core_transition / reassign_cores_for_all_threads / orch_to_sched_). Remove vestigial device-orch synchronization: with host orchestration the orchestrator runs to completion on the host before the device boots, so the device-side orchestrator_done_ flag is always set before the scheduler threads start (they gate on runtime_init_ready_, whose release/acquire already publishes total_tasks_). Removed orchestrator_done_, the always-true completion guard, and the never-called wait_for_orchestration_done_before_dispatch / orchestration_done() carried over from tmr's concurrent device-orch model. Preserved host-orch divergences (not overwritten by tmr): PTO2_MAX_RING_DEPTH==1 with rings[]/ring_id removed; no advance_ring_pointers / reset_for_reuse / check_and_handle_consumed (completion via completed_tasks_, consumer wait keys on fanout_refcount); flat runtime->workers; hbg's swimlane behavior (no on_aicore_ack hook — the just-filled buffer drains via the completion-before-dispatch invariant and the next-rotation / run-end backstop flushes). Skipped as not applicable to hbg: stall-classification publishing (shared-memory lacks the sched_stall_* fields; last_task_alive semantics differ); per-device scheduler timeout (aicpu_device_config.h / get_scheduler_timeout_ms absent); runtime->dev.* Runtime nesting. get_reg_ptr weak host fallback: route_ready_once transitively ODR-uses the early-dispatch doorbell inline (ring_one_doorbell -> get_reg_ptr) in the host lib, but no core is gated during host graph-build so it never fires; a weak hidden fallback satisfies the loader (same pattern as get_sys_cnt_aicpu). Verified: all 8 runtime targets build -Werror; a2a3sim host_build_graph scene suite 10/10; a2a3 onboard host_build_graph suite 10 passed / 1 skipped (paged_attention exercises the new handshake, route_ready_once wiring, and ready-claim path). tensormap_and_ringbuffer and the a5 runtimes are untouched.
…gbuffer hbg's scheduler was a copy of tmr@fb28fd71 and had fallen a full generation behind. This absorbs tmr's post-fork scheduler evolution while preserving hbg's host-orchestration invariants (single ring, no execution-time reclaim, flat Runtime, host-side orchestrator). Absorbed from tmr: - Remove PTO2LocalReadyBuffer local-first dispatch and its local_bufs threading (hw-native-sys#1245); pop/dispatch now take PTO2ReadyQueue* directly. - Ready-claim completion protocol: ready_state / mark_completed / mark_any_subtask_deferred (replaces the any_subtask_deferred bool). - Rename speculative -> early_dispatch and remove the auto-chain (spec_chain_active/depth, PTO2_SPEC_CHAIN_MAX); move allow_early_resolve from payload onto slot_state. - Per-shape early_dispatch_queues[] (was a single queue) + ready_sync_queues[] Tier-0 sync_start staging (hw-native-sys#1319); run_staging_order template; try_early_dispatch / early_dispatch_shape; has_any_free_slot predicates. - MIX subtasks placed per-core instead of uniform cluster placement (hw-native-sys#1308). - Remove the on-device wiring subsystem (PTO2SpscQueue / WiringState / drain_wiring_queue / wire_task, hw-native-sys#1263): the host orchestrator now wires fanout adjacency inline during submit and seeds readiness via the scheduler's push_ready_routed / route_ready_once, with no device-side wiring queue. - Single-round-trip / parallel AICore handshake (hw-native-sys#1279/hw-native-sys#1310): handshake_all_cores -> pre_handshake_init + per-thread handshake_partition + post_handshake_init, with the matching aicpu_executor boot restructure and AICore-worker protocol. Drop the now-dead two-round-trip Handshake fields aicpu_regs_ready / aicore_regs_ready (aligning the struct to tmr's). - Drop the per-run per-core memset in scheduler init/deinit (hw-native-sys#1212); gate dep_gen init under SIMPLER_DFX; compile out pmu_active when SIMPLER_DFX is off; remove the redundant second completion poll; remove the dead device-orch core transition (handle_core_transition / reassign_cores_for_all_threads / orch_to_sched_). Remove vestigial device-orch synchronization: with host orchestration the orchestrator runs to completion on the host before the device boots, so the device-side orchestrator_done_ flag is always set before the scheduler threads start (they gate on runtime_init_ready_, whose release/acquire already publishes total_tasks_). Removed orchestrator_done_, the always-true completion guard, and the never-called wait_for_orchestration_done_before_dispatch / orchestration_done() carried over from tmr's concurrent device-orch model. Preserved host-orch divergences (not overwritten by tmr): PTO2_MAX_RING_DEPTH==1 with rings[]/ring_id removed; no advance_ring_pointers / reset_for_reuse / check_and_handle_consumed (completion via completed_tasks_, consumer wait keys on fanout_refcount); flat runtime->workers; hbg's swimlane behavior (no on_aicore_ack hook — the just-filled buffer drains via the completion-before-dispatch invariant and the next-rotation / run-end backstop flushes). Skipped as not applicable to hbg: stall-classification publishing (shared-memory lacks the sched_stall_* fields; last_task_alive semantics differ); per-device scheduler timeout (aicpu_device_config.h / get_scheduler_timeout_ms absent); runtime->dev.* Runtime nesting. get_reg_ptr weak host fallback: route_ready_once transitively ODR-uses the early-dispatch doorbell inline (ring_one_doorbell -> get_reg_ptr) in the host lib, but no core is gated during host graph-build so it never fires; a weak hidden fallback satisfies the loader (same pattern as get_sys_cnt_aicpu). Verified: all 8 runtime targets build -Werror; a2a3sim host_build_graph scene suite 10/10; a2a3 onboard host_build_graph suite 10 passed / 1 skipped (paged_attention exercises the new handshake, route_ready_once wiring, and ready-claim path). tensormap_and_ringbuffer and the a5 runtimes are untouched.
…gbuffer (#1327) hbg's scheduler was a copy of tmr@fb28fd71 and had fallen a full generation behind. This absorbs tmr's post-fork scheduler evolution while preserving hbg's host-orchestration invariants (single ring, no execution-time reclaim, flat Runtime, host-side orchestrator). Absorbed from tmr: - Remove PTO2LocalReadyBuffer local-first dispatch and its local_bufs threading (#1245); pop/dispatch now take PTO2ReadyQueue* directly. - Ready-claim completion protocol: ready_state / mark_completed / mark_any_subtask_deferred (replaces the any_subtask_deferred bool). - Rename speculative -> early_dispatch and remove the auto-chain (spec_chain_active/depth, PTO2_SPEC_CHAIN_MAX); move allow_early_resolve from payload onto slot_state. - Per-shape early_dispatch_queues[] (was a single queue) + ready_sync_queues[] Tier-0 sync_start staging (#1319); run_staging_order template; try_early_dispatch / early_dispatch_shape; has_any_free_slot predicates. - MIX subtasks placed per-core instead of uniform cluster placement (#1308). - Remove the on-device wiring subsystem (PTO2SpscQueue / WiringState / drain_wiring_queue / wire_task, #1263): the host orchestrator now wires fanout adjacency inline during submit and seeds readiness via the scheduler's push_ready_routed / route_ready_once, with no device-side wiring queue. - Single-round-trip / parallel AICore handshake (#1279/#1310): handshake_all_cores -> pre_handshake_init + per-thread handshake_partition + post_handshake_init, with the matching aicpu_executor boot restructure and AICore-worker protocol. Drop the now-dead two-round-trip Handshake fields aicpu_regs_ready / aicore_regs_ready (aligning the struct to tmr's). - Drop the per-run per-core memset in scheduler init/deinit (#1212); gate dep_gen init under SIMPLER_DFX; compile out pmu_active when SIMPLER_DFX is off; remove the redundant second completion poll; remove the dead device-orch core transition (handle_core_transition / reassign_cores_for_all_threads / orch_to_sched_). Remove vestigial device-orch synchronization: with host orchestration the orchestrator runs to completion on the host before the device boots, so the device-side orchestrator_done_ flag is always set before the scheduler threads start (they gate on runtime_init_ready_, whose release/acquire already publishes total_tasks_). Removed orchestrator_done_, the always-true completion guard, and the never-called wait_for_orchestration_done_before_dispatch / orchestration_done() carried over from tmr's concurrent device-orch model. Preserved host-orch divergences (not overwritten by tmr): PTO2_MAX_RING_DEPTH==1 with rings[]/ring_id removed; no advance_ring_pointers / reset_for_reuse / check_and_handle_consumed (completion via completed_tasks_, consumer wait keys on fanout_refcount); flat runtime->workers; hbg's swimlane behavior (no on_aicore_ack hook — the just-filled buffer drains via the completion-before-dispatch invariant and the next-rotation / run-end backstop flushes). Skipped as not applicable to hbg: stall-classification publishing (shared-memory lacks the sched_stall_* fields; last_task_alive semantics differ); per-device scheduler timeout (aicpu_device_config.h / get_scheduler_timeout_ms absent); runtime->dev.* Runtime nesting. get_reg_ptr weak host fallback: route_ready_once transitively ODR-uses the early-dispatch doorbell inline (ring_one_doorbell -> get_reg_ptr) in the host lib, but no core is gated during host graph-build so it never fires; a weak hidden fallback satisfies the loader (same pattern as get_sys_cnt_aicpu). Verified: all 8 runtime targets build -Werror; a2a3sim host_build_graph scene suite 10/10; a2a3 onboard host_build_graph suite 10 passed / 1 skipped (paged_attention exercises the new handshake, route_ready_once wiring, and ready-claim path). tensormap_and_ringbuffer and the a5 runtimes are untouched.
…gbuffer (#1335) Follows PR #1327 (which synced hbg's scheduler to tmr's #1319 state). tmr then landed five more early-dispatch changes on the same subsystem; this ports them into host_build_graph's copies, preserving hbg's host-orchestration invariants (single ring, no execution-time reclaim, flat Runtime, no ACK-gate, host-side orchestrator). Absorbed from tmr: - #1304 Add early-dispatch for require_sync_start SPMD cohorts, incl. the drain_stage_cores parallel-drain refactor (handle_drain_mode two-stage). - #1326 Defer early dispatch until producer publication (correctness/race): published_block_count + record_published_blocks; propagate_dispatch_fanin is gated on published_block_count >= logical_block_num; the published_list ledger in dispatch and the stage_consumer_blocks two-sided publication/release handshake. - #1328 Shrink dispatch cold-write cost via a folded-gate src_payload (PTO2DispatchPayload: not_ready -> volatile uint64_t src_payload, 0 = ready, non-zero = gated source PTO2TaskPayload address; global_context to the tail; the PTO2_TASKPAYLOAD_*_OFFSET constants + static_asserts). build_payload writes args on the ready path and only src_payload on the gated path; the idle AICore fills args[] from src_payload during its doorbell wait; init-time prefill of async_ctx slab pointers/capacity + context-ptr args; deferred_slab reset moved off the dispatch path; software-pipelined prefetch of the next block. - #1329 Make early-dispatch doorbell ownership exclusive (correctness). - #1331 Serialize block range claims (correctness): every block-range claim now goes through slot_state->claim_block_range(...) instead of an inline next_block_idx CAS. Preserved host-orch divergences (not overwritten by tmr): PTO2_MAX_RING_DEPTH==1 with rings[]/ring_id removed; no advance_ring_pointers / reset_for_reuse / check_and_handle_consumed (completion via completed_tasks_, consumer wait keys on fanout_refcount); flat runtime->workers / runtime->func_id_to_addr_ (not runtime->dev.*); pto_runtime2_types.h keeps its dropped pto2_dispatch_payload.h include; hbg's AICore FIN-vs-swimlane-record ordering and its no-ACK-gate completion path (drains via completion-before-dispatch + backstop flushes); no device orchestrator (orchestrator_done_ absent, scheduler threads gate on runtime_init_ready_). Out of scope (unrelated tmr changes hbg still lacks, tracked for a follow-up): per-device scheduler timeout (get_scheduler_timeout_ms), PTO2_TENSOR_DATA_TIMEOUT MS-vs-cycles (#1189), stall sub-classification (#1182), runtime scope_tasks_cap (#1188). Verified: all 8 runtime targets build -Werror; a2a3sim host_build_graph scene suite 10/10; a2a3 onboard host_build_graph suite 10 passed / 1 skipped (paged_attention exercises the new claim_block_range serialization, drain_stage_cores drain, src_payload gated arg-fill, and published-block gating). tensormap_and_ringbuffer and the a5 runtimes are untouched.
Summary
Aligns the a2a3
tensormap_and_ringbufferscheduler dispatch with a singleoccupancy model: two task sources (normal ready ▸ speculative early), and
within each source
sync_start > MIX > C/V,idle > pending. Two commits:refactor — one shared staging-order skeleton.
dispatch_ready_tasksandtry_early_dispatcheach carried a hand-mirrored copy of the same order (MIXstrict priority, IDLE before PENDING, cross-thread idle gating). Extract it
into one
run_staging_orderhelper parameterized by the per-shape stagecallback; the two sources now differ only in that callback (normal = pickup /
is_ready, early = gated). Behavior-identical.feat — ready
sync_startas strict Tier-0 in normal dispatch. Normalsync_start cohorts previously rode
ready_queues[shape]mixed with regulartasks, so an AIC/AIV sync waited behind regular MIX. Park ready sync_start in
dedicated per-shape
ready_sync_queues[]and drain them as a Tier-0 passbefore regular ready work. The pass reuses
dispatch_shapeunchanged(now parameterized by the queue array): same fits-local-inline vs
stop-the-world drain decision, per-core MIX placement, per-task head-start
spacing. The regular tier passes
ready_queuesexactly as before, so regulardispatch is byte-identical; the early-dispatch gate now also drains the sync
lanes so early never preempts a queued normal sync.
Scope / notes
tensormap_and_ringbufferonly. Regular dispatch path unchanged;risk is isolated to the new sync Tier-0 pass and the shared-order extraction.
normal-source sync tier + the order unification; the early-source sync
tier lands separately.
Testing
attention, alternating, fanin, oob) — pass.
spmd_sync_start_stressx30, 0 failures, no 507018.
🤖 Generated with Claude Code