Skip to content

Fix: preserve A2A3 early dispatch on queue overflow - #1812

Open
sjduan wants to merge 1 commit into
hw-native-sys:mainfrom
sjduan:fix/a2a3-early-dispatch-queue
Open

Fix: preserve A2A3 early dispatch on queue overflow#1812
sjduan wants to merge 1 commit into
hw-native-sys:mainfrom
sjduan:fix/a2a3-early-dispatch-queue

Conversation

@sjduan

@sjduan sjduan commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • increase the A2A3 per-shape early-dispatch candidate queue from 64 to 256;
  • roll an early-dispatch candidate from STAGING back to NONE when its
    initial queue publication fails, preserving the ordinary readiness path;
  • add a wiring test for the queue-overflow fallback.

Root cause

One wide producer may publish substantially more early-dispatch candidates
than there are physical cores. DeepSeek V4 EP8 routed experts expose the
boundary clearly: balanced 64-token routing creates 64 local gate/up MM
candidates and passes, while 96 or 128 tokens create a burst of 128 candidates
and can stall with the former 64-entry queue.

The scheduler also ignored push_tagged() failure after changing a candidate
from NONE to STAGING. An unqueued candidate could therefore remain in a
speculative state without an early-dispatch drain owning it. The rollback uses
a compare-exchange so a concurrent producer release continues to own any state
transition it has already made.

The larger queue absorbs the known wide-producer burst. The fallback keeps
overflow semantically safe rather than relying on capacity alone.

Validation

  • A2A3 test_wiring: all 37 tests pass, including the new
    EarlyDispatchQueueOverflowFallsBackToNormalDispatch case.
  • DeepSeek V4 EP8 MoE, 4 consecutive epochs, 128 tokens, all baseline
    allow_early_resolve hints: PASS.
  • DeepSeek V4 CP8/EP8/TP4 synthetic prefill forward:
    • 6 layers, 1 GiB ring heap: PASS;
    • 43 layers, 1 GiB ring heap: PASS with all persistent outputs accepted,
      finite/nonzero hidden states, and valid logits from both TP4 groups.

A diagnostic build retaining queue capacity 64 but adding the rollback made
the 96-token workload pass, while 128 tokens still stalled. This confirms that
the state fallback and sufficient publication-burst capacity are both needed.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 175eba71-703d-4f68-ac67-92026c989e3a

📥 Commits

Reviewing files that changed from the base of the PR and between e4ab544 and 7d3655d.

📒 Files selected for processing (3)
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/pto_runtime2_types.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/scheduler/pto_scheduler.h
  • tests/ut/cpp/a2a3/test_wiring.cpp

📝 Walkthrough

Walkthrough

The change expands the early-dispatch queue and adds explicit overflow handling. Failed initial enqueueing restores candidates to NONE unless concurrent dispatch already changed the state. A unit test verifies queue overflow fallback.

Changes

Early-dispatch overflow handling

Layer / File(s) Summary
Expand early-dispatch queue capacity
src/a2a3/runtime/tensormap_and_ringbuffer/runtime/pto_runtime2_types.h
The queue capacity increases from 64 to 256 entries. The description now covers larger producer bursts.
Handle enqueue failure and validate fallback
src/a2a3/runtime/tensormap_and_ringbuffer/runtime/scheduler/pto_scheduler.h, tests/ut/cpp/a2a3/test_wiring.cpp
The scheduler checks enqueue success and conditionally changes STAGING back to NONE. The test verifies overflow leaves the candidate in NONE and preserves the full queue.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

A rabbit saw the queue grow wide,
Two-fifty-six slots side by side.
If staging cannot hop aboard,
It returns to normal dispatch’s door.
Concurrent hops stay safe inside.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: preserving A2A3 early dispatch when the queue overflows.
Description check ✅ Passed The description directly explains the queue increase, rollback behavior, root cause, test coverage, and validation results.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

zhangqi-chen pushed a commit to hw-native-sys/pypto-lib that referenced this pull request Aug 13, 2026
- Add prefill_cp_layer.py, a single-layer CP prefill entry for SWA, HCA,
  and CSA that composes the inline CP attention cores with four
  fixed-size baseline MoE waves, keeping the attention, layer-stage, and
  MoE communication windows separately owned.
- Add prefill_cp_fwd.py, a synthetic multi-layer CP prefill forward whose
  schedule is SWA, SWA, a pl.range pair loop over CSA/HCA, and an
  import-time final-CSA branch, selected by --num-layers (6, 8, 10, or
  the production 43; default 8) with no Python layer unroll.
- Reuse one communication bank per domain across layers, ordered by
  monotonically increasing epochs, with the HCA and CSA compact signal
  banks kept distinct from the tail, stage, and MoE banks.
- Give the SWA, HCA, and CSA cores a completion_token Out param plus
  tail_comm_epoch and compact_comm_epoch_base scalars, and capture the
  leaf commit/transport TaskIds so a terminal rank_complete task fans
  them in through pl.system.task_dummy.
- Split the dual tail-exchange wave's epoch argument into payload_epoch
  and comm_epoch so the cross-layer tail counters advance independently
  of invocation-local payload rows.
- Publish the last hidden through an SPMD final clear, then an inlined
  hc_head and rms_norm, then a host-launched grouped device lm_head.
- Keep raw KV, compressed KV, index caches, and compressor states
  rank-local, propagated as InOut tensors.

CP == EP holds for CP2, CP4, and CP8, with TP2/TP4 final-head groups. The
forward calls the attention cores and moe directly rather than the
single-layer @pl.jit children, and the baseline MoE early-resolve hints
are untouched, so CP does not fork the MoE scheduling policy. EP8 needs
the A2A3 early-dispatch queue fix in hw-native-sys/simpler#1812: a routed
expert producer can publish 128 early-dispatch candidates against a
former per-shape queue capacity of 64. This builds on the CP attention
cores from #889, uses synthetic weights for the multi-layer forward, and
leaves real-weight serving, CP != EP, full 43-layer golden compare, and
performance overlap out of scope.
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