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