CANN算子实现模式指南

发布时间:2026/6/6 14:44:24

CANN算子实现模式指南 实现模式【免费下载链接】cannbot-skillsCANNBot 是面向 CANN 开发的用于提升开发效率的系列智能体本仓库为其提供可复用的 Skills 模块。项目地址: https://gitcode.com/cann/cannbot-skills参考算子在算子工程根目录中选取一个已完成的算子作为结构参考参考其public 头文件形态源文件布局测试组织方式case 矩阵结构核函数入口结构不要照搬某个具体算子的数学逻辑。复用的是结构而非语义。构建与桩阶段创建include/{OP}.h其签名与算子的参数个数arity相匹配。创建一个桩src/{OP}.cpp返回Status::Ok()。为库和测试添加 CMake 目标。从桩阶段起就保留-xasc编译标志不要推迟到核函数实现时才加上。定义文档要求需记录公式输入/输出含义dtype 策略边界场景CPU 参考伪代码实现应遵循该文档而不是先在代码里臆造数学逻辑。迭代累加模式分析当源参考使用迭代累加例如在按 chunk 的循环内acc step时需评估浮点舍入误差是否会随迭代次数增长。该模式可能出现在任何参考实现中。对于序列生成类和线性递增类算子累计误差与 chunk 数量成正比在大数组上可能超出 fp32 测试容差例如约 560 次迭代后 max_diff 0.001。优先采用逐元素直接计算不要每次迭代都workUnit workStep而是计算base globalIdx * step。无论元素在数组中的位置如何这都将误差限定在一次乘加运算之内。在阶段 3 的源分析中标记出任何迭代累加模式并在定义文档中记录决策迭代 vs. 直接。设计文档要求需记录计算策略UB 缓冲区清单liveBytesPerElem切分公式向量指令序列如果算子使用了 local 拷贝路径需显式记录字节数、对齐假设与尾块处理。测试套件要求从一个可编译的占位测试开始。在核函数实现之前先加入 CPU 参考逻辑。加入 host 侧辅助函数测试与参数化的 NPU 测试。除非某个 case 明确针对边界或失败行为否则生成的输入应保持在算子的有效定义域内。核函数实现按以下顺序实现CalcTilingT()tile 处理例程核函数入口host 分发public API 接线每完成一个有意义的步骤后构建运行测试与定义文档和设计文档比对Ascend950 Reg API 模式对于 Ascend950 /dav-3510向量计算、类型转换Cast与规约应使用AscendC::Reg编写。详细参考见 reg-api-guide.md。默认 wrapper 形态__simd_vf__ inline void OpRegVf(__ubuf__ float *dstAddr, __ubuf__ float *srcAddr, uint32_t count, uint32_t chunkCount) { constexpr uint32_t vectorLength AscendC::VECTOR_REG_WIDTH / sizeof(float); AscendC::Reg::RegTensorfloat dstReg; AscendC::Reg::RegTensorfloat srcReg; for (uint32_t chunk 0; chunk chunkCount; chunk) { uint32_t offset chunk * vectorLength; uint32_t remaining count - offset; AscendC::Reg::MaskReg mask AscendC::Reg::UpdateMaskfloat(remaining); AscendC::Reg::LoadAlignfloat, AscendC::Reg::LoadDist::DIST_NORM(srcReg, srcAddr offset); // AscendC::Reg compute. AscendC::Reg::StoreAlignfloat, AscendC::Reg::StoreDist::DIST_NORM_B32(dstAddr offset, dstReg, mask); } } __aicore__ inline void OpReg(const AscendC::LocalTensorfloat dst, const AscendC::LocalTensorfloat src, int64_t count) { __ubuf__ float *dstAddr (__ubuf__ float *)dst.GetPhyAddr(); __ubuf__ float *srcAddr (__ubuf__ float *)src.GetPhyAddr(); constexpr uint32_t vectorLength AscendC::VECTOR_REG_WIDTH / sizeof(float); uint32_t elementCount static_castuint32_t(count); uint32_t chunkCount (elementCount vectorLength - 1) / vectorLength; asc_vf_callOpRegVf(dstAddr, srcAddr, elementCount, chunkCount); }Reg 规约的标量应使用 32B 槽位constexpr uint32_t reduceElems 32 / sizeof(float); AscendC::Reg::MaskReg scalarMask AscendC::Reg::UpdateMaskfloat(1);将第i行存储到dstAddr i * reduceElems。对于 Reg 规约产生的值避免使用LocalTensor::GetValue()将标量收尾与广播都保留在 Reg wrapper 内部。Reg sigmoid 应分解为Muls(-1) - Exp - Adds(1) - Div(1, denom)。在 Ascend950 Reg 路径中不要调用经典的AscendC::Sigmoid。B16 类型转换Cast应使用AscendC::Reg::CastTraitB16 输入用LoadDist::DIST_UNPACK_B16B16 输出用StoreDist::DIST_PACK_B32。对于 float 计算路径保持VECTOR_REG_WIDTH / sizeof(float)的 lane 逻辑除非有本地范例证明存在另一种合法形态。关键约定DataCopyPad的blockLen以字节计而非元素数。PipeBarrierPIPE_V()应遵循真依赖与冒险顺序在每个向量操作后都加一个虽然安全但偏保守。UB 到 UB 的DataCopy并不是任意长度的memcpy。在计算 DMA 块大小或传输元素数时对每一种受支持的 dtype 评估count * sizeof(T)。某个元素数对float满足 32B DMA 最小值8 个元素但对half可能低于最小值需要 16 个元素。以32 / sizeof(T)作为最小元素数。在CMakeLists.txt中ascend.cmake必须在project()之前 include。对std::uint16_t和float都需要显式的模板实例化。在 host 分发代码中使用 RAII 管理 device 侧内存。在 Ascend950 Reg 路径中asc_vf_call是唯一允许的原始asc_*调用。在 Ascend950 Reg 路径中经典 AscendC 的计算/类型转换/规约调用应替换为AscendC::Regwrapper。类型转换Cast支持矩阵AscendC 的Cast并不支持所有源到目标的类型对。特别是float - int8_t不受支持。请使用两步链float - halfCAST_NONE再half - int8_tCAST_ROUND。在假定存在直接路径之前务必对照 AscendC 文档核对每一步 Cast。当输出 dtype 与计算 dtype 不同时在设计阶段阶段 4规划 Cast 链并在 UB 缓冲区清单中记录每个中间缓冲区。TBuf 生命周期规则每个TBuf::GetT()调用都必须由与对应pipe.InitBuffer()相同的if constexpr条件守护。对未初始化的TBuf调用Get()是未定义行为。它在单核测试中可能看似正常但在多核分发下会破坏 pipe 管理ACL error 507035。当某缓冲区仅在特定 dtype 路径下需要时InitBuffer()和所有Get()调用都必须位于同一个编译期守护内。【免费下载链接】cannbot-skillsCANNBot 是面向 CANN 开发的用于提升开发效率的系列智能体本仓库为其提供可复用的 Skills 模块。项目地址: https://gitcode.com/cann/cannbot-skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻