- 模型编译
- 深度学习
- 推理引擎
【免费下载链接】tvm
Open Machine Learning Compiler Framework
导读
本文以 docs/tirx/api/backend.rst 为骨架,深入解析 Apache TVM 中tvm.backend这一后端扩展 API:它如何发现并加载"目标设备拥有(target-owned)"的 Python 语义,如何通过一次注册同时挂载 TVMScript 命名空间、tile-dispatch 实现、目标标签、编译流水线入口点与代码生成支持。读完本文,你将掌握tvm.backend.load/is_loaded的调用方式、自动加载的触发路径与开关、CUDA(tvm.backend.cuda)与 Trainium(tvm.backend.trn)两大内置后端的注册入口及其在编译流水线中的实际作用,并具备为自定义硬件编写独立后端包的能力。
一、Backend Extension API 是什么
在 TIRx(TVM 新一代 Tile IR 编程框架)中,核心 IR 与编译机制集中在tvm.tirx命名空间下;而目标设备(target)专属的语义——脚本命名空间、tile 原语分派、目标标签、编译流水线入口、代码生成回调——则统一由tvm.backend包承载。二者通过tvm.backend的"发现 + 加载"机制连接起来。
按照 docs/tirx/api/backend.rst 的官方描述:
tvm.backenddiscovers and loads target-owned Python semantics. Depending on the target, loading a backend registers its TVMScript namespaces, tile-dispatch implementations, target tags, compilation-pipeline entry points, and code-generation support.
即:加载一个后端(backend)的副作用(side effect)是向tvm.tirx注册该目标设备拥有的全部 Python 语义。这些注册是幂等的,因此多次导入不会产生重复注册。
tvm.backend的包入口非常精简,见 python/tvm/backend/init.py,其对外 API 只有两个:
tvm.backend.load(name):加载名为name的后端,触发其注册钩子;tvm.backend.is_loaded(name):查询该后端是否已加载。
二、后端加载机制:load 与 is_loaded
2.1 加载流程
load的实现位于 python/tvm/backend/loader.py,其执行步骤为:
- 幂等检查:若
name已存在于内部字典_LOADED_BACKENDS,直接返回; - 导入后端包:
importlib.import_module(f"tvm.backend.{name}"),即后端包必须位于tvm.backend.<name>; - 校验注册钩子:包内必须暴露
register_backend()函数,否则抛出AttributeError; - 挂载到 TIRx:将模块对象同时写入
tvm.tirx.<name>属性与sys.modules["tvm.tirx.<name>"]; - 调用
register_backend():执行全部注册副作用; - 建立公开别名:调用
_alias_loaded_backend_modules把tvm.backend.<name>.*下所有已加载子模块映射为tvm.tirx.<name>.*; - 失败回滚:任何异常都会从
_LOADED_BACKENDS与tvm.tirx上回滚,避免留下半加载状态。
2.2 公开别名机制
loader.py中通过_AliasModule、_AliasLoader与_BackendAliasFinder三件套实现了一个巧妙的导入重定向:当代码执行from tvm.tirx.cuda import ...时,sys.meta_path中的_BackendAliasFinder会将其重定向到真实的tvm.backend.cuda.*模块(见 python/tvm/backend/loader.py)。这意味着:
- 公开面:用户统一通过
tvm.tirx.<backend>.*访问后端能力; - 实现面:后端代码实际存放于
tvm.backend.<backend>.*,两者是同一模块的不同名字。
这一层抽象让"后端拥有(backend-owned)"的边界清晰可见:核心编译器不直接依赖任何具体硬件后端,而具体后端也不会污染核心命名空间。
2.3 自动加载与内置后端清单
python/tvm/backend/_autoload_backends.py 实现了import tvm时的自动加载:
- 内置后端元组
_BUILTIN_BACKENDS包含 9 个:cuda、metal、rocm、trn、opencl、vulkan、webgpu、hexagon、adreno; _load_builtin_backends()逐一调用load(name),并尝试加载libtvm_runtime_extra动态库以获取 C++ 侧注册副作用;- 通过环境变量
TVM_DEVICE_BACKEND_AUTOLOAD=0可整体关闭自动加载; - 纯运行时模式(
_RUNTIME_ONLY)下跳过内置后端加载。
2.4 树外(out-of-tree)后端扩展点
自动加载同样面向第三方扩展开放。_autoload_backends会遍历 Python 包入口点分组tvm.backends,并逐一调用声明的钩子函数(见 python/tvm/backend/_autoload_backends.py):
# pyproject.toml(以树外后端 tvm_foo 为例) [project.entry-points."tvm.backends"] tvm_foo = "tvm_foo:_autoload"其中tvm_foo._autoload()内部通常调用tvm.backend.load("foo")。若钩子抛异常,只会产生warnings.warn警告,不影响import tvm的其余流程。
三、CUDA 注册:register_backend 与脚本命名空间
CUDA 是 TIRx 中最重要的后端之一,其注册入口集中在 python/tvm/backend/cuda/init.py,对应文档 docs/tirx/api/backend.rst 中 "CUDA registration" 一节的三个公开函数:
3.1tvm.backend.cuda.register_backend()
执行以下注册动作(见 python/tvm/backend/cuda/init.py):
- 运行时侧库加载:尝试加载
tvm_runtime_cuda(RTLD_LOCAL模式),失败时静默跳过; - 设备目标探测器注册:调用
register_device_target_detector("cuda", _detect_target_from_device),让 TVM 能从Device对象自动推导 CUDATarget(sm_<compute_version>、共享内存/线程上限、warp 大小等,见同一文件_detect_target_from_device); - TVMScript 命名空间注册:遍历
script_namespaces()的返回值,逐个调用register_script_namespace(name, namespace)挂载到 TIRx 脚本构建器; - 导入触发副作用:导入
cpp、tile_primitive、target_tags三个子模块——它们本身不提供面向 kernel 作者的 API,但导入过程会注册 C++ 代码生成回调、tile 原语分派与命名 NVIDIA 目标标签(文档明确将这类模块称为"实现面,而非额外的 kernel 编写 API")。
3.2script_namespace()与script_namespaces()
script_namespaces()返回 5 个 CUDA 拥有的脚本命名空间对象(见 python/tvm/backend/cuda/init.py):cuda、nvshmem、ptx_legacy、ptx、s_tir;script_namespace()是取单个"cuda"命名空间的便捷封装。
加载完成后,Tx.cuda、Tx.ptx、Tx.nvshmem等脚本命名空间即可在from tvm.script import tirx as Tx后直接使用(用法示例见 docs/tirx/api/cuda.rst):
from tvm.script import tirx as Tx Tx.cuda.cta_sync() leader = Tx.cuda.elect_sync()CUDA 命名空间的辅助函数覆盖同步参与(any_sync/elect_sync/cta_sync/grid_sync/cluster_sync/__shfl_sync族)、屏障与内存序(mbarrier_wait/thread_fence/atomic_add/atomic_cas)、归约(warp_reduce/cta_sum/reduce_add_sync_u32等)、描述符与地址(wgmma.encode_matrix_descriptor/tcgen05.encode_matrix_descriptor/cvta_generic_to_shared/mov_sreg等)、加载调用与诊断(ldg/func_call/printf/clock64/ffs_u32)、数值转换与打包运算(half2float/float22half2/fmul2_rn/hmin2/fdividef等),以及插桩兼容(iket.mark/iket.range_start/timer_start/mma_store等)。单条 PTX 指令级操作则走表驱动的Tx.ptx命名空间(参见 docs/tirx/api/ptx.rst)。
3.3 CUDA 后端的模块化分工
按 docs/tirx/arch/backends.rst 中 "CUDA ownership" 一节的划分,tvm.backend.cuda按编译器职责切分为(源码目录见 python/tvm/backend/cuda):
| 模块 | 职责 |
|---|---|
script、ptx | 构建Tx.cuda、Tx.ptx、兼容命名空间与 NVSHMEM 命名空间 |
op | 定义 CUDA 脚本命名空间使用的 IR 构建器 |
tile_primitive | 注册Tx.tile常见操作的 CUDA 实现(copy/copy_async/gemm/elementwise/reduction/permute_layout 等子目录) |
codegen、cpp | 注册源码生成回调与 CUDA C++ 辅助(asm/builtins/descriptors/nvshmem 等) |
transforms | 提供 CUDA 专属编译 pass |
target_tags | 注册命名 NVIDIA 目标(见下) |
lang、iket | 提供可复用 kernel 工具(tile 调度器、流水线、barrier、SMEM/TMEM 池)与性能剖析编排 |
其中target_tags(python/tvm/backend/cuda/target_tags.py)通过register_tag注册形如nvidia/nvidia-a100(sm_80)、nvidia/nvidia-h100(sm_90a)等数据中心目标,并针对 Jetson 系列注册带aarch64-linux-gnuhost 配置的嵌入式目标,标签配置包含max_shared_memory_per_block、max_threads_per_block、thread_warp_size、registers_per_block等关键资源参数。
四、Trainium 注册:register_backend 与 NKI 命名空间
AWS Trainium 后端遵循与 CUDA 完全相同的集成边界,入口集中在 python/tvm/backend/trn/init.py,对应文档 "Trainium registration" 一节:
4.1tvm.backend.trn.register_backend()
注册动作(见 python/tvm/backend/trn/init.py):
- 脚本命名空间注册:将
script_namespaces()返回的{"nki": NKINamespace(...)}注册到 TIRx 脚本构建器; - 导入副作用:导入
tile_primitive(注册 Trainium 目标分派)、pipeline、target_tags(注册命名 AWS Trainium 目标)、transform(注册 Trainium 专属 pass); - 编译流水线注册:调用
compilation_pipeline.register_tir_pipeline("trn", trn_pipeline.trn_pipeline),把 Trainium 的 TIR pass 序列挂到命名流水线"trn"上。
4.2 脚本命名空间函数
script_namespace(op_wrapper=None)返回NKINamespace实例;script_namespaces(op_wrapper=None, **_)返回{"nki": ...}。
加载后Tx.nki命名空间即告就绪,当前支持的算子包括load、store、tensor_copy、matmul、activation、activation_reduce、reciprocal、tensorreduce、tensortensor、tensorscalar、memset、identity、affine_select等(完整列表见 docs/tirx/api/trainium.rst)。
4.3 Trainium 模块分工
同样依据 docs/tirx/arch/backends.rst 的 "Trainium ownership" 一节,tvm.backend.trn(源码见 python/tvm/backend/trn)的分工为:
script、op:构建Tx.nki编程面;tile_primitive:注册目标分派实现(binary/copy/gemm/reduction/select/unary/compose_op 等子目录);layout、transform:下沉 Trainium 专属内存映射(如TrnNaiveAllocator、TrnPrivateBufferAlloc);pipeline:组装 Trainium pass 序列;target_tags:注册命名 AWS Trainium 目标。
五、注册副作用背后的核心注册点
tvm.backend的每次register_backend()最终都落到 TIRx 核心的几个注册表上,这是理解后端集成机制的关键:
- 脚本命名空间注册:
register_script_namespace(name, namespace)将命名空间挂到 TIRx 脚本构建器门面并同步写入__all__(见 python/tvm/tirx/script/builder/ir.py)。CUDA 注册的cuda、ptx、nvshmem、s_tir,Trainium 注册的nki,都经由这条路径生效。 - 设备目标探测器注册:
register_device_target_detector(device_type, detector)写入SUPPORTED_DEVICE表(见 python/tvm/target/detect_target.py),使detect_target_from_device(dev)能按运行时设备类型自动生成对应Target。 - 编译流水线注册:
register_tir_pipeline(name, pipeline_factory)写入PIPELINE_MAP(见 python/tvm/tirx/compilation_pipeline.py),随后get_tir_pipeline(name)即可按名取用预置流水线——Trainium 的"trn"流水线正是如此注册的。 - 目标标签注册:
tvm.target.register_tag将命名标签(如nvidia/nvidia-h100)绑定到完整的 target 配置字典上,供用户在编译时按名引用。
此外,C++ 侧还通过tvm_runtime_extra、tvm_runtime_cuda等动态库的导入副作用注册设备辅助模块的 codegen(如codegen_cuda.cc需要找到的设备 helper 模块),这也是 CUDAregister_backend中import_module(f"{__name__}.cpp")等调用的根本目的——导入即注册,无新增 kernel API。
六、后端 API 的典型使用与关联文档地图
6.1 查询与手动加载
import tvm.backend as backend backend.is_loaded("cuda") # 检查 CUDA 后端是否已加载 backend.load("cuda") # 显式加载(幂等,可重复调用)正常情况下import tvm已自动加载内置后端;手动load主要用于树外后端或延迟加载场景。
6.2 关联文档导航
- docs/tirx/api/cuda.rst:kernel 面向的
Tx.cuda辅助函数、Tx.nvshmem命名空间、tvm.backend.cuda.lang可复用工具(tile 调度器、MBarrier、Pipeline、SMEMPool/TMEMPool等)、IKET 剖析与 CUDA 专属 transforms; - docs/tirx/api/ptx.rst:表驱动的 PTX 指令命名空间与合法修饰符/操作数形式;
- docs/tirx/api/trainium.rst:
Tx.nki编程面、tvm.backend.trn的 layout / pipeline / transform 辅助 API; - docs/tirx/arch/backends.rst:后端加载与注册的内部机制、CUDA 与 Trainium 的模块所有权划分。
6.3 集成点小结
回顾文档收尾的定义:tvm.backend.cuda.register_backend、script_namespace、script_namespaces与tvm.backend.trn对应三个函数,是后端集成点(backend integration points)——它们不面向 kernel 编写者直接使用,而是为后端包提供统一入口;kernel 编写者应使用各目标命名空间(Tx.cuda、Tx.ptx、Tx.nki)及配套 API。理解这一分层,既能帮助你排查"命名空间未注册 / 目标未识别"类问题,也能为接入新硬件后端提供清晰的接入范式:新建tvm.backend.<name>包 → 实现register_backend()→ 声明入口点(内置或tvm.backends组)→ 由tvm.backend.load完成注册与别名挂载。
- 模型编译
- 深度学习
- 推理引擎
【免费下载链接】tvm
Open Machine Learning Compiler Framework
相关推荐
TIRx 后端内部机制解析:tvm.backend 的加载注册、CUDA 与 Trainium 所有权划分
TIRx 后端内部机制解析:tvm.backend 的加载注册、CUDA 与 Trainium 所有权划分 TIRx 是 TVM 中以 tvm.tirx 为核心
模型编译深度学习推理引擎TVM TIRx Tile Primitive Dispatch 全解:TilePrimitiveCall 的选型、下降与扩展机制
TVM TIRx Tile Primitive Dispatch 全解:TilePrimitiveCall 的选型、下降与扩展机制 导读:TIRx 是 TVM
模型编译深度学习推理引擎Apache TVM TIRx Trainium 后端编写与支持 API 完全指南:Tx.nki 命名空间、布局助手与编译流水线
Apache TVM TIRx Trainium 后端编写与支持 API 完全指南:Tx.nki 命名空间、布局助手与编译流水线 导读 本文以 docs/tir
模型编译深度学习推理引擎
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考