diff --git a/sycl/sycl-rs/examples/kernel_launch.rs b/sycl/sycl-rs/examples/kernel_launch.rs index baabbda..1ee43ab 100644 --- a/sycl/sycl-rs/examples/kernel_launch.rs +++ b/sycl/sycl-rs/examples/kernel_launch.rs @@ -24,7 +24,7 @@ void iota(float start, float *ptr) { #[tokio::main] async fn main() -> sycl_rs::Result<()> { let mut queue = Queue::new(); - let mut device_buffer = queue.alloc_device::(1024)?.await?; + let mut device_array = queue.alloc_device::(1024)?.await?; let kernel = queue .get_context() @@ -36,16 +36,16 @@ async fn main() -> sycl_rs::Result<()> { queue.launch( NdRange::new([1024], [16]), &kernel, - (3.14_f32, &mut device_buffer), + (3.14_f32, &mut device_array), ) }? .await?; - let mut host_buffer = queue.alloc_host::(1024)?.await?; + let mut host_array = queue.alloc_host::(1024)?.await?; - queue.copy(&device_buffer, &mut host_buffer)?.await?; + queue.copy(&device_array, &mut host_array)?.await?; - for e in host_buffer.iter() { + for e in host_array.iter() { print!("{e} "); } println!(); diff --git a/sycl/sycl-rs/examples/kernel_launch_derive.rs b/sycl/sycl-rs/examples/kernel_launch_derive.rs index 0c94115..5bbd64d 100644 --- a/sycl/sycl-rs/examples/kernel_launch_derive.rs +++ b/sycl/sycl-rs/examples/kernel_launch_derive.rs @@ -24,12 +24,12 @@ void iota(float start, float *ptr) { #[derive(KernelArgumentList)] struct IotaArgs<'a> { start: f32, - ptr: &'a mut SharedBuffer, + ptr: &'a mut SharedUsmBox, } fn main() -> sycl_rs::Result<()> { let mut queue = Queue::new(); - let mut buffer = queue.alloc_shared::(1024)?.wait()?; + let mut array = queue.alloc_shared::(1024)?.wait()?; let kernel = queue .get_context() @@ -43,13 +43,13 @@ fn main() -> sycl_rs::Result<()> { &kernel, IotaArgs { start: 3.14_f32, - ptr: &mut buffer, + ptr: &mut array, }, ) }? .wait()?; - for e in buffer.iter() { + for e in array.iter() { print!("{e} "); } println!(); diff --git a/sycl/sycl-rs/src/lib.rs b/sycl/sycl-rs/src/lib.rs index 9022cc2..0073685 100644 --- a/sycl/sycl-rs/src/lib.rs +++ b/sycl/sycl-rs/src/lib.rs @@ -55,7 +55,7 @@ //! fn main() -> sycl_rs::Result<()> { //! // 1. Create a Queue. It's the main entry point to the SYCL API. //! let mut queue = Queue::new(); -//! let mut device_buffer = queue.alloc_device::(1024)?.wait()?; +//! let mut device_array = queue.alloc_device::(1024)?.wait()?; //! //! // 3. Build a SYCL kernel. //! let kernel = queue @@ -69,18 +69,18 @@ //! queue.launch( //! NdRange::new([1024], [16]), //! &kernel, -//! (3.14_f32, &mut device_buffer), +//! (3.14_f32, &mut device_array), //! ) //! }? //! .wait()?; //! -//! let mut host_buffer = queue.alloc_host::(1024)?.wait()?; +//! let mut host_array = queue.alloc_host::(1024)?.wait()?; //! //! // 5. Copy your data to the host. -//! queue.copy(&device_buffer, &mut host_buffer)?.wait()?; +//! queue.copy(&device_array, &mut host_array)?.wait()?; //! //! // You can access your host data just like a normal Rust slice. -//! for e in host_buffer.iter() { +//! for e in host_array.iter() { //! print!("{e} "); //! } //! println!(); @@ -90,10 +90,11 @@ //! ``` //! //! # Safety model -//! - USM allocations are represented by a zero-cost `Buffer` type managed through RAII. -//! - Note: Unlike SYCL buffers, SYCL-rs buffers do not rely on accessors. -//! - Buffers are zero-initialized by default. -//! - Buffers can only store types that implement [`bytemuck::Pod`]. +//! - USM allocations are represented by a zero-cost [`UsmBox`](crate::usmbox::UsmBox) type managed +//! through RAII. +//! - Note: `UsmBox` arrays do not rely on accessors, unlike SYCL buffers. +//! - `UsmBox`es are zero-initialized by default. +//! - `UsmBox`es can only store types that implement [`bytemuck::Pod`]. //! - Kernel launch is inherently unsafe. In particular, the caller must ensure that every argument //! has the correct representation, layout, and alignment. //! @@ -106,8 +107,8 @@ //! event returned by [`Queue::barrier()`](crate::queue::Queue::barrier). //! //! All basic SYCL wrapper types (`Queue`, `Event`, `Context`, `Platform`, `Device`) are thread safe as -//! indicated by the provided [`Send`] and [`Sync`] trait implementations. However - Buffers are -//! not thread-safe. If you need a thread-safe Buffer you need to wrap it in an `Arc>`. +//! indicated by the provided [`Send`] and [`Sync`] trait implementations. However - `UsmBox`es are +//! not thread-safe. If you need a thread-safe `UsmBox` you need to wrap it in an `Arc>`. //! //! # Required extensions //! This project requires the following SYCL extensions to work: @@ -118,7 +119,6 @@ //! - [sycl_ext_intel_queue_immediate_command_list](https://github.com/intel/llvm/blob/sycl/sycl/doc/extensions/supported/sycl_ext_intel_queue_immediate_command_list.asciidoc) //! - [sycl_ext_oneapi_enqueue_barrier](https://github.com/intel/llvm/blob/sycl/sycl/doc/extensions/supported/sycl_ext_oneapi_enqueue_barrier.asciidoc) -pub mod buffer; pub mod context; pub mod device; pub mod event; @@ -129,6 +129,7 @@ pub mod prelude; pub mod queue; pub mod range; pub mod usm; +pub mod usmbox; pub type SyclError = cxx::Exception; pub type Result = std::result::Result; diff --git a/sycl/sycl-rs/src/prelude.rs b/sycl/sycl-rs/src/prelude.rs index be320dc..379f8eb 100644 --- a/sycl/sycl-rs/src/prelude.rs +++ b/sycl/sycl-rs/src/prelude.rs @@ -1,5 +1,4 @@ pub use crate::{ - buffer::{Buffer, DeviceBuffer, HostBuffer, SharedBuffer}, context::Context, device::Device, info::{self, InfoTarget}, @@ -7,4 +6,5 @@ pub use crate::{ platform::Platform, queue::Queue, range::{NdRange, Range}, + usmbox::{DeviceUsmBox, HostUsmBox, SharedUsmBox, UsmBox}, }; diff --git a/sycl/sycl-rs/src/queue.rs b/sycl/sycl-rs/src/queue.rs index 2a99fc8..98c7be7 100644 --- a/sycl/sycl-rs/src/queue.rs +++ b/sycl/sycl-rs/src/queue.rs @@ -11,16 +11,16 @@ use bytemuck::Pod; use sycl_rs_sys::{queue::ffi, types::ffi::EventPtr}; use crate::{ - buffer::{ - Buffer, DeviceBuffer, EnqueuedBuffer, EnqueuedDeviceBuffer, EnqueuedHostBuffer, - EnqueuedSharedBuffer, HostBuffer, SharedBuffer, - }, context::Context, device::Device, event::Event, kernel::{Kernel, KernelArgumentList}, range::{NdRange, ValidDimension}, usm::{UsmAlloc, UsmAllocator}, + usmbox::{ + DeviceUsmBox, EnqueuedDeviceUsmBox, EnqueuedHostUsmBox, EnqueuedSharedUsmBox, + EnqueuedUsmBox, HostUsmBox, SharedUsmBox, UsmBox, + }, }; /// The `Queue` connects a host program to a single device. Programs submit tasks to a device via the @@ -44,74 +44,74 @@ impl Queue { ffi::get_context(&self.0).into() } - /// Allocates zeroed memory and creates a host-side [`Buffer`] that can store an array of T. - pub fn alloc_host(&mut self, len: usize) -> Result> { + /// Allocates zeroed memory and creates a host-side [`UsmBox`] that can store an array of T. + pub fn alloc_host(&mut self, len: usize) -> Result> { unsafe { - let mut buffer = self.alloc_uninit_host(len); - self.memset(&mut buffer, 0) - .map(|event| EnqueuedBuffer::new(buffer, event)) + let mut array = self.alloc_uninit_host(len); + self.memset(&mut array, 0) + .map(|event| EnqueuedUsmBox::new(array, event)) } } - /// Allocates zeroed memory and creates a shared [`Buffer`] that can store an array of T. - pub fn alloc_shared(&mut self, len: usize) -> Result> { + /// Allocates zeroed memory and creates a shared [`UsmBox`] that can store an array of T. + pub fn alloc_shared(&mut self, len: usize) -> Result> { unsafe { - let mut buffer = self.alloc_uninit_shared(len); - self.memset(&mut buffer, 0) - .map(|event| EnqueuedBuffer::new(buffer, event)) + let mut array = self.alloc_uninit_shared(len); + self.memset(&mut array, 0) + .map(|event| EnqueuedUsmBox::new(array, event)) } } - /// Allocates zeroed memory and creates a device [`Buffer`] that can store an array of T. - pub fn alloc_device(&mut self, len: usize) -> Result> { + /// Allocates zeroed memory and creates a device [`UsmBox`] that can store an array of T. + pub fn alloc_device(&mut self, len: usize) -> Result> { unsafe { - let mut buffer = self.alloc_uninit_device(len); - self.memset(&mut buffer, 0) - .map(|event| EnqueuedBuffer::new(buffer, event)) + let mut array = self.alloc_uninit_device(len); + self.memset(&mut array, 0) + .map(|event| EnqueuedUsmBox::new(array, event)) } } - /// Allocates memory and creates a host-side [`Buffer`] that can store an array of T. - /// Safety: the buffer contents are uninitialized. - pub unsafe fn alloc_uninit_host(&self, len: usize) -> HostBuffer { + /// Allocates memory and creates a host-side [`UsmBox`] that can store an array of T. + /// Safety: the array contents are uninitialized. + pub unsafe fn alloc_uninit_host(&self, len: usize) -> HostUsmBox { let allocator = UsmAllocator::from(self); - unsafe { Buffer::new(allocator, len) } + unsafe { UsmBox::new(allocator, len) } } - /// Allocates memory and creates a shared [`Buffer`] that can store an array of T. - /// Safety: the buffer contents are uninitialized. - pub unsafe fn alloc_uninit_shared(&self, len: usize) -> SharedBuffer { + /// Allocates memory and creates a shared [`UsmBox`] that can store an array of T. + /// Safety: the array contents are uninitialized. + pub unsafe fn alloc_uninit_shared(&self, len: usize) -> SharedUsmBox { let allocator = UsmAllocator::from(self); - unsafe { Buffer::new(allocator, len) } + unsafe { UsmBox::new(allocator, len) } } - /// Allocates memory and creates a device-side [`Buffer`] that can store an array of T. - /// Safety: the buffer contents are uninitialized. - pub unsafe fn alloc_uninit_device(&self, len: usize) -> DeviceBuffer { + /// Allocates memory and creates a device-side [`UsmBox`] that can store an array of T. + /// Safety: the array contents are uninitialized. + pub unsafe fn alloc_uninit_device(&self, len: usize) -> DeviceUsmBox { let allocator = UsmAllocator::from(self); - unsafe { Buffer::new(allocator, len) } + unsafe { UsmBox::new(allocator, len) } } /// Sets memory allocated with USM allocations. /// Safety: the caller must make sure the underlying memory isn't being aliased somewhere else. pub unsafe fn memset( &mut self, - buffer: &mut Buffer, + array: &mut UsmBox, value: i32, ) -> Result { - unsafe { self.memset_with_deps(buffer, value, &[]) } + unsafe { self.memset_with_deps(array, value, &[]) } } /// Sets memory allocated with USM allocations after all specified events finish. /// Safety: the caller must make sure the underlying memory isn't being aliased somewhere else. pub unsafe fn memset_with_deps( &mut self, - buffer: &mut Buffer, + array: &mut UsmBox, value: i32, dep_events: &[&Event], ) -> Result { - let ptr = buffer.get_byte_ptr(); - let num_bytes = buffer.get_byte_size(); + let ptr = array.get_byte_ptr(); + let num_bytes = array.get_byte_size(); let dep_events = dep_events .iter() .map(|e| EventPtr { @@ -162,10 +162,10 @@ impl Queue { unsafe { nd_range.launch(self, kernel, args) } } - /// Copies the contents of the source buffer to the destination buffer. + /// Copies the contents of the source array to the destination array. /// - /// Panics if the source and destination buffer lengths differ. - pub fn copy(&mut self, src: &Buffer, dst: &mut Buffer) -> Result + /// Panics if the source and destination array lengths differ. + pub fn copy(&mut self, src: &UsmBox, dst: &mut UsmBox) -> Result where T: Pod, A1: UsmAlloc, @@ -174,14 +174,14 @@ impl Queue { self.copy_with_deps(src, dst, &[]) } - /// Copies the contents of the source buffer to the destination buffer after all specified + /// Copies the contents of the source array to the destination array after all specified /// events finish. /// - /// Panics if the source and destination buffer lengths differ. + /// Panics if the source and destination array lengths differ. pub fn copy_with_deps( &mut self, - src: &Buffer, - dst: &mut Buffer, + src: &UsmBox, + dst: &mut UsmBox, dep_events: &[&Event], ) -> Result where @@ -192,7 +192,7 @@ impl Queue { assert_eq!( src.get_len(), dst.get_len(), - "source and destination buffer lengths differ" + "source and destination array lengths differ" ); // TODO: Resolve the C++ lifetime elision issue diff --git a/sycl/sycl-rs/src/usm.rs b/sycl/sycl-rs/src/usm.rs index 1db0ee3..a320d35 100644 --- a/sycl/sycl-rs/src/usm.rs +++ b/sycl/sycl-rs/src/usm.rs @@ -68,7 +68,7 @@ unsafe impl Allocator for UsmAllocator { } } -/// An allocator for Device-side buffers +/// An allocator for Device-side arrays /// /// Safety: memory allocated by this allocator cannot be accessed on the host side #[allow(dead_code)] @@ -80,7 +80,7 @@ impl UsmAllocatorKind for DeviceAllocator { } } -/// An allocator for Host-side buffers +/// An allocator for Host-side arrays pub struct HostAllocator; impl UsmAllocatorKind for HostAllocator { @@ -91,7 +91,7 @@ impl UsmAllocatorKind for HostAllocator { unsafe impl HostAccessible for UsmAllocator {} -/// An allocator for shared memory buffers +/// An allocator for shared memory arrays pub struct SharedAllocator; impl UsmAllocatorKind for SharedAllocator { diff --git a/sycl/sycl-rs/src/buffer.rs b/sycl/sycl-rs/src/usmbox.rs similarity index 55% rename from sycl/sycl-rs/src/buffer.rs rename to sycl/sycl-rs/src/usmbox.rs index 361dcd0..891e281 100644 --- a/sycl/sycl-rs/src/buffer.rs +++ b/sycl/sycl-rs/src/usmbox.rs @@ -27,27 +27,27 @@ use crate::{ }, }; -/// The Buffer struct defines a shared array of one, two or three dimensions that can be used -/// by the SYCL kernel. Buffers are templated on the type of their data, and the number of +/// The `UsmBox` struct defines a shared array of one, two or three dimensions that can be used +/// by the SYCL kernel. `UsmBox`es are generic w.r.t. the type of their data, and the number of /// dimensions that the data is stored and accessed through. /// -/// A Buffer does not map to only one underlying backend object, and all SYCL backend memory objects +/// A `UsmBox` does not map to only one underlying backend object, and all SYCL backend memory objects /// may be temporary for use on a specific device. /// -/// Buffers can be constructed by methods provided by the [`Queue`](`crate::queue::Queue`) class. +/// `UsmBox`es can be constructed by methods provided by the [`Queue`](`crate::queue::Queue`) class. /// -/// The Buffer struct template takes a template parameter [`UsmAlloc`](`crate::usm::UsmAlloc`) for +/// The `UsmBox` struct takes a generic parameter [`UsmAlloc`](`crate::usm::UsmAlloc`) for /// specifying an allocator which is used by the SYCL runtime when allocating temporary memory on /// the host. -pub struct Buffer { +pub struct UsmBox { data: NonNull, len: usize, layout: Layout, allocator: A, } -impl Buffer { - /// Creates a new buffer given an allocator. +impl UsmBox { + /// Creates a new array given an allocator. /// Safety: returns uninitialized memory. pub(crate) unsafe fn new(allocator: A, len: usize) -> Self { let layout = Layout::array::(len).unwrap(); @@ -83,20 +83,20 @@ impl Buffer { } } -impl Deref for Buffer { +impl Deref for UsmBox { type Target = [T]; fn deref(&self) -> &Self::Target { unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) } } } -impl DerefMut for Buffer { +impl DerefMut for UsmBox { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { slice::from_raw_parts_mut(self.data.as_ptr(), self.len) } } } -impl Drop for Buffer { +impl Drop for UsmBox { fn drop(&mut self) { unsafe { self.allocator.deallocate(self.data.cast(), self.layout); @@ -104,83 +104,83 @@ impl Drop for Buffer { } } -pub type HostBuffer = Buffer>; -pub type SharedBuffer = Buffer>; -pub type DeviceBuffer = Buffer>; +pub type HostUsmBox = UsmBox>; +pub type SharedUsmBox = UsmBox>; +pub type DeviceUsmBox = UsmBox>; -/// A [`Buffer`] whose initialization has been enqueued. You need to wait/await it. -pub struct EnqueuedBuffer { - buffer: Buffer, +/// A [`UsmBox`] whose initialization has been enqueued. You need to wait/await it. +pub struct EnqueuedUsmBox { + array: UsmBox, event: Event, } -impl EnqueuedBuffer { - pub(crate) fn new(buffer: Buffer, event: Event) -> Self { - Self { buffer, event } +impl EnqueuedUsmBox { + pub(crate) fn new(array: UsmBox, event: Event) -> Self { + Self { array, event } } } -impl EnqueuedBuffer { - /// Performs a blocking wait for the [`Buffer`] initialization to complete. Returns an error if +impl EnqueuedUsmBox { + /// Performs a blocking wait for the [`UsmBox`] initialization to complete. Returns an error if /// a synchronous SYCL exception occurs. /// - /// Dropping an enqueued buffer does not wait for its completion. - pub fn wait(mut self) -> Result> { - self.event.wait().map(|_| self.buffer) + /// Dropping an enqueued array does not wait for its completion. + pub fn wait(mut self) -> Result> { + self.event.wait().map(|_| self.array) } } -pub type EnqueuedHostBuffer = EnqueuedBuffer>; -pub type EnqueuedSharedBuffer = EnqueuedBuffer>; -pub type EnqueuedDeviceBuffer = EnqueuedBuffer>; +pub type EnqueuedHostUsmBox = EnqueuedUsmBox>; +pub type EnqueuedSharedUsmBox = EnqueuedUsmBox>; +pub type EnqueuedDeviceUsmBox = EnqueuedUsmBox>; #[pin_project] -/// A [`Future`] which represents a pending [`Buffer`] allocation. -pub struct BufferFuture { - buffer: Option>, +/// A [`Future`] which represents a pending [`UsmBox`] allocation. +pub struct UsmBoxFuture { + array: Option>, #[pin] event_future: EventFuture, } -impl Future for BufferFuture { - type Output = Result>; +impl Future for UsmBoxFuture { + type Output = Result>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.project(); this.event_future .poll(cx) - .map(|result| result.map(|_| this.buffer.take().unwrap())) + .map(|result| result.map(|_| this.array.take().unwrap())) } } -impl IntoFuture for EnqueuedBuffer { - type Output = Result>; - type IntoFuture = BufferFuture; +impl IntoFuture for EnqueuedUsmBox { + type Output = Result>; + type IntoFuture = UsmBoxFuture; fn into_future(self) -> Self::IntoFuture { Self::IntoFuture { - buffer: Some(self.buffer), + array: Some(self.array), event_future: self.event.into_future(), } } } -pub type HostBufferFuture = BufferFuture>; -pub type SharedBufferFuture = BufferFuture>; -pub type DeviceBufferFuture = BufferFuture>; +pub type HostUsmBoxFuture = UsmBoxFuture>; +pub type SharedUsmBoxFuture = UsmBoxFuture>; +pub type DeviceUsmBoxFuture = UsmBoxFuture>; -unsafe impl KernelArgument for Buffer { +unsafe impl KernelArgument for UsmBox { unsafe fn as_raw_arg(&self) -> &[u8] { unsafe { self.as_raw_arg_impl() } } } -unsafe impl KernelArgument for &Buffer { +unsafe impl KernelArgument for &UsmBox { unsafe fn as_raw_arg(&self) -> &[u8] { unsafe { self.as_raw_arg_impl() } } } -unsafe impl KernelArgument for &mut Buffer { +unsafe impl KernelArgument for &mut UsmBox { unsafe fn as_raw_arg(&self) -> &[u8] { unsafe { self.as_raw_arg_impl() } } diff --git a/sycl/sycl-rs/tests/alloc.rs b/sycl/sycl-rs/tests/alloc.rs index ca43bff..800b9a1 100644 --- a/sycl/sycl-rs/tests/alloc.rs +++ b/sycl/sycl-rs/tests/alloc.rs @@ -11,11 +11,11 @@ use sycl_rs::queue::Queue; #[test] fn shared_allocation_host_values() { let queue = Queue::new(); - let mut buffer = unsafe { queue.alloc_uninit_shared::(10) }; + let mut array = unsafe { queue.alloc_uninit_shared::(10) }; - for (index, value) in buffer.iter_mut().enumerate() { + for (index, value) in array.iter_mut().enumerate() { *value = index as u32; } - assert_eq!(buffer.as_ref(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + assert_eq!(array.as_ref(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); } diff --git a/sycl/sycl-rs/tests/async.rs b/sycl/sycl-rs/tests/async.rs index cf793a4..599cfe3 100644 --- a/sycl/sycl-rs/tests/async.rs +++ b/sycl/sycl-rs/tests/async.rs @@ -11,9 +11,9 @@ use sycl_rs::queue::Queue; #[tokio::test] async fn check_for_select_support() -> sycl_rs::Result<()> { let mut queue = Queue::new(); - let _selected_buffer = tokio::select! { - buffer1 = queue.alloc_device::(1024)? => buffer1, - buffer2 = queue.alloc_device::(10240)? => buffer2 + let _selected_array = tokio::select! { + array1 = queue.alloc_device::(1024)? => array1, + array2 = queue.alloc_device::(10240)? => array2 }; Ok(())