CANN/asc-devkit SuperKernel算子适配指南

📅 2026/6/17 14:53:25
CANN/asc-devkit SuperKernel算子适配指南
算子适配说明【免费下载链接】asc-devkit本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言原生支持C和C标准规范主要由类库和语言扩展层构成提供多层级API满足多维场景算子开发诉求。项目地址: https://gitcode.com/cann/asc-devkit自定义算子要支持融合进SuperKernel开发流程上与普通算子并无显著差异但需要遵循以下一系列特定约束。这些约束与具体的开启路径GE或aclgraph无关大部分约束与算子启动核数block num以及SuperKernel启动核数之间的关系相关需要开发者在算子设计阶段就予以关注。[!NOTE]说明 SuperKernel启动核数为其中所有子Kernel的最大启动核数。例如SuperKernel包含算子a启动核数为4和算子b启动核数为2则SuperKernel启动核数为4。全核同步约束自定义算子若进行全核同步需注意该子Kernel启动的核数需要与SuperKernel的核数一致通常需要启动当前硬件满核。若子Kernel启动的核数少于SuperKernel的核数全核同步会等待所有核完成导致卡住超时。MIX 1:1算子核数比例约束若自定义算子的Kernel类型设置为KERNEL_TYPE_MIX_AIC_1_1因为SuperKernel会根据启动核数等信息调整SuperKernel的启动比例此时需特别注意该算子也可以适应SuperKernel的1:2启动比例确保AIC与AIV之间的硬同步操作正确执行。比如算子内部使用了AIC与AIV之间的硬同步接口CrossCoreSetFlag和CrossCoreWaitFlag不要单独指定某些AIV核调用硬同步接口要使所有AIV核均调用硬同步接口防止因为硬同步数量不匹配而导致卡死超时。使用Matmul高阶API时算子逻辑应保证仅有一个AIV0核调用Matmul接口防止启动两个AIV核之后出现AIV1核消息无法接收导致卡死超时。标量读写与Cache一致性在开发自定义算子时开发者必须确保所有对GM的标量读写操作都按需正确插入DataCacheCleanAndInvalid指令。在单算子编译场景下毕昇编译器自动在算子末尾添加DataCacheCleanAndInvalid指令刷新整个DCache数据缓存。在SuperKernel中子Kernel被当作普通函数处理编译器不会自动插入该指令来确保数据缓存一致性开发者需要自行保证避免因容错机制改变而导致错误。出于性能考虑SuperKernel场景下Cache刷新机制如下如果开发者调用GlobalTensor的GetValue和SetValue接口对GM进行标量读写在GE入图及aclnn调用场景SuperKernel编译时会自动在两个接口内部插入DataCacheCleanAndInvalid指令刷新单个Cache Line保证一定的数据缓存一致性。不会在子Kernel调用前后插入DataCacheCleanAndInvalid。如果开发者通过GlobalTensor的()运算符接口来获取值读值时会插入DataCacheCleanAndInvalid指令刷新单个Cache Line保证数据缓存一致性但通过该接口直接改写了GlobalTensor对应位置的值时则不会自动插入DataCacheCleanAndInvalid指令开发者需要自行保证数据缓存一致性。例如AscendC::GlobalTensorfloat xGm; xGm.SetGlobalBuffer((__gm__ float *)(addr), length); // addr为GM地址length为对应GM长度 xGm(0) (float)(1.0); // 在获取值时SuperKernel能够保证自动刷新cache line但是写值时相当于普通变量直接赋值SuperKernel无法插入DataCacheCleanAndInvalid需要用户保证数据缓存的一致性。对于频繁调用GetValue和SetValue的算子建议使用dcci_before_kernel_start、dcci_after_kernel_end关闭指定算子内GetValue/SetValue中自动插入的缓存刷新指令而改为算子调用前后插入整个DCache刷新避免性能劣化。具体option说明请参考各自pytorch图模式SuperKernel文档option说明章节GE入图参考TorchAir用户指南“图内标定SuperKernel范围”npugraph_ex后端参考torchair仓库docs/zh/npugraph_ex/advanced/superkernel.md中super_kernel_optimize_options参数说明。Cache刷新机制示意图如下图所示核数获取接口约束在GE入图及aclnn调用场景子Kernel中调用GetBlockNum接口获取核数时无论是否融合SuperKernel获取的核数保持不变不受SuperKernel启动核数的影响。因此在使用该接口时开发者无需特别关注SuperKernel的启动核数使用方法和开发普通算子时一样。在SuperKernel场景下如下Ascend C API在算子编译过程中适配了SuperKernel子算子需要严格按照Ascend C提供的API进行编程从而无需感知是否开启SuperKernel。例如在获取核数和索引时不能调用block_idx、block_num等底层变量和相关API必须使用下表中的Ascend C APIAPI列表功能描述AscendC::GetBlockIdx()获取当前核的indexAscendC::GetBlockNum()获取当前任务配置的核数TPipe析构约束针对Atlas A3 训练系列产品/Atlas A3 推理系列产品在GE入图及aclnn调用场景子算子TPipe对象析构TPipe::Destroy接口内部的AscendC::PipeBarrierPIPE_ALL()指令会被去除如果算子内部使用了多个TPipe对象或手动调用Destroy函数时开发者需自行保障TPipe对象间流水的同步。样例场景一TPipe对象析构时同步当算子中存在多个TPipe对象且通过作用域大括号或算子结束触发析构时需在第一个TPipe析构后手动插入PipeBarrierPIPE_ALL()确保流水同步。// 场景一两个TPipe对象通过作用域析构需在第一个析构后插入PipeAll { AscendC::TPipe pipe1; AscendC::TQueAscendC::TPosition::VECOUT, 2 que1; uint8_t num1 2; uint32_t len1 128; pipe1.InitBuffer(que1, num1, len1); // ... 使用pipe1进行算子计算 ... } // pipe1析构但Destroy中的PipeBarrier已被去除 // 必须手动插入PipeAll保证pipe1流水完成后再使用pipe2 AscendC::PipeBarrierAscendC::PIPE_ALL(); { AscendC::TPipe pipe2; AscendC::TQueAscendC::TPosition::VECOUT, 2 que2; uint8_t num2 2; uint32_t len2 128; pipe2.InitBuffer(que2, num2, len2); // ... 使用pipe2进行算子计算 ... } // pipe2析构场景二手动调用Destroy时同步当算子中存在多个TPipe对象且手动调用Destroy接口时需在第一个TPipe的Destroy调用后手动插入PipeBarrierPIPE_ALL()确保流水同步。// 场景二两个TPipe对象手动调用Destroy需在第一个Destroy后插入PipeAll AscendC::TPipe pipe1; AscendC::TQueAscendC::TPosition::VECOUT, 2 que1; uint8_t num1 2; uint32_t len1 128; pipe1.InitBuffer(que1, num1, len1); // ... 使用pipe1进行算子计算 ... pipe1.Destroy(); // Destroy中的PipeBarrier已被去除 // 必须手动插入PipeAll保证pipe1流水完成后再使用pipe2 AscendC::PipeBarrierAscendC::PIPE_ALL(); AscendC::TPipe pipe2; AscendC::TQueAscendC::TPosition::VECOUT, 2 que2; uint8_t num2 2; uint32_t len2 128; pipe2.InitBuffer(que2, num2, len2); // ... 使用pipe2进行算子计算 ... pipe2.Destroy();性能优化建议任务间同步开发者在进行Kernel侧编程时可以通过调用SetNextTaskStart和WaitPreTaskEnd两个任务间接口进一步提升性能。调用SetNextTaskStart后的指令可以和后续其他的子Kernel实现并行提升整体性能。如图1所示SuperKernel按序调用子Kernel为保证子Kernel之间数据互不干扰会在子Kernel间插入算子间同步进行保序子KernelN-1调用该接口后之后的指令会和后续子KernelN实现并行。图1通过SetNextTaskStart实现并行示意图![](https://raw.gitcode.com/cann/asc-devkit/raw/53dc4118ba3145bede6cae97046a6ac4b1d500e4/docs/guide/figures/通过SetNextTaskStart实现并行示意图.png 通过SetNextTaskStart实现并行示意图?utm_sourcegitcode_repo_files)调用WaitPreTaskEnd前的指令可以和前序其他的子Kernel实现并行提升整体性能。如图2所示SuperKernel按序调用子Kernel为保证子Kernel之间数据互不干扰会在子Kernel间插入算子间同步进行保序子KernelN1调用该接口之前的指令会和前序子KernelN实现并行。图2通过WaitPreTaskEnd实现并行示意图![](https://raw.gitcode.com/cann/asc-devkit/raw/53dc4118ba3145bede6cae97046a6ac4b1d500e4/docs/guide/figures/通过WaitPreTaskEnd实现并行示意图.png 通过WaitPreTaskEnd实现并行示意图?utm_sourcegitcode_repo_files)二进制复用优化在GE入图Tiling下沉场景下可以通过--op_relocatable_kernel_binary编译选项开启二进制复用优化提升编译性能具体可参考算子工程编译。核函数直调算子的额外适配对于使用方式开发的Ascend C算子除了遵循上述通用约束外还需要在算子kernel入口侧增加SuperKernel入口函数。具体方法请参考核函数直调算子额外适配说明。【免费下载链接】asc-devkit本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言原生支持C和C标准规范主要由类库和语言扩展层构成提供多层级API满足多维场景算子开发诉求。项目地址: https://gitcode.com/cann/asc-devkit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考