CANN Runtime 内置任务(Built-in Task)下发与执行实战:Reduce 归约与随机数生成 CANN Runtime 内置任务Built-in Task下发与执行实战Reduce 归约与随机数生成【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime导读本文围绕 CANN Runtime 的内置任务built-in task能力展开该能力让开发者无需自研算子、不加载 kernel 二进制即可在 Stream 上异步下发两类高频基础计算任务Reduce 归约运算aclrtReduceAsync与随机数生成aclrtRandomNumAsync支持均匀/正态/截断正态分布与 Dropout Bitmask。文中以 example/2_advanced_features/built_in_task 目录下的两个可编译运行示例为骨架结合 include/external/acl/acl_rt.h 中的真实 API 声明与数据结构完整讲解任务下发 API 的参数语义、任务信息结构体字段布局、内存要求、产品支持范围与构建运行步骤。读完本文你可以直接在 CANN 环境中把这两个示例跑起来并掌握如何在自己的业务代码中组织aclrtRandomNumTaskInfo、如何为随机数任务准备 16 字节 counter 内存以及 Reduce 任务就地前缀和的输出规律。一、什么是 Runtime 内置任务CANN Runtime 的典型执行模型是编译 kernel → 加载二进制 → 在 Stream 上下发执行。但对于求和、极值比较、随机数生成这类基础性、通用性的计算逐次走完整的 kernel 加载链路既不必要也不高效。Runtime 因此提供了内置任务built-in task机制运行时内部预置对应实现应用只需通过一个异步下发 API把数据地址、参数与目标 Stream 一并交给 Runtime任务即以异步、有序的方式进入 Stream 的任务队列执行。从 example/2_advanced_features/built_in_task/README_en.md 的目录组织可以确认当前仓库围绕该能力提供两个官方示例示例目录核心 API能力说明0_reduce_taskaclrtReduceAsyncReduce 任务下发与结果读取1_random_num_taskaclrtRandomNumAsync随机数任务下发支持多种分布与数据类型两者的共同特点是不需要任何自定义算子源码只依赖acl_rt一个动态库即可链接运行见两个示例的 CMakeLists.txt 中target_link_libraries(main PRIVATE acl_rt)非常适合作为理解Stream 异步执行模型 Runtime 内建计算的入门与实战素材。二、示例构建与运行通用步骤两个示例的构建方式完全一致均由 run.sh 一键完成 cmake 配置、编译并直接执行。文档给出的运行步骤为# 将 ${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 源码其内部执行链路为source $_ASCEND_INSTALL_PATH/bin/setenv.bash加载 CANN 环境变量在示例目录下创建build/目录并进入执行cmake .. -DASCEND_CANN_PACKAGE_PATH${_ASCEND_INSTALL_PATH}将 CANN 安装路径传给 CMakemake -j$(nproc)编译生成build/main直接运行./build/main。构建细节来自 0_reduce_task/CMakeLists.txt还包括通过include_directories(${ASCEND_CANN_PACKAGE_PATH}/include)引入 CANN 头文件代码中使用#include acl/acl.h即可获得全部接口通过link_directories(${ASCEND_CANN_PACKAGE_PATH}/lib64)引入运行库目录链接acl_rt编译选项为-O2 -stdc17 -D_GLIBCXX_USE_CXX11_ABI0 -Wall -Werror即要求 C17 并启用_GLIBCXX_USE_CXX11_ABI0与 CANN 预编译库的 ABI 保持一致这是示例在各类发行版上可正常链接的关键之一。产品支持范围以当前仓库文档为准功能Ascend 950PR/Ascend 950DTAtlas A3 训练/推理系列Atlas A2 训练/推理系列Reduce 任务aclrtReduceAsync支持支持支持随机数任务aclrtRandomNumAsync不支持支持支持注意随机数内置任务在 Ascend 950 系列上不受支持部署前请务必核对目标产品型号。三、示例 1Reduce 归约任务3.1 任务语义就地前缀和Automatic SumReduce归约是并行计算中的基础操作用于对数组元素执行求和、求最大值等运算。本示例使用的是ACL_RT_MEMCPY_SDMA_AUTOMATIC_SUM自动求和即前缀和调用一次aclrtReduceAsync即可让 Device 侧在 Stream 上异步完成计算。示例的完整逻辑位于 0_reduce_task/main.cpp输入{1.0, 2.0, 3.0, 4.0}输出为Reduce SUM result[0] 2.000000 Reduce SUM result[1] 4.000000 Reduce SUM result[2] 6.000000 Reduce SUM result[3] 8.000000 [INFO] Sample run successfully.可以清楚看到每个输出元素是输入元素与其前一个输出元素之和result[0] 11result[1] 22result[2] 33result[3] 44即典型的前缀和语义。因此使用该接口时必须保证输出缓冲区与输入缓冲区均有效——示例中特意把输入数据先拷贝到devInput和devOutput两份内存aclrtMemcpy两次见 main.cppsrc 与 dst 是两个不同地址。3.2 核心 APIaclrtReduceAsync头文件 include/external/acl/acl_rt.h 中的真实声明为ACL_FUNC_VISIBILITY aclError aclrtReduceAsync( void* dst, const void* src, uint64_t count, aclrtReduceKind kind, aclDataType type, aclrtStream stream, void* reserve);参数语义如下参数说明dst输出地址Device 内存src输入地址Device 内存count数据大小字节kind归约类型见aclrtReduceKindtype数据类型如ACL_FLOATstream任务下发的目标 Streamreserve保留参数必须为NULL归约类型枚举完整定义位于 acl_rt.htypedef enum { ACL_RT_MEMCPY_SDMA_AUTOMATIC_SUM 10, // 自动求和前缀和 ACL_RT_MEMCPY_SDMA_AUTOMATIC_MAX 11, // 自动求最大值 ACL_RT_MEMCPY_SDMA_AUTOMATIC_MIN 12, // 自动求最小值 ACL_RT_MEMCPY_SDMA_AUTOMATIC_EQUAL 13, // 自动比较相等 } aclrtReduceKind;示例中以ACL_FLOAT32 位浮点为数据类型调用ret aclrtReduceAsync( devOutput, devInput, size, // 输出、输入、字节数 ACL_RT_MEMCPY_SDMA_AUTOMATIC_SUM, // 归约类型自动求和 ACL_FLOAT, // 数据类型 stream, NULL); CHECK_ERROR(ret);3.3 完整执行流程示例的程序流程就是一套标准的 AscendCL 生命周期可作为所有内置任务示例的通用模板初始化aclInit(NULL)初始化 AscendCL 配置设备管理aclrtSetDevice(0)指定计算 Device创建 StreamaclrtCreateStream(stream)准备数据Host 侧构造float hostInput[4]用aclrtMalloc(..., ACL_MEM_MALLOC_HUGE_FIRST)在 Device 申请输入/输出内存再用aclrtMemcpy(..., ACL_MEMCPY_HOST_TO_DEVICE)上板下发任务调用aclrtReduceAsync异步立即返回同步等待aclrtSynchronizeStream(stream)阻塞等待 Stream 上任务执行完毕回拷结果aclrtMemcpy(..., ACL_MEMCPY_DEVICE_TO_HOST)将结果拷回 Host 并打印释放资源aclrtFree释放 Device 内存、aclrtDestroyStream销毁 Stream、aclrtResetDeviceForce(0)强制复位计算 Device 并回收资源、aclFinalize()反初始化。值得注意的是示例使用aclrtResetDeviceForce强制复位而非普通的aclrtResetDevice用于确保 Device 资源被彻底回收便于示例反复运行。四、示例 2随机数任务4.1 核心 APIaclrtRandomNumAsync头文件 include/external/acl/acl_rt.h 中的真实声明为ACL_FUNC_VISIBILITY aclError aclrtRandomNumAsync( const aclrtRandomNumTaskInfo* taskInfo, const aclrtStream stream, void* reserve);其参数只有三个任务信息结构体指针、目标 Stream、保留字段须为NULL。所有生成什么分布、什么数据类型、范围/均值/方差、种子、数量、结果写到哪的信息全部封装在aclrtRandomNumTaskInfo中。4.2 任务信息结构体aclrtRandomNumTaskInfo头文件 include/external/acl/acl_rt.h 中的真实定义注意rsv为 8 字节与示例文档中打印的结构略有差异以头文件为准typedef struct { aclDataType dataType; aclrtRandomNumFuncParaInfo randomNumFuncParaInfo; void* randomParaAddr; void* randomResultAddr; void* randomCounterAddr; aclrtRandomParaInfo randomSeed; aclrtRandomParaInfo randomNum; uint8_t rsv[8]; } aclrtRandomNumTaskInfo;各字段说明字段说明dataType随机数输出数据类型如ACL_FLOAT、ACL_FLOAT16、ACL_BF16、ACL_INT32等randomNumFuncParaInfo函数类型与分布参数详见下节randomParaAddr参数地址示例中固定为NULL参数直接内嵌在结构体中randomResultAddr随机数结果输出地址Device 内存randomCounterAddr随机数状态 counter 地址Device 内存固定 16 字节randomSeed随机种子aclrtRandomParaInfo类型randomNum生成的随机数个数aclrtRandomParaInfo类型rsv[8]保留字段其中的通用参数类型aclrtRandomParaInfoacl_rt.h定义了立即数 or 设备内存地址的双通道传参方式typedef struct { uint8_t isAddr; // 是否为地址0 表示 valueOrAddr 直接存立即数值1 表示存设备内存地址 uint8_t valueOrAddr[8]; // 8 字节保存立即数值或设备内存地址 uint8_t size; // 参数大小字节 uint8_t rsv[6]; } aclrtRandomParaInfo;示例中所有参数均采用立即数方式isAddr 0例如随机种子与数量的填充*((uint64_t*)taskInfo.randomSeed.valueOrAddr) seed; // 种子写进 valueOrAddr taskInfo.randomSeed.size sizeof(uint64_t); taskInfo.randomSeed.isAddr 0; *((uint64_t*)taskInfo.randomNum.valueOrAddr) num; // 数量写进 valueOrAddr taskInfo.randomNum.size sizeof(uint64_t); taskInfo.randomNum.isAddr 0;如需把参数放入 Device 内存则把isAddr置 1、valueOrAddr存地址、size填参数字节数即可文档中参数可使用立即值或设备内存的说法与此结构完全对应。4.3 函数类型与分布参数函数类型枚举aclrtRandomNumFuncType与参数联合体定义于 acl_rt.htypedef enum { ACL_RT_RANDOM_NUM_FUNC_TYPE_DROPOUT_BITMASK 0, // dropout bitmask ACL_RT_RANDOM_NUM_FUNC_TYPE_UNIFORM_DIS, // uniform distribution ACL_RT_RANDOM_NUM_FUNC_TYPE_NORMAL_DIS, // normal distribution ACL_RT_RANDOM_NUM_FUNC_TYPE_TRUNCATED_NORMAL_DIS, // truncated normal distribution } aclrtRandomNumFuncType; typedef struct { aclrtRandomNumFuncType funcType; union { aclrtDropoutBitmaskInfo dropoutBitmaskInfo; aclrtUniformDisInfo uniformDisInfo; aclrtNormalDisInfo normalDisInfo; } paramInfo; } aclrtRandomNumFuncParaInfo;对应的分布参数子结构acl_rt.h// dropout bitmask typedef struct { aclrtRandomParaInfo dropoutRation; // Dropout 比例 } aclrtDropoutBitmaskInfo; // uniform distribution typedef struct { aclrtRandomParaInfo min; // 最小值 aclrtRandomParaInfo max; // 最大值 } aclrtUniformDisInfo; // normal distribution typedef struct { aclrtRandomParaInfo mean; // 均值 aclrtRandomParaInfo stddev; // 标准差 } aclrtNormalDisInfo;四种生成类型及支持的数据类型汇总如下生成类型函数类型标识参数支持的数据类型均匀分布UniformACL_RT_RANDOM_NUM_FUNC_TYPE_UNIFORM_DISmin/max浮点ACL_FLOAT、ACL_FLOAT16、ACL_BF16整型ACL_INT32、ACL_INT64、ACL_UINT32、ACL_UINT64正态分布NormalACL_RT_RANDOM_NUM_FUNC_TYPE_NORMAL_DISmean/stddevACL_FLOAT、ACL_FLOAT16、ACL_BF16截断正态分布Truncated NormalACL_RT_RANDOM_NUM_FUNC_TYPE_TRUNCATED_NORMAL_DISmean/stddevACL_FLOAT、ACL_FLOAT16、ACL_BF16Dropout Bitmask 生成ACL_RT_RANDOM_NUM_FUNC_TYPE_DROPOUT_BITMASKratio比例输出UINT8ratio 支持ACL_FLOAT、ACL_FLOAT16、ACL_BF16示例 1_random_num_task/main.cpp 以分组封装函数的形式演示了这些类型UniformFloatAsync、UniformFloat16Async、UniformBF16Async、UniformInt32/Int64/Uint32/Uint64Async覆盖均匀分布的全部数据形态NormalFloatAsync/NormalFloat16Async/NormalBF16Async通过isTruncated布尔参数在正态与截断正态之间切换见 main.cpp 中isTruncated ? ACL_RT_RANDOM_NUM_FUNC_TYPE_TRUNCATED_NORMAL_DIS : ACL_RT_RANDOM_NUM_FUNC_TYPE_NORMAL_DISDropoutBitmask用于生成 Dropout 掩码。4.4 随机数算法与内存要求算法当前仓库文档明确记录的算法为Philox4_32_10其特点为支持所有分布类型counter 为 128 bit需 16 字节存储。内存要求来自 1_random_num_task/README_en.mdCounter 内存固定 16 字节任意字节对齐地址均可。示例中用constexpr size_t kCounterSize 16U;申请并用aclrtMemset清零main.cpp输出内存根据数据类型与随机数个数动态计算大小示例统一按num * sizeof(uint64_t)申请足够大的缓冲区以容纳 128 个各类型结果main.cpp参数内存均值、标准差、取值范围等参数可内嵌立即数示例做法也可使用设备内存地址。关于 counter 需要注意Philox 算法依赖 counter 状态推进来生成随机数因此同一个 counter 内存在连续多次任务间会被改写示例在 5 组任务中反复复用同一个counterAddr而未重置恰好演示了复用 counter 得到连续随机序列的用法若希望每次生成相同序列则需要重置 counter 或换用不同种子。4.5 运行结果示例[INFO] Generate normal distribution random numbers, data type: float Random result[0] ... ... [INFO] Generate truncated normal distribution random numbers, data type: BF16 Random result[0] ... ... [INFO] Generate uniform distribution random numbers, data type: FP16 Random result[0] ... ... [INFO] Generate uniform distribution random numbers, data type: INT32 Random result[0] ... ... [INFO] Generate dropout bitmask, output data type: UINT8 Random result[0] ... [INFO] Sample run successfully.打印方式与数据类型对应float 用%fBF16/FP16 用%#x输出 16 位十六进制位模式BF16(1.0) 0x3F80、FP16(1.0) 0x3C00、BF16(2.0) 0x4000见 main.cppINT32 用%dUINT8 用%u。五、内置任务在 Runtime 中的定位从接口定义可见内置任务与普通 kernel 下发如aclrtLaunchKernel位于同一层级的 acl_rt.h 头文件中二者共享相同的Stream 异步执行模型API 调用后立即返回任务按序进入 Stream 队列通过aclrtSynchronizeStream或事件机制同步。这一模型带来的工程收益包括零自定义算子成本Reduce、随机数这类基础运算不再需要编写和编译 kernel异步流水线化与 Stream 上的其他任务拷贝、kernel、事件天然有序衔接可组合出完整的计算流水可预测的内存模型counter 固定 16 字节、参数支持立即数/地址两种传法内存管理可控。需要特别强调的是产品差异aclrtReduceAsync在 Ascend 950 系列与 Atlas A2/A3 系列均受支持而aclrtRandomNumAsync在 Ascend 950 系列上不受支持参见 1_random_num_task/README_en.md 的产品支持表。在 Atlas A2/A3 上使用随机数任务时建议像示例一样先aclInit/aclrtSetDevice初始化环境再创建 Stream、申请 counter 与输出内存最后下发任务并通过aclrtSynchronizeStream收尾整体流程可直接复用到生产代码中。六、参考与延伸阅读目录总览example/2_advanced_features/built_in_task/README_en.mdReduce 示例文档0_reduce_task/README_en.md源码0_reduce_task/main.cpp构建脚本0_reduce_task/run.sh随机数示例文档1_random_num_task/README_en.md源码1_random_num_task/main.cpp构建脚本1_random_num_task/run.shAPI 与数据结构定义include/external/acl/acl_rt.haclrtReduceAsync见 L4164-L4166aclrtRandomNumAsync见 L5411-L5412相关枚举与结构体见 L715-L821示例运行总说明example/README_en.md【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考