В сентябре 2026 года NVIDIA официально анонсировала развитие экосистемы CUDA Rust. Если раньше Rust использовался преимущественно для системной части (драйверы, инфраструктура), то теперь разработчики могут писать сами GPU-ядра на Rust, компилируя их напрямую в PTX. Это закрывает разрыв между безопасностью памяти на этапе компиляции и производительностью GPU.
Существует два основных пути разработки: SIMT (Single Instruction, Multiple Threads) — классический подход, знакомый по CUDA C++, и Tile — более высокоуровневая абстракция, где компилятор сам управляет маппингом потоков. Оба проекта обеспечивают безопасность памяти, но требуют разных инструментов и подходов.
01cuda-oxide: Нативная компиляция SIMT-ядер
cda-oxide — это кастомный бэкенд кодогенерации для rustc. Он перехватывает компиляцию, маршрутизирует функции с атрибутом #[kernel] через IR-фреймворк Pliron и LLVM, превращая их в PTX. Этот проект находится на ранней стадии альфа-тестирования и требует использования nightly-версии Rust.
Для работы потребуется Linux, GPU с вычислительной способностью 8.0+, CUDA Toolkit 12.x+ и clang. Установка осуществляется через 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 будет долгим, так как компилируется сам бэкенд. Далее используется кэш. Пример ядра сложения векторов выглядит так:
use cuda_device::{kernel, launch_bounds, launch_contract, thread, DisjointSlice};
use cuda_host::cuda_module;
use cuda_core::{CudaContext, DeviceBuffer, LaunchConfig1D};
#[cuda_module]
mod kernels {
use super::*;
#[kernel]
#[launch_bounds(256)]
#[launch_contract(domain = 1, block = (256, 1, 1))]
pub fn vecadd(a: &[f32], b: &[f32], mut c: DisjointSlice<f32>) {
let idx = thread::index_1d();
let idx_raw = idx.get();
if let Some(c_elem) = c.get_mut(idx) {
*c_elem = a[idx_raw] + b[idx_raw];
}
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let ctx = CudaContext::new(0)?;
let stream = ctx.default_stream();
const N: usize = 1024;
// Инициализация хост-данных
let a_host: Vec<f32> = (0..N).map(|i| i as f32).collect();
let b_host: Vec<f32> = (0..N).map(|i| (i * 2) as f32).collect();
// Перенос на устройство
let a_dev = DeviceBuffer::from_host(&stream, &a_host)?;
let b_dev = DeviceBuffer::from_host(&stream, &b_host)?;
let mut c_dev = DeviceBuffer::zeroed(&stream, N)?;
// Запуск ядра
let module = unsafe { kernels::load(&ctx)? };
let prepared = module.prepare_vecadd(LaunchConfig1D::new((N as u32).div_ceil(256), 256, 0))?;
module.vecadd(&stream, &prepared, &a_dev, &b_dev, &mut c_dev)?;
// Проверка результата
let c_host = c_dev.to_host_vec(&stream)?;
let errors = (0..N).filter(|&i| (c_host[i] - (a_host[i] + b_host[i])).abs() > 1e-5).count();
if errors == 0 {
println!("PASSED: all {} elements correct", N);
} else {
eprintln!("FAILED: {} errors", errors);
std::process::exit(1);
}
Ok(())
}DisjointSlice. Он гарантирует, что каждый поток получает эксклюзивный доступ к своему элементу, исключая гонки данных на уровне компиляции, чего нельзя сделать с обычным &mut [f32].02cutile-rs: Высокоуровневое программирование через Tile
cutile-rs работает на более высоком уровне абстракции. Вместо управления отдельными потоками вы оперируете «тайлами» (блоками данных). Компилятор сам решает, как маппировать эти тайлы на архитектуру GPU. Этот проект работает на стабильном Rust 1.89+ и не требует кастомного LLVM.
Проект уже интегрирован в HuggingFace Grout и mistral.rs. Установка и запуск примера:
git clone https://github.com/NVlabs/cutile-rs.git
cd cutile-rs
cargo run --example hello_worldВ отличие от cuda-oxide, здесь нет необходимости вручную указывать launch_bounds или управлять индексами потоков. Вы описываете логику обработки одного тайла, а cutile-rs генерирует оптимальный код для конкретного GPU.
03Сравнение подходов
Выбор между SIMT и Tile зависит от задачи. Tile рекомендуется как стартовая точка, так как код становится более переносимым между архитектурами. SIMT нужен, когда требуется тонкая настройка памяти и потоков.
| Характеристика | cda-oxide (SIMT) | cutile-rs (Tile) |
|---|---|---|
| Версия Rust | Nightly (pinned) | Stable 1.89+ |
| Зависимость от LLVM | Требует кастомный бэкенд | Стандартный LLVM |
| Управление памятью | DisjointSlice, ручные контракты | Разделение тензоров, ownership |
| Статус | Ранняя альфа | Используется в продакшене (Grout) |
| Сложность | Высокая (низкоуровневый контроль) | Средняя (абстракция тайлов) |
04Кому подойдёт / что запустится
cuda-oxide подойдет системным программистам и разработчикам библиотек, которым нужен полный контроль над PTX-генерацией и возможность писать ядра в стиле CUDA C++, но с гарантиями Rust. Это выбор для тех, кто готов работать с nightly-сборками и отлаживать сложные контракты запуска.
cutile-rs идеален для разработчиков AI-инференса и высокоуровневых библиотек. Если вы пишете модели, где операции можно разбить на матричные или тензорные блоки, этот инструмент позволит ускорить разработку, избегая ручного управления потоками. Он уже работает в стеках HuggingFace и готов к интеграции в production-среды на стабильном Rust.
Оба проекта заявляют о планах по межъязыковой интероперабельности с CUDA C++ и Python, что позволит постепенно мигрировать существующие GPU-вычисления на Rust без полной переписи кодовой базы.
Источник: NVIDIA Developer ↗
