CUDA-oxide: el compilador oficial de Rust a CUDA de Nvidia
(nvlabs.github.io)- cuda-oxide es un compilador experimental para escribir kernels GPU SIMT en Rust idiomático, cercano a la seguridad, y compilar código Rust estándar directamente a PTX
- Usa solo Rust, sin DSL ni bindings de lenguajes externos, y asume familiaridad con ownership, traits y genéricos; la sección sobre async también requiere conocimientos de
.await - La v0.1.0 es una versión alfa temprana, por lo que hay que esperar bugs, funciones incompletas y cambios de API incompatibles
- El ejemplo se ejecuta con
cargo oxide run vecadd, y la función#[kernel]dentro de#[cuda_module]realiza suma de vectores conthread::index_1d() #[cuda_module]incluye los artefactos del dispositivo en el binario host y genera un loader con tipos y métodos de ejecución por kernel
Forma de uso y código generado
-
Inicio rápido
- Después de cumplir con los requisitos de instalación, se puede compilar y ejecutar el ejemplo con
cargo oxide run vecadd - La guía de instalación está en prerequisites
- El ejemplo define la función
#[kernel]vecadddentro de un módulo#[cuda_module], obtiene el índice conthread::index_1d()y escribea[i] + b[i]enDisjointSlice<f32> - Del lado del host se usan
CudaContext::new(0), el stream por defecto ykernels::load(&ctx), y se ejecuta el kernel conDeviceBuffer::from_host,DeviceBuffer::<f32>::zeroedyLaunchConfig::for_num_elems(1024) - El resultado se recupera con
c.to_host_vec(&stream)y se verifica queresult[0] == 3.0
- Después de cumplir con los requisitos de instalación, se puede compilar y ejecutar el ejemplo con
-
Cómo funciona
#[cuda_module]#[cuda_module]incluye en el binario host los artefactos de dispositivo generados- Genera la función tipada
kernels::loady métodos de ejecución por kernel - Si se necesita cargar artefactos sidecar específicos o crear código de ejecución personalizado, también se pueden seguir usando la API de bajo nivel
load_kernel_moduleycuda_launch!
Requisitos y dirección del proyecto
- cuda-oxide busca que los kernels GPU se escriban con el sistema de tipos y el modelo de ownership de Rust, y pone la seguridad como objetivo de primera clase
- Como las GPU tienen aspectos sutiles, es necesario leer the safety model
- No es un DSL, sino un backend personalizado de generación de código para
rustcque compila Rust puro a PTX - Soporta ejecución asíncrona, componiendo el trabajo de GPU como un grafo de
DeviceOperationcon ejecución diferida, programándolo en un pool de streams y esperando los resultados con.await - Parte de la base de que el lector ya está familiarizado con ownership, traits y genéricos de Rust; los capítulos posteriores sobre programación GPU async también requieren conocimientos de
async/.awaity runtimes como tokio - Como material de referencia, ofrece The Rust Programming Language, Rust by Example, Async Book
- La versión v0.1.0 está en etapa alfa temprana, así que hay que esperar bugs, funciones incompletas y cambios de API incompatibles
1 comentarios
Comentarios en Hacker News
Sobre todo, me da curiosidad cómo se compararán los tiempos de compilación. La mayoría de los crates de Rust para CUDA dependen de CMake o de invocar
nvcc, así que compilar puede volverse dolorosamente lentoJusto la semana pasada, perfilando tiempos de compilación, vi que herramientas como
sccachepueden reducir bastante los tiempos de recompilación mediante caché de artefactos, pero aun así sigue estando el costo de las invocaciones personalizadas anvcc. Por ejemplo, candle de Hugging Face también invoca comandosnvccpersonalizados para compilar kernels: https://arpadvoros.com/posts/2026/05/05/speeding-up-rust-whi...En lo personal, no he sufrido tanto eso de que la mayoría de los crates de Rust para CUDA llamen a CMake o
nvccy por eso la compilación sea lenta. Si ves el cratecuda_setup, que hice para manejar scripts de compilación, es unbuild.rssimple, así que solo recompila cuando cambian archivos, y el tiempo de compilación es muy pequeño comparado con el código Rust del lado CPUEstaría buenísimo si fuera así, pero personalmente creo que probablemente sea más bien un complemento. También me da curiosidad cuál sería el factor diferenciador de cuda-oxide, más allá de que NVIDIA lo controle completamente
Tile IR está un poco más arriba en nivel de abstracción, así que es mucho más fácil apuntarle, y solo sales perdiendo en cosas como la fusión de epílogos
[1] https://docs.nvidia.com/cuda/tile-ir/
[2] https://developer.nvidia.com/cuda/tile
Me parece que escribir kernels para GPU es intrínsecamente inseguro. Por la forma en que funciona el hardware y porque siempre hay que optimizar al límite, suena dificilísimo hacer un lenguaje seguro para esto
cudaFreeSegundo, mientras que en C++ los argumentos
void*son un arreglo de punteros y solo se valida la cantidad, aquícuda_launch!fuerza los argumentos del kernelTercero, el problema del aliasing en escrituras mutables. En C++, incluso compila código donde dos o más hilos escriben a
out[i]con el mismoi, peroDisjointSliceyThreadIndexno tienen constructores públicos y solo permiten usar las APIs https://github.com/NVlabs/cuda-oxide/blob/2a03dfd9d5f3ecba52...index_1d,index_2d,index_2d_runtimeCuarto, en C++ puedes hacer
cuda memcpydestd::stringo prácticamente cualquier POD y corromper el estado, pero aquí solo aceptaDisjointSlice, escalares y closures https://nvlabs.github.io/cuda-oxide/gpu-programming/memory-a...Hay más detalles en https://nvlabs.github.io/cuda-oxide/gpu-safety/the-safety-mo... y https://nvlabs.github.io/cuda-oxide/gpu-programming/memory-a.... Claro, no detecta todo, pero sí parece dar muchas más barandillas de seguridad contra comportamiento indefinido que archivos
.curawFalta ver si es un lenguaje cómodo para programación GPU, pero no me sorprendería que se pudiera construir una especie de DSL o API razonable para escribir código seguro mientras se aprovechan todas las rarezas específicas de GPU. Al final, CUDA también es algo así, ¿no?
Hace falta un poco de tosquedad para los trabajos seguros pero paralelos que no encajan fácilmente en el modelo
Send/Syncde RustEstaría bien poder aprovechar el modelo de memoria o de ownership con poca fricción. Pero si eso vuelve muy incómoda la experiencia de uso, no lo querría así
Para mí, la línea base es lo que hace hoy Cudarc: no se mete demasiado con la gestión de memoria, y básicamente ofrece una sintaxis imperativa que envuelve FFI y unas cuantas líneas de script de compilación que invocan
nvcccuando cambia el kernelDicho eso, Slang me gusta bastante
[0]: https://shader-slang.org/
Por ejemplo, descriptor sets, registros de recursos, límites de dispatch y cosas así
Los lenguajes de shading también son más amigables para el usuario en términos de capacidades. Además, NVIDIA ya usa Slang en producción, y esa gente no va a reescribir su pipeline de shaders en Rust
Lo único que pude encontrar es esto
https://www.adacore.com/case-studies/nvidia-adoption-of-spar...
https://www.youtube.com/watch?v=2YoPoNx3L5E
Igual intenté ignorarlo y leer la documentación, y justo cuando el IR personalizado empezaba a ponerse interesante, me topé con una línea del estilo “la implementación de MLIR fue C++ con un toque de TableGen, un sistema de compilación que te obliga a compilar todo LLVM y sesiones de depuración que te hacen cuestionar tus decisiones de carrera”, y desde ahí ya me cuesta tomarme en serio esta industria
Esto se ve como el uso exacto de sus propios productos que uno esperaría de una empresa subida al hype de la IA
cuda-oxide vuelve estructuralmente seguro el caso común de “un hilo escribe un elemento”, y para los casos menos comunes como memoria compartida, warp shuffles y funciones intrínsecas de hardware, exige
unsafecon contratos documentados; mientras que para funciones de frontera como TMA, tensor cores y comunicación a nivel de clúster, lo deja totalmente manual, en línea con la complejidad del hardwarePero esto no se siente muy a lo Rust. En Rust, cuando las abstracciones existentes no encajan bien con el problema, se crean nuevas abstracciones seguras. Rust for Linux es un ejemplo
Si no va a ser seguro, entonces me pregunto cuál es el punto de usar Rust. Está bien ofrecer APIs
unsafepara la gente que necesita exprimir el último poco de rendimiento, pero eso no debería ser el valor por defectoMe hace pensar en librerías de espacio de usuario para APIs como
io_uringo Vulkan. Diseñar APIs seguras para esas cosas es bastante difícil, y de hecho ha habido intentos que ni siquiera resultaron soundIgual con la barrera de serialización/bytes entre ambos
Por ejemplo, me pregunto si las comprobaciones de límites de arreglos podrían provocar uso extra de registros y reducir la concurrencia del kernel