CUDA Rust — jetzt mit zwei Pfaden für die native Entwicklung von GPU-Kernels in Rust
Public- 09 Sep, 2026

Im September 2026 gab NVIDIA bekannt, auf die native GPU-Entwicklung in Rust zu setzen. CUDA C++ und CUDA Python sind ausgereifte, industrietaugliche Toolchains, aber die Systemebene der KI — Inference-Engines, Serving-Infrastruktur, Treiber und Agent-Runtimes — wird ständig umgeschrieben und zunehmend in Rust verfasst, das ganze Klassen von Fehlern bereits zur Kompilierzeit abfängt, ohne Leistung einzubüßen. NVIDIA selbst ist Teil dieses Wandels: Der Treiber Nova Linux ist in Rust geschrieben, NVIDIA Dynamo basiert auf einem Rust-Kern, und NVTX besitzt Rust-Bindings. Die Ausnahme blieb das GPU-Kernel, da sich Kernels zwar aus Rust starten ließen, aber meist in einer anderen Sprache geschrieben werden mussten. CUDA Rust schließt diese Lücke, indem es erlaubt, Kernels in Rust zu schreiben und nativ zu PTX zu kompilieren, statt Code aus fremden Quellen zu wrappen.

Es gibt zwei Wege, Rust zu verwenden, die den beiden Wegen entsprechen, die CUDA selbst bereits hat. SIMT ist das vertraute Modell aus CUDA C++ oder numba-cuda: Sie beschreiben, was ein einzelner Thread tut, und starten sie zu Tausenden. Tile ist ein neueres Programmiermodell, das auch in C++ und Python verfügbar ist, bei dem Sie beschreiben, was ein einzelnes Daten-Tile tut, und der Tile-IR-Compiler sich um alles Weitere kümmert. Die Empfehlung von NVIDIA lautet, zuerst zu Tile zu greifen, weil der Compiler selbst entscheidet, wie Tiles auf die jeweilige Architektur abgebildet werden und Ihr Quellcode frei von architekturspezifischen Entscheidungen bleibt; zu SIMT steigen Sie hinab, wenn Sie diese Kontrollebene benötigen oder Speicher und Threads selbst verwalten möchten. Die Wahl der Sprache ist von der Wahl des Modells getrennt, und sprachübergreifende Interoperabilität ist geplant, sodass der Umstieg auf Rust Sie nicht von den anderen Frontends aussperrt.

Der SIMT-Pfad ist cuda-oxide, ein benutzerdefiniertes Codegen-Backend für rustc. Es fängt die Kompilierung ab, führt #[kernel]-Funktionen durch Rust MIR, das Pliron-IR-Framework und LLVM IR bis hinunter zu PTX und übergibt alles andere dem Standard-Backend. Die GPU-Dialekte auf Pliron gehören NVIDIA, und jede Transformation bleibt in Rust, bis das Standard-LLVM-Backend übernimmt. Zu den Anforderungen zählen Linux, eine GPU mit Compute Capability 8.0 oder höher, ein CUDA Toolkit 12.x oder neuer, clang mit seinen libclang-Headern und die festgelegte Nightly-Toolchain. Das Cargo-Unterkommando cargo-oxide steuert den Build, und cargo oxide doctor prüft die Toolchain. Ein Projekt wird per Scaffold angelegt mit cargo oxide new, und der erste cargo oxide run baut das Codegen-Backend, sodass spätere Läufe den Cache nutzen.
Der Tile-Pfad ist cutile-rs, das eine Ebene höher arbeitet: Man führt Berechnungen auf Tiles statt auf Skalaren aus. Jeder Tile-Block führt den Kernel-Body einmal als einen einzigen logischen Thread über einen Sub-Tensor der Daten aus, und der Compiler entscheidet, wie viele echte GPU-Threads ihn unterstützen. Das Makro #[cutile::module] bettet den AST des Kernels in die Host-Binärdatei ein und JIT-kompiliert ihn über CUDA Tile IR beim ersten Zugriff auf das Kernel. Die Anforderungen sind leichter als beim SIMT-Pfad: eine GPU mit Compute Capability 8.0 oder höher, CUDA 13.3, stabiles Rust 1.89 oder neuer und Linux, ohne Nightly-Toolchain und ohne eigenes LLVM. Da cutile veröffentlicht ist, führt man einfach cargo add cutile, ohne etwas zu klonen.

Beide Pfade führen dasselbe Argument zur Speichersicherheit an. Im SIMT-Beispiel ist der veränderliche Ausgabepuffer ein DisjointSlice<f32>, ein eigens dafür geschaffener Typ, der jedem Thread exklusiven Zugriff auf sein eigenes Element gewährt, weil &mut [f32] die falsche Form hat, wenn jeder Thread dieselbe veränderliche Ausleihe benötigen würde. Der Start wird geprüft statt blind vertraut: Die Deklaration #[launch_contract] wird gegen die LaunchConfig1D und die tatsächlichen Gerätelimits validiert, und Kernels ohne Vertrag stellen nur rohe unsafe-Startmethoden zur Verfügung. Auf der Tile-Seite gibt die Partitionierung jedem Tile-Block einen beschreibbaren Sub-Tensor, der sich mit keinem anderen Block überschneiden kann, und diese Exklusivität ist genau das, was &mut bereits garantiert. Einen Ausgabepuffer eines Kernels als einen seiner eigenen Eingaben zu übergeben, kompiliert nicht, wodurch Aliasing-Races abgefangen werden, die sonst die Tests bestünden und erst in der Produktion zutage träten.