宅中地 - 每日更新
宅中地 - 每日更新

贊助商廣告

X

NVIDIA推出CUDA Rust:GPU核心編寫的兩條技術路徑

2026年09月09日 首頁 » 熱門科技

2026年9月,NVIDIA宣布將全力投入原生RustNVIDIA推出CUDARustGPU核心編寫的兩條技術路徑語言的GPU編程支持。CUDA C++和CUDA Python已經是成熟的企業級工具鏈,而NVIDIA將在2027年及以後持續發展和完善CUDA RustNVIDIA推出CUDARustGPU核心編寫的兩條技術路徑

AI系統層涵蓋推理引擎、服務基礎設施、驅動程式和智能體運行時,隨著模型和技術的變化,這一層始終在快速疊代。其中越來越多的部分正在用Rust編寫,因為Rust能在編譯階段就捕獲整類錯誤,同時不犧牲性能。

NVIDIA參與這一轉變出於同樣的原因。Nova LinuxNVIDIA推出CUDARustGPU核心編寫的兩條技術路徑驅動程式就是用Rust編寫的。NVIDIA DynamoNVIDIA推出CUDARustGPU核心編寫的兩條技術路徑基於Rust核心構建。NVTXNVIDIA推出CUDARustGPU核心編寫的兩條技術路徑也提供了Rust綁定。

GPU核心則是個例外。你可以從Rust中啟動核心,但核心本身往往必須用其他語言編寫。

NVIDIA CUDA Rust填補了這一空白。GPU核心現在可以用Rust編寫,直接原生編譯為PTXNVIDIA推出CUDARustGPU核心編寫的兩條技術路徑,而不是對其他語言代碼的封裝。

使用Rust有兩條路徑,對應CUDA自身的兩種編程模型。SIMTNVIDIA推出CUDARustGPU核心編寫的兩條技術路徑是你已經在CUDA C++或numba-cuda中使用的模型,你指定一個線程執行什麼操作,然後啟動成千上萬個線程。TileNVIDIA推出CUDARustGPU核心編寫的兩條技術路徑則是一種較新的編程模型,同樣在C++和Python中可用。所有這些前端都讓你描述一個數據塊(tile)該做什麼,剩下的工作由Tile IRNVIDIA推出CUDARustGPU核心編寫的兩條技術路徑編譯器完成。

在選擇構建基礎時,應優先考慮Tile。編譯器會決定如何將tile映射到各個架構上,因此你的源代碼不會包含特定架構的選擇,只有當你需要那種控制權,或想自行管理內存和線程時,才需要降級到SIMT。

選擇哪種語言是與選擇哪種模型完全獨立的問題。使用最適合你現有技術棧的CUDA接口。下面介紹的兩個項目適用於該技術棧是Rust的情況。我們計劃支持跨語言互操作,因此這個選擇不會將你鎖定在其他語言之外。

下面展示的是同一個核心在兩條技術路徑上的實現,執行1024個浮點數的逐元素加法。兩者都是完整的程序,都能運行,並列印相同的結果,你可以並排閱讀它們,看看有哪些變化。

SIMT路徑:cuda-oxideNVIDIA推出CUDARustGPU核心編寫的兩條技術路徑

cuda-oxide是一個自定義的rustc代碼生成後端。它攔截編譯過程,將帶有#[kernel]標記的函數通過Rust MIR、社區的Pliron IR框架、LLVM IR一路轉換為PTX,其餘部分則交給標準後端處理。Pliron之上的GPU方言是我們自己開發的。所有方言和轉換過程都保留在Rust中,直到標準LLVM後端接管為止。

你需要Linux系統、計算能力8.0或更高的GPU、CUDA工具包(12.x或更新版本)、帶有libclang頭文件的clang,以及固定版本的nightly工具鏈。cargo oxide doctor命令可以檢查所有這些依賴項,包括可選的系統LLVM。安裝cargo-oxide這個驅動構建過程的Cargo子命令:

cargo +nightly-2026-04-03 install --git https://github.com/NVlabs/cuda-oxide.git cargo-oxide

然後搭建項目並運行。該模板是一個完整的向量加法程序:

cargo oxide new vecadd_demo

cd vecadd_demo

cargo oxide doctor

cargo oxide run

第一次運行cargo oxide run會構建代碼生成後端,因此預計需要一段時間。之後的運行會復用緩存。

程序會列印出"PASSED: all 1024 elements correct"(通過:全部1024個元素正確)。這就是完成這項工作的完整程序,與cargo oxide new生成的內容一致,此處添加了注釋。

主機代碼和設備代碼存放在同一個文件中,用一條命令構建,不需要單獨的核心crate。

首先閱讀核心簽名,因為它承載了整個安全性論證。a和b是普通的共享切片,每個線程都可讀取。c是一個DisjointSlice類型,這種類型讓每個線程獨享其自身元素的訪問權限,且僅限於此元素。之所以需要這種設計,是因為&mut [f32]並不適合這項任務——每個線程都需要相同的&mut引用,而Rust會正確地拒絕這種做法。DisjointSlice將這一個可變借用拆分成每個線程各自的片段。

thread::index_1d()返回的是一個索引類型,而非普通整數,c.get_mut(idx)也只接受這種類型。你得到的返回值是一個Option,因此越界情況是你需要處理的一個分支,而不是日後才會發現的內存錯誤。

啟動過程是經過檢查的,而非全憑信任。#[launch_contract]聲明了該核心以一維方式索引,使用256線程的塊。prepare_vecadd會根據這一聲明和實際設備限制來驗證你的LaunchConfig1D,並返回安全的vecadd方法所需的證明。沒有契約聲明的核心只暴露原始的unsafe啟動方法,因為一個裸露的LaunchConfig完全無法說明它要啟動的是什麼核心。

Tile路徑:cutile-rs

cutile-rs的工作層級更高一級。你在tile(數據塊)而非標量上執行計算。每個tile block將核心體作為單一邏輯線程運行一次,處理一個子張量的數據,而由編譯器決定用多少個實際GPU線程來支撐它。#[cutile::module]宏會將核心的AST嵌入主機二進制文件中,並在核心首次被需要時通過CUDA Tile IR(NVIDIA的tile級編譯器IR)進行即時編譯。

其依賴要求比SIMT路徑更輕量。你只需要計算能力8.0或更高的GPU、CUDA 13.3、穩定版Rust 1.89或更新版本,以及Linux系統,不需要nightly工具鏈,也不需要自行配置LLVM。

cutile已經發布,因此無需克隆代碼:

cargo new vecadd_demo

cd vecadd_demo

cargo add cutile

以下是為tile編寫的同樣的逐元素加法程序。將其粘貼到src/main.rs中並運行cargo run。

PASSED: all 1024 elements correct

Tile路徑在穩定版Rust上得到了同樣的結果,其簽名也做出了同樣的安全性論證。這次沒有DisjointSlice。分區(partitioning)操作只對可變張量是必要的,它給每個tile block分配一個可寫的子張量,其他任何tile block都不能與之重疊。這種排他性正是&mut本身所保證的。

輸入形狀中的-1是一個占位符而非具體尺寸。這個維度會在啟動時從張量中讀取,因此形狀可以變化而無需重新編譯。

主機端代碼中最有意思的一行是.partition([128]),它同時完成了三項工作。首先,它使排他性成為現實:每個tile擁有自己128個元素的數據塊,其他tile無法觸碰。其次,它確定了啟動的幾何結構,因為1024除以128等於8個tile組成的網格。

網格大小是從分區推導出來的,而不是單獨計算後再與核心的索引方式進行核對。它還提供了B值,這個值在調用處從未被顯式寫出,因為啟動器會從分區中讀取tile寬度。這也是為什麼一個&mut輸出必須先經過分區才能被傳遞的原因。

再來看啟動調用返回的內容。你在主機上調用的add函數,是宏生成的啟動器,而非上面的設備函數本身。它取得了所有三個張量的所有權,並在GPU完成計算後將它們以元組形式返回。這就是.first()的作用——從中取出輸出結果。

在調用.sync_on(&stream)之前,什麼都不會運行。此前的一切都只是惰性描述,只是被記錄下來,而非提交執行。這包括ones、zeros、核心調用,乃至拷貝回主機的操作。整個程序是一條鏈,只有一個同步點。

編譯器能捕獲什麼

兩種核心對內存做出了相同的聲明:輸入是共享的,輸出則只屬於唯一的寫入者。它們的區別僅在於做出這一聲明的層級,以及是否需要一個專門設計的類型來實現這一聲明。

這一點很重要,因為成千上萬個線程會以無法保證的順序訪問相同的緩衝區。當其中兩個線程訪問同一地址且其中一個在寫入時,執行順序會決定最終結果。這類錯誤很少能按需復現,往往在通過測試後才會在生產環境中崩潰。

將SIMT核心的輸出緩衝區同時作為其自身的輸入傳入,無法通過編譯,無論該核心實際上是否會發生競爭:

error[E0502]: cannot borrow `c_dev` as mutable because it is also borrowed as immutable

Tile一側同樣的別名問題同樣無法通過編譯:

error[E0382]: use of moved value: `z`

兩個示例都在編譯期捕獲了經典的別名錯誤,但它們劃定界限的位置不同。cuda-oxide在每次啟動調用時進行檢查,而cutile-rs的所有權跟蹤貫穿整個啟動邊界,這是兩者中更強的一種保證。

Tile不會給你任何需要操心的共享內存或線程索引,因為編譯器同時掌控了這兩者。一個tile block就是單一邏輯線程,因此不存在需要競爭的多個線程。這正是它天生安全的原因,但這也是你所付出的代價。SIMT保留了那種控制權,而如今在SIMT中使用共享內存仍需要unsafe。共享內存是快速SIMT核心的基石,因此讓這條路徑變得安全是我們正在推進的工作。

兩個項目目前的進展

這兩個項目都處於早期階段,都還沒有達到生產就緒的水平。cuda-oxide目前是早期alpha版本。cutile-rs進展更靠前一些,已發布在crates.io上,並已在NVIDIA之外得到應用,包括HuggingFace的Grout推理引擎和mistral.rs。功能覆蓋尚不完整,API也會持續變動。如果你發現了粗糙之處,我們希望聽到你的反饋。

Cargo和crates生態系統給人的印象是上手很容易。而GPU編程歷史上一直恰恰相反,縮短這一差距正是我們工作的一部分。SIMT路徑目前仍需要固定版本的nightly工具鏈,而這正是我們希望不再要求用戶配置的東西。

Rust在GPU上的應用並非新鮮事。在我們之前,這個領域已經有出色的工作,並且仍在與我們並行推進。cuda-oxide指南中的生態系統附錄說明了我們相對於Rust-GPU、rust-cuda、CubeCL等項目所處的位置,我們也一直在與rust-cuda的維護者合作,共同推進這兩個項目的成熟。

真正新的是我們為此投入的工程力量,以及對未來方向的清晰規劃。

你現在可以做的事

運行SIMT示例:在cuda-oxide中先執行cargo oxide new,再執行cargo oxide run。

運行Tile示例:克隆cutile-rs,然後執行cargo run -p cutile-examples --example hello_world。

閱讀文檔:cuda-oxide指南和cuTile Rust文檔。

閱讀論文:《GPU上的無畏並發》(Fearless Concurrency on the GPU)。

提交問題:在cuda-oxide或cutile-rs上告訴我們哪裡出了問題,缺少了什麼。

加入討論:在兩個倉庫的GitHub Discussions中交流,或加入cuda-oxide的Discord。

參加演講:Melih Elibol將於2026年9月8日至11日在蒙特婁舉行的RustConf 2026大會上發表題為"GPU上的無畏並發"的演講。NVIDIA還會有其他員工出席,如果你也在現場,歡迎來找我們!

動手試試這些項目,和我們一起參與開發。現在還是早期階段,一切都是開放的,你現在構建的東西將塑造接下來的發展方向。

Rust社區

NVIDIA很高興能與Rust社區攜手,共同推進原生Rust GPU編程的發展。像rust-cuda、rust-gpu和cudarc這樣的項目率先開創了GPU與Rust的結合,這些項目背後的人們,包括VectorWare團隊,一直在持續影響著我們對自身工作的思考方式,我們也將繼續與Rust社區一起構建這一未來。

Q&A

Q1:CUDA Rust是什麼?

A:CUDA Rust是NVIDIA推出的原生GPU編程支持,讓開發者可以直接用Rust語言編寫GPU核心,並原生編譯為PTX,無需依賴其他語言代碼的封裝。

Q2:cuda-oxide和cutile-rs有什麼區別?

A:cuda-oxide對應SIMT編程模型,需要指定單個線程的操作並啟動大量線程,需要nightly工具鏈;cutile-rs對應Tile編程模型,以數據塊為單位編程,由編譯器決定線程映射,可在穩定版Rust上運行,安全性更高但控制粒度較粗。

Q3:這兩個項目現在能用於生產環境嗎?

A:目前都不建議用於生產環境。cuda-oxide處於早期alpha階段,cutile-rs進展更靠前,已發布在crates.io並被HuggingFace的Grout推理引擎、mistral.rs等項目使用,但功能覆蓋仍不完整,API也會持續變動。

宅中地 - Facebook 分享 宅中地 - Twitter 分享 宅中地 - Whatsapp 分享 宅中地 - Line 分享
相關內容
Copyright ©2026 | 服務條款 | DMCA | 聯絡我們
宅中地 - 每日更新