CANN Runtime Stream 遇错即停模式实战:从 aclrtSetStreamFailureMode 到 aclrtStreamStop/Abort

CANN Runtime Stream 遇错即停模式实战:从 aclrtSetStreamFailureMode 到 aclrtStreamStop/Abort CANN Runtime Stream 遇错即停模式实战从 aclrtSetStreamFailureMode 到 aclrtStreamStop/Abort【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime本篇技术指南基于 CANN runtime 仓库中的官方示例 1_stream_with_failure_mode完整讲解 Stream 执行任务遇错时的两种行为模式遇错继续 / 遇错即停、aclrtStreamStop与aclrtStreamAbort两种主动干预手段并结合 main.cpp 源码逐行拆解其实现原理。读完本文你将能够在业务代码中正确调用aclrtSetStreamFailureMode配置 Stream 的错误处理策略理解停止Stop与中止Abort的本质区别及各自的前置约束通过状态回调、同步接口返回值与错误码准确诊断 Stream 异常场景。一、场景与背景为什么需要遇错即停在昇腾异构计算架构中任务以 Stream流为执行载体串行或并行下发到 Device。默认情况下Stream 上某个任务执行失败后Stream 会继续执行后续任务错误并不会阻断整条流水线——这在容错场景下是优点但在依赖严格执行顺序的场景下则可能造成错误被掩盖、数据被污染的隐患。CANN Runtime 为此提供aclrtSetStreamFailureMode接口允许开发者显式配置 Stream 的任务失败行为默认的遇错继续ACL_CONTINUE_ON_FAILURE或遇错即停ACL_STOP_ON_FAILURE。本样例的核心价值就是用一段可复现、可观察的代码把这两种模式下的差异直观地跑出来。该能力在 docs/zh/api_ref/06_stream_management.md 所属的 Stream 管理 API 体系中属于异步任务执行控制层面的能力。从 include/external/acl/acl_rt.h 可以看到模式取值的精确定义#define ACL_CONTINUE_ON_FAILURE 0x00000000U #define ACL_STOP_ON_FAILURE 0x00000001U二、样例总览三个演示段落样例由三部分内容组成演示段落核心接口演示目的普通 Stream 遇错即停演示aclrtSetStreamFailureMode对比同一段成功-出错-成功任务序列在两种模式下的结果差异aclrtStreamStop辅助演示aclrtCreateStreamWithConfigaclrtStreamStop在 device-use-only Stream 上提交长时核任务后强制停止aclrtStreamAbort辅助演示aclrtStreamAbort在普通 Stream 上中止任务并验证其返回abort 类状态码属预期行为整体执行入口为 main.cpp 中的main函数。需要特别说明的是后两个辅助演示存在额外前置条件当前环境不满足时会打印WARN并跳过对应演示主流程的aclrtSetStreamFailureMode演示仍会继续执行不影响样例整体可用性。产品支持情况本样例支持以下产品README.md 原文产品是否支持Ascend 950PR/Ascend 950DT√Atlas A3 训练系列产品/Atlas A3 推理系列产品√Atlas A2 训练系列产品/Atlas A2 推理系列产品√需要强调的是aclrtStreamStop在 Atlas A2/Atlas A3 上要求目标 Stream 必须通过aclrtCreateStreamWithConfig(..., ACL_STREAM_DEVICE_USE_ONLY)创建README.md 原文说明而aclrtStreamAbort恰好不支持ACL_STREAM_DEVICE_USE_ONLYStream——这正是样例分别用两种 Stream 类型演示二者的根本原因。三、编译与运行3.1 前置条件一台已安装 CANN 软件包的昇腾环境满足样例中stop/abort辅助演示所需的产品约束不满足时自动跳过环境变量SOC_VERSION、ASCENDC_CMAKE_DIR可被自动识别。3.2 编译运行步骤第 1 步下载样例代码并切换到样例目录。cd ${git_clone_path}/example/1_basic_features/stream/1_stream_with_failure_mode第 2 步设置环境变量。# ${install_root} 替换为 CANN 安装根目录默认安装在 /usr/local/Ascend 目录 source ${install_root}/cann/set_env.sh # 自动识别 SOC_VERSION 和 ASCENDC_CMAKE_DIR source ${git_clone_path}/example/set_sample_env.shset_sample_env.sh位于 example/set_sample_env.sh作用是自动探测当前设备的 SOC 版本并导出ASCENDC_CMAKE_DIR避免手动配置。第 3 步执行运行脚本。bash run.shrun.sh 内部会依次完成校验ASCEND_HOME_PATH未设置则报错退出→ 引入bin/setenv.bash→ 使用 CMake 构建并安装 → 运行./build/main同时通过tee将 stdout/stderr 一并记录到output_msg.txt方便回看日志set -euo pipefail source ${_ASCEND_CANN_PATH}/bin/setenv.bash rm -rf build mkdir -p build cmake -B build -DASCEND_CANN_PACKAGE_PATH${_ASCEND_CANN_PATH} cmake --build build -j cmake --install build ./build/main 21 | tee output_msg.txt3.3 构建细节核函数如何被编译进样例CMakeLists.txt 通过ascendc_library把三个核函数源文件编译为静态库kernels再与主程序链接ascendc_library(kernels STATIC ../../../kernel_func/easy_OP.cpp ../../../kernel_func/error_OP.cpp ../../../kernel_func/long_OP.cpp)三个核函数分别位于仓库 example/kernel_func 目录easy_OP.cppEasyOPf对入参x执行x[idx] 1并针对__NPU_ARCH__ 3510架构做 cache 一致性处理dcci用于模拟正常成功的任务error_OP.cppErrorOPf函数体只有一行asm(trap)直接在核内触发 trap 异常用于模拟执行失败的任务long_OP.cppLongOPf通过两重浮点循环外层 10000 次、内层 25000 次模拟长时间运行的任务为aclrtStreamStop/aclrtStreamAbort提供任务还没跑完的执行窗口。四、核心演示一普通 Stream 上的遇错即停对比这是样例的主流程对应 main.cpp。其执行序列为在 Stream 上依次下发EasyOP → ErrorOP → EasyOP三个任务分别在不设置失败模式与设置ACL_STOP_ON_FAILURE两种情况下观察最终结果。4.1 初始化与资源准备CHECK_ERROR(aclInit(nullptr)); CHECK_ERROR(aclrtRegStreamStateCallback(stream_failure_mode_sample, StreamStateCallback, callbackTag)); CHECK_ERROR(aclrtSetDevice(deviceId)); CHECK_ERROR(aclrtCreateContext(context, deviceId)); CHECK_ERROR(aclrtCreateStream(stream)); CHECK_ERROR(aclrtMalloc(reinterpret_castvoid**(numDevice), size, ACL_MEM_MALLOC_HUGE_FIRST)); CHECK_ERROR(aclrtMemcpy(numDevice, size, num, size, ACL_MEMCPY_HOST_TO_DEVICE));涉及的关键接口aclInit运行时初始化配置样例传入nullptr使用默认配置程序末尾调用aclFinalize去初始化aclrtSetDevice/aclrtResetDeviceForce指定运算 Device结尾用aclrtResetDeviceForce强制复位当前 Device 并回收资源区别于普通aclrtResetDevice适用于需要清理异常残留的场景aclrtCreateContext/aclrtDestroyContext创建/销毁 ContextaclrtMalloc/aclrtFree申请/释放 Device 内存申请策略使用ACL_MEM_MALLOC_HUGE_FIRST优先大页内存aclrtMemcpy样例使用ACL_MEMCPY_HOST_TO_DEVICE下发初始值与ACL_MEMCPY_DEVICE_TO_HOST回读结果两种传输方向。4.2 第一段不设置失败模式默认遇错继续INFO_LOG(Assigning task without failure mode.); EasyOP(blockDim, stream, numDevice); ErrorOP(blockDim, stream); EasyOP(blockDim, stream, numDevice); CHECK_ERROR_WITHOUT_RETURN(aclrtSynchronizeStream(stream)); CHECK_ERROR(aclrtMemcpy(num, size, numDevice, size, ACL_MEMCPY_DEVICE_TO_HOST)); INFO_LOG(Without failure mode, the result is %d., num);三个任务连续下发后调用aclrtSynchronizeStream阻塞等待。由于默认ACL_CONTINUE_ON_FAILURE中间的ErrorOP触发 trap不会阻断后续任务第三个EasyOP依然会执行因此最终结果num 2两个EasyOP各加 1。同步返回的错误码507035只是被记录不影响后续任务执行。4.3 第二段设置遇错即停num 0; CHECK_ERROR(aclrtMemcpy(numDevice, size, num, size, ACL_MEMCPY_HOST_TO_DEVICE)); CHECK_ERROR(aclrtSetStreamFailureMode(stream, ACL_STOP_ON_FAILURE)); INFO_LOG(Assigning task with failure mode.); EasyOP(blockDim, stream, numDevice); ErrorOP(blockDim, stream); EasyOP(blockDim, stream, numDevice); CHECK_ERROR_WITHOUT_RETURN(aclrtSynchronizeStream(stream)); CHECK_ERROR(aclrtMemcpy(num, size, numDevice, size, ACL_MEMCPY_DEVICE_TO_HOST)); INFO_LOG(After set failure mode, the current result is: %d., num);同样三个任务唯一差别是先调用了aclrtSetStreamFailureMode(stream, ACL_STOP_ON_FAILURE)。此时中间的ErrorOP失败后Stream立即停止后续任务执行第三个EasyOP被丢弃因此回读结果为num 1仅第一个EasyOP生效。4.4 从源码看接口实现在 src/acl/aclrt_impl/stream.cpp 中可以找到aclrtSetStreamFailureModeImpl、aclrtStreamAbortImpl、aclrtStreamStopImpl的实现骨架三者均为典型的日志记录 调用下层 RT 接口的封装模式。可见上层aclrt只负责参数校验与日志埋点真正的失败模式控制逻辑由 Runtime 核心层src/runtime 目录完成。这解释了为什么遇错即停是 Stream 层面的运行时属性它影响的是任务调度器在检测到异常后的后续派发行为而非单个任务的执行。五、核心演示二aclrtStreamStop 辅助演示5.1 为什么必须用 device-use-only StreamaclrtStreamStop用于停止一条辅助 Stream停止后续任务的继续下发。在 Atlas A2/Atlas A3 上该接口要求目标 Stream 必须通过如下方式创建main.cppaclError ret aclrtCreateStreamWithConfig(stopStream, 0, ACL_STREAM_DEVICE_USE_ONLY); if (ret ! ACL_SUCCESS) { WARN_LOG(Skip aclrtStreamStop demo: aclrtCreateStreamWithConfig returned %d., ret); return; }ACL_STREAM_DEVICE_USE_ONLY的定义位于 include/external/acl/acl_rt.h#define ACL_STREAM_DEVICE_USE_ONLY 0x00000020U它表示这条 Stream 只用于 Device 侧内部使用不承载用户 Host 侧的下发队列语义只有这类 Stream 才允许被aclrtStreamStop停止。若当前环境不支持创建该类型 Stream样例打印WARN并跳过本段演示。5.2 完整执行序列// 申请并清零 scratch 缓冲 if (!PrepareScratchBuffer(stopScratch, kScratchSize, aclrtStreamStop)) { ... } INFO_LOG(Launching a long task on the device-use-only stream before aclrtStreamStop.); LongOP(kBlockDim, stopStream, stopScratch); LogOptionalResult(aclrtStreamStop, aclrtStreamStop(stopStream)); LogOptionalResult(aclrtSynchronizeStream(after stop), aclrtSynchronizeStream(stopStream));执行逻辑为在 device-use-only Stream 上提交LongOP长时核任务保证任务在调用 Stop 时仍在执行从而产生停止的窗口调用aclrtStreamStop(stopStream)停止该 Stream成功返回 0调用aclrtSynchronizeStream观察停止后的同步结果。5.3 预期输出解读[INFO] aclrtStreamStop returned 0. [WARN] aclrtSynchronizeStream(after stop) returned 507000.停止后再次同步返回507000对应错误码 ACL_ERROR_RT_INTERNAL_ERRORruntime 模块内部错误。这是停止动作后的预期结果样例会记录为WARN日志而不会将整个流程判定为失败。六、核心演示三aclrtStreamAbort 辅助演示6.1 与 Stop 的本质区别aclrtStreamAbort用于中止一条 Stream 上正在执行的任务语义比 Stop 更硬。与aclrtStreamStop相反aclrtStreamAbort不支持ACL_STREAM_DEVICE_USE_ONLYStream因此样例改用普通aclrtCreateStream创建的 Stream 单独演示main.cppaclError ret aclrtCreateStream(abortStream); if (ret ! ACL_SUCCESS) { WARN_LOG(Skip aclrtStreamAbort demo: aclrtCreateStream returned %d., ret); return; }6.2 完整执行序列INFO_LOG(Launching a long task on the regular stream before aclrtStreamAbort.); LongOP(kBlockDim, abortStream, abortScratch); LogOptionalResult(aclrtStreamAbort, aclrtStreamAbort(abortStream)); LogAbortSyncResult(aclrtSynchronizeStream(abortStream));与 Stop 演示结构对称先在普通 Stream 上提交LongOP长时任务再调用aclrtStreamAbort中止最后同步观察。6.3 预期输出解读[INFO] aclrtStreamAbort returned 0. [INFO] aclrtSynchronizeStream(after abort) returned 507035 after stream abort, which is expected.中止后再同步返回507035对应错误码 ACL_ERROR_RT_VECTOR_CORE_EXCEPTIONvector core 执行异常即本样例中ErrorOP的 trap 也是同类异常路径。样例通过 LogAbortSyncResult 特判只要返回了 abort 类状态码就打印which is expected并视为预期行为而不会让样例失败退出。七、Stream 状态回调aclrtRegStreamStateCallback样例在初始化时注册了 Stream 状态回调用于观察 Stream 生命周期事件void StreamStateCallback(aclrtStream stream, aclrtStreamState state, void* args) { const char* sampleName args nullptr ? stream_failure_mode : static_castconst char*(args); INFO_LOG(Stream state callback from %s: stream%p state%d, sampleName, stream, static_castint32_t(state)); }回调函数类型aclrtStreamStateCallback及状态枚举定义在 include/external/acl/acl_rt.htypedef enum { ACL_RT_STREAM_STATE_CREATE_POST 1, ACL_RT_STREAM_STATE_DESTROY_PRE, } aclrtStreamState; typedef void (*aclrtStreamStateCallback)(aclrtStream stm, aclrtStreamState state, void* args);接口签名aclError aclrtRegStreamStateCallback( const char* regName, aclrtStreamStateCallback callback, void* args);样例在main开头注册regName为stream_failure_mode_sampleargs传入用于日志标记的callbackTag在程序结尾注销main.cppCHECK_ERROR(aclrtRegStreamStateCallback(stream_failure_mode_sample, nullptr, nullptr));注册时机覆盖 Stream 创建CREATE_POST与销毁前DESTROY_PRE两个关键节点可用于业务侧实现 Stream 生命周期的监控、审计或联动清理。需要注意状态回调的注册与注销是成对使用的样例在清理阶段显式传入空回调完成注销避免回调悬挂。八、资源回收路径为什么全程使用Force系列接口样例的资源清理段main.cpp值得单独说明CHECK_ERROR(aclrtFree(numDevice)); CHECK_ERROR(aclrtDestroyStreamForce(stream)); CHECK_ERROR(aclrtDestroyContext(context)); CHECK_ERROR(aclrtRegStreamStateCallback(stream_failure_mode_sample, nullptr, nullptr)); CHECK_ERROR(aclrtResetDeviceForce(deviceId)); aclFinalize();aclrtDestroyStreamForce强制销毁 Stream、丢弃其上所有未完成任务。由于演示过程中 Stream 可能处于遇错即停后残留任务或被 abort的非正常状态普通aclrtDestroyStream可能因等待任务完成而卡住因此统一使用强制销毁aclrtResetDeviceForce强制复位 Device、回收 Device 上全部资源同样是针对异常场景的兜底清理手段aclFinalize去初始化注意它返回void无需CHECK_ERROR包裹。这套Force 清理 回调注销的顺序保证了无论演示过程产生了怎样的异常状态程序都能干净退出。辅助演示中的stopStream/abortStream同样通过 DestroyOptionalStream 走aclrtDestroyStreamForce回收。九、完整示例输出与结果对照成功运行后的完整输出README.md 原文[INFO] Assigning task without failure mode. [ERROR] Operation failed: aclrtSynchronizeStream(stream) returned error code 507035 [INFO] Without failure mode, the result is 2. [INFO] Assigning task with failure mode. [ERROR] Operation failed: aclrtSynchronizeStream(stream) returned error code 507035 [INFO] After set failure mode, the current result is: 1. [INFO] aclrtStreamStop returned 0. [WARN] aclrtSynchronizeStream(after stop) returned 507000. [INFO] aclrtStreamAbort returned 0. [INFO] aclrtSynchronizeStream(after abort) returned 507035 after stream abort, which is expected. [INFO] Resource cleanup completed. [INFO] Run the stream_with_failure_mode sample successfully.关键观察点汇总阶段同步返回码含义结果数据未设置失败模式507035ACL_ERROR_RT_VECTOR_CORE_EXCEPTION遇错继续错误仅记录num 2两个 EasyOP 均执行设置ACL_STOP_ON_FAILURE507035遇错即停后续任务被丢弃num 1仅第一个 EasyOP 执行Stop 后同步507000ACL_ERROR_RT_INTERNAL_ERROR停止动作的预期结果记录为 WARN—Abort 后同步507035中止后返回 abort 类状态码属预期—十、总结与工程建议通过本样例可以提炼出三条可直接迁移到业务代码中的实践经验按需显式配置失败模式默认ACL_CONTINUE_ON_FAILURE下异常任务之后的后续任务仍会执行可能污染计算结果在数据依赖严格、不允许带病继续的流水线中应在任务下发前调用aclrtSetStreamFailureMode(stream, ACL_STOP_ON_FAILURE)。Stop 与 Abort 各有限制、不可混用aclrtStreamStop要求 Stream 通过aclrtCreateStreamWithConfig(..., ACL_STREAM_DEVICE_USE_ONLY)创建Atlas A2/A3 上而aclrtStreamAbort恰好不支持该类型 Stream——选择接口前先确认 Stream 的创建方式。异常状态用 Force 系列接口兜底清理遇错即停或 abort 后的 Stream 处于非正常状态销毁与设备复位应使用aclrtDestroyStreamForce、aclrtResetDeviceForce同时结合aclrtRegStreamStateCallback注册的 Stream 状态回调监控生命周期帮助定位异常发生的上下文。该样例的完整可运行代码、构建脚本与核函数实现可继续在仓库中查阅README.md、main.cpp、run.sh、error_OP.cpp 以及 long_OP.cpp。【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考