TVM 核心库架构
TVM 的 C++ 产物被拆成多个共享库,职责清晰、可按需部署。本文按依赖层次 和编译/运行分工说明各库的功能与作用。
整体关系
#mermaid-svg-ZXGXMIyuToGmAL2i{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZXGXMIyuToGmAL2i .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZXGXMIyuToGmAL2i .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZXGXMIyuToGmAL2i .error-icon{fill:#552222;}#mermaid-svg-ZXGXMIyuToGmAL2i .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZXGXMIyuToGmAL2i .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZXGXMIyuToGmAL2i .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZXGXMIyuToGmAL2i .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZXGXMIyuToGmAL2i .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZXGXMIyuToGmAL2i .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZXGXMIyuToGmAL2i .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZXGXMIyuToGmAL2i .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZXGXMIyuToGmAL2i .marker.cross{stroke:#333333;}#mermaid-svg-ZXGXMIyuToGmAL2i svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZXGXMIyuToGmAL2i p{margin:0;}#mermaid-svg-ZXGXMIyuToGmAL2i .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZXGXMIyuToGmAL2i .cluster-label text{fill:#333;}#mermaid-svg-ZXGXMIyuToGmAL2i .cluster-label span{color:#333;}#mermaid-svg-ZXGXMIyuToGmAL2i .cluster-label span p{background-color:transparent;}#mermaid-svg-ZXGXMIyuToGmAL2i .label text,#mermaid-svg-ZXGXMIyuToGmAL2i span{fill:#333;color:#333;}#mermaid-svg-ZXGXMIyuToGmAL2i .node rect,#mermaid-svg-ZXGXMIyuToGmAL2i .node circle,#mermaid-svg-ZXGXMIyuToGmAL2i .node ellipse,#mermaid-svg-ZXGXMIyuToGmAL2i .node polygon,#mermaid-svg-ZXGXMIyuToGmAL2i .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZXGXMIyuToGmAL2i .rough-node .label text,#mermaid-svg-ZXGXMIyuToGmAL2i .node .label text,#mermaid-svg-ZXGXMIyuToGmAL2i .image-shape .label,#mermaid-svg-ZXGXMIyuToGmAL2i .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZXGXMIyuToGmAL2i .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZXGXMIyuToGmAL2i .rough-node .label,#mermaid-svg-ZXGXMIyuToGmAL2i .node .label,#mermaid-svg-ZXGXMIyuToGmAL2i .image-shape .label,#mermaid-svg-ZXGXMIyuToGmAL2i .icon-shape .label{text-align:center;}#mermaid-svg-ZXGXMIyuToGmAL2i .node.clickable{cursor:pointer;}#mermaid-svg-ZXGXMIyuToGmAL2i .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZXGXMIyuToGmAL2i .arrowheadPath{fill:#333333;}#mermaid-svg-ZXGXMIyuToGmAL2i .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZXGXMIyuToGmAL2i .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZXGXMIyuToGmAL2i .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZXGXMIyuToGmAL2i .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZXGXMIyuToGmAL2i .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZXGXMIyuToGmAL2i .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZXGXMIyuToGmAL2i .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZXGXMIyuToGmAL2i .cluster text{fill:#333;}#mermaid-svg-ZXGXMIyuToGmAL2i .cluster span{color:#333;}#mermaid-svg-ZXGXMIyuToGmAL2i div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZXGXMIyuToGmAL2i .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZXGXMIyuToGmAL2i rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZXGXMIyuToGmAL2i .icon-shape,#mermaid-svg-ZXGXMIyuToGmAL2i .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZXGXMIyuToGmAL2i .icon-shape p,#mermaid-svg-ZXGXMIyuToGmAL2i .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZXGXMIyuToGmAL2i .icon-shape .label rect,#mermaid-svg-ZXGXMIyuToGmAL2i .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZXGXMIyuToGmAL2i .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZXGXMIyuToGmAL2i .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZXGXMIyuToGmAL2i :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 共享库
Python层
按需加载
tvm Python 包
tvm_ffi Python 包
libtvm_ffi.so
基础设施
libtvm_runtime.so
通用运行时
libtvm_compiler.so
编译器
libtvm_runtime_cuda.so
CUDA 设备运行时
| 库 | 何时需要 | 典型体积 |
|---|---|---|
libtvm_ffi |
始终 | 小 |
libtvm_runtime |
始终(执行) | 中 |
libtvm_compiler |
编译/优化 IR | 大(含 LLVM) |
libtvm_runtime_cuda |
在 GPU 上跑 CUDA 算子 | 小 |
1. tvm-ffi(libtvm_ffi.so)
定位:最底层的开放 ABI 和 FFI 基础设施 ,已从 TVM 独立为 apache-tvm-ffi 项目,TVM 通过 3rdparty/tvm-ffi 引入。
核心能力
- 稳定 C ABI:跨语言、跨框架的统一调用约定
- 类型系统 :
Any/AnyView(类型擦除值)、Object/ObjectRef(引用计数对象) - 函数注册 :
Function+ 全局注册表(register_global_func/get_global_func) - Tensor 互操作 :基于 DLPack 与 PyTorch / JAX / CuPy 零拷贝交换
- Module 加载 :
load_module("xxx.so")动态加载用户编译出的 kernel
在 TVM 中的角色
libtvm_runtime 和 libtvm_compiler 都链接 tvm_ffi_shared(见 CMakeLists.txt)。Python 侧 import tvm 时,最先加载的是 tvm_ffi 的 Cython 扩展;TVM 的 C++ 代码通过 #include <tvm/ffi/...> 使用同一套基础设施。
类比:tvm-ffi 像「操作系统内核接口」------对象模型、函数调用、模块加载都由它定义,TVM 和其他 kernel 库(FlashInfer、TileLang 等)都建在其上。
2. libtvm_runtime(libtvm_runtime.so)
定位:设备无关的通用执行运行时,负责「跑已经编译好的程序」。
包含的源码
CMake 中 RUNTIME_SRCS 主要来自:
src/runtime/*.ccsrc/runtime/vm/*.ccsrc/runtime/memory/*.ccsrc/runtime/rpc/minrpc/*.cc(可选)
主要功能:
| 模块 | 作用 |
|---|---|
Module / PackedFunc |
加载 .so 模块、调用编译产物 |
| VM(Relax VM) | 执行 Relax 编译后的字节码 |
| Memory | 内存池、工作区管理 |
| RPC | 远程设备调试/部署(可选) |
| Registry | 全局函数/类型注册 |
关键设计
- 与设备后端解耦 :CUDA / ROCm / Vulkan 等设备 API 不在 此库,而是独立 DSO(如
libtvm_runtime_cuda.so)。 - RTLD_GLOBAL 加载 :符号暴露给后续动态加载的模块(NVRTC kernel、用户
.so等)。见python/tvm/base.py。 - 可单独部署 :runtime-only wheel 只带
libtvm_runtime,适合纯推理场景(如 mlc-llm 部署端)。
类比:通用「虚拟机 + 加载器」------知道如何加载模块、调度函数,但不知道具体怎么操作 GPU。
3. libtvm_compiler(libtvm_compiler.so)
定位:编译器前端 + 中端 + 代码生成,负责「把 IR 编译成可执行代码」。
包含的源码(节选)
CMake 中 COMPILER_SRCS 和 CODEGEN_SRCS 覆盖:
src/ir/、src/arith/、src/te/、src/tirx/、src/relax/src/driver/(tvm.compile()/tvm.build()入口)src/target/、src/backend/cuda/codegen/、src/backend/rocm/codegen/等
主要功能:
| 模块 | 作用 |
|---|---|
| IR(Relax / TIR / TIRx) | 中间表示、变换 Pass |
| Driver | tvm.compile() / tvm.build() 入口 |
| Codegen | 生成 LLVM IR、CUDA C、Metal、Vulkan SPIR-V 等 |
| LLVM 后端 | CPU 代码生成、CUDA LLVM 路径(需 USE_LLVM=ON) |
| Arith / TE | 表达式化简、张量表达式 |
关键设计
- 依赖 LLVM (
USE_LLVM=ON):CPU codegen 和 LLVM 路径的 CUDA codegen 都需要。 - RTLD_LOCAL 加载:编译器符号不污染全局命名空间,避免与 LLVM 等冲突。
- CUDA 编译 vs CUDA 运行是分开的 :
- 编译 (生成
.cu/ PTX / cubin):在libtvm_compiler(src/backend/cuda/codegen/) - 运行 (分配显存、启动 kernel):在
libtvm_runtime_cuda
- 编译 (生成
类比:GCC / Clang 编译器本身------读源码、优化、生成目标文件,但不负责在 GPU 上执行。
4. libtvm_runtime_cuda(libtvm_runtime_cuda.so)
定位:CUDA 设备运行时后端 (USE_CUDA=ON 时构建),负责「在 NVIDIA GPU 上执行」。
包含的源码
见 cmake/modules/CUDA.cmake:
src/backend/cuda/runtime/*.ccsrc/runtime/vm/cuda/*.cc
| 文件 | 作用 |
|---|---|
cuda_device_api.cc |
CUDADeviceAPI:设备枚举、显存 alloc/free、H2D/D2H 拷贝、Stream、设备属性 |
cuda_module.cc |
加载 cubin/PTX、启动 CUDA kernel |
src/runtime/vm/cuda/*.cc |
Relax VM 在 CUDA 上的 builtin 算子 |
cuda_device_api.cc 实现了 DeviceAPI 接口,例如 SetDevice、GetAttr、AllocDataSpace 等。
加载时机
不是 import tvm 时立即加载,而是在 CUDA backend 注册时按需加载 (见 python/tvm/backend/cuda/__init__.py 的 register_backend())。加载后会向全局注册表注册 device_api.cuda 等函数,使 tvm.cuda().exist 能检测到 GPU。
关键设计
- 链接
libcuda+libcudart:需要 NVIDIA 驱动和 CUDA runtime。 - 依赖
libtvm_runtime:复用通用 Module / PackedFunc 框架。 - 不含编译器逻辑:不会调用 nvcc,只负责执行已编译产物。
- 可交叉编译:编译 TVM 时不需要实际 GPU,只要有 CUDA toolkit。
类比:CUDA Driver API 的适配层------让 TVM runtime 能在 NVIDIA GPU 上分配内存、拷贝数据、启动 kernel。
5. libtvm_runtime_extra(补充)
虽然不在核心四件套之列,但编译时常遇到:libtvm_runtime_extra.so 是可选扩展运行时,包含 Disco 分布式、NCCL、NVSHMEM、cuDNN/cuBLAS/CUTLASS 等 contrib 模块。
- 源码来自
src/runtime/extra/及各cmake/modules/contrib/模块 USE_CUDA=ON时会PUBLIC链接libtvm_runtime_cuda- 若启用了含
.cu的 contrib(如USE_NCCL、USE_THRUST、USE_CUTLASS),需正确设置CMAKE_CUDA_ARCHITECTURES
完整生命周期:以 CUDA kernel 为例
NVIDIA GPU libtvm_runtime_cuda libtvm_runtime libtvm_compiler Python 用户 NVIDIA GPU libtvm_runtime_cuda libtvm_runtime libtvm_compiler Python 用户 #mermaid-svg-AmqUn6AsSD7Kbjlg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-AmqUn6AsSD7Kbjlg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-AmqUn6AsSD7Kbjlg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-AmqUn6AsSD7Kbjlg .error-icon{fill:#552222;}#mermaid-svg-AmqUn6AsSD7Kbjlg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-AmqUn6AsSD7Kbjlg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-AmqUn6AsSD7Kbjlg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-AmqUn6AsSD7Kbjlg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-AmqUn6AsSD7Kbjlg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-AmqUn6AsSD7Kbjlg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-AmqUn6AsSD7Kbjlg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-AmqUn6AsSD7Kbjlg .marker{fill:#333333;stroke:#333333;}#mermaid-svg-AmqUn6AsSD7Kbjlg .marker.cross{stroke:#333333;}#mermaid-svg-AmqUn6AsSD7Kbjlg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-AmqUn6AsSD7Kbjlg p{margin:0;}#mermaid-svg-AmqUn6AsSD7Kbjlg .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-AmqUn6AsSD7Kbjlg text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-AmqUn6AsSD7Kbjlg .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-AmqUn6AsSD7Kbjlg .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-AmqUn6AsSD7Kbjlg .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-AmqUn6AsSD7Kbjlg .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-AmqUn6AsSD7Kbjlg #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-AmqUn6AsSD7Kbjlg .sequenceNumber{fill:white;}#mermaid-svg-AmqUn6AsSD7Kbjlg #sequencenumber{fill:#333;}#mermaid-svg-AmqUn6AsSD7Kbjlg #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-AmqUn6AsSD7Kbjlg .messageText{fill:#333;stroke:none;}#mermaid-svg-AmqUn6AsSD7Kbjlg .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-AmqUn6AsSD7Kbjlg .labelText,#mermaid-svg-AmqUn6AsSD7Kbjlg .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-AmqUn6AsSD7Kbjlg .loopText,#mermaid-svg-AmqUn6AsSD7Kbjlg .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-AmqUn6AsSD7Kbjlg .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-AmqUn6AsSD7Kbjlg .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-AmqUn6AsSD7Kbjlg .noteText,#mermaid-svg-AmqUn6AsSD7Kbjlg .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-AmqUn6AsSD7Kbjlg .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-AmqUn6AsSD7Kbjlg .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-AmqUn6AsSD7Kbjlg .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-AmqUn6AsSD7Kbjlg .actorPopupMenu{position:absolute;}#mermaid-svg-AmqUn6AsSD7Kbjlg .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-AmqUn6AsSD7Kbjlg .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-AmqUn6AsSD7Kbjlg .actor-man circle,#mermaid-svg-AmqUn6AsSD7Kbjlg line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-AmqUn6AsSD7Kbjlg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Relax/TIR Passes CUDA Codegen 生成 .cu/PTX 封装为可加载的 .so 注册 CUDADeviceAPI tvm.compile(mod, target="cuda") 返回 CompiledModule mod.export_library("kernel.so") import tvm → 加载 libtvm_runtime_cuda 加载 kernel.so 并调用 DeviceAPI::CopyData / Launch cudaLaunchKernel / cuModuleLaunchKernel
- 编译阶段 (
libtvm_compiler):IR → CUDA 源码/PTX,不需要 GPU - 注册阶段 (
libtvm_runtime_cuda):注册 CUDA 设备 API - 执行阶段 (
libtvm_runtime+libtvm_runtime_cuda):加载模块、分配显存、启动 kernel
Python 加载顺序
import tvm_ffi # FFI 基础设施(Cython 扩展)
import tvm
├─ load libtvm_runtime.so (RTLD_GLOBAL,必须)
├─ load libtvm_compiler.so (RTLD_LOCAL,runtime-only 模式跳过)
└─ autoload backends
└─ load libtvm_runtime_cuda.so (按需,RTLD_LOCAL)
└─ load libtvm_runtime_extra.so (若存在,RTLD_LOCAL)
验证当前加载了哪些库:
python
import tvm
print(tvm.base._LOADED_LIBS.keys())
# dict_keys(['tvm_runtime', 'tvm_compiler', 'tvm_runtime_cuda', ...])
print("\n".join(f"{k}: {v}" for k, v in tvm.support.libinfo().items()))
# USE_CUDA: ON, USE_LLVM: ..., LLVM_VERSION: ...
部署场景对照
| 场景 | 需要的库 |
|---|---|
| 仅 CPU 推理 | libtvm_ffi + libtvm_runtime |
| CUDA 推理(mlc-llm 部署) | 上述 + libtvm_runtime_cuda + `libtvm_runtime_extra` |
| 本地编译 + CUDA 推理 | 全部四个核心库 |
| 交叉编译(如在 x86 上编译给 Jetson 用) | 编译端需要 libtvm_compiler;运行端只需 runtime 系列 |
相关文档
- Install from Source --- 从源码构建 TVM
- TVM FFI 文档 --- FFI 独立项目说明
CMakeLists.txt--- 库拆分与链接关系cmake/modules/CUDA.cmake--- CUDA 运行时构建