英伟达宣布“CUDA Rust”,基于Rust的原生GPU编程
NVIDIA在9月宣布认真押注Rust原生GPU编程。CUDA C++ 和CUDA Python已经是成熟的商用工具链,但这次它没有二选一,而是把CUDA Rust往2027年及以后持续打磨——明确了要长期养大这套生态,而不是试水。
驱动这个决定的是向下看的视角。AI的系统层——推理引擎、serving基础设施、驱动、agent运行时——日夜都在变,而这层越来越多用Rust写,因为它能在编译期拦掉整类bug又不牺牲性能。NVIDIA自己就是这股潮流的一部分:Nova Linux驱动用Rust写,Dynamo的核是Rust,NVTX有Rust绑定。唯独一个例外——GPU kernel。你可以从Rust发起kernel,可kernel本身往往得用别的语言写。这次CUDA Rust就是要堵上这个口子,让kernel也能直接用Rust写、原生编译成PTX,而不是包一层别的语言的代码。
它给出了两条平行路径,对应CUDA自己的两种模型。SIMT是你今天在CUDA C++ 或numba-cuda里已经熟悉的写法——你描述一个线程做什么,然后一次启动几千个线程。Tile是更新的模型,C++ 和Python里也都有——你描述一块tile的数据要做什么,剩下交给Tile IR编译器去编排。官方建议能选就优先Tile,因为编译器决定tile怎么映射到每种架构,源文件不需要写死特定架构的选择;而当你需要精细控制寄存器、亲手管内存和线程时,再降回SIMT。
语言和模型是两个独立问题。用哪种CUDA接口取决于你现有栈是什么,而下面两个项目专为Rust栈而生,并且计划支持语言间互通,选了它不会把你锁死在其他语言之外。
SIMT这条线叫cuda-oxide,一个自定义的rustc codegen后端。它拦下编译,把#[kernel]函数路由经过Rust MIR、社区Pliron IR框架、LLVM IR一路下到PTX,其余代码交给标准后端。GPU dialect和每一步变换都留在Rust,直到标准LLVM后端接手。驱动方式是Cargo子命令cargo-oxide,一条cargo oxide run把完整vector add程序跑通打印PASSED: all 1024 elements correct。它的内存安全靠一个DisjointSlice类型——输出buffer作为自身输入传入时直接编译不过。
Tile这条线叫cutile-rs,在更高一层工作:按tile而不是标量做计算,每个tile块作为单个逻辑线程跑一遍kernel正文,编译器决定背后用多少真实GPU线程。它唯一特殊的地方是host端那个 .partition([128]),三个任务一口气干完——让独占性成真、固定启动几何、顺带读出tile宽度。门槛比SIMT轻:稳定Rust 1.89+、CUDA 13.3、Linux,不需要nightly也不装自备LLVM,而且它已在crates.io发布,直接clone都不用。
最值得看的是「编译器能抓到什么」。两个kernel对内存做的声明其实是同一个:输入共享、输出独属一个写者,区别只在声明的层级、以及要不要为此造一个专用类型。几千个线程无固定顺序碰到同一buffer,一旦两个线程同时写同一地址,顺序就决定了结果——这类bug很少按需复现,往往过了测试才在生产炸开。两条路都在编译期不给通过:SIMT侧是E0502(可变借用与不可变借用冲突),Tile侧是E0382(move了已使用的值)。经典的内存别名错误,这次在Rust编译器眼皮底下就挡住了。
Rust用了这么多年,glue层早就Rust化了,唯独kernel这块硬骨头一直得换语言。现在两条轨道落地,等于把「kernel也归Rust管」补上了最后一块拼图。