cuda-oxide: NVIDIA GPU에 Rust의 안전성과 표현력을 가져오다

수년 동안 GPU 프로그래밍의 표준은 CUDA C++였습니다. 이는 강력하지만 메모리 안전성이 수동 부담이며, 호스트와 디바이스 코드 사이의 간격이 마치 심연처럼 느껴질 수 있는 위험한 언어입니다. NVIDIA에서 발표한 실험적인 Rust-to-CUDA 컴파일러인 cuda-oxide는 중요한 변화를 예고합니다. 개발자가 안전하고 관용적인 Rust로 SIMT (Single Instruction, Multiple Threads) GPU 커널을 작성할 수 있게 함으로써, NVIDIA는 고수준의 안전성 보장과 저수준 하드웨어 성능 사이의 간극을 메우고자 시도하고 있습니다.

DSL(Domain Specific Languages)이나 복잡한 FFI(foreign function interfaces)에 의존하던 이전의 GPU용 Rust 도입 시도들과 달리, cuda-oxide는 커스텀 rustc codegen backend입니다. 이는 표준 Rust 코드를 NVIDIA GPU에서 사용하는 저수준 가상 머신이자 명령어 집합 아키텍처인 PTX (Parallel Thread Execution)로 직접 컴파일합니다.

The Architecture of cuda-oxide

cuda-oxide의 핵심은 GPU 프로그래밍을 마치 네이티브 Rust 개발처럼 느끼게 만드는 것입니다. 이 프로젝트는 이를 달성하기 위해 몇 가지 주요 아키텍처 구성 요소를 도입합니다:

A Native SIMT Compiler

단순한 래퍼(wrapper) 역할을 하는 대신, cuda-oxide는 컴파일러로서 작동합니다. 이는 Rust의 Mid-level IR (MIR)을 GPU 실행 가능한 코드로 낮추는(lowering) 작업을 처리하기 위해 MLIR과 유사한 커스텀 IR (Intermediate Representation)인 Pliron을 활용합니다. 이 파이프라인을 통해 컴파일러는 GPU의 특정 실행 모델을 대상으로 하면서도 Rust의 타입 시스템과 제네릭을 유지할 수 있습니다.

Async GPU Programming

cuda-oxide의 가장 야심 찬 기능 중 하나는 비동기 실행 방식입니다. 컴파일러는 DeviceOperation 모델을 도입하여 개발자가 GPU 작업을 지연 그래프(lazy graphs)로 구성할 수 있게 합니다. 이러한 작업들은 스트림 풀(stream pools)을 통해 스케줄링될 수 있으며 Rust의 네이티브 .await 구문을 사용하여 대기할 수 있어, tokio 생태계의 편리함을 GPU로 가져옵니다.

The Safety Model

GPU 프로그래밍은 수천 개의 스레드가 동시에 동일한 메모리 공간에 접근하는 경우가 많기 때문에 Rust의 borrow checker에게 본질적으로 까다로운 작업입니다. cuda-oxide는 계층적 안전성 접근 방식을 통해 이를 해결합니다:

  • Safe by Construction: 한 스레드가 하나의 요소에 쓰는 일반적인 사례는 unsafe 블록 없이도 안전하게 처리됩니다.
  • Documented Contracts: 공유 메모리(shared memory) 및 warp shuffles와 같은 중간 단계의 복잡성은 unsafe를 필요로 하지만, 문서화된 계약(contracts)에 의해 관리됩니다.
  • Manual Control: Tensor Memory Accelerator (TMA) 및 tensor cores와 같은 최첨단 기능은 하드웨어의 극심한 복잡성을 반영하여 여전히 완전히 수동으로 제어됩니다.

Developer Experience: From C++ to Rust

현재 cudarc와 같은 crate를 사용하는 개발자들에게 cuda-oxide로의 전환은 마찰을 크게 줄여줄 것으로 기대됩니다. 현재의 워크플로우는 종종 바이트 배열과 Rust 데이터 구조 사이의 수동 직렬화가 필요하거나 CMake 및 nvcc와 같은 외부 빌드 도구에 의존해야 하며, 이는 빌드 시간을 늘릴 수 있습니다.

cuda-oxide를 사용하면 #[cuda_module] 속성을 통해 생성된 디바이스 아티팩트를 호스트 바이너리에 직접 임베딩할 수 있습니다. 이는 별도의 사이드카 아티팩트가 필요 없음을 의미하며, 커널을 위한 타입이 지정된 런칭 메서드를 제공하여 배포 파이프라인을 단순화합니다.

Community Perspectives and Critiques

열광적인 반응이 있는 한편, 기술 커뮤니티에서는 프로젝트의 방향성과 구현에 관한 몇 가지 비판적인 지점을 제고했습니다.

The "Rustiness" of GPU Safety

일부 개발자들은 공유 메모리 및 하드웨어 인트린직(intrinsics)을 위해 unsafe에 의존하는 것이 Rust를 사용하는 주요 이유를 약화시킨다고 주장합니다. 한 댓글 작성자는 다음과 같이 언급했습니다:

"Rust에서는 기존의 방식이 당면한 문제에 완벽하게 매핑핑되지 않을 때 새로운 안전한 추상화(abstractions)를 만듭니다... 만약 그것이 안전하지 않다면... Rust를 사용하는 의미가 무엇인가요?"

The Closed-Source Ecosystem

cuda-oxide는 NVIDIA 드라이버 및 런타임의 폐쇄형 소스 특성 때문에 단순히 "pig의 lipstick" (겉모습만 번지르르한) 해결책에 불과하다는 지속적인 우려가 있습니다. PTX를 대상으로 하며 NVIDIA의 독점적 툴체인을 사용하기 때문에, 오픈 소스 GPU 스택을 원하는 사람들에게는 큰 변화를 없습니다.

Performance Overheads

Rust의 배열 경계 검사(array bounds checking)와 같은 표준 안전성 기능이 레지스터 사용량에 영향을 미치고, 결과적으로 GPU 커널의 점유율(occupancy)을 낮출 수 있는지에 대한 의문이 제기됩니다. 모든 레지스터가 중요한 CUDA의 초고적합화된 세계에서는 이는 매우 중요한 검토 대상입니다.

Conclusion

cuda-oxide는 현재 초기 단계의 알파(v0.1.0) 버전이며, NVIDIA는 커뮤니티가 프로젝트의 방향을 형성하는 데 도움을 주기를 권장하고 있습니다. 비록 폐쇄형 소스 드라이버의 근본적인 문제를 해결할 수는 없겠지만, cuda-oxide는 고성능 GPU 커널을 작성할 수 있는 능력을 포sac지 않으면서 Rust의 생산성과 안전성을 원하는 개발자들에게 강력한 새로운 도구를 제공합니다. DSL을 넘어 네이티브 컴파일러 백엔드로 나아감으로써, NVIDIA는 GPU 프로그래밍의 미래가 성능뿐만 아니라 이를 표현하는 언어에 대한 것이라고 믿고 있습니다.

Sources