From bdba7bcc94792864547cf0ac35ec8c82a4e0eb91 Mon Sep 17 00:00:00 2001 From: Crane-Liu Date: Fri, 24 Jul 2026 05:43:58 -0700 Subject: [PATCH] Refactor: separate A2A3 device launch and reap Split the A2/A3 onboard DeviceRunner::run() kernel submission boundary into launch_run(), and move stream synchronization, device-error recovery, profiling export and timing collection into reap_run(). run() stays strictly synchronous as launch_run() followed immediately by reap_run(). The effective statement sequence, every error return code and every recovery action are unchanged, including the collector teardown on the sync-failure path and print_handshake_results() on the success path only. reap_run() takes no arguments and reads only members, so a later change can defer it without re-splitting its inputs. Correct the run() step list, which named the AICPU kernel before the AICore kernel while the launch has submitted AICore first. No ACK states, resource banks, background reaping, or execution overlap are added here. --- .../platform/onboard/host/device_runner.cpp | 27 ++++++++++++++++--- .../platform/onboard/host/device_runner.h | 9 +++++-- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/a2a3/platform/onboard/host/device_runner.cpp b/src/a2a3/platform/onboard/host/device_runner.cpp index 3f99e5d61..484196b8c 100644 --- a/src/a2a3/platform/onboard/host/device_runner.cpp +++ b/src/a2a3/platform/onboard/host/device_runner.cpp @@ -432,6 +432,24 @@ int DeviceRunner::run(Runtime &runtime, const CallConfig &config) { l2_swimlane_collector_.set_core_types(core_types.data(), num_aicore); } + rc = launch_run(runtime, num_aicore, launch_aicpu_num); + if (rc != 0) return rc; + + rc = reap_run(); + if (rc != 0) return rc; + + // Print handshake results (reads from device memory, must be before free) + print_handshake_results(); + + return 0; +} + +int DeviceRunner::launch_run(Runtime &runtime, int num_aicore, int launch_aicpu_num) { + // KernelLaunch is the pipeline boundary: this method clears the handshake + // consumed by the launch and submits exactly the AICore and AICPU kernels. + // It intentionally performs no stream synchronization or per-run cleanup. + int rc = 0; + // Launch the AICore worker BEFORE the AICPU Run task — mirrors the a5 path // so the two arches stay symmetric. First-launch latency optimization + // op-timeout-family defense-in-depth: with the AICPU Run task launched first @@ -478,7 +496,11 @@ int DeviceRunner::run(Runtime &runtime, const CallConfig &config) { return rc; } - rc = sync_run_streams(); + return 0; +} + +int DeviceRunner::reap_run() { + int rc = sync_run_streams(); if (rc != 0) { // sync_run_streams surfaces the AICore op-timeout (STARS-reaped op -> // 507000/507018/507046 at AICPU/AICore stream sync). The op-timeout @@ -517,9 +539,6 @@ int DeviceRunner::run(Runtime &runtime, const CallConfig &config) { } } - // Print handshake results (reads from device memory, must be before free) - print_handshake_results(); - return 0; } diff --git a/src/a2a3/platform/onboard/host/device_runner.h b/src/a2a3/platform/onboard/host/device_runner.h index 62904e293..f5a2231d8 100644 --- a/src/a2a3/platform/onboard/host/device_runner.h +++ b/src/a2a3/platform/onboard/host/device_runner.h @@ -97,8 +97,8 @@ class DeviceRunner : public DeviceRunnerBase { * 1. Initializes device if not already done (lazy initialization) * 2. Initializes worker handshake buffers in the runtime based on block_dim * 3. Transfers runtime to device memory - * 4. Launches AICPU main kernel - * 5. Launches AICore kernel + * 4. Launches AICore kernel + * 5. Launches AICPU main kernel * 6. Synchronizes streams * 7. Cleans up runtime memory * @@ -219,6 +219,11 @@ class DeviceRunner : public DeviceRunnerBase { // recovery. See run() and recover_device_or_mark_unusable(). bool device_unusable_{false}; + // Keep the kernel submission boundary separate from stream synchronization + // and teardown. run() still invokes these back-to-back in this change. + int launch_run(Runtime &runtime, int num_aicore, int launch_aicpu_num); + int reap_run(); + // On an AICore launch/sync error, best-effort drain the device so a later // run() on the same DeviceRunner can recover in place; if the drain itself // errors the context is unrecoverable without a full reset, so flip