Struct Task

Source
pub struct Task<'a> { /* private fields */ }
Expand description

Represents an MCL task whose kernel has been set but the arguments and target device are missing

Implementations§

Source§

impl<'a> Task<'a>

Source

pub fn arg(self, arg: TaskArg<'a>) -> Self

Set a new argument arg for this mcl task. Note the order in which tasks are set must match the order expected by the kernel

Returns the Task with the arg set

§Examples
     let mcl = mcl_rs::MclEnvBuilder::new().initialize();
     mcl.create_prog("my_prog",mcl_rs::PrgType::Src)
         .with_compile_args("-D MYDEF").load();
     
     let data = vec![0; 4];
     let mut out = vec![0; 4];
     let pes: [u64; 3] = [1, 1, 1];

     let mcl_future = mcl.task("my_kernel", 1)
                 .arg(mcl_rs::TaskArg::input_slice(&data)) //the first argument to the kernel is  the input array
                 .arg(mcl_rs::TaskArg::output_slice(&mut out))//the second argument to the kernel is  the output array
                 .exec(pes);
     futures::executor::block_on(mcl_future);
Source

pub fn arg_buffer(self, buffer: RegisteredBuffer<'a>) -> Self

Set a new argument registered buffer arg for this mcl task in preparation

Returns the Task with the arg set

§Examples
     let mcl = mcl_rs::MclEnvBuilder::new().initialize();
     mcl.create_prog("my_prog",mcl_rs::PrgType::Src)
         .with_compile_args("-D MYDEF").load();
     
     let mut a = vec![0;100];
     let buf = mcl.register_buffer(mcl_rs::TaskArg::inout_slice(&mut a)
            .resident(true)
            .dynamic(true),
     );
     let pes: [u64; 3] = [1, 1, 1];

     let mcl_future = mcl.task("my_kernel", 1)
                 .arg_buffer(buf)
                 .exec(pes);
     futures::executor::block_on(mcl_future);
Source

pub unsafe fn arg_shared_buffer(self, buffer: SharedMemBuffer) -> Self

Available on crate features shared_mem or pocl_extensions only.

Set a new shared argument buffer arg for this mcl task in preparation

Returns the Task with the arg set

§Saftey

We track the reader and writers associated with this buffer to protect access, but that only applies to this process

Regardless of and local saftey guarentees we provide, using a shared buffer is still inherently unsafe as this represents a multi-processed shared memory buffer, managed by the MCL c-library, no guarantees can be provided on multiple processes modifying this buffer simultaneously

§Examples
     let mcl = mcl_rs::MclEnvBuilder::new().initialize();
     mcl.create_prog("my_prog",mcl_rs::PrgType::Src)
         .with_compile_args("-D MYDEF").load();
     
     let num_elems = 100;
     let buf = mcl.create_shared_buffer(mcl_rs::TaskArg::inout_shared::<u32>("my_buffer", num_elems));
     let pes: [u64; 3] = [1, 1, 1];

     let mcl_future = unsafe {
         mcl.task("my_kernel", 1)
             .arg_shared(buf) //potentially accessed by other proccesses hence unsafe
             .exec(pes)
     };
     futures::executor::block_on(mcl_future);
Source

pub fn lwsize(self, les: [u64; 3]) -> Self

Set the local workgroup size les to the mcl task in preparation

Returns the Task with the local workgroup size set

§Examples
     let mcl = mcl_rs::MclEnvBuilder::new().initialize();
     mcl.create_prog("my_prog",mcl_rs::PrgType::Src)
         .with_compile_args("-D MYDEF").load();
     let data = vec![0; 4];
     let les: [u64; 3] = [1, 1, 1];
     let pes: [u64; 3] = [1, 1, 1];
     let mcl_future = mcl.task("my_kernel", 1)
                 .arg(mcl_rs::TaskArg::input_slice(&data))
                 .lwsize(les)
                 .exec(pes);
     futures::executor::block_on(mcl_future);
Source

pub fn dev(self, dev: DevType) -> Self

Set the preferred device dev to the mcl task in preparation

Returns the Task with the desired device set

§Examples
     let mcl = mcl_rs::MclEnvBuilder::new().initialize();
     mcl.create_prog("my_prog",mcl_rs::PrgType::Src)
         .with_compile_args("-D MYDEF").load();
     let data = vec![0; 4];
     let les: [u64; 3] = [1, 1, 1];
     let pes: [u64; 3] = [1, 1, 1];
     let mcl_future = mcl.task("my_kernel", 1)
                 .arg(mcl_rs::TaskArg::input_slice(&data))
                 .lwsize(les)
                 .dev(mcl_rs::DevType::CPU)
                 .exec(pes);
     futures::executor::block_on(mcl_future);
Source

pub fn shared_id(&self) -> Option<u32>

Available on crate features shared_mem or pocl_extensions only.

If this is a shared task return the task id otherwise return None

§Examples
     let mcl = mcl_rs::MclEnvBuilder::new().initialize();
     mcl.load_prog("my_prog",mcl_rs::PrgType::Src);
     let data = vec![0; 4];
     let pes: [u64; 3] = [1, 1, 1];

     let task = mcl.task("my_kernel", 1);
     assert_eq!(task.shared_id(), None);

     let shared_task = mcl.shared_task("my_kernel2", 1);
     assert!(shared_task.shared_id().is_some());
Source

pub async fn exec(self, pes: [u64; 3])

Submit the task for execution This is an asynchronous operation, meaning that no work is actually performed until the returned future is actualy awaited. While awaiting a task execution, the user application will not make forward progress until the underylying device has executed the task and performed any necessary data transfers. Upon return from the await call, any output data is gauranteed to be written to its approriate buffer.

Task execution order can be enforced by sequentially awaiting tasks, or may be executed simultaneously using data structures such as Join_all https://docs.rs/futures/latest/futures/future/fn.join_all.html

§Examples
     let mcl = mcl_rs::MclEnvBuilder::new().num_workers(10).initialize();
     mcl.load_prog("my_path", mcl_rs::PrgType::Src);
     let data = vec![0; 4];
     let pes: [u64; 3] = [1, 1, 1];
     let task_1 = mcl.task("my_kernel", 1)
                 .arg(mcl_rs::TaskArg::input_slice(&data))
                 .dev(mcl_rs::DevType::CPU)
                 .exec(pes); //this creates a future we need to await
     let task_2 = mcl.task("my_kernel", 1)
                 .arg(mcl_rs::TaskArg::input_slice(&data))
                 .dev(mcl_rs::DevType::CPU)
                 .exec(pes); //this creates a future we need to await
     let sequential_tasks = async move{
         task_1.await; //task will execute before task 2 is even submitted
         task_2.await;
     };
     futures::executor::block_on(sequential_tasks);
     
     let task_3 = mcl.task("my_kernel", 1)
                 .arg(mcl_rs::TaskArg::input_slice(&data))
                 .dev(mcl_rs::DevType::CPU)
                 .exec(pes); //this creates a future we need to await
     let task_4 = mcl.task("my_kernel", 1)
                 .arg(mcl_rs::TaskArg::input_slice(&data))
                 .dev(mcl_rs::DevType::CPU)
                 .exec(pes); //this creates a future we need to await
     let simultaneous_tasks = futures::future::join_all([task_3,task_4]);
     futures::executor::block_on(simultaneous_tasks); //both tasks submitted "simultaneously"

Trait Implementations§

Source§

impl Drop for Task<'_>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl Send for Task<'_>

Source§

impl Sync for Task<'_>

Auto Trait Implementations§

§

impl<'a> Freeze for Task<'a>

§

impl<'a> RefUnwindSafe for Task<'a>

§

impl<'a> Unpin for Task<'a>

§

impl<'a> UnwindSafe for Task<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.