Crate oneapi_rs

Crate oneapi_rs 

Source
Expand description

§oneAPI-rs

oneAPI-rs is a set of (mostly) safe Rust bindings for SYCL - an open, royalty-free, cross-platform abstraction layer that enables code for heterogeneous and offload processors to be written using modern ISO C++, and provides APIs and abstractions to find devices (CPUs, GPUs, FPGAs …) on which code can be executed, and to manage data resources and code execution on those devices.

§System dependencies

Make sure to install the Intel oneAPI toolkit. Then source the setvars.sh file:

source <oneapi_install_directory>/setvars.sh

§Getting started

§Building the crate

Before building this crate you need to source the setvars.sh file. You can then build it as usual with cargo:

cargo build --release

You must also source setvars.sh before running any SYCL program.

§Hello world

  1. Create a Queue. It’s the main entry point to the SYCL API.
let mut queue = Queue::new();
  1. Create an USM buffer for your data.
let mut device_buffer = queue.alloc_device::<f64>(1024).wait();
  1. Build a SYCL kernel.
let kernel = queue
    .get_context()
    .create_kernel_bundle_from_source(IOTA_SRC)
    .build()
    .get_kernel("iota");
  1. Launch your kernel.
unsafe {
    queue.launch(
        NdRange::new([1024], [16]),
        &kernel,
        (3.14, &mut device_buffer),
    )
}
.wait();
  1. Copy your data to the host.
let mut host_buffer = queue.alloc_host::<f64>(1024).wait();
queue.copy(&device_buffer, &mut host_buffer).wait();

You can access your host data just like a normal Rust slice.

for e in host_buffer.iter() {
    print!("{e} ");
}
println!();

§Safety model

  • USM allocations are represented by a zero-cost Buffer type managed through RAII.
    • Note: Unlike SYCL buffers, oneAPI-rs buffers do not rely on accessors.
  • Buffers are zero-initialized by default.
  • Buffers can only store types that implement [bytemuck::Pod].
  • Kernel launch is inherently unsafe.

§Asynchronous programming model

Each queue operation returns an Event. You can synchronously .wait() for it, or asynchronously .await it.

You can also synchronously call Queue::wait() to wait for a Queue directly. To do the same asynchronously you have to .await an event returned by Queue::barrier().

Modules§

buffer
context
device
event
info
kernel
platform
prelude
queue
range
usm