Skip to content

host_build_graph: fail-fast boot barriers on an out-of-range AICPU thread - #1566

Open
ChaoZheng109 wants to merge 1 commit into
hw-native-sys:mainfrom
ChaoZheng109:hbg-boot-barrier-abort
Open

host_build_graph: fail-fast boot barriers on an out-of-range AICPU thread#1566
ChaoZheng109 wants to merge 1 commit into
hw-native-sys:mainfrom
ChaoZheng109:hbg-boot-barrier-abort

Conversation

@ChaoZheng109

Copy link
Copy Markdown
Collaborator

What

Make the host_build_graph device-boot barriers fail fast instead of hanging when an AICPU thread gets an out-of-range thread_idx.

Follow-up to #1553 — addresses the boot-barrier deadlock flagged in review there (discussion).

Why

run() starts by validating thread_idx (from the affinity mapping, or the thread_idx_++ counter). On an out-of-range index it used to LOG_ERROR and return -1 before reaching either boot barrier:

  • the boot leader then spins forever on classify_arrived_ < aicpu_thread_num_ (the missing thread never arrives), and
  • finished_count_ never reaches aicpu_thread_num_, so finished_ never publishes.

Either way the whole op hangs into the op-execute timeout (507018) — the generic host code that masks the real cause, so it reads as a runtime hang rather than the misconfiguration it is.

The path is only reachable via a fatal platform misconfiguration (a broken affinity mapping, or run() invoked more than aicpu_thread_num_ times). It cannot happen under correct configuration — every thread gets a distinct valid index. This change is purely about turning that hang into a legible, fast failure.

How

One shared abort, closing both boot barriers (classify_arrived_ and finished_count_):

  • The invalid thread no longer returns early. It publishes a boot_abort_ flag, records the error, and falls through.
  • Every boot wait (classify_ready_, classify_arrived_, runtime_init_ready_) also breaks on boot_abort_, so a missing participant can never leave the rest spinning.
  • Dispatch is skipped under boot_abort_ on every thread. A run missing a core-owning thread can never reach is_completed(), so merely un-hanging the boot barriers would just move the hang into the dispatch loop — the survivors must fail fast, not run a graph that can never complete.
  • The invalid thread skips the index-keyed work (boot attach, its classify slice, shutdown) but still reaches the shared finish barrier, so finished_count_ always reaches aicpu_thread_num_ and finished_ publishes.
  • Every thread returns -1 on abort, so the host reads no partial success.

boot_abort_ is one-shot per run, reset in deinit() alongside the other boot flags. Boot/init path only — no dispatch-hot-path cost.

Note on the review suggestion

The reviewer proposed "a shared abort state checked by every boot wait, and route participants through normal shutdown." This does exactly that, with one refinement worth calling out: an out-of-range thread is routed to the finish barrier (so finished_ still publishes) but not through shutdown(thread_idx), because it owns no core slice keyed by that index — calling shutdown with the bad index would be the same class of bug. Valid threads still shutdown normally.

Scope

a2a3 host_build_graph only.

Test

matmul, vector_example, predicated_dispatch pass on a2a3 (device-locked) — the normal (all-valid-index) boot path is unchanged. The abort path is a misconfiguration guard; it is not exercised by the functional suite, which never produces an out-of-range index.

🤖 Generated with Claude Code

…read

An out-of-range thread_idx (a broken affinity mapping, or run() invoked
more than aicpu_thread_num_ times) returned -1 before reaching the
classify barrier and the finish barrier. The boot leader then spun
forever on `classify_arrived_ < aicpu_thread_num_`, and `finished_` never
reached the thread count — so the whole op hung into the op-execute
timeout (507018) that masks the real cause.

Route the invalid thread through a shared abort instead:

- A `boot_abort_` flag is published by any run() that cannot participate.
  Every boot wait (classify_ready_, classify_arrived_, runtime_init_ready_)
  also breaks on it, so a missing participant never leaves the rest
  spinning.
- Dispatch is skipped under boot_abort_ on every thread: a run missing a
  core-owning thread can never reach is_completed(), so the survivors
  would otherwise spin the dispatch loop forever rather than fail fast.
- The invalid thread skips the index-keyed work (boot, classify slice,
  shutdown) but still reaches the shared finish barrier, so finished_
  publishes and the host observes the failure promptly.
- Every thread returns -1 on abort so the host reads no partial success.

This closes both boot-barrier hangs (classify_arrived_ and
finished_count_) with one mechanism. The path is only reachable via a
fatal platform misconfiguration; the change converts the resulting hang
into a clean, legible failure. Scope: a2a3 host_build_graph only.
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

AicpuExecutor now coordinates out-of-range thread failures through shared barriers, prevents incomplete dispatch, handles shutdown selectively, reports aborted executions as failures, and resets the abort state during deinitialization.

Changes

AICPU boot-abort coordination

Layer / File(s) Summary
Abort state and validation
src/a2a3/runtime/host_build_graph/aicpu/aicpu_executor.cpp
Adds shared boot_abort_ state and records invalid thread indices in run_rc without leaving barrier coordination early.
Barrier and dispatch gating
src/a2a3/runtime/host_build_graph/aicpu/aicpu_executor.cpp
Updates classify barrier waits to observe boot_abort_ and skips dispatch scheduling for aborted runs.
Shutdown and run-state cleanup
src/a2a3/runtime/host_build_graph/aicpu/aicpu_executor.cpp
Skips shutdown for invalid threads, preserves valid shutdown errors, forces aborted runs to fail, and resets boot_abort_ during deinitialization.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Poem

I’m a bunny guarding the boot-time gate,
No lost thread shall make its partners wait.
Barriers wake, dispatch stays still,
Errors hop neatly up the hill.
Fresh runs start with flags reset—
A tidy burrow, safest yet! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: fail-fast handling for out-of-range AICPU thread boot barriers.
Description check ✅ Passed The description clearly matches the changeset and explains the fail-fast boot-abort behavior.
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.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/a2a3/runtime/host_build_graph/aicpu/aicpu_executor.cpp`:
- Around line 229-246: Update the run admission and shared finish-barrier logic
around valid_idx and finished_count_ so only the first aicpu_thread_num_
participants are admitted to the per-run cohort and may contribute to classify
or finish counters. Overflow invocations must set boot_abort_, return -1, and
bypass both barriers, preventing them from satisfying the configured finish
count or triggering premature runtime destruction; preserve normal behavior for
admitted participants.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ced891c4-3fdc-4629-b41e-05551f422c0a

📥 Commits

Reviewing files that changed from the base of the PR and between 321954b and ccdafbf.

📒 Files selected for processing (1)
  • src/a2a3/runtime/host_build_graph/aicpu/aicpu_executor.cpp

Comment on lines +229 to +246
// An out-of-range thread_idx — a broken affinity mapping, or run() invoked
// more than aicpu_thread_num_ times — cannot own the core slice or the
// per-index boot work, so it skips boot / classify / dispatch / shutdown. It
// is still one of the aicpu_thread_num_ run() invocations the finish barrier
// counts, and the boot barriers expect every participant to arrive. Publish
// boot_abort_ so peers stop spinning on classify_arrived_ / runtime_init_ready_
// and skip dispatch — a run missing a core-owning thread can never reach
// is_completed() — then fall through to the shared finish barrier so finished_
// still publishes and the host sees the failure instead of hanging into the
// op-execute timeout (507018).
const bool valid_idx = thread_idx >= 0 && thread_idx < aicpu_thread_num_ && thread_idx < MAX_AICPU_THREADS;
if (!valid_idx) {
LOG_ERROR(
"Thread index %d out of bounds (active=%d max=%d exec_idx=%d)", thread_idx, aicpu_thread_num_,
MAX_AICPU_THREADS, affinity_exec_idx
"Thread index %d out of bounds (active=%d max=%d exec_idx=%d) — aborting boot", thread_idx,
aicpu_thread_num_, MAX_AICPU_THREADS, affinity_exec_idx
);
return -1;
boot_abort_.store(true, std::memory_order_release);
run_rc = -1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Do not let an extra invocation satisfy the configured finish-barrier count.

For aicpu_thread_num_ = N, an (N+1)th call sets boot_abort_ but still reaches finished_count_.fetch_add(). If it finishes first, the Nth arrival destroys the runtime and triggers deinit() while one valid participant is still running. Track an admitted per-run cohort separately: only the first N participants may enter classify/finish counters; overflow calls should set the abort flag and return -1 without contributing to either barrier.

Also applies to: 334-340

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/a2a3/runtime/host_build_graph/aicpu/aicpu_executor.cpp` around lines 229
- 246, Update the run admission and shared finish-barrier logic around valid_idx
and finished_count_ so only the first aicpu_thread_num_ participants are
admitted to the per-run cohort and may contribute to classify or finish
counters. Overflow invocations must set boot_abort_, return -1, and bypass both
barriers, preventing them from satisfying the configured finish count or
triggering premature runtime destruction; preserve normal behavior for admitted
participants.

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