news 2026/6/19 12:07:47

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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的GetValueSetValue接口对GM进行标量读写,在GE入图及aclnn调用场景,SuperKernel编译时会自动在两个接口内部插入DataCacheCleanAndInvalid指令刷新单个Cache Line,保证一定的数据缓存一致性。不会在子Kernel调用前后插入DataCacheCleanAndInvalid。

  • 如果开发者通过GlobalTensor的()运算符接口来获取值(读值时会插入DataCacheCleanAndInvalid指令刷新单个Cache Line保证数据缓存一致性),但通过该接口直接改写了GlobalTensor对应位置的值时,则不会自动插入DataCacheCleanAndInvalid指令,开发者需要自行保证数据缓存一致性。例如:

    AscendC::GlobalTensor<float> xGm; xGm.SetGlobalBuffer((__gm__ float *)(addr), length); // addr为GM地址,length为对应GM长度 xGm(0) = (float)(1.0); // 在获取值时,SuperKernel能够保证自动刷新cache line,但是写值时,相当于普通变量直接赋值,SuperKernel无法插入DataCacheCleanAndInvalid,需要用户保证数据缓存的一致性。

对于频繁调用GetValueSetValue的算子,建议使用dcci_before_kernel_startdcci_after_kernel_end关闭指定算子内GetValue/SetValue中自动插入的缓存刷新指令,而改为算子调用前后插入整个DCache刷新,避免性能劣化。具体option说明,请参考各自pytorch图模式SuperKernel文档option说明章节:GE入图参考TorchAir用户指南“图内标定SuperKernel范围”,npugraph_ex后端参考torchair仓库docs/zh/npugraph_ex/advanced/superkernel.mdsuper_kernel_optimize_options参数说明。

Cache刷新机制示意图如下图所示:

核数获取接口约束

在GE入图及aclnn调用场景,子Kernel中调用GetBlockNum接口获取核数时,无论是否融合SuperKernel,获取的核数保持不变,不受SuperKernel启动核数的影响。因此,在使用该接口时,开发者无需特别关注SuperKernel的启动核数,使用方法和开发普通算子时一样。

在SuperKernel场景下,如下Ascend C API在算子编译过程中适配了SuperKernel,子算子需要严格按照Ascend C提供的API进行编程,从而无需感知是否开启SuperKernel。例如在获取核数和索引时,不能调用block_idxblock_num等底层变量和相关API,必须使用下表中的Ascend C API:

API列表功能描述
AscendC::GetBlockIdx()获取当前核的index
AscendC::GetBlockNum()获取当前任务配置的核数

TPipe析构约束

针对Atlas A3 训练系列产品/Atlas A3 推理系列产品,在GE入图及aclnn调用场景,子算子TPipe对象析构(TPipe::Destroy)接口内部的AscendC::PipeBarrier<PIPE_ALL>()指令会被去除,如果算子内部使用了多个TPipe对象或手动调用Destroy函数时开发者需自行保障TPipe对象间流水的同步。

样例:

  • 场景一:TPipe对象析构时同步

    当算子中存在多个TPipe对象,且通过作用域(大括号或算子结束)触发析构时,需在第一个TPipe析构后手动插入PipeBarrier<PIPE_ALL>(),确保流水同步。

    // 场景一:两个TPipe对象通过作用域析构,需在第一个析构后插入PipeAll { AscendC::TPipe pipe1; AscendC::TQue<AscendC::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::PipeBarrier<AscendC::PIPE_ALL>(); { AscendC::TPipe pipe2; AscendC::TQue<AscendC::TPosition::VECOUT, 2> que2; uint8_t num2 = 2; uint32_t len2 = 128; pipe2.InitBuffer(que2, num2, len2); // ... 使用pipe2进行算子计算 ... } // pipe2析构
  • 场景二:手动调用Destroy时同步

    当算子中存在多个TPipe对象,且手动调用Destroy接口时,需在第一个TPipe的Destroy调用后手动插入PipeBarrier<PIPE_ALL>(),确保流水同步。

    // 场景二:两个TPipe对象手动调用Destroy,需在第一个Destroy后插入PipeAll AscendC::TPipe pipe1; AscendC::TQue<AscendC::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::PipeBarrier<AscendC::PIPE_ALL>(); AscendC::TPipe pipe2; AscendC::TQue<AscendC::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_source=gitcode_repo_files)

    • 调用WaitPreTaskEnd前的指令可以和前序其他的子Kernel实现并行,提升整体性能。如图2所示,SuperKernel按序调用子Kernel,为保证子Kernel之间数据互不干扰,会在子Kernel间插入算子间同步进行保序,子KernelN+1调用该接口之前的指令会和前序子KernelN实现并行。

    图2通过WaitPreTaskEnd实现并行示意图
    ![](https://raw.gitcode.com/cann/asc-devkit/raw/53dc4118ba3145bede6cae97046a6ac4b1d500e4/docs/guide/figures/通过WaitPreTaskEnd实现并行示意图.png "通过WaitPreTaskEnd实现并行示意图"?utm_source=gitcode_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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/17 14:37:23

ComfyUI-LTXVideo深度解析:5个高级技巧实现专业级AI视频生成

ComfyUI-LTXVideo深度解析&#xff1a;5个高级技巧实现专业级AI视频生成 【免费下载链接】ComfyUI-LTXVideo LTX-Video Support for ComfyUI 项目地址: https://gitcode.com/GitHub_Trending/co/ComfyUI-LTXVideo ComfyUI-LTXVideo作为ComfyUI平台上最先进的AI视频生成插…

作者头像 李华
网站建设 2026/6/19 12:56:12

2026 无线延长器的核心原理是什么?潜创微专业方案商深度解析

一、无线延长器的核心原理解无线延长器的核心作用是突破音视频信号的传输距离限制&#xff0c;其技术原理围绕信号转换、稳定传输、还原输出三个核心环节&#xff0c;分为有线和无线两类主流技术路线。&#xff08;一&#xff09;有线HDMI延长器原理&#xff08;以潜创微HDMI网…

作者头像 李华
网站建设 2026/6/17 14:25:49

终身学习与多模态智能体的技术挑战与解决方案

1. 终身模仿学习的技术挑战与核心思路在机器人控制和智能体学习领域&#xff0c;让系统具备持续学习新任务而不遗忘旧知识的能力一直是个关键挑战。传统机器学习方法通常假设训练数据是独立同分布的&#xff0c;但在真实世界中&#xff0c;智能体需要面对的是连续不断的新任务流…

作者头像 李华
网站建设 2026/6/17 14:22:52

用PowerShell精准掌控Windows 11网络适配器:从优先级调整到高级属性管理

1. 为什么需要手动管理网络适配器优先级&#xff1f; 在Windows 11系统中&#xff0c;当你的设备同时连接了有线网卡、Wi-Fi、虚拟机网卡等多种网络适配器时&#xff0c;系统会自动为这些连接分配优先级。但自动分配的优先级往往不符合实际需求&#xff0c;比如你可能希望&…

作者头像 李华
网站建设 2026/6/17 13:56:38

Proxy能够监听到对象中的对象的引用吗?

简短结论 原生的 new Proxy(target, handler)只能代理「它直接包裹的那一层对象」&#xff0c;对 target内部的嵌套对象&#xff0c;默认是"透传"的——返回的是裸对象&#xff0c;后续操作完全逃逸监听。 为什么会"听不到"嵌套对象&#xff1f; const o…

作者头像 李华