Компиляция rust кода в ptx

Rust мощный язык системного уровня, однако компиляция в NVidia PTX из коробки недоступна. Поставлю себе задачу найти способ компиляции Rust функций на видеокарты прямо из файла исходников как обычные функции. Задача состоит из двух частей: собственно сам способ компиляции и интеграция этого способа в среду разработки.

После ряда опытов был найден репозиторий https://github.com/rust-accel/nvptx, который формирует среду компиляции с целью nvptx-nvidia-cuda. Клонируем репозиторий, выполняем команды cargo install nvptx и nvptx install. В результате появляется новый тулчейн accel-nvptx. Проверить его наличие можно rustup toolchain list.

$ rustup toolchain list
nightly-x86_64-unknown-linux-gnu
accel-nvptx

Вторая половина задачи решилась репозиторием https://github.com/rust-accel/accel. Предварительно необходимо установить CUDA (версия 10.0 на текущий момент), llvm версии 6.0 или выше, и ночную сборку Rust (И переустановить тулчейн nvptx для ночного Rust).

После установки в Cargo.toml зависимостей

[dependencies]
accel = "0.2.0"
accel-derive = "0.2.0"

Компилируется и запускается вот такой пример со смешанным кодом для CPU и GPU.

extern crate accel;
extern crate accel_derive;
 
use accel_derive::kernel;
use accel::*;
 
#[kernel]
#[crate("accel-core" = "0.2.0-alpha")]
pub unsafe fn add(a: *const f64, b: *const f64, c: *mut f64, n: usize) {
    let i = accel_core::index();
    if (i as usize) < n {
        *c.offset(i) = *a.offset(i) + *b.offset(i);
    }
}
 
fn main() {
    let n = 32;
    let mut a = UVec::new(n).unwrap();
    let mut b = UVec::new(n).unwrap();
    let mut c = UVec::new(n).unwrap();
 
    for i in 0..n {
        a[i] = i as f64;
        b[i] = 2.0 * i as f64;
    }
    println!("a = {:?}", a.as_slice());
    println!("b = {:?}", b.as_slice());
 
    let grid = Grid::x(1);
    let block = Block::x(n as u32);
    add(grid, block, a.as_ptr(), b.as_ptr(), c.as_mut_ptr(), n);
 
    device::sync().unwrap();
    println!("c = {:?}", c.as_slice());
}
 

Замер времени выполнения ядра показал что-то около 145 микросекунд. Надо отметить что исполняемый код не сбалансирован по блокам и нитям и представляет чисто демонстрационную ценность. Однако в дальнейшем он пригодится для новых опытов с CUDA + Rust.

Хорошее объяснение принципов работы CUDA можно найти в книге "CUDA by Example" (Jason Sanders & Edward Kandrot, ISBN-13: 978-0-13-138768-3), у которой есть и русский перевод на просторах Интернета.


2018-10-17