DeepGEMM C++ 核心架构与 JIT 编译引擎深度分析
分析日期:2026-07-30
代码库:/Users/backyes/work/triton/DeepGEMM
目标受众:AI 系统研究人员、编译器工程师、芯片体系结构研究者
目录
- 总体架构概览
- C++ API 层架构
- 2.1 pybind11 入口与模块注册
- 2.2 register_apis 模式
- 2.3 各 API 模块详解 - JIT 编译管线
- 3.1 完整生命周期
- 3.2 编译器抽象层
- 3.3 NVCC 编译器实现
- 3.4 NVRTC 编译器实现
- 3.5 Include Parser 与依赖追踪 - Kernel Caching 机制
- 4.1 Cache Key 设计
- 4.2 Cache 目录管理
- 4.3 运行时 Cache - Kernel Runtime 与 Launch
- 5.1 KernelRuntime 加载
- 5.2 LaunchRuntime 模板
- 5.3 TMA Descriptor 构建
- 5.4 Kernel Launch 流程 - Device Runtime
- 6.1 CUDA 设备管理
- 6.2 cuBLASLt 集成
- 6.3 架构检测与 arch 字符串 - Handle 管理与 CUDA Driver 抽象
- Utility 层
- 8.1 compatibility.hpp
- 8.2 exception.hpp
- 8.3 format.hpp
- 8.4 hash.hpp
- 8.5 layout.hpp
- 8.6 lazy_init.hpp
- 8.7 math.hpp
- 8.8 system.hpp - Heuristics 与自动调优
- 错误处理体系
- 内存管理
- 关键设计洞察与架构评价
1. 总体架构概览
DeepGEMM 的 C++ 层是一个精心设计的 JIT (Just-In-Time) 编译框架,其核心设计哲学是:
将 GEMM kernel 的编译延迟到运行时,通过模板实例化生成针对具体问题规模(problem size)优化的 CUDA kernel,同时通过多层缓存机制避免重复编译。
整个 C++ 架构可以分为以下层次:
graph TB
subgraph "Python Layer"
PY[deep_gemm/__init__.py]
end
subgraph "C++ API Layer (csrc/apis/)"
GEMM[gemm.hpp]
ATTN[attention.hpp]
MEGA[mega.hpp]
EINSUM[einsum.hpp]
HC[hyperconnection.hpp]
LAYOUT[layout.hpp]
RUNTIME[runtime.hpp]
end
subgraph "JIT Kernel Implementations (csrc/jit_kernels/impls/)"
K_SM90[sm90_fp8_gemm_1d1d.hpp]
K_SM100[sm100_fp8_fp4_gemm_1d1d.hpp]
K_SM90_BF16[sm90_bf16_gemm.hpp]
K_SM100_BF16[sm100_bf16_gemm.hpp]
K_OTHERS[...]
end
subgraph "JIT Engine (csrc/jit/)"
COMP[compiler.hpp<br/>NVCC/NVRTC]
CACHE[cache.hpp]
KRUN[kernel_runtime.hpp]
DEV[device_runtime.hpp]
HANDLE[handle.hpp]
INCPAR[include_parser.hpp]
end
subgraph "Heuristics (csrc/jit_kernels/heuristics/)"
H_COMMON[common.hpp]
H_SM90[sm90.hpp]
H_SM100[sm100.hpp]
H_CONFIG[config.hpp]
H_RUNTIME[runtime.hpp]
end
subgraph "Utils (csrc/utils/)"
UTILS[exception/format/hash/layout/<br/>lazy_init/math/system/compatibility]
end
subgraph "CUDA Infrastructure"
NVCC[NVCC Compiler]
NVRTC[NVRTC Runtime Compiler]
CUDA_DRV[CUDA Driver API]
CUDA_RT[CUDA Runtime API]
CUBLASLT[cuBLASLt]
end
PY --> GEMM & ATTN & MEGA & EINSUM & HC & LAYOUT & RUNTIME
GEMM & ATTN --> K_SM90 & K_SM100 & K_SM90_BF16 & K_SM100_BF16 & K_OTHERS
K_SM90 & K_SM100 --> COMP
K_SM90 & K_SM100 --> H_COMMON & H_SM90 & H_SM100
COMP --> CACHE & KRUN
KRUN --> DEV & HANDLE
COMP --> INCPAR
DEV --> HANDLE
COMP --> NVCC & NVRTC
KRUN --> CUDA_DRV & CUDA_RT
DEV --> CUBLASLT
COMP & KRUN & DEV --> UTILS
关键模块职责一览:
| 模块 | 文件 | 核心职责 |
|---|---|---|
| Python API | python_api.cpp |
pybind11 模块入口,注册所有 C++ API |
| GEMM API | apis/gemm.hpp |
FP8/BF16 GEMM 的 4 种矩阵布局 (nt/nn/tn/tt) |
| Attention API | apis/attention.hpp |
MQA logits 计算、paged KV cache |
| Mega API | apis/mega.hpp |
MoE 对称通信 + 计算融合 |
| Einsum API | apis/einsum.hpp |
爱因斯坦求和约定 kernel |
| HyperConnection | apis/hyperconnection.hpp |
TF32 HC prenorm GEMM |
| Layout API | apis/layout.hpp |
Scaling factor 布局变换 |
| Runtime API | apis/runtime.hpp |
SM 数量、PDL、编译维度控制 |
| JIT Compiler | jit/compiler.hpp |
NVCC/NVRTC 抽象、编译、缓存 |
| Kernel Cache | jit/cache.hpp |
内存中的 KernelRuntime 缓存 |
| Kernel Runtime | jit/kernel_runtime.hpp |
CUBIN 加载、kernel launch |
| Device Runtime | jit/device_runtime.hpp |
设备属性、cuBLASLt handle |
| Handle | jit/handle.hpp |
CUDA Driver API 懒加载封装 |
| Include Parser | jit/include_parser.hpp |
头文件依赖解析与 hash |
2. C++ API 层架构
2.1 pybind11 入口与模块注册
csrc/python_api.cpp 是整个 C++ 扩展的入口点,极其精简:
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
m.doc() = "DeepGEMM C++ library";
deep_gemm::attention::register_apis(m);
deep_gemm::einsum::register_apis(m);
deep_gemm::hyperconnection::register_apis(m);
deep_gemm::gemm::register_apis(m);
deep_gemm::layout::register_apis(m);
deep_gemm::mega::register_apis(m);
deep_gemm::runtime::register_apis(m);
}
设计要点:
- 使用 TORCH_EXTENSION_NAME 宏(由 torch.utils.cpp_extension 注入),确保与 PyTorch 的 setuptools 构建系统兼容
- 每个 API 模块是自注册的:只需实现 register_apis(pybind11::module_&) 函数
- 注册顺序无关,因为 pybind11 模块内部是符号表
2.2 register_apis 模式
所有 API 模块遵循统一的注册模式:
namespace deep_gemm::xxx {
static void register_apis(pybind11::module_& m) {
#if DG_FP8_COMPATIBLE and DG_TENSORMAP_COMPATIBLE
m.def("function_name", &function_impl,
py::arg("arg1"), py::arg("arg2") = default_value, ...);
#endif
}
}
关键设计特征:
- 条件编译守卫:
#if DG_FP8_COMPATIBLE and DG_TENSORMAP_COMPATIBLE确保在不兼容的 CUDA/PyTorch 版本下优雅降级 - static 函数:所有实现函数都是
static,避免符号冲突 - 默认参数:通过
py::arg(...) = default_value实现 Python 侧可选参数 - 别名机制:如
m.attr("fp8_gemm_nt") = m.attr("fp8_fp4_gemm_nt")实现向后兼容
2.3 各 API 模块详解
2.3.1 gemm.hpp — 核心 GEMM API
这是最复杂的 API 模块,提供 4 种矩阵布局 × 3 种精度类型 = 12+ 个变体:
| 布局 | FP8/FP4 | BF16 | cuBLASLt |
|---|---|---|---|
| NT (default) | fp8_fp4_gemm_nt |
bf16_gemm_nt |
cublaslt_gemm_nt |
| NN | fp8_fp4_gemm_nn |
bf16_gemm_nn |
cublaslt_gemm_nn |
| TN | fp8_fp4_gemm_tn |
bf16_gemm_tn |
cublaslt_gemm_tn |
| TT | fp8_fp4_gemm_tt |
bf16_gemm_tt |
cublaslt_gemm_tt |
架构分派逻辑:
flowchart TD
A[fp8_fp4_gemm_nt] --> B{arch_major}
B -->|9| C[sm90_fp8_gemm_1d1d<br/>sm90_fp8_gemm_1d2d]
B -->|10| D[sm100_fp8_fp4_gemm_1d1d]
A2[bf16_gemm_nt] --> E{arch_major}
E -->|9| F[sm90_bf16_gemm]
E -->|10| G[sm100_bf16_gemm]
A3[m_grouped_fp8_fp4_gemm_nt_contiguous] --> H{arch_major}
H -->|9| I[sm90_m_grouped_fp8_gemm_contiguous_1d2d]
H -->|10| J[sm100_m_grouped_fp8_fp4_gemm_contiguous_1d1d]
核心数据流:
Python Tensor → early_return 检查 → layout::transform_sf_pair_into_required_layout
→ check_ab_fp8_fp4 (形状校验) → device_runtime->get_arch_major()
→ 分派到具体 sm90/sm100 实现
early_return 优化:处理空问题(m=0 或 n=0)和 k=0 的退化情况,避免不必要的 kernel launch。
2.3.2 attention.hpp — MQA Logits API
提供两种 MQA (Multi-Query Attention) logits 计算模式:
- 连续 KV 模式 (
fp8_fp4_mqa_logits):KV 在内存中连续存储 - Paged KV Cache 模式 (
fp8_fp4_paged_mqa_logits):KV 分块存储,通过 block_table 索引
关键设计:
- 支持 FP4 和 FP8 两种精度,通过 q_sf.has_value() 区分
- 使用 torch::from_blob 从 fused KV cache 中零拷贝派生子张量
- 调度元数据 (schedule_metadata) 用于负载均衡
2.3.3 mega.hpp — MoE 融合 API
Mega MoE 是 DeepGEMM 针对 Mixture-of-Experts 的创新设计:
static void fp8_fp4_mega_moe(
const torch::Tensor& y,
const std::tuple<torch::Tensor, torch::Tensor>& l1_weights_,
const std::tuple<torch::Tensor, torch::Tensor>& l2_weights_,
const torch::Tensor& sym_buffer, // 对称通信 buffer
const std::vector<int64_t>& sym_buffer_ptrs,
...
);
核心特性:
- 使用对称 buffer (sym_buffer) 实现 all-to-all 通信与 GEMM 计算的 overlap
- get_symm_buffer_size_for_mega_moe 计算 buffer 布局,返回 slice_input_buffers lambda
- 仅支持 SM100 (Blackwell) 和 SwiGLU activation
2.3.4 einsum.hpp — 爱因斯坦求和
目前支持硬编码的表达式:
- "bmk,bnk->mn" — batched GEMM
- "bhr,hdr->bhd" — attention 中的 QK^T
- "bhd,hdr->bhr" — attention 中的 weighted sum
FP8 Einsum 通过 permute 将任意维度映射到 (batch, m, n, k) 后复用 FP8 BMM。
2.3.5 hyperconnection.hpp — TF32 HC Prenorm GEMM
为 HyperConnection 架构设计的特殊 GEMM:
- A: BF16, B: FP32, D: FP32
- 额外输入 sqr_sum 用于 pre-normalization
- 支持 num_splits 维度
2.3.6 layout.hpp — Scaling Factor 布局变换
这是 JIT kernel 正确运行的前置步骤,将用户提供的 scaling factor 转换为 TMA 硬件要求的布局:
static torch::Tensor transform_sf_into_required_layout(
const torch::Tensor& sf,
const int& mn, const int& k,
const std::variant<std::tuple<int,int,int>, std::tuple<int,int>>& recipe,
...
);
支持的变换路径:
| 输入类型 | 架构 | 变换 |
|---|---|---|
| FP32, gran_mn=1, gran_k=128 | SM90 | → MN-major TMA-aligned |
| FP32, gran_mn=128, gran_k=128 | SM90 | 仅校验 |
| FP32, gran_k=32/128 | SM100 | → INT8 UE8M0 packed, MN-major TMA-aligned |
| INT8, gran_mn=1, gran_k=32/128 | SM100 | 校验 TMA alignment |
2.3.7 runtime.hpp — 运行时配置
提供对 JIT 引擎和 heuristics 的运行时控制:
m.def("init", [&](const std::string& library_root_path,
const std::string& cuda_home_path_by_python) {
Compiler::prepare_init(library_root_path, cuda_home_path_by_python);
KernelRuntime::prepare_init(cuda_home_path_by_python);
IncludeParser::prepare_init(library_root_path);
});
可配置参数:
- set_num_sms / get_num_sms:控制使用的 SM 数量
- set_tc_util / get_tc_util:Tensor Core 利用率 (0-100)
- set_pdl / get_pdl:Programmatic Dependent Launch
- set_ignore_compile_dims:忽略编译维度(调试用)
- set_block_size_multiple_of:block size 对齐约束
3. JIT 编译管线
3.1 完整生命周期
DeepGEMM 的 JIT 编译是一个精心设计的 5 阶段管线:
sequenceDiagram
participant PY as Python
participant API as C++ API (apis/)
participant KI as Kernel Impl (jit_kernels/impls/)
participant COMP as Compiler
participant CACHE as KernelRuntimeCache
participant FS as File System
participant CUDA as CUDA Driver
PY->>API: fp8_fp4_gemm_nt(a, b, d, ...)
API->>API: early_return 检查
API->>API: layout::transform_sf_pair_into_required_layout
API->>KI: sm90_fp8_gemm_1d1d(a, sfa, b, sfb, ...)
KI->>KI: 构造 GemmDesc
KI->>KI: get_best_config<SM90ArchSpec>(desc)
KI->>KI: make_tma_a_desc / make_tma_b_desc / ...
KI->>KI: LaunchRuntime::generate(args)
Note over KI: 生成 C++ 代码字符串
KI->>COMP: compiler->build("sm90_fp8_gemm_1d1d", code)
COMP->>COMP: 计算 kernel_signature hash
COMP->>CACHE: kernel_runtime_cache->get(dir_path)
alt Cache Hit
CACHE-->>COMP: 返回缓存的 KernelRuntime
else Cache Miss
COMP->>FS: 创建临时目录
COMP->>FS: 写入 kernel.cu
COMP->>CUDA: NVCC/NVRTC 编译
CUDA-->>FS: 生成 kernel.cubin
COMP->>FS: 可选:cuobjdump 反汇编
COMP->>FS: fsync_dir + atomic rename
COMP->>CACHE: 创建新 KernelRuntime
CACHE->>CUDA: load_kernel(cubin_path)
CUDA-->>CACHE: KernelHandle
end
COMP-->>KI: 返回 KernelRuntime
KI->>KI: LaunchRuntime::launch(runtime, args)
KI->>CUDA: launch_kernel(kernel, config, args...)
CUDA-->>PY: 执行完成
3.2 编译器抽象层
Compiler 类是 JIT 编译的核心抽象:
class Compiler {
std::string signature, flags;
std::filesystem::path cache_dir_path;
std::shared_ptr<KernelRuntime> build(const std::string& name,
const std::string& code) const;
virtual void compile(const std::string& code,
const std::filesystem::path& dir_path,
const std::filesystem::path &cubin_path, ...) const = 0;
};
静态配置(通过 prepare_init 设置):
- library_root_path:DeepGEMM 库根目录
- library_include_path:library_root_path/include
- cuda_home:CUDA 安装路径
- cuobjdump_path:cuda_home/bin/cuobjdump
环境变量控制:
| 环境变量 | 默认值 | 作用 |
|---|---|---|
DG_JIT_CACHE_DIR |
~/.deep_gemm |
缓存目录 |
DG_JIT_CPP_STANDARD |
20 | C++ 标准 |
DG_JIT_DEBUG |
0 | 调试输出 |
DG_JIT_DUMP_ASM |
0 | dump SASS |
DG_JIT_DUMP_PTX |
0 | dump PTX |
DG_JIT_PTXAS_VERBOSE |
0 | PTXAS 详细日志 |
DG_JIT_PTXAS_CHECK |
0 | 检查 local memory |
DG_JIT_WITH_LINEINFO |
0 | 包含行信息 |
DG_JIT_USE_NVRTC |
0 | 使用 NVRTC 替代 NVCC |
DG_JIT_NVCC_COMPILER |
自动检测 | NVCC 路径 |
DG_JIT_PRINT_COMPILER_COMMAND |
0 | 打印编译命令 |
DG_JIT_PRINT_LOAD_TIME |
0 | 打印加载时间 |
3.3 NVCC Compiler 实现
NVCCCompiler 通过外部进程调用 NVCC:
class NVCCCompiler final: public Compiler {
std::filesystem::path nvcc_path;
void compile(...) const override {
// 1. 写入 kernel.cu
put(code_path, code);
// 2. 在临时目录中编译(避免 cwd 文件污染)
const auto command = fmt::format("cd {} && {} {} -cubin -o {} {}",
compile_dir.c_str(), nvcc_path.c_str(), code_path.c_str(),
cubin_path.c_str(), flags);
call_external_command(command);
// 3. 可选:生成 PTX
if (ptx_path.has_value()) { ... }
}
};
NVCC 编译 flags:
-std=c++20 --diag-suppress=39,161,174,177,186,940
--ptxas-options=--register-usage-level=10
-I{library_include_path}
--gpu-architecture=sm_{arch}
--compiler-options=-fPIC,-O3,-fconcepts,-Wno-deprecated-declarations,-Wno-abi
-O3 --expt-relaxed-constexpr --expt-extended-lambda
版本检测: 通过正则 release (\d+\.\d+) 解析 NVCC 版本,要求 >= 12.3,推荐 >= 12.9。
3.4 NVRTC Compiler 实现
NVRTCCompiler 使用 CUDA Runtime Compilation API,避免进程创建开销:
class NVRTCCompiler final: public Compiler {
void compile(...) const override {
// 1. 创建 NVRTC program
nvrtcCreateProgram(&program, code.c_str(), "kernel.cu", 0, nullptr, nullptr);
// 2. 编译
nvrtcCompileProgram(program, num_options, options);
// 3. 获取 CUBIN
nvrtcGetCUBINSize(program, &cubin_size);
nvrtcGetCUBIN(program, cubin_data.data());
// 4. 写入文件
put(cubin_path, cubin_data);
}
};
NVRTC 特有优化:
- PCH (Pre-Compiled Headers):NVRTC >= 12.8 时启用 --pch,显著加速编译
- -default-device:确保设备代码编译
- --device-int128:支持 124 位整数运算
3.5 Include Parser 与依赖追踪
IncludeParser 是 JIT 正确性的关键组件,它解析 kernel 代码中的 #include <deep_gemm/*> 指令,递归计算所有依赖头文件的 hash:
class IncludeParser {
std::unordered_map<std::string, std::optional<std::string>> cache;
std::string get_hash_value(const std::string& code, bool exclude_code = true) {
for (const auto& i: get_includes(code))
ss << get_hash_value_by_path(library_include_path / i) << "$";
return get_hex_digest(ss.str());
}
};
设计要点:
- 只解析 <deep_gemm/*> 风格的 include(angle bracket)
- 递归计算依赖树,检测循环依赖(通过 std::optional 标记中间状态)
- 结果缓存避免重复计算
- 最终 hash 注入到生成的代码中:// Includes' hash value: {hash}
4. Kernel Caching 机制
4.1 Cache Key 设计
Cache key 是一个 4 元组 hash:
const auto kernel_signature = fmt::format("{}$${}$${}$${}",
name, // kernel 名称,如 "sm90_fp8_gemm_1d1d"
signature, // 编译器签名,如 "NVCC12.9"
flags, // 编译 flags
code // 生成的 C++ 代码
);
const auto dir_path = cache_dir_path / "cache" /
fmt::format("kernel.{}.{}", name, get_hex_digest(kernel_signature));
Cache key 包含的维度:
graph LR
A[Kernel Name] --> E[kernel_signature]
B[Compiler Signature<br/>NVCC/NVRTC + version] --> E
C[Compile Flags<br/>arch, include paths, options] --> E
D[Generated Code<br/>template args + include hash] --> E
E --> F[get_hex_digest<br/>FNV-1a + SplitMix64]
F --> G[Cache Dir Path]
Hash 算法 (hash.hpp):
- 使用 双种子 FNV-1a 生成两个 64-bit 状态
- 通过 SplitMix64 混淆得到最终 128-bit hex digest
- 冲突概率极低(约 2^-64),适合缓存场景
4.2 Cache 目录管理
目录结构:
~/.deep_gemm/
├── tmp/ # 临时目录(编译中)
│ └── {uuid}/
└── cache/ # 最终缓存
└── kernel.{name}.{hash}/
├── kernel.cu # 源代码
├── kernel.cubin # 编译产物
├── kernel.ptx # 可选:PTX
└── kernel.sass # 可选:SASS
原子性保证:
1. 编译在 tmp/{uuid}/ 中进行
2. 完成后 fsync_dir 确保数据落盘
3. std::filesystem::rename 是原子操作(同一文件系统内)
4. 如果多进程并发,只有一个 rename 成功,其他进程安全清理
分布式文件系统兼容:
- fsync_path 确保文件数据可见
- fsync_dir 递归 fsync 目录项
- safe_remove_all 处理 skip_permission_denied,避免分布式 FS 上的 segfault
4.3 运行时 Cache
KernelRuntimeCache 是内存中的二级缓存:
class KernelRuntimeCache {
std::unordered_map<std::string, std::shared_ptr<KernelRuntime>> cache;
std::shared_ptr<KernelRuntime> get(const std::filesystem::path& dir_path) {
// 1. 内存缓存命中
if (cache.contains(dir_path)) return cache[dir_path];
// 2. 文件系统校验
if (KernelRuntime::check_validity(dir_path))
return cache[dir_path] = std::make_shared<KernelRuntime>(dir_path);
return nullptr; // 需要重新编译
}
};
Cache 层级:
flowchart TD
A[build(name, code)] --> B{内存缓存命中?}
B -->|Yes| C[返回缓存的 KernelRuntime]
B -->|No| D{文件系统缓存命中?}
D -->|Yes| E[加载 CUBIN → 创建 KernelRuntime]
D -->|No| F[NVCC/NVRTC 编译]
F --> G[写入文件系统]
G --> E
E --> H[存入内存缓存]
H --> C
5. Kernel Runtime 与 Launch
5.1 KernelRuntime 加载
KernelRuntime 负责从 CUBIN 文件加载 kernel:
class KernelRuntime {
LibraryHandle library;
KernelHandle kernel;
explicit KernelRuntime(const std::filesystem::path& dir_path) {
const auto cubin_path = dir_path / "kernel.cubin";
// 方案1: CUDA 12.08+ Runtime API
// cudaLibraryLoadFromFile → cudaLibraryGetKernel
// 方案2: Driver API (默认)
// cuModuleLoad → cuModuleGetFunction
// 或 CUDA 12.4+: cuLibraryLoadFromFile → cuLibraryEnumerateKernels
kernel = load_kernel(cubin_path, symbol_name, &library);
}
};
符号提取策略:
- 默认通过 cuobjdump -symbols 解析 CUBIN
- 过滤 STT_FUNC + STO_ENTRY 类型的符号
- 排除非法符号:vprintf, __instantiate_kernel, __internal, __assertfail
- 要求恰好 1 个合法符号
5.2 LaunchRuntime 模板
LaunchRuntime 是一个 CRTP (Curiously Recurring Template Pattern) 模板类:
template <typename Derived>
class LaunchRuntime {
// 代码生成(静态多态)
template <typename Args>
static std::string generate(const Args& args) {
auto code = Derived::generate_impl(args);
code = fmt::format("// Includes' hash value: {}\n{}",
include_hash, code);
return code;
}
// 内核启动
template <typename Args>
static void launch(const std::shared_ptr<KernelRuntime>& runtime,
const Args& args) {
// 1. 获取当前 CUDA stream
const auto stream = at::cuda::getCurrentCUDAStream();
// 2. 构造 launch config
auto config = construct_launch_config(kernel, stream,
smem_size, grid_dim, block_dim, cluster_dim, enable_pdl);
// 3. 派生类实现具体 launch 逻辑
Derived::launch_impl(kernel, config, args);
}
};
使用示例(SM90FP8Gemm1D1DRuntime):
class SM90FP8Gemm1D1DRuntime final: public LaunchRuntime<SM90FP8Gemm1D1DRuntime> {
struct Args {
GemmDesc gemm_desc;
GemmConfig gemm_config;
LaunchArgs launch_args;
void *gmem_a_ptr, *gmem_b_ptr, *grouped_layout, *tensor_map_buffer;
CUtensorMap tensor_map_a_base, tensor_map_b_base;
CUtensorMap tensor_map_sfa, tensor_map_sfb, tensor_map_cd;
};
static std::string generate_impl(const Args& args) {
return fmt::format(R"(
#include <deep_gemm/impls/sm90_fp8_gemm_1d1d.cuh>
static void __instantiate_kernel() {{
auto ptr = reinterpret_cast<void*>(&sm90_fp8_gemm_1d1d_impl<
{}, {}, {}, ... // 编译时常量参数
>);
}};
)", ...);
}
static void launch_impl(const KernelHandle& kernel,
const LaunchConfigHandle& config, Args args) {
launch_kernel(kernel, config,
args.gmem_a_ptr, args.gmem_b_ptr,
args.grouped_layout, args.tensor_map_buffer,
args.gemm_desc.m, args.gemm_desc.n, args.gemm_desc.k,
args.tensor_map_a_base, args.tensor_map_b_base,
args.tensor_map_sfa, args.tensor_map_sfb, args.tensor_map_cd);
}
};
5.3 TMA Descriptor 构建
TMA (Tensor Memory Accelerator) 是 Hopper+ 架构的关键硬件特性。DeepGEMM 通过 runtime_utils.hpp 提供完整的 TMA descriptor 构建:
static CUtensorMap make_tma_2d_desc(
const torch::Tensor& t,
int gmem_inner_dim, int gmem_outer_dim,
int smem_inner_dim, int smem_outer_dim,
const int& gmem_outer_stride,
const int& swizzle_mode, ...);
TMA 配置参数:
- CU_TENSOR_MAP_INTERLEAVE_NONE:无交错
- CU_TENSOR_MAP_SWIZZLE_32B/64B/128B:shared memory swizzle 模式
- CU_TENSOR_MAP_L2_PROMOTION_L2_256B:L2 提升
- CU_TENSOR_MAP_FLOAT_OOB_FILL_NONE:越界不填充
Swizzle 模式映射:
| swizzle_mode | 结果 |
|---|---|
| 0, 16 | CU_TENSOR_MAP_SWIZZLE_NONE |
| 32 | CU_TENSOR_MAP_SWIZZLE_32B |
| 64 | CU_TENSOR_MAP_SWIZZLE_64B |
| 128 | CU_TENSOR_MAP_SWIZZLE_128B |
| base=32, mode=128 | CU_TENSOR_MAP_SWIZZLE_128B_ATOM_32B (SM100) |
5.4 Kernel Launch 流程
flowchart TD
A[LaunchRuntime::launch] --> B[获取当前 CUDA Stream]
A --> C[读取 device_runtime->get_pdl()]
B --> D[construct_launch_config]
C --> D
D --> E{smem_size > 0?}
E -->|Yes| F[cudaFuncSetAttribute<br/>MaxDynamicSharedMemorySize]
E -->|No| G[构建 gridDim/blockDim]
F --> G
G --> H{cluster_dim > 1?}
H -->|Yes| I[添加 ClusterDimension 属性]
H -->|No| J{enable_pdl?}
I --> J
J -->|Yes| K[添加 PDL 属性]
J -->|No| L[launch_kernel]
K --> L
Launch 属性:
- Cluster Dimension:Hopper+ 的 Thread Block Cluster 特性,支持 2-SM 协作
- PDL (Programmatic Dependent Launch):kernel 间的程序化同步
6. Device Runtime
6.1 CUDA 设备管理
DeviceRuntime 封装了 CUDA 设备属性和状态:
class DeviceRuntime {
int num_sms = 0, tc_util = 0;
bool enable_pdl = false;
std::shared_ptr<cudaDeviceProp> cached_prop;
// 架构检测
std::pair<int, int> get_arch_pair(); // {major, minor}
std::string get_arch(bool number_only, bool support_arch_family);
int get_arch_major(); // 9 (Hopper) or 10 (Blackwell)
// SM 管理
int get_num_sms(); // 默认全部 SM
void set_num_sms(int new_num_sms);
// TC util
int get_tc_util(); // 默认 100%
// PDL 控制
bool get_pdl();
void set_pdl(bool new_enable_pdl);
};
arch 字符串映射:
| GPU | major.minor | get_arch() | get_arch(number_only) | get_arch(x, true) |
|---|---|---|---|---|
| H100 | 9.0 | "90a" | "90" | "90a" |
| B200 | 10.0 | "100a" | "100" | "100f" |
| B300 | 10.1 | "100a" | "100" | "100f" |
6.2 cuBLASLt 集成
DeviceRuntime 同时管理 cuBLASLt handle 和 workspace:
class DeviceRuntime {
cublasLtHandle_t cublaslt_handle;
torch::Tensor cublaslt_workspace; // 32 MB
cublasLtHandle_t get_cublaslt_handle() const;
torch::Tensor get_cublaslt_workspace() const;
};
两种 handle 模式:
1. 自管理(默认):cublasLtCreate 创建独立 handle
2. PyTorch 托管:通过 at::cuda::getCurrentCUDABlasLtHandle() 获取(需 PyTorch >= 2.3)
Workspace 模式:
1. 持久化(默认):构造时分配 32MB tensor
2. 临时:每次调用重新分配(用于 compute-sanitizer 测试)
6.3 架构检测与 arch 字符串
std::string get_arch(const bool& number_only, const bool& support_arch_family) {
const auto [major, minor] = get_arch_pair();
if (major == 10 and minor != 1) {
if (number_only) return "100";
return support_arch_family ? "100f" : "100a";
}
return std::to_string(major * 10 + minor) + (number_only ? "" : "a");
}
注意: SM100 (Blackwell) 的 arch family 后缀 (100f) 仅在 NVCC/NVRTC >= 12.9 时支持。
7. Handle 管理与 CUDA Driver 抽象
handle.hpp 是 CUDA Driver API 的懒加载封装层:
// 懒加载 CUDA driver
static void* get_driver_handle() {
static void* handle = dlopen("libcuda.so.1", RTLD_LAZY | RTLD_LOCAL);
return handle;
}
// 宏定义懒加载的 driver API
#define DECL_LAZY_CUDA_DRIVER_FUNCTION(name) \
template <typename... Args> \
static auto lazy_##name(Args&&... args) -> decltype(name(args...)) { \
static FuncType func = nullptr; \
if (func == nullptr) \
func = reinterpret_cast<FuncType>(dlsym(get_driver_handle(), #name)); \
return func(std::forward<Args>(args)...); \
}
懒加载的 Driver API:
- cuGetErrorName, cuGetErrorString
- cuFuncSetAttribute
- cuModuleLoad, cuModuleUnload, cuModuleGetFunction
- cuLibraryLoadFromFile, cuLibraryUnload, cuKernelGetFunction
- cuLaunchKernelEx
- cuTensorMapEncodeTiled
- cuLibraryGetKernelCount, cuLibraryEnumerateKernels (CUDA 12.4+)
双 API 后端:
#if CUDART_VERSION >= 12080 and defined(DG_JIT_USE_RUNTIME_API)
// CUDA Runtime Unified API
using LibraryHandle = cudaLibrary_t;
using KernelHandle = cudaKernel_t;
cudaLibraryLoadFromFile(...);
cudaLaunchKernelExC(...);
#else
// CUDA Driver API
using LibraryHandle = CUlibrary; // or CUmodule
using KernelHandle = CUfunction;
cuLibraryLoadFromFile(...);
cuLaunchKernelEx(...);
#endif
8. Utility 层
8.1 compatibility.hpp
提供编译时特性检测宏:
#define DG_FP8_COMPATIBLE (TORCH_VERSION_MAJOR > 2 or (TORCH_VERSION_MAJOR == 2 and TORCH_VERSION_MINOR >= 1))
#define DG_TENSORMAP_COMPATIBLE (CUDA_VERSION >= 12010)
#define DG_CUBLAS_GET_ERROR_STRING_COMPATIBLE (CUDART_VERSION >= 11042)
#define DG_CUBLASLT_ADVANCED_FEATURES_COMPATIBLE (CUDART_VERSION >= 11080)
8.2 exception.hpp
定义了统一的异常体系和检查宏:
class DGException final : public std::exception {
std::string message;
public:
explicit DGException(const char *name, const char* file,
const int line, const std::string& error);
};
// 检查宏
#define DG_HOST_ASSERT(cond) ...
#define DG_HOST_UNREACHABLE(reason) ...
#define DG_NVRTC_CHECK(cmd) ...
#define DG_CUDA_DRIVER_CHECK(cmd) ...
#define DG_CUDA_RUNTIME_CHECK(cmd) ...
#define DG_CUBLASLT_CHECK(cmd) ...
错误传播路径:
C++ 异常 → pybind11 自动转换 → Python RuntimeError
8.3 format.hpp
简单的 fmt 库封装:
#define FMT_HEADER_ONLY
#include <fmt/base.h>
#include <fmt/format.h>
8.4 hash.hpp
提供 FNV-1a + SplitMix64 的 128-bit hash:
static std::string get_hex_digest(const std::string& data) {
const auto state_0 = fnv1a(data, 0xc6a4a7935bd1e995ull);
const auto state_1 = fnv1a(data, 0x9e3779b97f4a7c15ull);
// SplitMix64 混淆
return hex(state_0) + hex(state_1);
}
8.5 layout.hpp
提供 tensor 布局检查和 scaling factor 校验:
// Major type 检测
cute::UMMA::Major get_major_type_ab(const torch::Tensor& t);
// SF layout 校验
torch::Tensor check_sf_layout(const torch::Tensor& sf,
const int& mn, const int& k, const int& gran_mn, const int& gran_k, ...);
// Recipe 默认值
std::tuple<int, int, int> get_default_recipe(
const torch::ScalarType& sfa_dtype, const torch::ScalarType& sfb_dtype);
8.6 lazy_init.hpp
通用的懒初始化模板:
template <typename T>
class LazyInit {
std::shared_ptr<T> ptr;
std::function<std::shared_ptr<T>()> factory;
public:
T* operator -> () {
if (ptr == nullptr) ptr = factory();
return ptr.get();
}
};
使用场景:
- LazyInit<Compiler>:编译器实例
- LazyInit<DeviceRuntime>:设备运行时
- LazyInit<HeuristicsRuntime>:启发式运行时
8.7 math.hpp
提供数学常量和工具函数:
constexpr auto kPackedFP4 = torch::kInt8; // FP4 打包为 int8
template <typename T> static T ceil_div(const T& a, const T& b);
template <typename T> static constexpr T align(const T& a, const T& b);
static int get_tma_aligned_size(const int& x, const int& element_size);
8.8 system.hpp
系统级工具函数:
// 环境变量读取
template <typename dtype_t>
static dtype_t get_env(const std::string& name, const dtype_t& default_value);
// 外部命令执行
static std::tuple<int, std::string> call_external_command(std::string command);
// 文件收集
static std::vector<std::filesystem::path> collect_files(const std::filesystem::path& root);
// 目录操作
static std::filesystem::path make_dirs(const std::filesystem::path& path);
static void safe_remove_all(const std::filesystem::path& path);
// UUID 生成
static std::string get_uuid();
9. Heuristics 与自动调优
DeepGEMM 的 heuristics 系统自动选择最优的 GEMM 配置:
template <typename ArchSpec>
static GemmConfig get_best_config(const GemmDesc& desc) {
// 1. 生成 layout 候选
const auto layout_candidates = ArchSpec::get_layout_candidates(desc);
// 2. 评估每个候选
for (auto& candidate : layout_candidates) {
auto info = ArchSpec::get_layout_info(desc, candidate);
if (ArchSpec::compare(info, best_info)) best = candidate;
}
// 3. 推导其他配置
auto storage_config = ArchSpec::get_storage_config(desc, layout);
auto pipeline_config = ArchSpec::get_pipeline_config(desc, layout, storage_config);
auto launch_config = ArchSpec::get_launch_config(desc, layout);
return {layout, storage_config, pipeline_config, launch_config};
}
配置维度:
| 配置 | 参数 | 说明 |
|---|---|---|
| Layout | block_m, block_n, block_k, cluster_m, cluster_n | tile 大小和集群配置 |
| Storage | swizzle_a/b/cd_mode, load/store block | TMA swizzle 和访存模式 |
| Pipeline | smem_size, num_stages | shared memory 和流水线深度 |
| Launch | num_sms, num_threads, tma/math threads | 启动配置 |
SM90 ArchSpec 特性:
- smem_capacity = 232448 (227 KB)
- block_m 候选:{16, 32, 64, 128, 256}(根据问题规模)
- block_k 固定:128 / element_size
- 支持 cluster size 2 (multicast)
10. 错误处理体系
DeepGEMM 使用 异常 + 宏 的错误处理策略:
graph TD
A[错误发生] --> B{错误类型}
B -->|主机断言失败| C[DGException<br/>Assertion]
B -->|NVRTC 错误| D[DGException<br/>NVRTC]
B -->|CUDA Driver 错误| E[DGException<br/>CUDA driver]
B -->|CUDA Runtime 错误| F[DGException<br/>CUDA runtime]
B -->|cuBLASLt 错误| G[DGException<br/>cuBLASLt]
C --> H[what() 返回<br/>name + file:line + error]
D --> H
E --> H
F --> H
G --> H
H --> I[pybind11 自动转换]
I --> J[Python RuntimeError]
关键设计:
- 所有检查宏都包含 __FILE__ 和 __LINE__,便于定位
- CUDA 错误码转换为可读字符串
- NVRTC 编译失败时打印完整 log
- 不支持 cublasGetErrorString 的旧版本使用 fallback 实现
11. 内存管理
11.1 GPU 内存分配
DeepGEMM 的 GPU 内存管理遵循 "谁分配谁负责" 原则:
| 内存类型 | 分配方式 | 生命周期 |
|---|---|---|
| 输入/输出 tensor | Python 侧 (torch::empty) | Python GC |
| cuBLASLt workspace | DeviceRuntime 构造函数 | 与 DeviceRuntime 同生命周期 |
| TMA tensor map buffer | 各 kernel 函数内 (torch::empty) | 函数作用域 |
| Scaling factor 变换结果 | transform_sf_* 函数 | 返回给 Python |
| 对称通信 buffer (Mega) | Python 侧 | Python GC |
11.2 零拷贝视图
大量使用 torch::from_blob 创建零拷贝视图:
// 从 fused KV cache 中派生子张量
kv_cache = torch::from_blob(
fused_kv_cache.data_ptr(),
{num_kv_blocks, block_kv, head_dim / 2},
{kv_cache_stride_bytes, head_dim / 2, 1},
torch::TensorOptions().dtype(kPackedFP4)
);
11.3 内存对齐
TMA 硬件要求 16-byte 对齐:
static int get_tma_aligned_size(const int& x, const int& element_size) {
constexpr int kNumTMAAlignmentBytes = 16;
return align(x, kNumTMAAlignmentBytes / element_size);
}
12. 关键设计洞察与架构评价
12.1 设计亮点
- 分层缓存策略:内存缓存 + 文件系统缓存,兼顾速度和持久化
- 原子性保证:通过
tmp → rename模式避免缓存损坏 - 编译器无关抽象:NVCC/NVRTC 可切换,适应不同部署环境
- CRTP 静态多态:
LaunchRuntime<Derived>避免虚函数开销 - 懒加载 Driver API:
dlopen/dlsym避免启动时依赖 - 环境变量驱动调试:丰富的
DG_JIT_*环境变量
12.2 架构权衡
| 设计决策 | 优势 | 代价 |
|---|---|---|
| JIT 编译 | 针对具体问题规模优化 | 首次编译延迟 |
| 模板实例化 | 零运行时开销 | 编译时间长 |
| 文件系统缓存 | 跨进程共享 | 需要 fsync 保证一致性 |
| 硬编码表达式 | 高效 | 灵活性受限 |
| 双 API 后端 | 兼容性 | 代码复杂度 |
12.3 与传统 GEMM 库的对比
| 特性 | cuBLAS | CUTLASS | DeepGEMM |
|---|---|---|---|
| 编译模式 | 预编译 | 预编译 | JIT |
| FP8 支持 | 有限 | 需要手动适配 | 原生 |
| Block Scale | 不支持 | 复杂 | 原生 |
| M-grouped GEMM | 不支持 | 需要自定义 | 原生 |
| MoE 融合 | 不支持 | 不支持 | 原生 (Mega) |
12.4 关键创新点
- compiled_dims 机制:允许将 M/N/K 的某一维作为编译时常量,启用编译器优化
- Include Hash:追踪头文件依赖变化,确保缓存正确性
- PDL 支持:利用 Hopper+ 的 Programmatic Dependent Launch 实现 kernel 间同步
- UE8M0 Cast:SM100 的 FP4 scale factor 特殊编码格式
- 对称通信 buffer:Mega MoE 中 all-to-all 与 GEMM 的深度融合
附录 A:关键数据结构关系图
classDiagram
class Compiler {
+signature: string
+flags: string
+cache_dir_path: path
+build(name, code) shared_ptr~KernelRuntime~
+compile(code, dir, cubin) void
}
class NVCCCompiler {
+nvcc_path: path
+compile(code, dir, cubin) void
}
class NVRTCCompiler {
+compile(code, dir, cubin) void
}
class KernelRuntime {
+library: LibraryHandle
+kernel: KernelHandle
+check_validity(dir) bool
}
class KernelRuntimeCache {
+cache: unordered_map
+get(dir) shared_ptr~KernelRuntime~
}
class DeviceRuntime {
+num_sms: int
+tc_util: int
+enable_pdl: bool
+get_arch() string
+get_arch_major() int
}
class LaunchArgs {
+grid_dim: pair~int,int~
+num_threads: int
+smem_size: int
+cluster_dim: int
+enable_pdl: bool
}
class GemmDesc {
+gemm_type: GemmType
+kernel_type: KernelType
+m, n, k: int
+num_sms, tc_util: int
+compiled_dims: string
}
class GemmConfig {
+layout: Layout
+storage_config: StorageConfig
+pipeline_config: PipelineConfig
+launch_config: LaunchConfig
}
Compiler <|-- NVCCCompiler
Compiler <|-- NVRTCCompiler
Compiler --> KernelRuntime : creates
KernelRuntimeCache --> KernelRuntime : caches
KernelRuntime --> DeviceRuntime : uses
LaunchArgs --> KernelRuntime : launches
GemmDesc --> GemmConfig : generates
GemmConfig --> LaunchArgs : derives
附录 B:环境变量完整参考
| 环境变量 | 类型 | 默认值 | 描述 |
|---|---|---|---|
DG_JIT_CACHE_DIR |
string | ~/.deep_gemm |
JIT 缓存目录 |
DG_JIT_CPP_STANDARD |
int | 20 | C++ 标准版本 |
DG_JIT_DEBUG |
int | 0 | 调试模式(打印详细信息) |
DG_JIT_DUMP_ASM |
int | 0 | dump SASS 汇编 |
DG_JIT_DUMP_PTX |
int | 0 | dump PTX |
DG_JIT_DUMP_SASS |
int | 0 | dump SASS |
DG_JIT_PTXAS_VERBOSE |
int | 0 | PTXAS 详细输出 |
DG_JIT_PTXAS_CHECK |
int | 0 | 检查 local memory 使用 |
DG_JIT_WITH_LINEINFO |
int | 0 | 包含行信息 |
DG_JIT_USE_NVRTC |
int | 0 | 使用 NVRTC 替代 NVCC |
DG_JIT_NVCC_COMPILER |
string | 自动 | NVCC 编译器路径 |
DG_JIT_PRINT_COMPILER_COMMAND |
int | 0 | 打印编译命令 |
DG_JIT_PRINT_LOAD_TIME |
int | 0 | 打印 kernel 加载时间 |
DG_USE_PYTORCH_CUBLASLT_HANDLE |
int | 0 | 使用 PyTorch 的 cuBLASLt handle |
DG_USE_TEMP_CUBLASLT_WORKSPACE |
int | 0 | 使用临时 workspace |
DG_PRINT_CONFIGS |
int | 0 | 打印 heuristics 配置 |
DG_COMM_KERNEL_DEBUG |
int | 0 | Mega MoE debug 模式 |
文档生成:基于 DeepGEMM v2.4.2 源码分析