- CANN
- Ascend
- 人工智能
- 任务调度
【免费下载链接】runtime
本项目提供CANN运行时组件和维测功能组件。
导读
本篇文章以 CANN Runtime 开源仓库中的0_overflow_detection示例为核心,系统讲解在昇腾设备上基于 Stream 的浮点溢出检测能力:如何查询并切换 Device 的浮点饱和模式、如何开启并回读流级溢出开关、如何通过固定大小的状态缓冲异步获取溢出状态并同步回 Host,以及如何在退出前完成状态复位与资源清理。读完本文,你将掌握aclrtSetStreamOverflowSwitch、aclrtGetOverflowStatus、aclrtResetOverflowStatus这一组溢出检测 API 的完整用法、底层调用链与兼容性注意事项,可直接将示例改造接入自己的训练或推理程序。
一、示例概览:什么是流级溢出检测
浮点溢出(Float Overflow)是 AI 训练与推理中常见的数值异常来源,当算子计算过程中出现上溢/下溢等异常值时,往往会导致最终结果不可信。CANN Runtime 提供了一套流级(Stream 级)溢出检测能力:开发者可以针对某个 Stream 开启溢出检测开关,随后在流上算子任务执行完成后,异步查询该流上是否发生过浮点溢出,并在必要时复位溢出状态、重新开始一轮检测。
本示例位于仓库的可靠性(Reliability)样例集下:
- example/4_reliability/overflow_detection/0_overflow_detection/README_en.md
- main.cpp
- run.sh
- CMakeLists.txt
根据 example/README_en.md 的介绍,4_reliability样例集聚焦可靠性能力,包括溢出检测、错误恢复等场景,是开发者快速上手 Runtime 关键特性的参考入口。本示例演示的核心流程为:流级溢出检测开关的开启 → 溢出状态的查询 → 溢出状态的复位。
二、示例功能清单与执行流程
原文档明确了本示例的五个功能要点,逐个展开如下:
- 查询当前 Device 的浮点溢出模式,并将其切换为
ACL_RT_OVERFLOW_MODE_SATURATION(饱和模式):流级溢出检测依赖饱和模式,因此示例先读取原始模式,再切换到饱和模式,并在结尾恢复原始模式。 - 在饱和模式下创建 Stream,开启溢出检测开关,并回读当前开关配置:通过
aclrtSetStreamOverflowSwitch(stream, 1)开启、aclrtGetStreamOverflowSwitch确认开关状态。 - 分配一块固定的 64 字节 Device 状态缓冲,异步获取一次溢出状态,并同步到 Host:状态缓冲用于承载 Device 侧写入的溢出标志,读取后通过
aclrtMemcpy同步回 Host 解析。 - 调用
aclrtResetOverflowStatus再次查询状态,并在结束时恢复原始的饱和模式:复位后再次查询,用于验证复位语义,最后把 Device 模式还原为运行前的值。 - 销毁 Stream、Context 与状态缓冲:按资源依赖逆序释放,完成干净退出。
整体执行顺序可概括为:初始化 → 模式探测与切换 → 建流与开关配置 → 状态缓冲分配 → 溢出状态查询 → 复位与二次查询 → 资源清理。
三、运行环境与产品支持
原文档明确列出了本示例的产品支持矩阵,整理如下:
| 产品 | 支持情况 |
|---|---|
| Ascend 950PR / Ascend 950DT | 支持 |
| Atlas A3 训练系列产品 / Atlas A3 推理系列产品 | 支持 |
| Atlas A2 训练系列产品 / Atlas A2 推理系列产品 | 支持 |
需要说明的是,根据 example/README_en.md 的产品支持表约定,该表仅列出已验证或已明确声明支持状态的产品;未列出的产品并不意味着不支持,若产品被明确不支持,示例 README 会以×标注并附加说明。
此外,从仓库的构建配置可以推断,arch5162_unsupported_acl_api.def 涉及对部分溢出检测相关 API 的剔除声明(该文件同时出现在aclrtSetStreamOverflowSwitch、aclrtGetOverflowStatus、aclrtResetOverflowStatus等符号的检索结果中),说明溢出检测能力存在芯片架构与 Runtime 构建形态相关的差异性——这正是示例代码需要做"可选能力探测"(见第六节)的根本原因。
四、构建与运行
4.1 环境准备
运行本示例需要具备:
- 已安装固件、驱动与 CANN 软件包的计算环境(安装与升级步骤详见 example/README_en.md 的环境准备章节);
- 满足产品支持矩阵中列出的昇腾设备;
- 若对仓库
src目录源码做了自定义修改,还需按根目录 README_en.md 的指引编译部署 Runtime 后再运行示例。
4.2 编译与运行
按原文档的步骤执行:
# 将 ${install_root} 替换为 CANN 安装根目录,默认安装目录为 /usr/local/Ascend source ${install_root}/cann/set_env.sh export ASCEND_INSTALL_PATH=${install_root}/cann # 构建并运行 bash run.sh其中run.sh内部完成的工作如下(详见 run.sh):
- 加载
${ASCEND_INSTALL_PATH}/bin/setenv.bash环境脚本; - 在示例目录下创建
build目录并执行 CMake 配置,传入-DASCEND_CANN_PACKAGE_PATH=${_ASCEND_INSTALL_PATH}; - 执行
make -j$(nproc)完成编译; - 运行生成的
./build/main可执行文件。
对应的 CMakeLists.txt 展示了编译要点:
include_directories引入${ASCEND_CANN_PACKAGE_PATH}/include与样例公共头文件目录;- 编译选项为
-O2 -std=c++17 -D_GLIBCXX_USE_CXX11_ABI=0 -Wall -Werror; - 链接
${ASCEND_CANN_PACKAGE_PATH}/lib64/libascendcl.so,即 AscendCL 动态库。
五、关键 API 与调用链解析
本示例涉及的核心 API 均声明于 include/external/acl/acl_rt.h,以下逐一解析。
5.1 浮点溢出模式枚举
aclrtFloatOverflowMode定义了 Device 侧浮点溢出的处理模式(见 acl_rt.h):
typedef enum aclrtFloatOverflowMode { ACL_RT_OVERFLOW_MODE_SATURATION = 0, // 饱和模式:溢出时数值钳制到可表示范围 ACL_RT_OVERFLOW_MODE_INFNAN, // 溢出时输出 Inf/NaN,保留异常数值 ACL_RT_OVERFLOW_MODE_UNDEF, // 未定义/默认值 } aclrtFloatOverflowMode;示例代码在打印日志时,通过OverflowModeToString辅助函数将枚举值映射为可读字符串(ACL_RT_OVERFLOW_MODE_SATURATION/ACL_RT_OVERFLOW_MODE_INFNAN/ACL_RT_OVERFLOW_MODE_UNDEF/ACL_RT_OVERFLOW_MODE_UNKNOWN)。
5.2 设备饱和模式管理
aclrtGetDeviceSatMode(aclrtFloatOverflowMode* mode):查询当前 Device 的饱和模式;aclrtSetDeviceSatMode(aclrtFloatOverflowMode mode):设置目标饱和模式。
声明见 acl_rt.h。从 ACL 实现层看(src/acl/aclrt_impl/device.cpp):
aclError aclrtGetDeviceSatModeImpl(aclrtFloatOverflowMode* mode) { ACL_LOG_INFO("start to execute aclrtGetDeviceSatMode"); ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(mode); rtFloatOverflowMode_t rtMode = RT_OVERFLOW_MODE_UNDEF; ACL_REQUIRES_RTS_OK(rtGetDeviceSatMode(&rtMode)); *mode = static_cast<aclrtFloatOverflowMode>(rtMode); ... } aclError aclrtSetDeviceSatModeImpl(aclrtFloatOverflowMode mode) { ACL_LOG_INFO("start to execute aclrtSetDeviceSatMode, mode is %s", acl::GetFloatOverflowModeDesc(mode)); ACL_REQUIRES_RTS_OK(rtSetDeviceSatMode(static_cast<rtFloatOverflowMode_t>(mode))); ... }可见 ACL 层是薄封装:aclrtGetDeviceSatMode最终调用 Runtime 的rtGetDeviceSatMode,aclrtSetDeviceSatMode最终调用rtSetDeviceSatMode,二者通过ACL_REQUIRES_RTS_OK宏将 Runtime 返回值转换为 ACL 错误码并上报日志。
5.3 流级溢出开关
aclrtSetStreamOverflowSwitch(aclrtStream stream, uint32_t flag):开启或关闭指定流上的溢出检测,flag取0表示关闭、1表示开启;aclrtGetStreamOverflowSwitch(aclrtStream stream, uint32_t* flag):查询指定流当前的溢出开关状态,返回0表示关闭、其他值表示开启。
声明与参数语义见 acl_rt.h。
5.4 溢出状态获取与复位
aclrtGetOverflowStatus(void* outputAddr, size_t outputSize, aclrtStream stream):异步获取指定流的溢出状态,写入outputAddr指向的 Device 侧地址;aclrtResetOverflowStatus(aclrtStream stream):异步复位指定流的溢出状态。
两个接口的 Restriction 都明确指出:调用后必须调用aclrtSynchronizeStream确保流上任务执行完成,再继续后续操作(见 acl_rt.h)。这是示例代码中每次查询/复位后紧跟aclrtSynchronizeStream的规范依据。
从 ACL 实现层看(src/acl/aclrt_impl/device.cpp):
aclError aclrtGetOverflowStatusImpl(void* outputAddr, size_t outputSize, aclrtStream stream) { ACL_PROFILING_REG(acl::AclProfType::AclrtGetOverflowStatus); ACL_LOG_INFO("start to execute aclrtGetOverflowStatus, outputSize = %lu", outputSize); ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(outputAddr); ACL_REQUIRES_RTS_OK(rtGetDeviceSatStatus(outputAddr, outputSize, static_cast<rtStream_t>(stream))); ... } aclError aclrtResetOverflowStatusImpl(aclrtStream stream) { ACL_PROFILING_REG(acl::AclProfType::AclrtResetOverflowStatus); ACL_LOG_INFO("start to execute aclrtResetOverflowStatus"); ACL_REQUIRES_RTS_OK(rtCleanDeviceSatStatus(static_cast<rtStream_t>(stream))); ... }可以确认的底层调用链为:aclrtGetOverflowStatus → rtGetDeviceSatStatus,aclrtResetOverflowStatus → rtCleanDeviceSatStatus。同时这两个接口带有ACL_PROFILING_REG埋点,说明溢出状态查询/复位会纳入 ACL Profiling 统计。
5.5 状态缓冲的数据格式
示例以 64 字节固定大小缓冲承载溢出状态。状态缓冲的首 4 个字节为溢出标志位(uint32_t),通过ReadOverflowFlag函数std::copy_n拷贝解析:
constexpr size_t kOverflowStatusBufferSize = 64; uint32_t ReadOverflowFlag(const uint8_t* statusBuffer) { uint32_t overflowFlag = 0; std::copy_n(statusBuffer, sizeof(overflowFlag), reinterpret_cast<unsigned char*>(&overflowFlag)); return overflowFlag; }该缓冲分配在 Device 侧(aclrtMalloc+ACL_MEM_MALLOC_HUGE_FIRST),由 Device 写入,再通过aclrtMemcpy以ACL_MEMCPY_DEVICE_TO_HOST方向同步回 Host 栈上数组进行解析。
六、示例代码逐段解析
6.1 可选能力探测机制
由于溢出检测能力并非在所有产品/所有 Runtime 构建上都可用,示例定义了一个关键辅助函数HandleOptionalOverflowRet,将"能力探测失败"与"真正的执行错误"区分对待:
int32_t HandleOptionalOverflowRet(const char* apiName, aclError ret, const char* reason) { if (ret == ACL_SUCCESS) { return 0; } if (ret == ACL_ERROR_RT_FEATURE_NOT_SUPPORT) { WARN_LOG("%s is unavailable in the current environment (ret=%d): %s", apiName, static_cast<int32_t>(ret), reason); return 1; // 能力不支持:告警后按探测结束处理 } ERROR_LOG("Operation failed: %s returned error code %d", apiName, static_cast<int32_t>(ret)); return -1; // 真实错误:终止示例 }该函数对ACL_ERROR_RT_FEATURE_NOT_SUPPORT(错误码 207000)返回1(环境不支持,仅告警),对其他错误码返回-1(真实失败)。调用方据此决定是提前优雅退出还是报错终止,这与原文档"Known Issues"一节描述的兼容性行为完全对应。
6.2 初始化与上下文管理
const int32_t deviceId = 0; CHECK_ERROR(aclInit(nullptr)); // ACL 初始化 CHECK_ERROR(aclrtSetDevice(deviceId)); // 绑定 Device 0 CHECK_ERROR(aclrtCreateContext(&context, deviceId)); // 创建 Context示例使用aclInit/aclFinalize完成初始化与去初始化,aclrtSetDevice/aclrtResetDeviceForce管理 Device。值得注意的是,示例在结束时使用aclrtResetDeviceForce清理本进程占用的 Device 资源——按照 example/README_en.md 的约定,单机单进程示例通常使用aclrtResetDeviceForce,而多进程 IPC 示例则使用aclrtResetDevice以避免影响同主机上的其他进程。
6.3 模式探测与切换
const int32_t getModeStatus = HandleOptionalOverflowRet( "aclrtGetDeviceSatMode(&originalMode)", aclrtGetDeviceSatMode(&originalMode), "the current device/runtime does not expose device saturation mode"); if (getModeStatus < 0) { return -1; } if (getModeStatus > 0) { WARN_LOG("Overflow detection is unavailable in the current environment, sample finished after probing."); return 0; } const int32_t setModeStatus = HandleOptionalOverflowRet( "aclrtSetDeviceSatMode(ACL_RT_OVERFLOW_MODE_SATURATION)", aclrtSetDeviceSatMode(ACL_RT_OVERFLOW_MODE_SATURATION), "stream overflow detection requires saturation mode and is only supported on specific products/runtime builds"); if (setModeStatus < 0) { return -1; } if (setModeStatus > 0) { WARN_LOG("Overflow detection is unavailable in the current environment, sample finished after probing."); return 0; } saturationModeChanged = true; CHECK_ERROR(aclrtGetDeviceSatMode(¤tMode)); INFO_LOG("Device saturation mode switched from %s to %s.", OverflowModeToString(originalMode), OverflowModeToString(currentMode));这段代码体现了两个设计要点:一是先保存原始模式(originalMode),为结尾恢复做准备;二是探测失败即优雅退出——若当前设备/Runtime 不暴露饱和模式能力,示例记录告警后结束(return 0),避免在不受支持的平台上继续执行而产生误导性失败。
6.4 创建流并配置溢出开关
CHECK_ERROR(aclrtCreateStream(&stream)); streamCreated = true; const int32_t setOverflowSwitchStatus = HandleOptionalOverflowRet( "aclrtSetStreamOverflowSwitch(stream, 1)", aclrtSetStreamOverflowSwitch(stream, 1), "the current environment does not expose stream-level overflow detection even in saturation mode"); if (setOverflowSwitchStatus < 0) { return -1; } if (setOverflowSwitchStatus > 0) { WARN_LOG("Stream overflow detection is unavailable in the current environment, sample finished after probing."); return 0; } uint32_t queriedSwitch = 0; CHECK_ERROR(aclrtGetStreamOverflowSwitch(stream, &queriedSwitch)); INFO_LOG("Overflow switch=%u", queriedSwitch);开启开关后立即回读,确认queriedSwitch == 1,保证后续状态查询建立在开关确实生效的前提下。
6.5 分配状态缓冲并查询溢出状态
CHECK_ERROR(aclrtMalloc(reinterpret_cast<void**>(&statusDevice), kOverflowStatusBufferSize, ACL_MEM_MALLOC_HUGE_FIRST)); statusAllocated = true; uint8_t statusHost[kOverflowStatusBufferSize] = {}; uint32_t overflowFlag = 0; CHECK_ERROR(aclrtGetOverflowStatus(statusDevice, kOverflowStatusBufferSize, stream)); CHECK_ERROR(aclrtSynchronizeStream(stream)); // 确保异步状态写入完成 CHECK_ERROR(aclrtMemcpy(statusHost, sizeof(statusHost), statusDevice, kOverflowStatusBufferSize, ACL_MEMCPY_DEVICE_TO_HOST)); overflowFlag = ReadOverflowFlag(statusHost); INFO_LOG("Overflow status before reset=%u", overflowFlag);这是一个典型的异步状态读取四步法:
aclrtMalloc分配 Device 侧状态缓冲(ACL_MEM_MALLOC_HUGE_FIRST优先大页分配);aclrtGetOverflowStatus将查询任务下发到流上(异步);aclrtSynchronizeStream同步等待,确保状态已写入 Device 缓冲(对应头文件中 Restriction 的强制要求);aclrtMemcpy(DEVICE_TO_HOST)将状态同步回 Host,解析首 4 字节溢出标志。
6.6 复位并二次查询
CHECK_ERROR(aclrtResetOverflowStatus(stream)); CHECK_ERROR(aclrtSynchronizeStream(stream)); std::fill_n(statusHost, kOverflowStatusBufferSize, static_cast<uint8_t>(0)); overflowFlag = 0; CHECK_ERROR(aclrtGetOverflowStatus(statusDevice, kOverflowStatusBufferSize, stream)); CHECK_ERROR(aclrtSynchronizeStream(stream)); CHECK_ERROR(aclrtMemcpy(statusHost, sizeof(statusHost), statusDevice, kOverflowStatusBufferSize, ACL_MEMCPY_DEVICE_TO_HOST)); overflowFlag = ReadOverflowFlag(statusHost); INFO_LOG("Overflow status after reset=%u", overflowFlag);复位同样采用"下发 → 同步 → 拷贝 → 解析"的流程。二次查询前先清零 Host 侧缓冲,避免残留数据影响对"复位后状态"的解读,是值得借鉴的防御性写法。
6.7 逆序资源清理
示例在 lambda 结束后统一进行资源清理,严格按照逆序释放(状态缓冲 → 恢复饱和模式 → 销毁 Stream → 销毁 Context → 复位 Device → Finalize),并使用状态位(statusAllocated、saturationModeChanged、streamCreated等)保证只在相应资源确实建立后才执行释放:
if (statusAllocated) { const aclError freeRet = aclrtFree(statusDevice); ... } if (saturationModeChanged) { const aclError restoreModeRet = aclrtSetDeviceSatMode(originalMode); // 恢复原始饱和模式 ... } if (streamCreated) { const aclError destroyStreamRet = aclrtDestroyStream(stream); ... } if (contextCreated) { const aclError destroyContextRet = aclrtDestroyContext(context); ... } if (deviceSet) { const aclError resetDeviceRet = aclrtResetDeviceForce(deviceId); ... } if (aclInitialized) { const aclError finalizeRet = aclFinalize(); ... } if (finalResult == 0) { INFO_LOG("Overflow detection sample finished successfully."); }该模式确保即便中途出错,已分配的资源也能被回收,并且不会遗漏对 Device 饱和模式的恢复——这是"探测/临时修改系统状态后必须还原"的最佳实践。
七、示例输出解读
正常运行(无溢出发生)时,示例输出如下:
[INFO] Device saturation mode switched from ACL_RT_OVERFLOW_MODE_INFNAN to ACL_RT_OVERFLOW_MODE_SATURATION. [INFO] Overflow switch=1 [INFO] Overflow status before reset=0 [INFO] Overflow status after reset=0 [INFO] Overflow detection sample finished successfully.逐行解读:
- 第一行确认模式从
ACL_RT_OVERFLOW_MODE_INFNAN切换为ACL_RT_OVERFLOW_MODE_SATURATION(原始模式值以实际设备为准); - 第二行确认流级溢出开关已开启(
Overflow switch=1); - 第三、四行分别打印复位前后的溢出标志,本例流上未执行可能溢出的算子任务,因此前后均为
0,这也演示了"状态查询与复位"两个动作本身可正常执行; - 第五行表示示例全流程成功完成。
八、已知问题与兼容性注意事项
原文档的 Known Issues 部分是本示例最关键的实战提醒,需重点理解:
aclrtSetStreamOverflowSwitch在ACL_RT_OVERFLOW_MODE_SATURATION和ACL_RT_OVERFLOW_MODE_INFNAN两种模式下均可使用,即溢出开关本身不强制要求饱和模式;但示例选择先切换到饱和模式,是为了演示"模式切换 + 开关配置"的完整组合流程。- 若当前产品不支持该能力,相关接口可能返回
ACL_ERROR_RT_FEATURE_NOT_SUPPORT (207000)。此时示例的做法是:记录告警日志,完成资源清理后退出(返回成功),而不是以失败状态退出——这在多形态 Runtime 环境下非常实用。 - 从代码实现看,
aclrtSetStreamOverflowSwitch、aclrtGetOverflowStatus、aclrtResetOverflowStatus均出现在 arch5162_unsupported_acl_api.def 的检索结果中,可以推断部分芯片架构的 Runtime 构建会剔除这些符号,因此在交叉部署场景(如更换设备型号)时务必先做能力探测。
九、总结与延伸阅读
本示例以最小可运行程序演示了 CANN Runtime 流级溢出检测的完整闭环:模式探测与切换(aclrtGetDeviceSatMode/aclrtSetDeviceSatMode)→ 开关配置(aclrtSetStreamOverflowSwitch/aclrtGetStreamOverflowSwitch)→ 异步状态查询(aclrtGetOverflowStatus+aclrtSynchronizeStream+aclrtMemcpy)→ 状态复位(aclrtResetOverflowStatus)→ 逆序资源清理与模式还原,并提供了完备的环境不支持降级路径,可直接作为可靠性检测模块的接入模板。
若要在真实训练/推理链路中落地,可在此基础上于"开启开关"与"查询状态"之间插入实际算子下发,并在before reset/after reset两次查询之间执行一轮关键计算,即可实现对某一阶段数值溢出的事后监控。
延伸阅读建议:
- 可靠性样例集总览:example/4_reliability/README_en.md
- 样例工程通用运行指南:example/README_en.md
- 溢出检测相关 API 声明:include/external/acl/acl_rt.h
- ACL 实现层与底层调用链:src/acl/aclrt_impl/device.cpp
- CANN
- Ascend
- 人工智能
- 任务调度
【免费下载链接】runtime
本项目提供CANN运行时组件和维测功能组件。
相关推荐
CANN Runtime 流级溢出检测实战:从开关配置到状态查询与重置
CANN Runtime 流级溢出检测实战:从开关配置到状态查询与重置 导读 本篇文章以 CANN / runtime 仓库中的 overflow_detect
CANNAscend人工智能任务调度CANN Runtime 流级溢出检测实战:开关配置、状态查询与重置流程深度解析
CANN Runtime 流级溢出检测实战:开关配置、状态查询与重置流程深度解析 浮点溢出(Overflow)是昇腾 AI 算子执行中最常见的数值异常之一,若不
CANNAscend人工智能任务调度CANN Runtime 溢出检测实战:基于 ACL RT 接口实现流级溢出开关、状态查询与重置
CANN Runtime 溢出检测实战:基于 ACL RT 接口实现流级溢出开关、状态查询与重置 导读 本文以 CANN Runtime 仓库中的溢出检测示例(
CANNAscend人工智能任务调度
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考