前言

在异构计算生态中,一个核心挑战是如何让上层多样化的AI框架(如PyTorch、TensorFlow)能够无缝地利用底层专用硬件加速器。CANN(Compute Architecture for Neural Networks)的 runtime 仓库(截至2026年初的最新代码)通过一套精心设计的单算子执行接口(Single Op Execution API),巧妙地扮演了“通用翻译官”的角色。它不仅为开发者提供了直接调用高性能算子的能力,更构建了一座坚固的桥梁,实现了与主流AI框架的深度兼容。

本文将深入剖析 CANN runtime 的源码实现,聚焦于 src/acl 目录下的核心逻辑,从接口抽象、内部调度到与框架的集成细节,层层递进地揭示其如何实现高效、灵活且兼容性强的单算子执行能力。

一、设计理念:统一抽象与最小依赖

CANN runtime 的单算子执行接口设计遵循两大核心原则:

  1. 统一抽象:无论底层硬件如何变化,向上提供一套稳定、简洁的C语言API。
  2. 最小依赖:接口本身不绑定任何特定的AI框架,使其可以被任何需要高性能计算的场景所复用。

这套接口的核心定义在 include/acl/acl_op.hinclude/acl/acl_rt.h 中,主要包括:

  • aclCreateOpCompiler / aclFinalizeOp:用于动态编译和注册自定义算子。
  • aclnnXXX 系列函数(如 aclnnAdd, aclnnMatMul):直接调用预置的高性能算子。
  • aclrtMalloc / aclrtMemcpy:设备内存管理。
  • aclrtStream / aclrtEvent:异步执行与同步原语。

这种设计使得PyTorch的ATen后端、TensorFlow的XLA后端等都可以基于这套API构建自己的适配层。


二、接口实现:从API调用到内核派发

让我们以 aclnnMatMul 为例,解析一次单算子调用的完整生命周期。

2.1 用户态调用:参数封装

用户(或框架适配层)调用 aclnnMatMul,传入输入/输出张量描述符、计算属性和执行流。

// 用户/框架代码
aclTensor* inputA, *inputB, *outputC;
aclnnMatMul(workspace, workspaceSize, inputA, inputB, outputC, stream);

2.2 Runtime管理层:OpExecutor 的调度

src/acl/op/acl_op_executor.cpp 中,aclnnMatMul 的实现会创建一个 OpExecutor 对象,并启动执行流程。

// src/acl/op/acl_op_executor.h (简化)
class OpExecutor {
public:
    OpExecutor(const std::string& op_type, const OpDesc& desc);
    aclError Run(aclrtStream stream);
    
private:
    std::string op_type_; // "MatMul"
    OpDesc op_desc_;      // 包含输入/输出/属性
    std::shared_ptr<KernelLauncher> launcher_;
};

OpExecutor::Run 方法是核心,它负责:

  1. 算子查找:根据 op_type_ 在全局算子注册表(OpRegistry)中查找对应的算子实现。
  2. 内核选择:算子实现通常包含多个针对不同数据类型、形状的内核(Kernel)。OpExecutor 会根据输入张量的具体信息(如 dtype, shape)选择最优内核。
  3. 任务派发:调用 launcher_->Launch(...) 将内核执行任务提交到指定的 stream

2.3 内核执行层:与Driver的交互

KernelLauncher 的具体实现(如 GeKernelLauncher)位于 src/acl/ge/ 目录。它最终会通过 CANN 的 图引擎(Graph Engine, GE)或直接通过 driver 的接口来派发任务。

对于单算子场景,为了追求极致性能,runtime 通常会选择绕过完整的图编译流程,直接构造一个轻量级的任务描述符,并通过 driver 提供的 DCMI(DaVinci Card Management Interface) ioctl 接口提交给硬件。

// src/acl/driver/driver_interface.cpp (示意)
aclError DirectKernelLaunch(
    const KernelDesc& kernel,
    const std::vector<void*>& args,
    aclrtStream stream) 
{
    // 1. 从stream获取关联的device context
    auto ctx = GetDeviceContext(stream);
    
    // 2. 构造硬件可识别的任务包
    DcTaskPackage pkg;
    pkg.kernel_addr = kernel.bin_addr;
    pkg.args = args;
    
    // 3. 通过ioctl提交到driver
    return ctx->dc_interface->SubmitTask(pkg);
}

这里的 dc_interface 就是对 driver 仓库中 /dev/davinci_manager 设备节点的封装。这清晰地展示了 runtime 如何作为策略层,而 driver 作为机制层协同工作。


三、多框架兼容性:插件化适配架构

CANN runtime 本身并不直接集成PyTorch或TensorFlow,而是通过插件化的方式支持它们。

3.1 PyTorch: TorchNPU 插件

华为开源的 TorchNPU 项目是PyTorch的官方后端插件。其核心工作是在PyTorch的 ATen(A Tensor Library) 层进行拦截。

  • 当PyTorch执行 torch.add(a, b) 时,ATen会尝试调用注册的后端实现。
  • TorchNPU 在初始化时,会将 add 操作映射到 CANN runtime 的 aclnnAdd
  • TorchNPU 负责将PyTorch的 at::Tensor 对象转换为 CANN 的 aclTensor 描述符,并管理内存同步。

关键代码位于 TorchNPUaten/RegisterNPUNativeFunctions.cpp

// TorchNPU 伪代码
at::Tensor add_npu(const at::Tensor& self, const at::Tensor& other) {
    // 1. 获取CANN runtime的Tensor描述符
    auto acl_self = torch_npu::GetAclTensor(self);
    auto acl_other = torch_npu::GetAclTensor(other);
    
    // 2. 调用CANN runtime API
    aclnnAdd(acl_self, acl_other, ...);
    
    // 3. 返回结果
    return self;
}

3.2 TensorFlow: 自定义OP或XLA Backend

对于TensorFlow,有两条路径:

  1. 自定义OP:开发者可以使用 CANN runtime API 编写 TensorFlow 的 Custom OP。
  2. XLA Backend:更高级的方式是实现一个 XLA 的后端(Backend),将 XLA HLO IR 直接编译成 CANN 的算子调用序列。这需要利用 CANN 的图编译能力(GE),但单算子执行接口仍然是构建这个后端的基础积木。

无论是哪种方式,CANN runtime 提供的稳定、高效的单算子API都是不可或缺的基石。


四、动态算子编译:扩展性的关键

除了预置算子,CANN runtime 还支持动态算子编译,这是其兼容性和扩展性的另一大支柱。

开发者可以使用 Ascend C 等专用语言编写自定义算子内核,然后通过 aclCreateOpCompiler 在运行时将其编译并加载。

// 动态编译示例
aclOpCompiler* compiler = aclCreateOpCompiler("MyCustomOp");
aclSetOpCompilerInput(compiler, ...); // 设置内核代码、输入输出格式
aclFinalizeOp(compiler); // 完成编译并注册到OpRegistry

// 之后就可以像调用内置算子一样调用它
aclnnMyCustomOp(...);

这一机制使得 CANN 生态能够快速支持新兴模型中的新算子,而无需等待整个软件栈的更新,极大地增强了其生命力。


结语

CANN runtime 的单算子执行接口,通过统一的C语言抽象、高效的内部调度机制以及与底层 driver 的紧密协同,成功地解决了异构计算中的“最后一公里”问题。它不仅是开发者直接利用硬件算力的利器,更是连接PyTorch、TensorFlow等上层框架与底层硬件的通用桥梁。其插件化的设计思想和动态算子编译能力,确保了CANN软件生态在面对快速演进的AI模型时,依然能保持强大的适应性和竞争力。


cann组织链接:https://atomgit.com/cann
runtime仓库链接:https://atomgit.com/cann/runtime

更多推荐