<<<>>>直调新开发算子

写在前面

该文档主要说明,开发者完成CATLASS新算子开发后,如何通过Ascend C的<<<>>>算子调用符直接启动新开发的算子,以及相关注意事项。

<<<>>> 语法

算子调用符<<<...>>>是Ascend C提供的一种语法,封装了对Runtime API的调用,方便开发者将算子调度到NPU的AI Core上执行。 以下是通过<<<>>>调用Kernel执行的示例:

kernel_name<<<blockDim, l2ctrl, stream>>>(argument_list);

三个参数的含义如下:

参数 类型 说明
blockDim uint32_t 用多少个AI Core来执行该算子
l2ctrl void* 保留参数,固定设为nullptr
stream aclrtStream 管理异步操作执行顺序的流对象

其中blockDim表示需要多少个硬件AI Core来执行算子,一般通过platform_ascendc::PlatformAscendCManager::GetInstance()->GetCoreNumAic()。算子内可通过GetBlockIdx()获取当前核索引,通过GetBlockNum()获取总核数。

说明:算子的调用是异步的,<<<>>>调用结束后控制权立刻返回给Host端。如需等待执行完成,需调用aclrtSynchronizeStream(stream)

直调流程

基于CATLASS模板组件开发新Kernel后,使用<<<>>>直调的整体流程如下:

  1. 环境初始化:aclInitaclrtSetDeviceaclrtCreateStream
  2. 数据准备:aclrtMallocHost分配并初始化Host内存,aclrtMalloc分配Device内存,aclrtMemcpy将数据拷入Device。
  3. 组装模板组件:选择ArchTag、DispatchPolicy、TileShape、数据类型,组装BlockMmad等组件,拼出Kernel类型。
  4. 使用<<<>>>调用算子:
    auto aicCoreNum = platform_ascendc::PlatformAscendCManager::GetInstance()->GetCoreNumAic();
    Catlass::KernelAdapter<MyKernel><<<aicCoreNum, nullptr, stream>>>(params);
    
  5. 结果拷回:通过aclrtMemcpy将Device上的运算结果拷贝回Host。
  6. 同步等待:aclrtSynchronizeStream
  7. 资源释放:aclrtDestroyStreamaclrtResetDeviceaclFinalize

<<<>>> 直调与DeviceGemm的对比

CATLASS的Device层(如DeviceGemm)内部就是通过<<<>>>启动算子的,并额外封装了CanImplement检查、Workspace管理等便利功能。

对比维度 <<<>>>直调 DeviceGemm
调用方式 手写KernelAdapter<...><<<>>>(params) matmulOp(stream, blockDim)
Workspace管理 需手动处理 封装在适配器内
推荐场景 原型开发、调测阶段、非标Kernel 标准GEMM/GEMV/Conv

简单来说,开发标准算子推荐用DeviceGemm;需要更多控制权时再选择直调。