Skip to content

Refactor: split device enqueue from completion drain - #1683

Merged
ChaoWao merged 1 commit into
hw-native-sys:mainfrom
ChaoWao:worker-async-b6a-enqueue-drain
Aug 4, 2026
Merged

Refactor: split device enqueue from completion drain#1683
ChaoWao merged 1 commit into
hw-native-sys:mainfrom
ChaoWao:worker-async-b6a-enqueue-drain

Conversation

@ChaoWao

@ChaoWao ChaoWao commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Split DeviceRunner execution into enqueue, nonblocking poll, and drain across a2a3/a5 onboard and simulation backends.
  • Retain the compatibility executor and current public completion semantics while establishing the completion-query seam needed by the next change.
  • Keep run-owned streams, simulated threads, DFX state, and cleanup alive through drain; serialize a2a3 query/retirement and publish completion only after a proven device fence.
  • Update lifecycle documentation and add deterministic state-machine coverage.

Testing

  • Build all 8 runtime variants: a2a3sim/a5sim/a2a3/a5, HBG/TMR
  • Focused C++ tests: run-stream slots, sim completion, launch signal
  • a2a3sim native-run lifecycle
  • a5sim vector smoke
  • a2a3 onboard native-run lifecycle
  • a2a3 onboard async endpoint (concurrent rtStreamQuery/drain path)
  • Pre-commit hooks, including clang-tidy, cpplint, and markdownlint
  • a5 onboard hardware (local host is a2a3; defer to CI)

@coderabbitai

coderabbitai Bot commented Aug 4, 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 Plus

Run ID: 1dd07f19-e6ee-41fe-970c-a019cca3fff3

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 runner API now separates execution into enqueue_run, poll_run, and drain_run. Compatibility run wrappers remain. Onboard and simulation implementations track asynchronous ownership, completion, cleanup, stream retirement, and device recovery. Documentation and tests reflect the new lifecycle.

Changes

Execution lifecycle

Layer / File(s) Summary
Lifecycle contracts and completion primitives
src/common/platform/..., src/common/worker/..., src/common/platform/sim/...
Runner interfaces now define enqueue, poll, and drain phases. Stream slots and simulation completion state track asynchronous completion and errors.
A2/A3 onboard runner phases
src/a2a3/platform/onboard/host/device_runner.*
A2/A3 onboard execution launches asynchronously, polls stream pairs, drains resources, retires streams with completion status, and updates device recovery state atomically.
A5 onboard runner phases
src/a5/platform/onboard/host/device_runner.*
A5 onboard execution adds slot validation, run-state ownership, enqueue rollback, drain cleanup, and atomic poisoned-device handling.
Simulation runner phases
src/a2a3/platform/sim/host/device_runner.*, src/a5/platform/sim/host/device_runner.*
Simulation runners retain active-run state and worker threads across enqueue and drain. Completion and execution errors are reported through SimRunCompletion.
Polling integration, documentation, and validation
src/common/platform/*/host/c_api_shared.cpp, docs/*, src/*/docs/*, tests/ut/cpp/*
C API polling waits for host cleanup before terminal completion. Lifecycle documentation, dynamic-linking descriptions, and unit tests were updated.

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

Possibly related PRs

Poem

A rabbit sees enqueue hop,
Polling checks but does not stop.
Drain joins threads and frees the way,
Streams retire when work says “okay.”
Errors stick, then cleanup’s done—
Async runners now run as one!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.88% 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 and concisely describes the main change: separating device enqueue from completion drain.
Description check ✅ Passed The description directly explains the enqueue, poll, and drain refactor, preserved completion semantics, resource lifetime, and testing.
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: 3

🧹 Nitpick comments (1)
tests/ut/cpp/common/test_sim_run_completion.cpp (1)

40-40: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert sticky terminal polling.

After the final task completes, call completion.poll() a second time. The current tests verify the first terminal result only. They do not verify the sticky result.

Proposed test coverage
     task.join();
     EXPECT_EQ(completion.poll(), SIMPLER_NATIVE_RUN_POLL_COMPLETE);
+    EXPECT_EQ(completion.poll(), SIMPLER_NATIVE_RUN_POLL_COMPLETE);
     EXPECT_EQ(completion.first_error(), 0);
@@
     completion.task_finished(-9);
     EXPECT_EQ(completion.poll(), SIMPLER_NATIVE_RUN_POLL_COMPLETE);
+    EXPECT_EQ(completion.poll(), SIMPLER_NATIVE_RUN_POLL_COMPLETE);
     EXPECT_EQ(completion.first_error(), -7);

Also applies to: 53-53

🤖 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 `@tests/ut/cpp/common/test_sim_run_completion.cpp` at line 40, Extend the
completion assertions in the test around completion.poll() to invoke it a second
time after the final task completes, and assert that the repeated call also
returns SIMPLER_NATIVE_RUN_POLL_COMPLETE, covering sticky terminal polling at
both referenced test cases.
🤖 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/platform/sim/host/device_runner.cpp`:
- Around line 296-307: The enqueue_run method arms run_completion_.reset(1)
before the final task count is known, and if initialization fails,
cleanup_active_run() will null out active_run_ while poll_run() may still return
SIMPLER_NATIVE_RUN_POLL_NOT_READY, creating a state mismatch. Fix this in both
src/a2a3/platform/sim/host/device_runner.cpp (lines 296-307) and
src/a5/platform/sim/host/device_runner.cpp (lines 251-262) by either making
cleanup_active_run() publish a terminal completion state to run_completion_, or
making poll_run() check if active_run_ is nullptr and return a terminal error
code instead of NOT_READY. Apply the same solution to both files to keep them
consistent.

In `@src/a2a3/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp`:
- Line 969: Update the execution_rc parameter documentation to describe both
outcomes: it contains the drain result after a successful enqueue_run(), or the
enqueue_run() error when enqueueing fails and drain_run() is not called. Apply
this wording at the corresponding sites in
src/a2a3/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp (969-969),
src/a2a3/runtime/host_build_graph/host/runtime_maker.cpp (912-912),
src/a5/runtime/host_build_graph/host/runtime_maker.cpp (912-912), and
src/a5/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp (952-952),
preserving byte-for-byte parity between the corresponding a2a3 and a5
host_build_graph files.

In `@src/a5/platform/onboard/host/device_runner.cpp`:
- Around line 377-380: Move the run_poll_state_ store to RunPollState::Submitted
until after launch_aicpu_kernel(stream_aicpu_, ...) returns successfully,
ensuring poll_run cannot query streams before the current AICPU run is queued.
Preserve the existing ownership publication and launch-failure behavior, or
introduce a launched state only if poll_run uses it to gate DeviceComplete.

---

Nitpick comments:
In `@tests/ut/cpp/common/test_sim_run_completion.cpp`:
- Line 40: Extend the completion assertions in the test around completion.poll()
to invoke it a second time after the final task completes, and assert that the
repeated call also returns SIMPLER_NATIVE_RUN_POLL_COMPLETE, covering sticky
terminal polling at both referenced test cases.
🪄 Autofix

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: da4372c6-0973-4e63-b087-a80f76c92c21

📥 Commits

Reviewing files that changed from the base of the PR and between b714174 and 70160a5.

📒 Files selected for processing (35)
  • docs/chip-level-arch.md
  • docs/dfx/dep-gen.md
  • docs/dfx/host-trace.md
  • docs/dynamic-linking.md
  • src/a2a3/platform/docs/tpush-tpop-sim.md
  • src/a2a3/platform/onboard/host/device_runner.cpp
  • src/a2a3/platform/onboard/host/device_runner.h
  • src/a2a3/platform/sim/host/device_runner.cpp
  • src/a2a3/platform/sim/host/device_runner.h
  • src/a2a3/runtime/host_build_graph/host/runtime_maker.cpp
  • src/a2a3/runtime/host_build_graph/runtime/dep_gen_host_graph.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp
  • src/a5/platform/docs/tpush-tpop-sim.md
  • src/a5/platform/onboard/host/device_runner.cpp
  • src/a5/platform/onboard/host/device_runner.h
  • src/a5/platform/sim/host/device_runner.cpp
  • src/a5/platform/sim/host/device_runner.h
  • src/a5/runtime/host_build_graph/host/runtime_maker.cpp
  • src/a5/runtime/host_build_graph/runtime/dep_gen_host_graph.h
  • src/a5/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp
  • src/common/platform/include/host/run_stream_slots.h
  • src/common/platform/onboard/host/c_api_shared.cpp
  • src/common/platform/onboard/host/device_runner_base.h
  • src/common/platform/onboard/host/device_runner_helpers.cpp
  • src/common/platform/onboard/host/device_runner_helpers.h
  • src/common/platform/shared/host/args_dump_collector.cpp
  • src/common/platform/shared/host/l2_swimlane_collector.cpp
  • src/common/platform/sim/host/c_api_shared.cpp
  • src/common/platform/sim/host/device_runner_base.h
  • src/common/platform/sim/host/sim_run_completion.h
  • src/common/worker/native_run_state.h
  • src/common/worker/pto_runtime_c_api.h
  • tests/ut/cpp/CMakeLists.txt
  • tests/ut/cpp/common/test_sim_run_completion.cpp
  • tests/ut/cpp/hierarchical/test_run_stream_slots.cpp

Comment thread src/a2a3/platform/sim/host/device_runner.cpp
Comment thread src/a2a3/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp Outdated
Comment thread src/a5/platform/onboard/host/device_runner.cpp
@ChaoWao
ChaoWao force-pushed the worker-async-b6a-enqueue-drain branch from 70160a5 to 81b9b70 Compare August 4, 2026 11:40
@ChaoWao

ChaoWao commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai Addressed the review summary:

  • Added repeated sticky COMPLETE polling assertions.
  • Added sticky ERROR publication for simulation enqueue rollback, including late-completion and reset-reuse coverage.
  • Corrected execution_rc documentation in all four runtime variants.
  • Replied inline with the supported launch/poll ordering that makes the A5 Submitted concern unreachable; moving the store would introduce a signal-to-store race.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== Changed files and summary =='
git diff --stat HEAD^ HEAD
git diff --name-only HEAD^ HEAD | sed -n '1,240p'

echo '== Focused outlines =='
for f in \
  src/common/platform/sim/host/sim_run_completion.h \
  tests/ut/cpp/common/test_sim_run_completion.cpp \
  src/a5/platform/onboard/host/device_runner.cpp \
  src/a5/platform/onboard/host/device_runner.h \
  src/common/platform/onboard/host/c_api_shared.cpp \
  src/common/platform/sim/host/c_api_shared.cpp \
  src/a2a3/runtime/host_build_graph/host/runtime_maker.cpp \
  src/a2a3/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp \
  src/a5/runtime/host_build_graph/host/runtime_maker.cpp \
  src/a5/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp
do
  if [ -f "$f" ]; then
    echo "---- $f ----"
    ast-grep outline "$f" --items all 2>/dev/null || true
  fi
done

echo '== Completion, rollback, and A5 lifecycle references =='
rg -n -C 5 -i \
  'sticky|poll_run|simpler_poll_run|enqueue.*rollback|rollback.*enqueue|run_completion_|submitted|complete|completion|drain_run|rtStreamQuery' \
  tests/ut/cpp/common/test_sim_run_completion.cpp \
  src/a2a3/platform/sim/host/device_runner.cpp \
  src/a5/platform/sim/host/device_runner.cpp \
  src/a5/platform/onboard/host/device_runner.cpp \
  src/a5/platform/onboard/host/device_runner.h \
  src/common/platform/onboard/host/c_api_shared.cpp \
  src/common/platform/sim/host/c_api_shared.cpp \
  src/common/platform/sim/host/sim_run_completion.h \
  2>/dev/null || true

echo '== execution_rc documentation =='
rg -n -C 3 'execution_rc' \
  src/a2a3/runtime/host_build_graph/host/runtime_maker.cpp \
  src/a2a3/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp \
  src/a5/runtime/host_build_graph/host/runtime_maker.cpp \
  src/a5/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp

Length of output: 97023


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== A5 enqueue launch ordering =='
sed -n '360,410p' src/a5/platform/onboard/host/device_runner.cpp

echo '== Onboard launch and polling gate =='
sed -n '739,854p' src/common/platform/onboard/host/c_api_shared.cpp

echo '== Launch marker implementation and call sites =='
rg -n -C 6 'publish_task_accepted|launch_signal|launch_aicpu_kernel\s*\(' \
  src/common/platform/onboard/host \
  src/a5/platform/onboard/host \
  src/common/worker \
  2>/dev/null || true

echo '== Native run phase and launch-signal definitions =='
rg -n -C 6 'enum class NativeRunPhase|NativeRunPhase|launch_signal' \
  src/common/worker/native_run_state.h \
  src/common/platform/onboard/host/c_api_shared.cpp \
  2>/dev/null || true

Length of output: 44920


@ChaoWao Verified the reported changes.

  • test_sim_run_completion.cpp now verifies sticky COMPLETE and sticky ERROR results. It also covers late completion after abandon() and reuse after reset().
  • Both simulation enqueue_run() rollback paths call SimRunCompletion::abandon().
  • All four execution_rc documentation blocks now describe drain status after successful enqueue and enqueue status on failure.
  • The A5 Submitted concern does not apply. simpler_launch_run() waits for the launch signal. launch_aicpu_kernel() emits that signal only after successful AICPU launch, and AICore launch occurs first. Therefore, public polling cannot call DeviceRunner::poll_run() before both launches complete.

✏️ Learnings added
Learnt from: ChaoWao
URL: https://github.com/hw-native-sys/simpler/pull/1683

Timestamp: 2026-08-04T11:42:13.678Z
Learning: For onboard native runs, `simpler_launch_run()` in `src/common/platform/onboard/host/c_api_shared.cpp` waits for `NativeRunLaunchSignal` before it changes the run phase to `NativeRunPhase::Running`. `DeviceRunnerBase::launch_aicpu_kernel()` publishes this signal only after a successful AICPU launch, and both onboard architectures enqueue AICore before AICPU. Therefore, the public `simpler_poll_run()` path cannot call `DeviceRunner::poll_run()` during the pre-launch `RunPollState::Submitted` interval.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

@ChaoWao
ChaoWao force-pushed the worker-async-b6a-enqueue-drain branch from 81b9b70 to 1309709 Compare August 4, 2026 12:15
@ChaoWao

ChaoWao commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator Author

CI triage for the remaining red ut-a2a3 job:

No B6a code change is justified by this failure. runner-dev8-11 / devices 8–11 need reset or quarantine, followed by a rerun on a healthy A2/A3 runner; I am not blindly rerunning the unchanged fixed pool.

- Retain the compatibility executor while exposing real nonblocking
  completion queries in every backend.
- Keep run-owned threads, stream handles, diagnostics, and cleanup alive
  until the explicit drain phase.
- Serialize a2a3 query and retirement, and publish completion only after
  a proven device fence.
- Publish a sticky simulation error when enqueue rolls back, preventing
  late task completion from masking the failure.
@ChaoWao
ChaoWao force-pushed the worker-async-b6a-enqueue-drain branch from 1309709 to 9585a67 Compare August 4, 2026 14:37
@ChaoWao
ChaoWao merged commit 639b95f into hw-native-sys:main Aug 4, 2026
18 checks passed
@ChaoWao
ChaoWao deleted the worker-async-b6a-enqueue-drain branch August 4, 2026 14:55
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