MTRTC 运行时编译用户指南
1. 概述
1.1 什么是 MTRTC?
MTRTC(MUSA Runtime Compilation) 是 MUSA SDK 提供的运行时编译库,库文件为 libmtrtc.so。MTRTC 接收字符串形式的 MUSA 设备端源码,并在运行时将其编译为可加载的二进制产物,再交给 MUSA Driver API 完成模块加载、符号查找和内核启动。
如果您已经熟悉离线 mcc 编译流程,可以将 MTRTC 理解为运行时场景下的设备端编译入口。MTRTC 的输出形式、支持选项和异常路径,以当前实现为准。
1.2 为什么使用 MTRTC?
MTRTC 主要面向“源码只能在运行时确定”的场景。在这些场景中,纯离线编译往往不够用,应用通常需要在运行时动态生成源码、拼接宏和头文件,或者按模板实例化结果解析 C++ 符号。
如果没有运行时编译库,应用通常只能预编译大量变体,或者在运行时调用外部编译工具处理源码。这会增加编译链路复杂度,也会让部署和调试变得更重。MTRTC 把这条流程收敛为一组库接口,直接提供 program 生命周期管理、构建日志获取、二进制产物获取,以及底层符号名(lowered name)查询。
因此,MTRTC 特别适合运行时生成源码、内存内依赖管理、C++ 符号查找,以及需要把编译产物直接接入 MUSA Driver API 的场景。
1.3 关键特性
| 特性 | 说明 | 好处 |
|---|---|---|
| 运行时编译 | 直接编译字符串形式的设备端源码 | 适合动态生成内核或按需编译 |
| 二进制编译产物 | 编译结果通过 mtrtcGetFatBin(Size) 获取 | 可直接交给 MUSA Driver API 加载 |
| 额外头文件输入 | mtrtcCreateProgram 支持通过字符串提供额外头文件 | 不依赖磁盘文件,便于封装 |
| 底层符号名查询 | 通过 mtrtcAddNameExpression 和 mtrtcGetLoweredName 获取底层符号名(lowered name) | 便于处理模板内核、命名空间内核和全局变量 |
| 可重复编译 | 同一 program 支持再次调用 mtrtcCompileProgram | 适合动态调参或重复构建 |
| 选项支持范围明确 | mtrtcCompileProgram 支持的编译选项以当前版本为准 | 便于建立稳定预期 |
详细 API、参数、返回值和条件可用能力,参见第 3 节。与 NVRTC 的接口对应关系见 4.1 NVRTC 接口对应关系。
1.4 MTRTC 如何工作?
1.4.1 典型使用路径
MTRTC 的工作流程可以概括为:在运行时接收源码,完成编译,再把编译产物直接交给 MUSA Driver API 加载执行。主路径如下:源码字符串 / 额外头文件 -> mtrtcCreateProgram -> mtrtcCompileProgram -> 构建日志 / 二进制产物 / lowered name -> MUSA Driver API 加载执行。
按调用顺序,MTRTC 的典型使用路径可以概括为 5 个阶段:
- 创建 program:用源码字符串和可选额外头文件创建
mtrtcProgram。 - 注册名称表达式:如需查询模板内核或全局变量符号,请在编译前调用
mtrtcAddNameExpression。 - 执行编译:通过
mtrtcCompileProgram传入支持的选项子集,生成二进制产物。 - 获取结果:读取构建日志、二进制产物和 lowered name。
- MUSA Driver API 加载执行:用
muModuleLoadData加载编译产物,再查找符号并启动内核。
1.4.2 系统架构
1.4.1 典型使用路径 说明调用顺序,本节说明组件分工。MTRTC 在系统中的位置可以概括为:Host 程序提供源码输入,libmtrtc.so 负责运行时编译,libmusa.so 负责加载并在 GPU 上执行。
┌──────────────────────────────┐
│ Host 侧程序(C/C++) │
└──────────────┬───────────────┘
│
│ 源码字符串 / 额外头文件
v
┌──────────────────────────────┐
│ libmtrtc.so │
│ 运行时编译 / 生成二进制产物 │
└──────────────┬───────────────┘
│
│ 编译产物
v
┌──────────────────────────────┐
│ libmusa.so │
│ 加载 / 查找符号 / 启动 │
└──────────────┬───────────────┘
│
v
┌──────────────────────────────┐
│ GPU 执行 │
└──────────────────────────────┘
各组件的职责如下:
| 组件 | 主要职责 |
|---|---|
| Host 侧程序 | 准备源码字 符串、额外头文件内容和编译选项,并串联整个调用流程。 |
libmtrtc.so | 接收输入、完成运行时编译,并产出构建日志、二进制产物和 lowered name。 |
libmusa.so | 加载编译产物、查找内核或全局变量符号,并发起执行。 |
| GPU | 执行加载后的设备端代码。 |
1.4.3 核心机制
额外头文件输入
MTRTC 支持把源码和额外头文件内容都直接作为字符串传入。头文件内容放在 headers[],头文件名放在 includeNames[],源码再通过 #include "..." 引用对应头文件。
src 字符串 + headers[] + includeNames[]
|
v
mtrtcCreateProgram
|
v
#include "extra_header.h"
在内存中完成解析
这样,运行时编译所需输入可以全部保存在内存中,而不依赖磁盘上的真实头文件。
名称表达式与底层符号名(lowered name)
对于模板内核、命名空间内核、C++ 修饰后的符号,以及 __device__ / __constant__ 变量,您通常需要先获取 lowered name,MUSA Driver API 才能正确查找对应符号。
"fill_const<float>"
|
v
mtrtcAddNameExpression
|
v
mtrtcCompileProgram
|
v
mtrtcGetLoweredName
|
v
muModuleGetFunction / muModuleGetGlobal
使用时请注意:
- 必须在
mtrtcCompileProgram之前调用mtrtcAddNameExpression。 - 只能在编译成功后调用
mtrtcGetLoweredName。 mtrtcGetLoweredName的表达式字符串必须与mtrtcAddNameExpression完全一致。- 返回的 lowered name 指针由
program持有;再次编译或销毁program后,该指针失效。 static __global__当前不支持 name expression 注册。
同一 program 支持重复编译。再次调用 mtrtcCompileProgram 后,旧的二进制产物、构建日志和 lowered name 结果都会失效;已注册的 name expression 会保留,并在下一轮编译中重新解析。