写过 Rust 的人都踩过这个坑——写高性能 GPU 代码只能用 C++,Rust 再快也只能在 CPU 侧打转。今天这件事被 NVIDIA 9 月 8 日正式发布的 CUDA Rust 项目彻底原生化了
写过 Rust 的人都踩过这个坑——写高性能 GPU 代码只能用 C++,Rust 再快也只能在 CPU 侧打转。今天这件事被 NVIDIA 9 月 8 日正式发布的 CUDA Rust 项目彻底原生化了。
背景:NVIDIA 为什么要在 Rust 上押注
AI 推理引擎、驱动、运行时,大量系统层代码正在往 Rust 迁移。NVIDIA 自己的 Nova Linux 驱动、Dynamo 的一部分、NVTX Rust 绑定都已经用上了 Rust。但 GPU Kernel 这块一直是空白——能用 Rust 发起调用,但 Kernel 本体还是得用 C++ 写。
CUDA Rust 补的就是这个缺口。NVIDIA 一次性开源了两个项目:cuda-oxide(SIMT 模式)和 cutile-rs(Tile 模式),分别对应 CUDA 的两种编程模型,让 Kernel 本体也能用纯 Rust 写,编译成 PTX 直接跑在 NVIDIA GPU 上。
cuda-oxide:怎么把 Rust 编译成 GPU 指令
cuda-oxide 是一个自定义的 rustc codegen 后端。流程是这样的:
Rust 源码
→ rustc 前端(做类型检查/借用检查/MIR 优化)
→ Stable MIR
→ Pliron IR(NVIDIA 出品的纯 Rust MLIR-like 框架)
→ LLVM IR
→ llc(LLVM 的 NVPTX 后端)
→ PTX(NVIDIA GPU 指令集)
整个链路除了最后一步调用外部 llc,全部是 Rust 代码,没有 C++ 工具链,没有 CMake,没有 tablegen。cargo oxide new 一个项目,跑 cargo oxide run vecadd,就能在 GPU 上跑起来。
写一个 Kernel 长什么样
用 #[kernel] 标注函数,用 DisjointSlice 做无数据竞争的输出,用 thread::index_1d() 取线程硬件索引:
“`rust
use cuda_device::{kernel, thread, DisjointSlice};
[kernel]
pub fn scale(input: &[f32], factor: f32, mut out: DisjointSlice) {
let idx = thread::index_1d();
if let Some(elem) = out.get_mut(idx) {
- elem = input[idx.get()] * factor;
}
}
“`
Host 侧用 cuda_launch! 宏把参数标量化后分发给 GPU:
“`rust
use cuda_core::{CudaContext, DeviceBuffer, LaunchConfig};
use cuda_host::{cuda_launch, load_kernel_module};
let ctx = CudaContext::new(0).unwrap();
let module = load_kernel_module(&ctx, “scale_example”).unwrap();
cuda_launch! {
kernel: scale,
stream: stream,
module: module,
config: LaunchConfig::for_num_elems(1024),
args: [slice(input), 2.5f32, slice_mut(output)]
}.unwrap();
“`
这里最值得说的是 DisjointSlice + ThreadIndex 的设计:每个线程拿到的 ThreadIndex 是硬件寄存器(threadIdx)生成的 opaque type,DisjointSlice::get_mut() 只接受 ThreadIndex,所以不同线程的写入天然不会 race,不需要任何 unsafe。
v0.2.0 社区版:四周 37 个 PR
cuda-oxide 5 月初 v0.1.0 以个人项目名义开源,四周内收到 37 个 PR,来自 23 位贡献者,于是有了 9 月 8 日的 v0.2.0「首个社区版」。这次更新内容包括:
- CUDA 常量内存:
#[constant]标注的数据走.const地址空间,Host 侧自动生成 setter - 设备侧数学函数:f32::max/min/atan、atan2
- 编译期正确性:之前部分静默错误编译现在改为编译时报错,不会生成错误 PTX
- 嵌入式 Kernel:PTX/NVVM-IR/LTO-IR 直接打包进 Host 二进制,
cargo oxide run生成一个自包含的可执行文件,不需要单独的 .ptx 文件 - 社区贡献的原子操作、cuFFTDx/cuBLASDx 集成
官方的 GEMM 示例(矩阵乘法)在 B200 GPU 上跑出 868 TFLOPS,达到 cuBLAS 性能的 58%。
cutile-rs:Tile 模型,更安全但更高级
Tile 模式是 CUDA 的另一套编程模型,描述的是「一个 Tile 做什么」,线程映射和内存布局由硬件决定,对开发者更友好。cutile-rs 走这条路,内存安全保证更强(Hugging Face Grout 和 mistral.rs 已经在生产环境用上了),而且不需要 nightly Rust,稳定版 1.89+ 就能跑。
两种模式的推荐策略是:优先 Tile,有特殊需求(显式线程控制、shared memory)再用 SIMT。
为什么这件事对 Rust 生态意义重大
Rust 写高性能代码快,但 GPU 这块一直是断的。你可以在 Rust 里调用 CUDA API,但 Kernel 还是要用 C++ 写。cuda-oxide 把这个链路打通了:
- 单一语言仓库:Host 代码和 Kernel 代码都在一个
.rs文件里,不需要维护两套工具链 - 编译期安全:借用检查器 + ThreadIndex 类型系统让一部分内存错误在编译期就暴露,而不是在 GPU 上跑出错误结果
- 纯 Rust 工具链:不需要装 CUDA C++ 编译器,不需要 CMake,整个编译链路 cargo build 就能跑通
局限和坑
v0.2.0 仍然是 alpha,官方明确说了会有 bug、API 会变、不能上生产。最大的坑是工具链依赖复杂:需要 pinned nightly Rust(当前用 nightly-2026-04-03)、rust-src、rustc-dev、CUDA Toolkit 12.x+、LLVM 21+ with NVPTX target、Clang 21。好在 cargo oxide doctor 能帮你逐项检查环境。
shared memory 的操作目前还需要 unsafe,这是官方已知的 TODO。
下一步
如果你想试:从 cargo install cargo-oxide 开始,跑 cargo oxide doctor 确认环境,跑 cargo oxide run vecadd 验证能不能在 GPU 上跑起来。GitHub 仓库 NVlabs/cuda-oxide 有 190+ 个示例,从向量加法到 GEMM 到 BlackWell tensor core 都有覆盖。
如果你是搞 AI 推理引擎或高性能计算系统的,cuda-oxide 和 cutile-rs 值得关注——Rust 在系统层的版图又补上了一块关键缺口。
评论区
登录后可评论。