142 KiB
cudarc::driver Module safe Copy item path Source
Safe abstractions over crate::driver::result provided by CudaSlice, CudaContext, CudaStream, and more.
Re-exports pub use crate::driver::result::DriverError; Structs CudaContext Represents a primary cuda context on a certain device. When created with CudaContext::new() it will push a new primary context onto the stack. CudaEvent A lightweight synchronization primitive used to synchronize between CudaStreams. CudaFunction Wrapper around sys::CUfunction. Used by CudaStream::launch_builder to execute kernels. CudaGraph Represents a replay-able Cuda Graph. Create with CudaStream::begin_capture() and CudaStream::end_capture(). CudaModule Wrapper around sys::CUmodule. Create with CudaContext::load_module(). CudaSlice Vec on a cuda device. You can allocate and modify this with CudaStream. CudaStream A wrapper around sys::CUstream that you can schedule work on. CudaView &[T] on a cuda device. An immutable sub-view into a CudaSlice created by CudaSlice::as_view()/CudaSlice::slice(). CudaViewMut &mut [T] on a cuda device. A mutable sub-view into a CudaSlice created by CudaSlice::as_view_mut()/CudaSlice::slice_mut(). ExternalMemory An abstraction for imported external memory. LaunchArgs The kernel launch builder. Instantiate with CudaStream::launch_builder(), and then launch the kernel with LaunchArgs::launch() LaunchConfig Configuration for result::launch_kernel MappedBuffer An abstraction for a mapped buffer for some external memory. PinnedHostSlice Rust side data that the cuda driver knows is pinned. This is different than Pin<Vec> mainly because cuda driver manages this memory and ensures it is page locked. Profiler Calls profiler_start() in Profiler::new(), and profiler_stop() in Drop. UnifiedSlice Unified memory allocated with CudaContext::alloc_unified() (via cuMemAllocManaged). Enums SyncOnDrop A synchronization primitive to enable stream & event synchronization. Primarily used with DevicePtr and DevicePtrMut Traits DevicePtr Abstraction over CudaSlice/CudaView DevicePtrMut Abstraction over CudaSlice/CudaViewMut DeviceRepr Something that can be copied to device memory and turned into a parameter for result::launch_kernel. DeviceSlice Base trait for abstracting over CudaSlice/CudaView/CudaViewMut. HostSlice Abstraction over &[T], &Vec and PinnedHostSlice. PushKernelArg Something that can be copied to device memory and turned into a parameter for result::launch_kernel. ValidAsZeroBits Marker trait to indicate that the type is valid when all of its bits are set to 0. Functions profiler_start Enables profile collection by the active profiling tool for the current context. If profiling is already enabled, then profiler_start() has no effect. More info in Cuda docs For RAII version see Profiler::new. profiler_stop Disables profile collection by the active profiling tool for the current context. If profiling is already disabled, then profiler_stop() has no effect.
pub struct CudaContext { /* private fields */ } Represents a primary cuda context on a certain device. When created with CudaContext::new() it will push a new primary context onto the stack.
This is the entrypoint to using any cuda calls, all objects maintain a pointer to Arc to ensure proper lifetimes.
On thread safety This object is thread safe and can be shared/used on multiple threads. All safe apis call CudaContext::bind_to_thread() before doing work in a certain context.
Implementations Source impl CudaContext Source pub fn new(ordinal: usize) -> Result<Arc, DriverError> Creates a new context on the specified device ordinal.
Examples found in repository? examples/01-allocate.rs (line 4) 3fn main() -> Result<(), DriverError> { 4 let ctx = CudaContext::new(0)?; 5 let stream = ctx.default_stream(); 6 7 // unsafe initialization of unset memory 8 let _: CudaSlice = unsafe { stream.alloc::(10) }?; 9 10 // this will have memory initialized as 0 11 let _: CudaSlice = stream.alloc_zeros::(10)?; 12 13 // initialize with slices! 14 let _: CudaSlice = stream.memcpy_stod(&[0; 10])?; 15 let _: CudaSlice = stream.memcpy_stod(&[1, 2, 3])?; 16 17 Ok(()) 18} More examples Hide additional examples examples/05-device-repr.rs (line 33) 32fn main() -> Result<(), DriverError> { 33 let ctx = CudaContext::new(0)?; 34 let stream = ctx.default_stream(); 35 36 let ptx = compile_ptx(PTX_SRC).unwrap(); 37 let module = ctx.load_module(ptx)?; 38 let f = module.load_function("my_custom_kernel")?; 39 40 // try changing some of these values to see a device assert 41 let thing = MyCoolRustStruct { 42 a: 1.0, 43 b: 2.34, 44 c: 57, 45 d: 420, 46 }; 47 48 let mut builder = stream.launch_builder(&f); 49 // since MyCoolRustStruct implements DeviceRepr, we can pass it to launch. 50 builder.arg(&thing); 51 unsafe { builder.launch(LaunchConfig::for_num_elems(1)) }?; 52 53 Ok(()) 54} examples/cufile-copy.rs (line 19) 2fn main() -> Result<(), Box> { 3 use std::fs; 4 5 use cudarc::{cufile::safe::Cufile, driver::CudaContext}; 6 7 const N: usize = 100000; 8 let data: Vec = (0..N).flat_map(|x| (x as f32).to_le_bytes()).collect(); 9 let data_sz = data.len(); 10 let src_file = "/tmp/cufile_test.bin"; 11 fs::write(src_file, &data)?; 12 13 let cufile = Cufile::new()?; 14 println!("{:?}", cufile.get_properties()?); 15 16 let file = fs::File::open(src_file)?; 17 let handle = cufile.register(file)?; 18 19 let ctx = CudaContext::new(0)?; 20 let stream = ctx.default_stream(); 21 let mut buf = stream.alloc_zeros::(data_sz)?; 22 23 handle.sync_read(0, &mut buf)?; 24 25 let verify_dst = stream.memcpy_dtov(&buf)?; 26 assert_eq!(verify_dst, data); 27 28 Ok(()) 29} examples/02-copy.rs (line 4) 3fn main() -> Result<(), DriverError> { 4 let ctx = CudaContext::new(0)?; 5 let stream = ctx.default_stream(); 6 7 let a: CudaSlice = stream.alloc_zeros::(10)?; 8 let mut b = stream.alloc_zeros::(10)?; 9 10 // you can do device to device copies of course 11 stream.memcpy_dtod(&a, &mut b)?; 12 13 // but also host to device copys with already allocated buffers 14 stream.memcpy_htod(&vec![2.0; b.len()], &mut b)?; 15 // you can use any type of slice 16 stream.memcpy_htod(&[3.0; 10], &mut b)?; 17 18 // you can transfer back using memcpy_dtov 19 let mut a_host: Vec = stream.memcpy_dtov(&a)?; 20 assert_eq!(a_host, [0.0; 10]); 21 22 let b_host = stream.memcpy_dtov(&b)?; 23 assert_eq!(b_host, [3.0; 10]); 24 25 // or transfer into a pre allocated slice 26 stream.memcpy_dtoh(&b, &mut a_host)?; 27 assert_eq!(a_host, b_host); 28 29 Ok(()) 30} examples/03-launch-kernel.rs (line 7) 6fn main() -> Result<(), DriverError> { 7 let ctx = CudaContext::new(0)?; 8 let stream = ctx.default_stream(); 9 10 // You can load a function from a pre-compiled PTX like so: 11 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?; 12 13 // and then load a function from it: 14 let f = module.load_function("sin_kernel").unwrap(); 15 16 let a_host = [1.0, 2.0, 3.0]; 17 18 let a_dev = stream.memcpy_stod(&a_host)?; 19 let mut b_dev = a_dev.clone(); 20 21 // we use a buidler pattern to launch kernels. 22 let n = 3i32; 23 let cfg = LaunchConfig::for_num_elems(n as u32); 24 let mut launch_args = stream.launch_builder(&f); 25 launch_args.arg(&mut b_dev); 26 launch_args.arg(&a_dev); 27 launch_args.arg(&n); 28 unsafe { launch_args.launch(cfg) }?; 29 30 let a_host_2 = stream.memcpy_dtov(&a_dev)?; 31 let b_host = stream.memcpy_dtov(&b_dev)?; 32 33 println!("Found {b_host:?}"); 34 println!("Expected {:?}", a_host.map(f32::sin)); 35 assert_eq!(&a_host, a_host_2.as_slice()); 36 37 Ok(()) 38} examples/matmul-kernel.rs (line 28) 22fn main() -> Result<(), DriverError> { 23 let start = std::time::Instant::now(); 24 25 let ptx = compile_ptx(PTX_SRC).unwrap(); 26 println!("Compilation succeeded in {:?}", start.elapsed()); 27 28 let ctx = CudaContext::new(0)?; 29 let stream = ctx.default_stream(); 30 println!("Built in {:?}", start.elapsed()); 31 32 let module = ctx.load_module(ptx)?; 33 let f = module.load_function("matmul")?; 34 println!("Loaded in {:?}", start.elapsed()); 35 36 let a_host = [1.0f32, 2.0, 3.0, 4.0]; 37 let b_host = [1.0f32, 2.0, 3.0, 4.0]; 38 let mut c_host = [0.0f32; 4]; 39 40 let a_dev = stream.memcpy_stod(&a_host)?; 41 let b_dev = stream.memcpy_stod(&b_host)?; 42 let mut c_dev = stream.memcpy_stod(&c_host)?; 43 44 println!("Copied in {:?}", start.elapsed()); 45 46 let mut builder = stream.launch_builder(&f); 47 builder.arg(&a_dev); 48 builder.arg(&b_dev); 49 builder.arg(&mut c_dev); 50 builder.arg(&2i32); 51 let cfg = LaunchConfig { 52 block_dim: (2, 2, 1), 53 grid_dim: (1, 1, 1), 54 shared_mem_bytes: 0, 55 }; 56 unsafe { builder.launch(cfg) }?; 57 58 stream.memcpy_dtoh(&c_dev, &mut c_host)?; 59 println!("Found {:?} in {:?}", c_host, start.elapsed()); 60 Ok(()) 61} Additional examples can be found in: examples/04-streams.rs examples/06-threading.rs Source pub fn device_count() -> Result<i32, DriverError> The number of devices available.
Source pub fn ordinal(&self) -> usize Get the ordinal index of the device this is on.
Source pub fn name(&self) -> Result<String, DriverError> Get the name of this device.
Source pub fn uuid(&self) -> Result<CUuuid, DriverError> Get the UUID of this device.
Source pub fn cu_device(&self) -> CUdevice Get the underlying sys::CUdevice of this CudaContext.
Safety While this function is marked as safe, actually using the returned object is unsafe.
You must not free/release the device pointer, as it is still owned by the CudaContext.
Source pub fn cu_ctx(&self) -> CUcontext Get the underlying sys::CUcontext of this CudaContext.
Safety While this function is marked as safe, actually using the returned object is unsafe.
You must not free/release the context pointer, as it is still owned by the CudaContext.
Source pub fn bind_to_thread(&self) -> Result<(), DriverError> Binds this context to the calling thread. Calling this is key for thread safety.
Source pub fn attribute(&self, attrib: CUdevice_attribute) -> Result<i32, DriverError> Get the value of the specified attribute of the device in CudaContext.
Source pub fn synchronize(&self) -> Result<(), DriverError> Synchronize this context. Will only block CPU if you call CudaContext::set_flags() with sys::CUctx_flags::CU_CTX_SCHED_BLOCKING_SYNC.
Source pub fn set_blocking_synchronize(&self) -> Result<(), DriverError> Ensures calls to CudaContext::synchronize() block the calling thread.
Sets sys::CUctx_flags::CU_CTX_SCHED_BLOCKING_SYNC
Source pub fn set_flags(&self, flags: CUctx_flags) -> Result<(), DriverError> Set flags for this context
Source pub fn is_in_multi_stream_mode(&self) -> bool Whether multiple streams have been created in this context. If so, the CudaSlice::read and CudaSlice::write events will be activated.
This only get’s set to true by CudaContext::new_stream().
Source pub fn is_event_tracking(&self) -> bool Whether event tracking is being managed by this context (via CudaContext::enable_event_tracking(), which is the default behavior), or false if the user is manually managing stream synchronization (via CudaContext::disable_event_tracking()).
Source pub fn is_managing_stream_synchronization(&self) -> bool Whether the context is automatically managing multiple stream synchronization. Both of these must be true:
CudaContext::is_in_multi_stream_mode() CudaContext::is_event_tracking() Source pub unsafe fn enable_event_tracking(&self) When turned on, all CudaSlice created after calling this function will record usages using CudaEvent to ensure proper synchronization between streams.
Safety If CudaContext::disable_event_tracking() was called previously, then any CudaSlice created after that and before this current call won’t have CudaEvent tracking their uses. Those CudaSlice will not manage their synchronization, even after this call.
Source pub unsafe fn disable_event_tracking(&self) When turned on, all CudaSlice created after calling this function will not track uses via CudaEvents.
Safety It is up to the user to ensure proper synchronization between multiple streams:
Ensure that no CudaSlice is freed before a use on another stream is finished. Ensure that a CudaSlice is not used on another stream before allocation on the allocating stream finishes. Ensure that a CudaSlice is not written two concurrently by multiple streams. Source pub fn check_err(&self) -> Result<(), DriverError> Checks to see if there have been any calls that stored an Err in a function that couldn’t return a result (e.g. Drop calls).
If there are any errors stored, this method will return the Err value, and then clear the stored error state.
Source pub fn record_err(&self, result: Result<T, DriverError>) Records a result for later inspection when a Result can be returned.
Source impl CudaContext Source pub fn new_event( self: &Arc, flags: Option<CUevent_flags>, ) -> Result<CudaEvent, DriverError> Creates a new CudaEvent with no work recorded. If flags is None, the event is created with sys::CUevent_flags::CU_EVENT_DISABLE_TIMING.
Source impl CudaContext Source pub fn default_stream(self: &Arc) -> Arc Get’s the default stream for this context (the null ptr stream). Note that context’s on the same device can all submit to the same default stream from separate context objects.
Examples found in repository? examples/01-allocate.rs (line 5) 3fn main() -> Result<(), DriverError> { 4 let ctx = CudaContext::new(0)?; 5 let stream = ctx.default_stream(); 6 7 // unsafe initialization of unset memory 8 let _: CudaSlice = unsafe { stream.alloc::(10) }?; 9 10 // this will have memory initialized as 0 11 let _: CudaSlice = stream.alloc_zeros::(10)?; 12 13 // initialize with slices! 14 let _: CudaSlice = stream.memcpy_stod(&[0; 10])?; 15 let _: CudaSlice = stream.memcpy_stod(&[1, 2, 3])?; 16 17 Ok(()) 18} More examples Hide additional examples examples/05-device-repr.rs (line 34) 32fn main() -> Result<(), DriverError> { 33 let ctx = CudaContext::new(0)?; 34 let stream = ctx.default_stream(); 35 36 let ptx = compile_ptx(PTX_SRC).unwrap(); 37 let module = ctx.load_module(ptx)?; 38 let f = module.load_function("my_custom_kernel")?; 39 40 // try changing some of these values to see a device assert 41 let thing = MyCoolRustStruct { 42 a: 1.0, 43 b: 2.34, 44 c: 57, 45 d: 420, 46 }; 47 48 let mut builder = stream.launch_builder(&f); 49 // since MyCoolRustStruct implements DeviceRepr, we can pass it to launch. 50 builder.arg(&thing); 51 unsafe { builder.launch(LaunchConfig::for_num_elems(1)) }?; 52 53 Ok(()) 54} examples/cufile-copy.rs (line 20) 2fn main() -> Result<(), Box> { 3 use std::fs; 4 5 use cudarc::{cufile::safe::Cufile, driver::CudaContext}; 6 7 const N: usize = 100000; 8 let data: Vec = (0..N).flat_map(|x| (x as f32).to_le_bytes()).collect(); 9 let data_sz = data.len(); 10 let src_file = "/tmp/cufile_test.bin"; 11 fs::write(src_file, &data)?; 12 13 let cufile = Cufile::new()?; 14 println!("{:?}", cufile.get_properties()?); 15 16 let file = fs::File::open(src_file)?; 17 let handle = cufile.register(file)?; 18 19 let ctx = CudaContext::new(0)?; 20 let stream = ctx.default_stream(); 21 let mut buf = stream.alloc_zeros::(data_sz)?; 22 23 handle.sync_read(0, &mut buf)?; 24 25 let verify_dst = stream.memcpy_dtov(&buf)?; 26 assert_eq!(verify_dst, data); 27 28 Ok(()) 29} examples/02-copy.rs (line 5) 3fn main() -> Result<(), DriverError> { 4 let ctx = CudaContext::new(0)?; 5 let stream = ctx.default_stream(); 6 7 let a: CudaSlice = stream.alloc_zeros::(10)?; 8 let mut b = stream.alloc_zeros::(10)?; 9 10 // you can do device to device copies of course 11 stream.memcpy_dtod(&a, &mut b)?; 12 13 // but also host to device copys with already allocated buffers 14 stream.memcpy_htod(&vec![2.0; b.len()], &mut b)?; 15 // you can use any type of slice 16 stream.memcpy_htod(&[3.0; 10], &mut b)?; 17 18 // you can transfer back using memcpy_dtov 19 let mut a_host: Vec = stream.memcpy_dtov(&a)?; 20 assert_eq!(a_host, [0.0; 10]); 21 22 let b_host = stream.memcpy_dtov(&b)?; 23 assert_eq!(b_host, [3.0; 10]); 24 25 // or transfer into a pre allocated slice 26 stream.memcpy_dtoh(&b, &mut a_host)?; 27 assert_eq!(a_host, b_host); 28 29 Ok(()) 30} examples/03-launch-kernel.rs (line 8) 6fn main() -> Result<(), DriverError> { 7 let ctx = CudaContext::new(0)?; 8 let stream = ctx.default_stream(); 9 10 // You can load a function from a pre-compiled PTX like so: 11 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?; 12 13 // and then load a function from it: 14 let f = module.load_function("sin_kernel").unwrap(); 15 16 let a_host = [1.0, 2.0, 3.0]; 17 18 let a_dev = stream.memcpy_stod(&a_host)?; 19 let mut b_dev = a_dev.clone(); 20 21 // we use a buidler pattern to launch kernels. 22 let n = 3i32; 23 let cfg = LaunchConfig::for_num_elems(n as u32); 24 let mut launch_args = stream.launch_builder(&f); 25 launch_args.arg(&mut b_dev); 26 launch_args.arg(&a_dev); 27 launch_args.arg(&n); 28 unsafe { launch_args.launch(cfg) }?; 29 30 let a_host_2 = stream.memcpy_dtov(&a_dev)?; 31 let b_host = stream.memcpy_dtov(&b_dev)?; 32 33 println!("Found {b_host:?}"); 34 println!("Expected {:?}", a_host.map(f32::sin)); 35 assert_eq!(&a_host, a_host_2.as_slice()); 36 37 Ok(()) 38} examples/matmul-kernel.rs (line 29) 22fn main() -> Result<(), DriverError> { 23 let start = std::time::Instant::now(); 24 25 let ptx = compile_ptx(PTX_SRC).unwrap(); 26 println!("Compilation succeeded in {:?}", start.elapsed()); 27 28 let ctx = CudaContext::new(0)?; 29 let stream = ctx.default_stream(); 30 println!("Built in {:?}", start.elapsed()); 31 32 let module = ctx.load_module(ptx)?; 33 let f = module.load_function("matmul")?; 34 println!("Loaded in {:?}", start.elapsed()); 35 36 let a_host = [1.0f32, 2.0, 3.0, 4.0]; 37 let b_host = [1.0f32, 2.0, 3.0, 4.0]; 38 let mut c_host = [0.0f32; 4]; 39 40 let a_dev = stream.memcpy_stod(&a_host)?; 41 let b_dev = stream.memcpy_stod(&b_host)?; 42 let mut c_dev = stream.memcpy_stod(&c_host)?; 43 44 println!("Copied in {:?}", start.elapsed()); 45 46 let mut builder = stream.launch_builder(&f); 47 builder.arg(&a_dev); 48 builder.arg(&b_dev); 49 builder.arg(&mut c_dev); 50 builder.arg(&2i32); 51 let cfg = LaunchConfig { 52 block_dim: (2, 2, 1), 53 grid_dim: (1, 1, 1), 54 shared_mem_bytes: 0, 55 }; 56 unsafe { builder.launch(cfg) }?; 57 58 stream.memcpy_dtoh(&c_dev, &mut c_host)?; 59 println!("Found {:?} in {:?}", c_host, start.elapsed()); 60 Ok(()) 61} Additional examples can be found in: examples/04-streams.rs examples/06-threading.rs Source pub fn new_stream(self: &Arc) -> Result<Arc, DriverError> Create a new sys::CUstream_flags::CU_STREAM_NON_BLOCKING stream.
This will swap the calling context to multi stream mode CudaContext::is_in_multi_stream_mode(). If the context is not already in multiple stream mode, then this function will also call CudaContext::synchronize().
Source impl CudaContext Source pub unsafe fn alloc_pinned<T: DeviceRepr>( self: &Arc, len: usize, ) -> Result<PinnedHostSlice, DriverError> Allocates page locked host memory with sys::CU_MEMHOSTALLOC_WRITECOMBINED flags.
See cuda docs
Safety This is unsafe because the memory is unset after this call. Source impl CudaContext Source pub fn load_module( self: &Arc, ptx: Ptx, ) -> Result<Arc, DriverError> Dynamically load a compiled ptx into this context.
ptx contains the compiled ptx
Examples found in repository?
examples/05-device-repr.rs (line 37)
32fn main() -> Result<(), DriverError> {
33 let ctx = CudaContext::new(0)?;
34 let stream = ctx.default_stream();
35
36 let ptx = compile_ptx(PTX_SRC).unwrap();
37 let module = ctx.load_module(ptx)?;
38 let f = module.load_function("my_custom_kernel")?;
39
40 // try changing some of these values to see a device assert
41 let thing = MyCoolRustStruct {
42 a: 1.0,
43 b: 2.34,
44 c: 57,
45 d: 420,
46 };
47
48 let mut builder = stream.launch_builder(&f);
49 // since MyCoolRustStruct implements DeviceRepr, we can pass it to launch.
50 builder.arg(&thing);
51 unsafe { builder.launch(LaunchConfig::for_num_elems(1)) }?;
52
53 Ok(())
54}
More examples
Hide additional examples
examples/03-launch-kernel.rs (line 11)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 // You can load a function from a pre-compiled PTX like so:
11 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
12
13 // and then load a function from it:
14 let f = module.load_function("sin_kernel").unwrap();
15
16 let a_host = [1.0, 2.0, 3.0];
17
18 let a_dev = stream.memcpy_stod(&a_host)?;
19 let mut b_dev = a_dev.clone();
20
21 // we use a buidler pattern to launch kernels.
22 let n = 3i32;
23 let cfg = LaunchConfig::for_num_elems(n as u32);
24 let mut launch_args = stream.launch_builder(&f);
25 launch_args.arg(&mut b_dev);
26 launch_args.arg(&a_dev);
27 launch_args.arg(&n);
28 unsafe { launch_args.launch(cfg) }?;
29
30 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
31 let b_host = stream.memcpy_dtov(&b_dev)?;
32
33 println!("Found {b_host:?}");
34 println!("Expected {:?}", a_host.map(f32::sin));
35 assert_eq!(&a_host, a_host_2.as_slice());
36
37 Ok(())
38}
examples/matmul-kernel.rs (line 32)
22fn main() -> Result<(), DriverError> {
23 let start = std::time::Instant::now();
24
25 let ptx = compile_ptx(PTX_SRC).unwrap();
26 println!("Compilation succeeded in {:?}", start.elapsed());
27
28 let ctx = CudaContext::new(0)?;
29 let stream = ctx.default_stream();
30 println!("Built in {:?}", start.elapsed());
31
32 let module = ctx.load_module(ptx)?;
33 let f = module.load_function("matmul")?;
34 println!("Loaded in {:?}", start.elapsed());
35
36 let a_host = [1.0f32, 2.0, 3.0, 4.0];
37 let b_host = [1.0f32, 2.0, 3.0, 4.0];
38 let mut c_host = [0.0f32; 4];
39
40 let a_dev = stream.memcpy_stod(&a_host)?;
41 let b_dev = stream.memcpy_stod(&b_host)?;
42 let mut c_dev = stream.memcpy_stod(&c_host)?;
43
44 println!("Copied in {:?}", start.elapsed());
45
46 let mut builder = stream.launch_builder(&f);
47 builder.arg(&a_dev);
48 builder.arg(&b_dev);
49 builder.arg(&mut c_dev);
50 builder.arg(&2i32);
51 let cfg = LaunchConfig {
52 block_dim: (2, 2, 1),
53 grid_dim: (1, 1, 1),
54 shared_mem_bytes: 0,
55 };
56 unsafe { builder.launch(cfg) }?;
57
58 stream.memcpy_dtoh(&c_dev, &mut c_host)?;
59 println!("Found {:?} in {:?}", c_host, start.elapsed());
60 Ok(())
61}
examples/04-streams.rs (line 10)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
11 let f = module.load_function("sin_kernel")?;
12
13 let n = 3i32;
14 let a_host = [1.0, 2.0, 3.0];
15 let a_dev = stream.memcpy_stod(&a_host)?;
16 let mut b_dev = stream.alloc_zeros::(n as usize)?;
17
18 // we can safely create a second stream using [CudaStream::fork()].
19 // This synchronizes with the source stream, so
20 // the memcpy_vtod & alloc_zeros above will complete before
21 // work on this stream can start.
22 let stream2 = stream.fork()?;
23
24 // now we launch this work on the other stream
25 let mut builder = stream2.launch_builder(&f);
26 builder.arg(&mut b_dev); // NOTE: tells cudarc that we are mutating this.
27 builder.arg(&a_dev); // NOTE: tells cudarc that we are reading from this slice
28 builder.arg(&n);
29 unsafe { builder.launch(LaunchConfig::for_num_elems(n as u32)) }?;
30
31 // cudarc automatically manages multi stream synchronization,
32 // so even though we launched the above on a separate stream,
33 // doing this device to host transfer will still properly synchronize.
34 // a_dev doesn't need to synchronize at all since we specified it is just
35 // being read from.
36 // b_dev DOES need to be synchronized, because it was mutated on a different stream.
37 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
38 let b_host = stream.memcpy_dtov(&b_dev)?;
39
40 println!("Found {b_host:?}");
41 println!("Expected {:?}", a_host.map(f32::sin));
42 assert_eq!(&a_host, a_host_2.as_slice());
43
44 Ok(())
45}
examples/06-threading.rs (line 18)
12fn main() -> Result<(), DriverError> {
13 {
14 // Option 1: sharing ctx & module between threads
15 thread::scope(|s| {
16 let ptx = compile_ptx(KERNEL_SRC).unwrap();
17 let ctx = CudaContext::new(0)?;
18 let module = ctx.load_module(ptx)?;
19 for i in 0..10i32 {
20 let thread_ctx = ctx.clone();
21 let thread_module = module.clone();
22 s.spawn(move || {
23 let stream = thread_ctx.default_stream();
24 let f = thread_module.load_function("hello_world")?;
25 unsafe {
26 stream
27 .launch_builder(&f)
28 .arg(&i)
29 .launch(LaunchConfig::for_num_elems(1))
30 }
31 });
32 }
33 Ok(())
34 })?;
35 }
36
37 {
38 // Option 2: initializing different context in each
39 // Note that this will still schedule to the same stream since we are using the
40 // default stream here on the same device.
41 thread::scope(move |s| {
42 for i in 0..10i32 {
43 s.spawn(move || {
44 let ptx = compile_ptx(KERNEL_SRC).unwrap();
45 let ctx = CudaContext::new(0)?;
46 let module = ctx.load_module(ptx)?;
47 let stream = ctx.default_stream();
48 let f = module.load_function("hello_world")?;
49 unsafe {
50 stream
51 .launch_builder(&f)
52 .arg(&i)
53 .launch(LaunchConfig::for_num_elems(1))
54 }
55 });
56 }
57 Ok(())
58 })?;
59 }
60
61 Ok(())
62}
Source
impl CudaContext
Source
pub unsafe fn import_external_memory(
self: &Arc,
file: File,
size: u64,
) -> Result<ExternalMemory, DriverError>
Import external memory from a File.
Safety size must be the size of the external memory in bytes.
Source impl CudaContext Source pub unsafe fn alloc_unified<T: DeviceRepr>( self: &Arc, len: usize, attach_global: bool, ) -> Result<UnifiedSlice, DriverError> Allocates managed memory using cuMemAllocManaged.
If attach_global is true, then allocates the memory with flag sys::CUmemAttach_flags::CU_MEM_ATTACH_GLOBAL, otherwise uses flag sys::CUmemAttach_flags::CU_MEM_ATTACH_HOST.
Note that only these two flags are valid during allocation, you can change the attach mode later via UnifiedSlice::attach()
If the device does not support managed memory (sys::CUdevice_attribute::CU_DEVICE_ATTRIBUTE_MANAGED_MEMORY is 0), then this method will return Err with sys::cudaError_enum::CUDA_ERROR_NOT_PERMITTED.
Safety This is unsafe because this method has no restrictions that T is valid for any bit pattern.
Trait Implementations Source impl Debug for CudaContext Source fn fmt(&self, f: &mut Formatter<'_>) -> Result Formats the value using the given formatter. Read more Source impl Drop for CudaContext Source fn drop(&mut self) Executes the destructor for this type. Read more Source impl PartialEq for CudaContext Source fn eq(&self, other: &Self) -> bool Tests for self and other values to be equal, and is used by ==. 1.0.0 · Source fn ne(&self, other: &Rhs) -> bool Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason. Source impl Eq for CudaContext Source impl Send for CudaContext Source impl Sync for CudaContext Auto Trait Implementations impl !Freeze for CudaContext impl RefUnwindSafe for CudaContext impl Unpin for CudaContext impl UnwindSafe for CudaContext Blanket Implementations Source impl Any for T where T: 'static + ?Sized, Source fn type_id(&self) -> TypeId Gets the TypeId of self. Read more Source impl Borrow for T where T: ?Sized, Source fn borrow(&self) -> &T Immutably borrows from an owned value. Read more Source impl BorrowMut for T where T: ?Sized, Source fn borrow_mut(&mut self) -> &mut T Mutably borrows from an owned value. Read more Source impl From for T Source fn from(t: T) -> T Returns the argument unchanged.
Source impl<T, U> Into for T where U: From, Source fn into(self) -> U Calls U::from(self).
That is, this conversion is whatever the implementation of From for U chooses to do.
Source impl<T, U> TryFrom for T where U: Into, 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>::Error> Performs the conversion. Source impl<T, U> TryInto for T where U: TryFrom, Source type Error = <U as TryFrom>::Error The type returned in the event of a conversion error. Source fn try_into(self) -> Result<U, <U as TryFrom>::Error> Performs the conversion. Source§ impl<V, T> VZip for T where V: MultiLane,
pub struct CudaEvent { /* private fields */ } A lightweight synchronization primitive used to synchronize between CudaStreams.
Create using CudaContext::new_event(). Record a point of time in a stream using CudaEvent::record(). Either call CudaEvent::synchronize() or CudaStream::wait() to use. Note that calls to CudaEvent::record() will not change any previous calls to CudaStream::wait().
Thread safety This object is thread safe
Implementations Source impl CudaEvent Source pub fn cu_event(&self) -> CUevent The underlying cu_event object.
Safety Do not destroy this value
Source pub fn context(&self) -> &Arc The context this was created in.
Source pub fn record(&self, stream: &CudaStream) -> Result<(), DriverError> Records the current amount of work in CudaStream into this event.
This does not affect any previous calls to CudaStream::wait()
If stream belongs to a different CudaContext, this will fail with sys::cudaError_enum::CUDA_ERROR_INVALID_CONTEXT.
See cuda docs
Source pub fn synchronize(&self) -> Result<(), DriverError> Will only block CPU thraed if sys::CUevent_flags::CU_EVENT_BLOCKING_SYNC was used to create this event.
Source pub fn elapsed_ms(&self, end: &Self) -> Result<f32, DriverError> The time between two events. self is the start event, and end is the end event. This is effectively end - self.
Source pub fn is_complete(&self) -> bool Returns true if all recorded work has been completed, false otherwise.
Trait Implementations Source impl Debug for CudaEvent Source fn fmt(&self, f: &mut Formatter<'_>) -> Result Formats the value using the given formatter. Read more Source impl Drop for CudaEvent Source fn drop(&mut self) Executes the destructor for this type. Read more Source impl Send for CudaEvent Source impl Sync for CudaEvent Auto Trait Implementations impl Freeze for CudaEvent impl RefUnwindSafe for CudaEvent impl Unpin for CudaEvent impl UnwindSafe for CudaEvent Blanket Implementations Source impl Any for T where T: 'static + ?Sized, Source fn type_id(&self) -> TypeId Gets the TypeId of self. Read more Source impl Borrow for T where T: ?Sized, Source fn borrow(&self) -> &T Immutably borrows from an owned value. Read more Source impl BorrowMut for T where T: ?Sized, Source fn borrow_mut(&mut self) -> &mut T Mutably borrows from an owned value. Read more Source impl From for T Source fn from(t: T) -> T Returns the argument unchanged.
Source impl<T, U> Into for T where U: From, Source fn into(self) -> U Calls U::from(self).
That is, this conversion is whatever the implementation of From for U chooses to do.
Source impl<T, U> TryFrom for T where U: Into, 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>::Error> Performs the conversion. Source impl<T, U> TryInto for T where U: TryFrom, Source type Error = <U as TryFrom>::Error The type returned in the event of a conversion error. Source fn try_into(self) -> Result<U, <U as TryFrom>::Error> Performs the conversion. Source impl<V, T> VZip for T where V: MultiLane,
pub struct CudaFunction { /* private fields */ } Wrapper around sys::CUfunction. Used by CudaStream::launch_builder to execute kernels.
Implementations Source impl CudaFunction Source pub fn occupancy_available_dynamic_smem_per_block( &self, num_blocks: u32, block_size: u32, ) -> Result<usize, DriverError> Source pub fn occupancy_max_active_blocks_per_multiprocessor( &self, block_size: u32, dynamic_smem_size: usize, flags: Option<CUoccupancy_flags_enum>, ) -> Result<u32, DriverError> Source pub fn occupancy_max_active_clusters( &self, config: LaunchConfig, stream: &CudaStream, ) -> Result<u32, DriverError> Source pub fn occupancy_max_potential_block_size( &self, block_size_to_dynamic_smem_size: extern "C" fn(block_size: c_int) -> usize, dynamic_smem_size: usize, block_size_limit: u32, flags: Option<CUoccupancy_flags_enum>, ) -> Result<(u32, u32), DriverError> Source pub fn occupancy_max_potential_cluster_size( &self, config: LaunchConfig, stream: &CudaStream, ) -> Result<u32, DriverError> Source pub fn set_attribute( &self, attribute: CUfunction_attribute_enum, value: i32, ) -> Result<(), DriverError> Set the value of a specific attribute of this CudaFunction.
Source pub fn set_function_cache_config( &self, attribute: CUfunc_cache_enum, ) -> Result<(), DriverError> Set the cache config of this CudaFunction.
Trait Implementations Source impl Clone for CudaFunction Source fn clone(&self) -> CudaFunction Returns a duplicate of the value. Read more 1.0.0 · Source fn clone_from(&mut self, source: &Self) Performs copy-assignment from source. Read more Source impl Debug for CudaFunction Source fn fmt(&self, f: &mut Formatter<'_>) -> Result Formats the value using the given formatter. Read more Source impl Send for CudaFunction Source impl Sync for CudaFunction Auto Trait Implementations impl Freeze for CudaFunction impl RefUnwindSafe for CudaFunction impl Unpin for CudaFunction impl UnwindSafe for CudaFunction Blanket Implementations Source impl Any for T where T: 'static + ?Sized, Source fn type_id(&self) -> TypeId Gets the TypeId of self. Read more Source impl Borrow for T where T: ?Sized, Source fn borrow(&self) -> &T Immutably borrows from an owned value. Read more Source impl BorrowMut for T where T: ?Sized, Source fn borrow_mut(&mut self) -> &mut T Mutably borrows from an owned value. Read more Source impl CloneToUninit for T where T: Clone, Source unsafe fn clone_to_uninit(&self, dest: *mut u8) 🔬This is a nightly-only experimental API. (clone_to_uninit) Performs copy-assignment from self to dest. Read more Source impl From for T Source fn from(t: T) -> T Returns the argument unchanged.
Source impl<T, U> Into for T where U: From, Source fn into(self) -> U Calls U::from(self).
That is, this conversion is whatever the implementation of From for U chooses to do.
Source impl ToOwned for T where T: Clone, Source type Owned = T The resulting type after obtaining ownership. Source fn to_owned(&self) -> T Creates owned data from borrowed data, usually by cloning. Read more Source fn clone_into(&self, target: &mut T) Uses borrowed data to replace owned data, usually by cloning. Read more Source impl<T, U> TryFrom for T where U: Into, 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>::Error> Performs the conversion. Source impl<T, U> TryInto for T where U: TryFrom, Source type Error = <U as TryFrom>::Error The type returned in the event of a conversion error. Source fn try_into(self) -> Result<U, <U as TryFrom>::Error> Performs the conversion. Source impl<V, T> VZip for T where V: MultiLane,
pub struct CudaGraph { /* private fields */ } Represents a replay-able Cuda Graph. Create with CudaStream::begin_capture() and CudaStream::end_capture().
Once created you can replay with CudaGraph::launch().
On Thread safety This object is NOT thread safe.
From official docs:
Graph objects (cudaGraph_t, CUgraph) are not internally synchronized and must not be accessed concurrently from multiple threads. API calls accessing the same graph object must be serialized externally.
Note that this includes APIs which may appear to be read-only, such as cudaGraphClone() (cuGraphClone()) and cudaGraphInstantiate() (cuGraphInstantiate()). No API or pair of APIs is guaranteed to be safe to call on the same graph object from two different threads without serialization.
https://docs.nvidia.com/cuda/cuda-driver-api/graphs-thread-safety.html#graphs-thread-safety
Implementations Source impl CudaGraph Source pub fn launch(&self) -> Result<(), DriverError> See cuda docs
Trait Implementations Source impl Drop for CudaGraph Source fn drop(&mut self) Executes the destructor for this type. Read more Auto Trait Implementations impl Freeze for CudaGraph impl RefUnwindSafe for CudaGraph impl !Send for CudaGraph impl !Sync for CudaGraph impl Unpin for CudaGraph impl UnwindSafe for CudaGraph Blanket Implementations Source impl Any for T where T: 'static + ?Sized, Source fn type_id(&self) -> TypeId Gets the TypeId of self. Read more Source impl Borrow for T where T: ?Sized, Source fn borrow(&self) -> &T Immutably borrows from an owned value. Read more Source impl BorrowMut for T where T: ?Sized, Source fn borrow_mut(&mut self) -> &mut T Mutably borrows from an owned value. Read more Source impl From for T Source fn from(t: T) -> T Returns the argument unchanged.
Source impl<T, U> Into for T where U: From, Source fn into(self) -> U Calls U::from(self).
That is, this conversion is whatever the implementation of From for U chooses to do.
Source impl<T, U> TryFrom for T where U: Into, 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>::Error> Performs the conversion. Source impl<T, U> TryInto for T where U: TryFrom, Source type Error = <U as TryFrom>::Error The type returned in the event of a conversion error. Source fn try_into(self) -> Result<U, <U as TryFrom>::Error> Performs the conversion. Source impl<V, T> VZip for T where V: MultiLane,
pub struct CudaModule { /* private fields */ } Wrapper around sys::CUmodule. Create with CudaContext::load_module().
Call CudaModule::load_function to load a CudaFunction.
Implementations Source impl CudaModule Source pub fn load_function( self: &Arc, fn_name: &str, ) -> Result<CudaFunction, DriverError> Loads a function from the loaded module with the given name.
Examples found in repository?
examples/05-device-repr.rs (line 38)
32fn main() -> Result<(), DriverError> {
33 let ctx = CudaContext::new(0)?;
34 let stream = ctx.default_stream();
35
36 let ptx = compile_ptx(PTX_SRC).unwrap();
37 let module = ctx.load_module(ptx)?;
38 let f = module.load_function("my_custom_kernel")?;
39
40 // try changing some of these values to see a device assert
41 let thing = MyCoolRustStruct {
42 a: 1.0,
43 b: 2.34,
44 c: 57,
45 d: 420,
46 };
47
48 let mut builder = stream.launch_builder(&f);
49 // since MyCoolRustStruct implements DeviceRepr, we can pass it to launch.
50 builder.arg(&thing);
51 unsafe { builder.launch(LaunchConfig::for_num_elems(1)) }?;
52
53 Ok(())
54}
More examples
Hide additional examples
examples/03-launch-kernel.rs (line 14)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 // You can load a function from a pre-compiled PTX like so:
11 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
12
13 // and then load a function from it:
14 let f = module.load_function("sin_kernel").unwrap();
15
16 let a_host = [1.0, 2.0, 3.0];
17
18 let a_dev = stream.memcpy_stod(&a_host)?;
19 let mut b_dev = a_dev.clone();
20
21 // we use a buidler pattern to launch kernels.
22 let n = 3i32;
23 let cfg = LaunchConfig::for_num_elems(n as u32);
24 let mut launch_args = stream.launch_builder(&f);
25 launch_args.arg(&mut b_dev);
26 launch_args.arg(&a_dev);
27 launch_args.arg(&n);
28 unsafe { launch_args.launch(cfg) }?;
29
30 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
31 let b_host = stream.memcpy_dtov(&b_dev)?;
32
33 println!("Found {b_host:?}");
34 println!("Expected {:?}", a_host.map(f32::sin));
35 assert_eq!(&a_host, a_host_2.as_slice());
36
37 Ok(())
38}
examples/matmul-kernel.rs (line 33)
22fn main() -> Result<(), DriverError> {
23 let start = std::time::Instant::now();
24
25 let ptx = compile_ptx(PTX_SRC).unwrap();
26 println!("Compilation succeeded in {:?}", start.elapsed());
27
28 let ctx = CudaContext::new(0)?;
29 let stream = ctx.default_stream();
30 println!("Built in {:?}", start.elapsed());
31
32 let module = ctx.load_module(ptx)?;
33 let f = module.load_function("matmul")?;
34 println!("Loaded in {:?}", start.elapsed());
35
36 let a_host = [1.0f32, 2.0, 3.0, 4.0];
37 let b_host = [1.0f32, 2.0, 3.0, 4.0];
38 let mut c_host = [0.0f32; 4];
39
40 let a_dev = stream.memcpy_stod(&a_host)?;
41 let b_dev = stream.memcpy_stod(&b_host)?;
42 let mut c_dev = stream.memcpy_stod(&c_host)?;
43
44 println!("Copied in {:?}", start.elapsed());
45
46 let mut builder = stream.launch_builder(&f);
47 builder.arg(&a_dev);
48 builder.arg(&b_dev);
49 builder.arg(&mut c_dev);
50 builder.arg(&2i32);
51 let cfg = LaunchConfig {
52 block_dim: (2, 2, 1),
53 grid_dim: (1, 1, 1),
54 shared_mem_bytes: 0,
55 };
56 unsafe { builder.launch(cfg) }?;
57
58 stream.memcpy_dtoh(&c_dev, &mut c_host)?;
59 println!("Found {:?} in {:?}", c_host, start.elapsed());
60 Ok(())
61}
examples/04-streams.rs (line 11)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
11 let f = module.load_function("sin_kernel")?;
12
13 let n = 3i32;
14 let a_host = [1.0, 2.0, 3.0];
15 let a_dev = stream.memcpy_stod(&a_host)?;
16 let mut b_dev = stream.alloc_zeros::(n as usize)?;
17
18 // we can safely create a second stream using [CudaStream::fork()].
19 // This synchronizes with the source stream, so
20 // the memcpy_vtod & alloc_zeros above will complete before
21 // work on this stream can start.
22 let stream2 = stream.fork()?;
23
24 // now we launch this work on the other stream
25 let mut builder = stream2.launch_builder(&f);
26 builder.arg(&mut b_dev); // NOTE: tells cudarc that we are mutating this.
27 builder.arg(&a_dev); // NOTE: tells cudarc that we are reading from this slice
28 builder.arg(&n);
29 unsafe { builder.launch(LaunchConfig::for_num_elems(n as u32)) }?;
30
31 // cudarc automatically manages multi stream synchronization,
32 // so even though we launched the above on a separate stream,
33 // doing this device to host transfer will still properly synchronize.
34 // a_dev doesn't need to synchronize at all since we specified it is just
35 // being read from.
36 // b_dev DOES need to be synchronized, because it was mutated on a different stream.
37 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
38 let b_host = stream.memcpy_dtov(&b_dev)?;
39
40 println!("Found {b_host:?}");
41 println!("Expected {:?}", a_host.map(f32::sin));
42 assert_eq!(&a_host, a_host_2.as_slice());
43
44 Ok(())
45}
examples/06-threading.rs (line 24)
12fn main() -> Result<(), DriverError> {
13 {
14 // Option 1: sharing ctx & module between threads
15 thread::scope(|s| {
16 let ptx = compile_ptx(KERNEL_SRC).unwrap();
17 let ctx = CudaContext::new(0)?;
18 let module = ctx.load_module(ptx)?;
19 for i in 0..10i32 {
20 let thread_ctx = ctx.clone();
21 let thread_module = module.clone();
22 s.spawn(move || {
23 let stream = thread_ctx.default_stream();
24 let f = thread_module.load_function("hello_world")?;
25 unsafe {
26 stream
27 .launch_builder(&f)
28 .arg(&i)
29 .launch(LaunchConfig::for_num_elems(1))
30 }
31 });
32 }
33 Ok(())
34 })?;
35 }
36
37 {
38 // Option 2: initializing different context in each
39 // Note that this will still schedule to the same stream since we are using the
40 // default stream here on the same device.
41 thread::scope(move |s| {
42 for i in 0..10i32 {
43 s.spawn(move || {
44 let ptx = compile_ptx(KERNEL_SRC).unwrap();
45 let ctx = CudaContext::new(0)?;
46 let module = ctx.load_module(ptx)?;
47 let stream = ctx.default_stream();
48 let f = module.load_function("hello_world")?;
49 unsafe {
50 stream
51 .launch_builder(&f)
52 .arg(&i)
53 .launch(LaunchConfig::for_num_elems(1))
54 }
55 });
56 }
57 Ok(())
58 })?;
59 }
60
61 Ok(())
62}
Trait Implementations
Source
impl Debug for CudaModule
Source
fn fmt(&self, f: &mut Formatter<'_>) -> Result
Formats the value using the given formatter. Read more
Source
impl Drop for CudaModule
Source
fn drop(&mut self)
Executes the destructor for this type. Read more
Source
impl Send for CudaModule
Source
impl Sync for CudaModule
Auto Trait Implementations
impl Freeze for CudaModule
impl RefUnwindSafe for CudaModule
impl Unpin for CudaModule
impl UnwindSafe for CudaModule
Blanket Implementations
Source
impl Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl Borrow for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl BorrowMut for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl From for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source impl<T, U> Into for T where U: From, Source fn into(self) -> U Calls U::from(self).
That is, this conversion is whatever the implementation of From for U chooses to do.
Source impl<T, U> TryFrom for T where U: Into, 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>::Error> Performs the conversion. Source impl<T, U> TryInto for T where U: TryFrom, Source type Error = <U as TryFrom>::Error The type returned in the event of a conversion error. Source fn try_into(self) -> Result<U, <U as TryFrom>::Error> Performs the conversion. Source impl<V, T> VZip for T where V: MultiLane,
pub struct CudaModule { /* private fields */ } Wrapper around sys::CUmodule. Create with CudaContext::load_module().
Call CudaModule::load_function to load a CudaFunction.
Implementations Source impl CudaModule Source pub fn load_function( self: &Arc, fn_name: &str, ) -> Result<CudaFunction, DriverError> Loads a function from the loaded module with the given name.
Examples found in repository?
examples/05-device-repr.rs (line 38)
32fn main() -> Result<(), DriverError> {
33 let ctx = CudaContext::new(0)?;
34 let stream = ctx.default_stream();
35
36 let ptx = compile_ptx(PTX_SRC).unwrap();
37 let module = ctx.load_module(ptx)?;
38 let f = module.load_function("my_custom_kernel")?;
39
40 // try changing some of these values to see a device assert
41 let thing = MyCoolRustStruct {
42 a: 1.0,
43 b: 2.34,
44 c: 57,
45 d: 420,
46 };
47
48 let mut builder = stream.launch_builder(&f);
49 // since MyCoolRustStruct implements DeviceRepr, we can pass it to launch.
50 builder.arg(&thing);
51 unsafe { builder.launch(LaunchConfig::for_num_elems(1)) }?;
52
53 Ok(())
54}
More examples
Hide additional examples
examples/03-launch-kernel.rs (line 14)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 // You can load a function from a pre-compiled PTX like so:
11 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
12
13 // and then load a function from it:
14 let f = module.load_function("sin_kernel").unwrap();
15
16 let a_host = [1.0, 2.0, 3.0];
17
18 let a_dev = stream.memcpy_stod(&a_host)?;
19 let mut b_dev = a_dev.clone();
20
21 // we use a buidler pattern to launch kernels.
22 let n = 3i32;
23 let cfg = LaunchConfig::for_num_elems(n as u32);
24 let mut launch_args = stream.launch_builder(&f);
25 launch_args.arg(&mut b_dev);
26 launch_args.arg(&a_dev);
27 launch_args.arg(&n);
28 unsafe { launch_args.launch(cfg) }?;
29
30 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
31 let b_host = stream.memcpy_dtov(&b_dev)?;
32
33 println!("Found {b_host:?}");
34 println!("Expected {:?}", a_host.map(f32::sin));
35 assert_eq!(&a_host, a_host_2.as_slice());
36
37 Ok(())
38}
examples/matmul-kernel.rs (line 33)
22fn main() -> Result<(), DriverError> {
23 let start = std::time::Instant::now();
24
25 let ptx = compile_ptx(PTX_SRC).unwrap();
26 println!("Compilation succeeded in {:?}", start.elapsed());
27
28 let ctx = CudaContext::new(0)?;
29 let stream = ctx.default_stream();
30 println!("Built in {:?}", start.elapsed());
31
32 let module = ctx.load_module(ptx)?;
33 let f = module.load_function("matmul")?;
34 println!("Loaded in {:?}", start.elapsed());
35
36 let a_host = [1.0f32, 2.0, 3.0, 4.0];
37 let b_host = [1.0f32, 2.0, 3.0, 4.0];
38 let mut c_host = [0.0f32; 4];
39
40 let a_dev = stream.memcpy_stod(&a_host)?;
41 let b_dev = stream.memcpy_stod(&b_host)?;
42 let mut c_dev = stream.memcpy_stod(&c_host)?;
43
44 println!("Copied in {:?}", start.elapsed());
45
46 let mut builder = stream.launch_builder(&f);
47 builder.arg(&a_dev);
48 builder.arg(&b_dev);
49 builder.arg(&mut c_dev);
50 builder.arg(&2i32);
51 let cfg = LaunchConfig {
52 block_dim: (2, 2, 1),
53 grid_dim: (1, 1, 1),
54 shared_mem_bytes: 0,
55 };
56 unsafe { builder.launch(cfg) }?;
57
58 stream.memcpy_dtoh(&c_dev, &mut c_host)?;
59 println!("Found {:?} in {:?}", c_host, start.elapsed());
60 Ok(())
61}
examples/04-streams.rs (line 11)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
11 let f = module.load_function("sin_kernel")?;
12
13 let n = 3i32;
14 let a_host = [1.0, 2.0, 3.0];
15 let a_dev = stream.memcpy_stod(&a_host)?;
16 let mut b_dev = stream.alloc_zeros::(n as usize)?;
17
18 // we can safely create a second stream using [CudaStream::fork()].
19 // This synchronizes with the source stream, so
20 // the memcpy_vtod & alloc_zeros above will complete before
21 // work on this stream can start.
22 let stream2 = stream.fork()?;
23
24 // now we launch this work on the other stream
25 let mut builder = stream2.launch_builder(&f);
26 builder.arg(&mut b_dev); // NOTE: tells cudarc that we are mutating this.
27 builder.arg(&a_dev); // NOTE: tells cudarc that we are reading from this slice
28 builder.arg(&n);
29 unsafe { builder.launch(LaunchConfig::for_num_elems(n as u32)) }?;
30
31 // cudarc automatically manages multi stream synchronization,
32 // so even though we launched the above on a separate stream,
33 // doing this device to host transfer will still properly synchronize.
34 // a_dev doesn't need to synchronize at all since we specified it is just
35 // being read from.
36 // b_dev DOES need to be synchronized, because it was mutated on a different stream.
37 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
38 let b_host = stream.memcpy_dtov(&b_dev)?;
39
40 println!("Found {b_host:?}");
41 println!("Expected {:?}", a_host.map(f32::sin));
42 assert_eq!(&a_host, a_host_2.as_slice());
43
44 Ok(())
45}
examples/06-threading.rs (line 24)
12fn main() -> Result<(), DriverError> {
13 {
14 // Option 1: sharing ctx & module between threads
15 thread::scope(|s| {
16 let ptx = compile_ptx(KERNEL_SRC).unwrap();
17 let ctx = CudaContext::new(0)?;
18 let module = ctx.load_module(ptx)?;
19 for i in 0..10i32 {
20 let thread_ctx = ctx.clone();
21 let thread_module = module.clone();
22 s.spawn(move || {
23 let stream = thread_ctx.default_stream();
24 let f = thread_module.load_function("hello_world")?;
25 unsafe {
26 stream
27 .launch_builder(&f)
28 .arg(&i)
29 .launch(LaunchConfig::for_num_elems(1))
30 }
31 });
32 }
33 Ok(())
34 })?;
35 }
36
37 {
38 // Option 2: initializing different context in each
39 // Note that this will still schedule to the same stream since we are using the
40 // default stream here on the same device.
41 thread::scope(move |s| {
42 for i in 0..10i32 {
43 s.spawn(move || {
44 let ptx = compile_ptx(KERNEL_SRC).unwrap();
45 let ctx = CudaContext::new(0)?;
46 let module = ctx.load_module(ptx)?;
47 let stream = ctx.default_stream();
48 let f = module.load_function("hello_world")?;
49 unsafe {
50 stream
51 .launch_builder(&f)
52 .arg(&i)
53 .launch(LaunchConfig::for_num_elems(1))
54 }
55 });
56 }
57 Ok(())
58 })?;
59 }
60
61 Ok(())
62}
Trait Implementations
Source
impl Debug for CudaModule
Source
fn fmt(&self, f: &mut Formatter<'_>) -> Result
Formats the value using the given formatter. Read more
Source
impl Drop for CudaModule
Source
fn drop(&mut self)
Executes the destructor for this type. Read more
Source
impl Send for CudaModule
Source
impl Sync for CudaModule
Auto Trait Implementations
impl Freeze for CudaModule
impl RefUnwindSafe for CudaModule
impl Unpin for CudaModule
impl UnwindSafe for CudaModule
Blanket Implementations
Source
impl Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl Borrow for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl BorrowMut for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl From for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source impl<T, U> Into for T where U: From, Source fn into(self) -> U Calls U::from(self).
That is, this conversion is whatever the implementation of From for U chooses to do.
Source impl<T, U> TryFrom for T where U: Into, 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>::Error> Performs the conversion. Source impl<T, U> TryInto for T where U: TryFrom, Source type Error = <U as TryFrom>::Error The type returned in the event of a conversion error. Source fn try_into(self) -> Result<U, <U as TryFrom>::Error> Performs the conversion. Source impl<V, T> VZip for T where V: MultiLane,
pub struct CudaSlice { /* private fields */ } Vec on a cuda device. You can allocate and modify this with CudaStream.
This object is thread safe.
Implementations Source impl CudaSlice Source pub fn len(&self) -> usize The number of elements of T in this object.
Examples found in repository? examples/02-copy.rs (line 14) 3fn main() -> Result<(), DriverError> { 4 let ctx = CudaContext::new(0)?; 5 let stream = ctx.default_stream(); 6 7 let a: CudaSlice = stream.alloc_zeros::(10)?; 8 let mut b = stream.alloc_zeros::(10)?; 9 10 // you can do device to device copies of course 11 stream.memcpy_dtod(&a, &mut b)?; 12 13 // but also host to device copys with already allocated buffers 14 stream.memcpy_htod(&vec![2.0; b.len()], &mut b)?; 15 // you can use any type of slice 16 stream.memcpy_htod(&[3.0; 10], &mut b)?; 17 18 // you can transfer back using memcpy_dtov 19 let mut a_host: Vec = stream.memcpy_dtov(&a)?; 20 assert_eq!(a_host, [0.0; 10]); 21 22 let b_host = stream.memcpy_dtov(&b)?; 23 assert_eq!(b_host, [3.0; 10]); 24 25 // or transfer into a pre allocated slice 26 stream.memcpy_dtoh(&b, &mut a_host)?; 27 assert_eq!(a_host, b_host); 28 29 Ok(()) 30} Source pub fn num_bytes(&self) -> usize The number of bytes in this object.
Source pub fn is_empty(&self) -> bool True if there are no elements in the object.
Source pub fn ordinal(&self) -> usize The device ordinal this belongs to
Source pub fn context(&self) -> &Arc The context this belongs to
Source pub fn stream(&self) -> &Arc The stream this object was allocated on and later will be dropped on.
Source impl<T: DeviceRepr> CudaSlice Source pub fn try_clone(&self) -> Result<Self, DriverError> Allocates copy of self and schedules a device to device copy of memory.
Source impl CudaSlice Source pub fn as_view(&self) -> CudaView<', T> Source impl CudaSlice Source pub fn as_view_mut(&mut self) -> CudaViewMut<', T> Source impl CudaSlice Source pub fn slice(&self, bounds: impl RangeBounds) -> CudaView<'_, T> Creates a CudaView at the specified offset from the start of self.
Panics if range.start >= self.len.
Example let mut slice = stream.alloc_zeros::(100).unwrap(); let mut view = slice.slice(0..50); do_something(&view); Like a normal slice, borrow checking prevents the underlying CudaSlice from being dropped.
ⓘ let view = { let mut slice = stream.alloc_zeros::(100).unwrap(); // cannot return view, since it borrows from slice slice.slice(0..50) }; do_something(&view); Source pub fn try_slice( &self, bounds: impl RangeBounds, ) -> Option<CudaView<'_, T>> Fallible version of CudaSlice::slice().
Source pub fn slice_mut( &mut self, bounds: impl RangeBounds, ) -> CudaViewMut<'_, T> Creates a CudaViewMut at the specified offset from the start of self.
Panics if range and 0...self.len() are not overlapping.
Example let mut slice = stream.alloc_zeros::(100).unwrap(); let mut view = slice.slice_mut(0..50); do_something(&mut view); Like a normal mutable slice, borrow checking prevents the underlying CudaSlice from being dropped.
ⓘ let mut view = { let mut slice = stream.alloc_zeros::(100).unwrap(); // cannot return view, since it borrows from slice slice.slice_mut(0..50) }; do_something(&mut view); Like with normal mutable slices, one cannot mutably slice twice into the same CudaSlice:
ⓘ let mut slice = stream.alloc_zeros::(100).unwrap(); let mut view1 = slice.slice_mut(0..50); // cannot borrow twice from slice let mut view2 = slice.slice_mut(50..100); do_something(view1, view2); If you need non-overlapping mutable views into a CudaSlice, you can use CudaSlice::split_at_mut().
Source pub fn try_slice_mut( &mut self, bounds: impl RangeBounds, ) -> Option<CudaViewMut<'_, T>> Fallible version of CudaSlice::slice_mut
Source
pub unsafe fn transmute(&self, len: usize) -> Option<CudaView<'_, S>>
Reinterprets the slice of memory into a different type. len is the number of elements of the new type S that are expected. If not enough bytes are allocated in self for the view, then this returns None.
Safety This is unsafe because not the memory for the view may not be a valid interpretation for the type S.
Source
pub unsafe fn transmute_mut(
&mut self,
len: usize,
) -> Option<CudaViewMut<'_, S>>
Reinterprets the slice of memory into a different type. len is the number of elements of the new type S that are expected. If not enough bytes are allocated in self for the view, then this returns None.
Safety This is unsafe because not the memory for the view may not be a valid interpretation for the type S.
Source pub fn split_at(&self, mid: usize) -> (CudaView<', T>, CudaView<', T>) Source pub fn try_split_at( &self, mid: usize, ) -> Option<(CudaView<', T>, CudaView<', T>)> Fallible version of CudaSlice::split_at. Returns None if mid > self.len.
Source pub fn split_at_mut( &mut self, mid: usize, ) -> (CudaViewMut<', T>, CudaViewMut<', T>) Splits the CudaSlice into two at the given index, returning two CudaViewMut for the two halves.
Panics if mid > self.len.
This method can be used to create non-overlapping mutable views into a CudaSlice.
let mut slice = stream.alloc_zeros::(100).unwrap(); // split the slice into two non-overlapping, mutable views let (mut view1, mut view2) = slice.split_at_mut(50); do_something(view1, view2); Source pub fn try_split_at_mut( &mut self, mid: usize, ) -> Option<(CudaViewMut<', T>, CudaViewMut<', T>)> Fallible version of CudaSlice::split_at_mut.
Returns None if mid > self.len.
Source impl CudaSlice Source pub fn leak(self) -> CUdeviceptr Takes ownership of the underlying sys::CUdeviceptr. It is up to the owner to free this value.
Drops the underlying host_buf if there is one.
Trait Implementations Source impl<T: DeviceRepr> Clone for CudaSlice Source fn clone(&self) -> Self Returns a duplicate of the value. Read more 1.0.0 · Source fn clone_from(&mut self, source: &Self) Performs copy-assignment from source. Read more Source impl<T: Debug> Debug for CudaSlice Source fn fmt(&self, f: &mut Formatter<'_>) -> Result Formats the value using the given formatter. Read more Source impl DevicePtr for CudaSlice Source fn device_ptr<'a>( &'a self, stream: &'a CudaStream, ) -> (CUdeviceptr, SyncOnDrop<'a>) Retrieve the device pointer with the intent to read the device memory associated with it. Read more Source impl DevicePtrMut for CudaSlice Source fn device_ptr_mut<'a>( &'a mut self, stream: &'a CudaStream, ) -> (CUdeviceptr, SyncOnDrop<'a>) Retrieve the device pointer with the intent to modify the device memory associated with it. Read more Source impl DeviceSlice for CudaSlice Source fn len(&self) -> usize Source fn stream(&self) -> &Arc Source fn num_bytes(&self) -> usize Source fn is_empty(&self) -> bool Source impl Drop for CudaSlice Source fn drop(&mut self) Executes the destructor for this type. Read more Source impl<'a, 'b: 'a, T> PushKernelArg<&'b CudaSlice> for LaunchArgs<'a> Source fn arg(&mut self, arg: &'b CudaSlice) -> &mut Self Source impl<'a, 'b: 'a, T> PushKernelArg<&'b mut CudaSlice> for LaunchArgs<'a> Source fn arg(&mut self, arg: &'b mut CudaSlice) -> &mut Self Source impl<T: Clone + Default + DeviceRepr> TryFrom<CudaSlice> for Vec Source type Error = DriverError The type returned in the event of a conversion error. Source fn try_from(value: CudaSlice) -> Result<Self, Self::Error> Performs the conversion. Source impl Send for CudaSlice Source impl Sync for CudaSlice Auto Trait Implementations impl Freeze for CudaSlice impl RefUnwindSafe for CudaSlice where T: RefUnwindSafe, impl Unpin for CudaSlice impl UnwindSafe for CudaSlice where T: RefUnwindSafe, Blanket Implementations Source impl Any for T where T: 'static + ?Sized, Source fn type_id(&self) -> TypeId Gets the TypeId of self. Read more Source impl Borrow for T where T: ?Sized, Source fn borrow(&self) -> &T Immutably borrows from an owned value. Read more Source impl BorrowMut for T where T: ?Sized, Source fn borrow_mut(&mut self) -> &mut T Mutably borrows from an owned value. Read more Source impl CloneToUninit for T where T: Clone, Source unsafe fn clone_to_uninit(&self, dest: *mut u8) 🔬This is a nightly-only experimental API. (clone_to_uninit) Performs copy-assignment from self to dest. Read more Source impl From for T Source fn from(t: T) -> T Returns the argument unchanged.
Source impl<T, U> Into for T where U: From, Source fn into(self) -> U Calls U::from(self).
That is, this conversion is whatever the implementation of From for U chooses to do.
Source impl ToOwned for T where T: Clone, Source type Owned = T The resulting type after obtaining ownership. Source fn to_owned(&self) -> T Creates owned data from borrowed data, usually by cloning. Read more Source fn clone_into(&self, target: &mut T) Uses borrowed data to replace owned data, usually by cloning. Read more Source impl<T, U> TryFrom for T where U: Into, 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>::Error> Performs the conversion. Source impl<T, U> TryInto for T where U: TryFrom, Source type Error = <U as TryFrom>::Error The type returned in the event of a conversion error. Source fn try_into(self) -> Result<U, <U as TryFrom>::Error> Performs the conversion. Source impl<V, T> VZip for T where V: MultiLane,
pub struct CudaStream { /* private fields */ } A wrapper around sys::CUstream that you can schedule work on.
Create with CudaContext::new_stream(), CudaContext::default_stream(), or CudaStream::fork(). Work done on this is asynchronous with respect to the host.
See CUDA C/C++ Streams and Concurrency See 3. Stream synchronization behavior See 6.6. Event Management See Out-of-order execution See Dependence analysis
Implementations Source impl CudaStream Source pub fn memcpy_ftod<'a, T: DeviceRepr, Dst: DevicePtrMut>( self: &Arc, fh: &'a FileHandle, file_offset: i64, dst: &mut Dst, ) -> Result<AsyncFileRead<'a>, CufileError> Copy memory from a file into a destination buffer on the device.
The return value of this is initialized with 0, and after the operation successfully finishes on the stream, it will contain a value other than 0. See the docs for possible values.
Wrapper around cuFileReadAsync
See FileHandle::sync_read() for synchronous version.
Source pub fn memcpy_dtof<'a, T: DeviceRepr, Src: DevicePtr>( self: &Arc, src: &Src, fh: &'a mut FileHandle, file_offset: i64, ) -> Result<AsyncFileWrite<'a>, CufileError> Copy memory from a device buffer to a file.
The return value of this is initialized with 0, and after the operation successfully finishes on the stream, it will contain a value other than 0. See the docs for possible values.
Wrapper around cuFileWriteAsync
See FileHandle::sync_write() for synchronous version.
Source impl CudaStream Source pub fn fork(&self) -> Result<Arc, DriverError> Create’s a new stream and then makes the new stream wait on self
Examples found in repository?
examples/04-streams.rs (line 22)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
11 let f = module.load_function("sin_kernel")?;
12
13 let n = 3i32;
14 let a_host = [1.0, 2.0, 3.0];
15 let a_dev = stream.memcpy_stod(&a_host)?;
16 let mut b_dev = stream.alloc_zeros::(n as usize)?;
17
18 // we can safely create a second stream using [CudaStream::fork()].
19 // This synchronizes with the source stream, so
20 // the memcpy_vtod & alloc_zeros above will complete before
21 // work on this stream can start.
22 let stream2 = stream.fork()?;
23
24 // now we launch this work on the other stream
25 let mut builder = stream2.launch_builder(&f);
26 builder.arg(&mut b_dev); // NOTE: tells cudarc that we are mutating this.
27 builder.arg(&a_dev); // NOTE: tells cudarc that we are reading from this slice
28 builder.arg(&n);
29 unsafe { builder.launch(LaunchConfig::for_num_elems(n as u32)) }?;
30
31 // cudarc automatically manages multi stream synchronization,
32 // so even though we launched the above on a separate stream,
33 // doing this device to host transfer will still properly synchronize.
34 // a_dev doesn't need to synchronize at all since we specified it is just
35 // being read from.
36 // b_dev DOES need to be synchronized, because it was mutated on a different stream.
37 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
38 let b_host = stream.memcpy_dtov(&b_dev)?;
39
40 println!("Found {b_host:?}");
41 println!("Expected {:?}", a_host.map(f32::sin));
42 assert_eq!(&a_host, a_host_2.as_slice());
43
44 Ok(())
45}
Source
pub fn cu_stream(&self) -> CUstream
The underlying cuda stream object
Safety Do not destroy this value.
Source pub fn context(&self) -> &Arc The context the stream belongs to.
Source pub fn synchronize(&self) -> Result<(), DriverError> Will only block CPU if you call CudaContext::set_flags() with sys::CUctx_flags::CU_CTX_SCHED_BLOCKING_SYNC.
See cuda docs
Source pub fn record_event( &self, flags: Option<CUevent_flags>, ) -> Result<CudaEvent, DriverError> Creates a new CudaEvent and records the current work in the stream to the event.
Source pub fn wait(&self, event: &CudaEvent) -> Result<(), DriverError> Waits for the work recorded in CudaEvent to be completed.
You can record new work in event after calling this method without affecting this call.
See cuda docs
Source pub fn join(&self, other: &CudaStream) -> Result<(), DriverError> Ensures this stream waits for the current workload in other to complete. This is shorthand for self.wait(other.record_event())
Source impl CudaStream Source pub fn null(self: &Arc) -> Result<CudaSlice, DriverError> Allocates an empty CudaSlice with 0 length.
Source pub unsafe fn alloc<T: DeviceRepr>( self: &Arc, len: usize, ) -> Result<CudaSlice, DriverError> Allocates a CudaSlice with len elements of type T.
Safety This is unsafe because the memory is unset.
Examples found in repository? examples/01-allocate.rs (line 8) 3fn main() -> Result<(), DriverError> { 4 let ctx = CudaContext::new(0)?; 5 let stream = ctx.default_stream(); 6 7 // unsafe initialization of unset memory 8 let _: CudaSlice = unsafe { stream.alloc::(10) }?; 9 10 // this will have memory initialized as 0 11 let _: CudaSlice = stream.alloc_zeros::(10)?; 12 13 // initialize with slices! 14 let _: CudaSlice = stream.memcpy_stod(&[0; 10])?; 15 let _: CudaSlice = stream.memcpy_stod(&[1, 2, 3])?; 16 17 Ok(()) 18} Source pub fn alloc_zeros<T: DeviceRepr + ValidAsZeroBits>( self: &Arc, len: usize, ) -> Result<CudaSlice, DriverError> Allocates a CudaSlice with len elements of type T. All values are zero’d out.
Examples found in repository?
examples/01-allocate.rs (line 11)
3fn main() -> Result<(), DriverError> {
4 let ctx = CudaContext::new(0)?;
5 let stream = ctx.default_stream();
6
7 // unsafe initialization of unset memory
8 let _: CudaSlice = unsafe { stream.alloc::(10) }?;
9
10 // this will have memory initialized as 0
11 let _: CudaSlice = stream.alloc_zeros::(10)?;
12
13 // initialize with slices!
14 let _: CudaSlice = stream.memcpy_stod(&[0; 10])?;
15 let _: CudaSlice = stream.memcpy_stod(&[1, 2, 3])?;
16
17 Ok(())
18}
More examples
Hide additional examples
examples/cufile-copy.rs (line 21)
2fn main() -> Result<(), Box> {
3 use std::fs;
4
5 use cudarc::{cufile::safe::Cufile, driver::CudaContext};
6
7 const N: usize = 100000;
8 let data: Vec = (0..N).flat_map(|x| (x as f32).to_le_bytes()).collect();
9 let data_sz = data.len();
10 let src_file = "/tmp/cufile_test.bin";
11 fs::write(src_file, &data)?;
12
13 let cufile = Cufile::new()?;
14 println!("{:?}", cufile.get_properties()?);
15
16 let file = fs::File::open(src_file)?;
17 let handle = cufile.register(file)?;
18
19 let ctx = CudaContext::new(0)?;
20 let stream = ctx.default_stream();
21 let mut buf = stream.alloc_zeros::(data_sz)?;
22
23 handle.sync_read(0, &mut buf)?;
24
25 let verify_dst = stream.memcpy_dtov(&buf)?;
26 assert_eq!(verify_dst, data);
27
28 Ok(())
29}
examples/02-copy.rs (line 7)
3fn main() -> Result<(), DriverError> {
4 let ctx = CudaContext::new(0)?;
5 let stream = ctx.default_stream();
6
7 let a: CudaSlice = stream.alloc_zeros::(10)?;
8 let mut b = stream.alloc_zeros::(10)?;
9
10 // you can do device to device copies of course
11 stream.memcpy_dtod(&a, &mut b)?;
12
13 // but also host to device copys with already allocated buffers
14 stream.memcpy_htod(&vec![2.0; b.len()], &mut b)?;
15 // you can use any type of slice
16 stream.memcpy_htod(&[3.0; 10], &mut b)?;
17
18 // you can transfer back using memcpy_dtov
19 let mut a_host: Vec = stream.memcpy_dtov(&a)?;
20 assert_eq!(a_host, [0.0; 10]);
21
22 let b_host = stream.memcpy_dtov(&b)?;
23 assert_eq!(b_host, [3.0; 10]);
24
25 // or transfer into a pre allocated slice
26 stream.memcpy_dtoh(&b, &mut a_host)?;
27 assert_eq!(a_host, b_host);
28
29 Ok(())
30}
examples/04-streams.rs (line 16)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
11 let f = module.load_function("sin_kernel")?;
12
13 let n = 3i32;
14 let a_host = [1.0, 2.0, 3.0];
15 let a_dev = stream.memcpy_stod(&a_host)?;
16 let mut b_dev = stream.alloc_zeros::(n as usize)?;
17
18 // we can safely create a second stream using [CudaStream::fork()].
19 // This synchronizes with the source stream, so
20 // the memcpy_vtod & alloc_zeros above will complete before
21 // work on this stream can start.
22 let stream2 = stream.fork()?;
23
24 // now we launch this work on the other stream
25 let mut builder = stream2.launch_builder(&f);
26 builder.arg(&mut b_dev); // NOTE: tells cudarc that we are mutating this.
27 builder.arg(&a_dev); // NOTE: tells cudarc that we are reading from this slice
28 builder.arg(&n);
29 unsafe { builder.launch(LaunchConfig::for_num_elems(n as u32)) }?;
30
31 // cudarc automatically manages multi stream synchronization,
32 // so even though we launched the above on a separate stream,
33 // doing this device to host transfer will still properly synchronize.
34 // a_dev doesn't need to synchronize at all since we specified it is just
35 // being read from.
36 // b_dev DOES need to be synchronized, because it was mutated on a different stream.
37 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
38 let b_host = stream.memcpy_dtov(&b_dev)?;
39
40 println!("Found {b_host:?}");
41 println!("Expected {:?}", a_host.map(f32::sin));
42 assert_eq!(&a_host, a_host_2.as_slice());
43
44 Ok(())
45}
Source
pub fn memset_zeros<T: DeviceRepr + ValidAsZeroBits, Dst: DevicePtrMut>(
self: &Arc,
dst: &mut Dst,
) -> Result<(), DriverError>
Set’s all the memory in dst to 0. dst can be a CudaSlice or CudaViewMut
Source pub fn memcpy_stod<T: DeviceRepr, Src: HostSlice + ?Sized>( self: &Arc, src: &Src, ) -> Result<CudaSlice, DriverError> Copy a [T]/Vec/PinnedHostSlice to a new CudaSlice.
Examples found in repository?
examples/01-allocate.rs (line 14)
3fn main() -> Result<(), DriverError> {
4 let ctx = CudaContext::new(0)?;
5 let stream = ctx.default_stream();
6
7 // unsafe initialization of unset memory
8 let _: CudaSlice = unsafe { stream.alloc::(10) }?;
9
10 // this will have memory initialized as 0
11 let _: CudaSlice = stream.alloc_zeros::(10)?;
12
13 // initialize with slices!
14 let _: CudaSlice = stream.memcpy_stod(&[0; 10])?;
15 let _: CudaSlice = stream.memcpy_stod(&[1, 2, 3])?;
16
17 Ok(())
18}
More examples
Hide additional examples
examples/03-launch-kernel.rs (line 18)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 // You can load a function from a pre-compiled PTX like so:
11 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
12
13 // and then load a function from it:
14 let f = module.load_function("sin_kernel").unwrap();
15
16 let a_host = [1.0, 2.0, 3.0];
17
18 let a_dev = stream.memcpy_stod(&a_host)?;
19 let mut b_dev = a_dev.clone();
20
21 // we use a buidler pattern to launch kernels.
22 let n = 3i32;
23 let cfg = LaunchConfig::for_num_elems(n as u32);
24 let mut launch_args = stream.launch_builder(&f);
25 launch_args.arg(&mut b_dev);
26 launch_args.arg(&a_dev);
27 launch_args.arg(&n);
28 unsafe { launch_args.launch(cfg) }?;
29
30 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
31 let b_host = stream.memcpy_dtov(&b_dev)?;
32
33 println!("Found {b_host:?}");
34 println!("Expected {:?}", a_host.map(f32::sin));
35 assert_eq!(&a_host, a_host_2.as_slice());
36
37 Ok(())
38}
examples/matmul-kernel.rs (line 40)
22fn main() -> Result<(), DriverError> {
23 let start = std::time::Instant::now();
24
25 let ptx = compile_ptx(PTX_SRC).unwrap();
26 println!("Compilation succeeded in {:?}", start.elapsed());
27
28 let ctx = CudaContext::new(0)?;
29 let stream = ctx.default_stream();
30 println!("Built in {:?}", start.elapsed());
31
32 let module = ctx.load_module(ptx)?;
33 let f = module.load_function("matmul")?;
34 println!("Loaded in {:?}", start.elapsed());
35
36 let a_host = [1.0f32, 2.0, 3.0, 4.0];
37 let b_host = [1.0f32, 2.0, 3.0, 4.0];
38 let mut c_host = [0.0f32; 4];
39
40 let a_dev = stream.memcpy_stod(&a_host)?;
41 let b_dev = stream.memcpy_stod(&b_host)?;
42 let mut c_dev = stream.memcpy_stod(&c_host)?;
43
44 println!("Copied in {:?}", start.elapsed());
45
46 let mut builder = stream.launch_builder(&f);
47 builder.arg(&a_dev);
48 builder.arg(&b_dev);
49 builder.arg(&mut c_dev);
50 builder.arg(&2i32);
51 let cfg = LaunchConfig {
52 block_dim: (2, 2, 1),
53 grid_dim: (1, 1, 1),
54 shared_mem_bytes: 0,
55 };
56 unsafe { builder.launch(cfg) }?;
57
58 stream.memcpy_dtoh(&c_dev, &mut c_host)?;
59 println!("Found {:?} in {:?}", c_host, start.elapsed());
60 Ok(())
61}
examples/04-streams.rs (line 15)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
11 let f = module.load_function("sin_kernel")?;
12
13 let n = 3i32;
14 let a_host = [1.0, 2.0, 3.0];
15 let a_dev = stream.memcpy_stod(&a_host)?;
16 let mut b_dev = stream.alloc_zeros::(n as usize)?;
17
18 // we can safely create a second stream using [CudaStream::fork()].
19 // This synchronizes with the source stream, so
20 // the memcpy_vtod & alloc_zeros above will complete before
21 // work on this stream can start.
22 let stream2 = stream.fork()?;
23
24 // now we launch this work on the other stream
25 let mut builder = stream2.launch_builder(&f);
26 builder.arg(&mut b_dev); // NOTE: tells cudarc that we are mutating this.
27 builder.arg(&a_dev); // NOTE: tells cudarc that we are reading from this slice
28 builder.arg(&n);
29 unsafe { builder.launch(LaunchConfig::for_num_elems(n as u32)) }?;
30
31 // cudarc automatically manages multi stream synchronization,
32 // so even though we launched the above on a separate stream,
33 // doing this device to host transfer will still properly synchronize.
34 // a_dev doesn't need to synchronize at all since we specified it is just
35 // being read from.
36 // b_dev DOES need to be synchronized, because it was mutated on a different stream.
37 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
38 let b_host = stream.memcpy_dtov(&b_dev)?;
39
40 println!("Found {b_host:?}");
41 println!("Expected {:?}", a_host.map(f32::sin));
42 assert_eq!(&a_host, a_host_2.as_slice());
43
44 Ok(())
45}
Source
pub fn memcpy_htod<T: DeviceRepr, Src: HostSlice + ?Sized, Dst: DevicePtrMut>(
self: &Arc,
src: &Src,
dst: &mut Dst,
) -> Result<(), DriverError>
Copy a [T]/Vec/PinnedHostSlice into an existing CudaSlice/CudaViewMut.
Examples found in repository? examples/02-copy.rs (line 14) 3fn main() -> Result<(), DriverError> { 4 let ctx = CudaContext::new(0)?; 5 let stream = ctx.default_stream(); 6 7 let a: CudaSlice = stream.alloc_zeros::(10)?; 8 let mut b = stream.alloc_zeros::(10)?; 9 10 // you can do device to device copies of course 11 stream.memcpy_dtod(&a, &mut b)?; 12 13 // but also host to device copys with already allocated buffers 14 stream.memcpy_htod(&vec![2.0; b.len()], &mut b)?; 15 // you can use any type of slice 16 stream.memcpy_htod(&[3.0; 10], &mut b)?; 17 18 // you can transfer back using memcpy_dtov 19 let mut a_host: Vec = stream.memcpy_dtov(&a)?; 20 assert_eq!(a_host, [0.0; 10]); 21 22 let b_host = stream.memcpy_dtov(&b)?; 23 assert_eq!(b_host, [3.0; 10]); 24 25 // or transfer into a pre allocated slice 26 stream.memcpy_dtoh(&b, &mut a_host)?; 27 assert_eq!(a_host, b_host); 28 29 Ok(()) 30} Source pub fn memcpy_dtov<T: DeviceRepr, Src: DevicePtr>( self: &Arc, src: &Src, ) -> Result<Vec, DriverError> Copy a CudaSlice/CudaView to a new Vec.
Examples found in repository?
examples/cufile-copy.rs (line 25)
2fn main() -> Result<(), Box> {
3 use std::fs;
4
5 use cudarc::{cufile::safe::Cufile, driver::CudaContext};
6
7 const N: usize = 100000;
8 let data: Vec = (0..N).flat_map(|x| (x as f32).to_le_bytes()).collect();
9 let data_sz = data.len();
10 let src_file = "/tmp/cufile_test.bin";
11 fs::write(src_file, &data)?;
12
13 let cufile = Cufile::new()?;
14 println!("{:?}", cufile.get_properties()?);
15
16 let file = fs::File::open(src_file)?;
17 let handle = cufile.register(file)?;
18
19 let ctx = CudaContext::new(0)?;
20 let stream = ctx.default_stream();
21 let mut buf = stream.alloc_zeros::(data_sz)?;
22
23 handle.sync_read(0, &mut buf)?;
24
25 let verify_dst = stream.memcpy_dtov(&buf)?;
26 assert_eq!(verify_dst, data);
27
28 Ok(())
29}
More examples
Hide additional examples
examples/02-copy.rs (line 19)
3fn main() -> Result<(), DriverError> {
4 let ctx = CudaContext::new(0)?;
5 let stream = ctx.default_stream();
6
7 let a: CudaSlice = stream.alloc_zeros::(10)?;
8 let mut b = stream.alloc_zeros::(10)?;
9
10 // you can do device to device copies of course
11 stream.memcpy_dtod(&a, &mut b)?;
12
13 // but also host to device copys with already allocated buffers
14 stream.memcpy_htod(&vec![2.0; b.len()], &mut b)?;
15 // you can use any type of slice
16 stream.memcpy_htod(&[3.0; 10], &mut b)?;
17
18 // you can transfer back using memcpy_dtov
19 let mut a_host: Vec = stream.memcpy_dtov(&a)?;
20 assert_eq!(a_host, [0.0; 10]);
21
22 let b_host = stream.memcpy_dtov(&b)?;
23 assert_eq!(b_host, [3.0; 10]);
24
25 // or transfer into a pre allocated slice
26 stream.memcpy_dtoh(&b, &mut a_host)?;
27 assert_eq!(a_host, b_host);
28
29 Ok(())
30}
examples/03-launch-kernel.rs (line 30)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 // You can load a function from a pre-compiled PTX like so:
11 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
12
13 // and then load a function from it:
14 let f = module.load_function("sin_kernel").unwrap();
15
16 let a_host = [1.0, 2.0, 3.0];
17
18 let a_dev = stream.memcpy_stod(&a_host)?;
19 let mut b_dev = a_dev.clone();
20
21 // we use a buidler pattern to launch kernels.
22 let n = 3i32;
23 let cfg = LaunchConfig::for_num_elems(n as u32);
24 let mut launch_args = stream.launch_builder(&f);
25 launch_args.arg(&mut b_dev);
26 launch_args.arg(&a_dev);
27 launch_args.arg(&n);
28 unsafe { launch_args.launch(cfg) }?;
29
30 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
31 let b_host = stream.memcpy_dtov(&b_dev)?;
32
33 println!("Found {b_host:?}");
34 println!("Expected {:?}", a_host.map(f32::sin));
35 assert_eq!(&a_host, a_host_2.as_slice());
36
37 Ok(())
38}
examples/04-streams.rs (line 37)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
11 let f = module.load_function("sin_kernel")?;
12
13 let n = 3i32;
14 let a_host = [1.0, 2.0, 3.0];
15 let a_dev = stream.memcpy_stod(&a_host)?;
16 let mut b_dev = stream.alloc_zeros::(n as usize)?;
17
18 // we can safely create a second stream using [CudaStream::fork()].
19 // This synchronizes with the source stream, so
20 // the memcpy_vtod & alloc_zeros above will complete before
21 // work on this stream can start.
22 let stream2 = stream.fork()?;
23
24 // now we launch this work on the other stream
25 let mut builder = stream2.launch_builder(&f);
26 builder.arg(&mut b_dev); // NOTE: tells cudarc that we are mutating this.
27 builder.arg(&a_dev); // NOTE: tells cudarc that we are reading from this slice
28 builder.arg(&n);
29 unsafe { builder.launch(LaunchConfig::for_num_elems(n as u32)) }?;
30
31 // cudarc automatically manages multi stream synchronization,
32 // so even though we launched the above on a separate stream,
33 // doing this device to host transfer will still properly synchronize.
34 // a_dev doesn't need to synchronize at all since we specified it is just
35 // being read from.
36 // b_dev DOES need to be synchronized, because it was mutated on a different stream.
37 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
38 let b_host = stream.memcpy_dtov(&b_dev)?;
39
40 println!("Found {b_host:?}");
41 println!("Expected {:?}", a_host.map(f32::sin));
42 assert_eq!(&a_host, a_host_2.as_slice());
43
44 Ok(())
45}
Source
pub fn memcpy_dtoh<T: DeviceRepr, Src: DevicePtr, Dst: HostSlice + ?Sized>(
self: &Arc,
src: &Src,
dst: &mut Dst,
) -> Result<(), DriverError>
Copy a CudaSlice/CudaView to a existing [T]/Vec/PinnedHostSlice.
Examples found in repository? examples/02-copy.rs (line 26) 3fn main() -> Result<(), DriverError> { 4 let ctx = CudaContext::new(0)?; 5 let stream = ctx.default_stream(); 6 7 let a: CudaSlice = stream.alloc_zeros::(10)?; 8 let mut b = stream.alloc_zeros::(10)?; 9 10 // you can do device to device copies of course 11 stream.memcpy_dtod(&a, &mut b)?; 12 13 // but also host to device copys with already allocated buffers 14 stream.memcpy_htod(&vec![2.0; b.len()], &mut b)?; 15 // you can use any type of slice 16 stream.memcpy_htod(&[3.0; 10], &mut b)?; 17 18 // you can transfer back using memcpy_dtov 19 let mut a_host: Vec = stream.memcpy_dtov(&a)?; 20 assert_eq!(a_host, [0.0; 10]); 21 22 let b_host = stream.memcpy_dtov(&b)?; 23 assert_eq!(b_host, [3.0; 10]); 24 25 // or transfer into a pre allocated slice 26 stream.memcpy_dtoh(&b, &mut a_host)?; 27 assert_eq!(a_host, b_host); 28 29 Ok(()) 30} More examples Hide additional examples examples/matmul-kernel.rs (line 58) 22fn main() -> Result<(), DriverError> { 23 let start = std::time::Instant::now(); 24 25 let ptx = compile_ptx(PTX_SRC).unwrap(); 26 println!("Compilation succeeded in {:?}", start.elapsed()); 27 28 let ctx = CudaContext::new(0)?; 29 let stream = ctx.default_stream(); 30 println!("Built in {:?}", start.elapsed()); 31 32 let module = ctx.load_module(ptx)?; 33 let f = module.load_function("matmul")?; 34 println!("Loaded in {:?}", start.elapsed()); 35 36 let a_host = [1.0f32, 2.0, 3.0, 4.0]; 37 let b_host = [1.0f32, 2.0, 3.0, 4.0]; 38 let mut c_host = [0.0f32; 4]; 39 40 let a_dev = stream.memcpy_stod(&a_host)?; 41 let b_dev = stream.memcpy_stod(&b_host)?; 42 let mut c_dev = stream.memcpy_stod(&c_host)?; 43 44 println!("Copied in {:?}", start.elapsed()); 45 46 let mut builder = stream.launch_builder(&f); 47 builder.arg(&a_dev); 48 builder.arg(&b_dev); 49 builder.arg(&mut c_dev); 50 builder.arg(&2i32); 51 let cfg = LaunchConfig { 52 block_dim: (2, 2, 1), 53 grid_dim: (1, 1, 1), 54 shared_mem_bytes: 0, 55 }; 56 unsafe { builder.launch(cfg) }?; 57 58 stream.memcpy_dtoh(&c_dev, &mut c_host)?; 59 println!("Found {:?} in {:?}", c_host, start.elapsed()); 60 Ok(()) 61} Source pub fn memcpy_dtod<T, Src: DevicePtr, Dst: DevicePtrMut>( self: &Arc, src: &Src, dst: &mut Dst, ) -> Result<(), DriverError> Copy a CudaSlice/CudaView to a existing CudaSlice/CudaViewMut.
Examples found in repository? examples/02-copy.rs (line 11) 3fn main() -> Result<(), DriverError> { 4 let ctx = CudaContext::new(0)?; 5 let stream = ctx.default_stream(); 6 7 let a: CudaSlice = stream.alloc_zeros::(10)?; 8 let mut b = stream.alloc_zeros::(10)?; 9 10 // you can do device to device copies of course 11 stream.memcpy_dtod(&a, &mut b)?; 12 13 // but also host to device copys with already allocated buffers 14 stream.memcpy_htod(&vec![2.0; b.len()], &mut b)?; 15 // you can use any type of slice 16 stream.memcpy_htod(&[3.0; 10], &mut b)?; 17 18 // you can transfer back using memcpy_dtov 19 let mut a_host: Vec = stream.memcpy_dtov(&a)?; 20 assert_eq!(a_host, [0.0; 10]); 21 22 let b_host = stream.memcpy_dtov(&b)?; 23 assert_eq!(b_host, [3.0; 10]); 24 25 // or transfer into a pre allocated slice 26 stream.memcpy_dtoh(&b, &mut a_host)?; 27 assert_eq!(a_host, b_host); 28 29 Ok(()) 30} Source pub fn clone_dtod<T: DeviceRepr, Src: DevicePtr>( self: &Arc, src: &Src, ) -> Result<CudaSlice, DriverError> Copy a CudaSlice/CudaView to a new CudaSlice.
Source impl CudaStream Source pub unsafe fn upgrade_device_ptr( self: &Arc, cu_device_ptr: CUdeviceptr, len: usize, ) -> CudaSlice Creates a CudaSlice from a sys::CUdeviceptr. Useful in conjunction with CudaSlice::leak().
Safety cu_device_ptr must be a valid allocation cu_device_ptr must space for len * std::mem::size_of() bytes The memory may not be valid for type T, so some sort of memset operation should be called on the memory. Source impl CudaStream Source pub fn begin_capture( &self, mode: CUstreamCaptureMode, ) -> Result<(), DriverError> See cuda docs
Source pub fn end_capture( self: &Arc, flags: CUgraphInstantiate_flags, ) -> Result<Option, DriverError> See cuda docs
flags is passed to cuGraphInstantiate
Source pub fn capture_status(&self) -> Result<CUstreamCaptureStatus, DriverError> See cuda docs
Source impl CudaStream Source pub fn launch_builder<'a>(&'a self, func: &'a CudaFunction) -> LaunchArgs<'a> Creates a new kernel launch builder that will launch func on stream self.
Add arguments to the builder using LaunchArgs::arg(), and submit it to the stream using LaunchArgs::launch().
Examples found in repository?
examples/05-device-repr.rs (line 48)
32fn main() -> Result<(), DriverError> {
33 let ctx = CudaContext::new(0)?;
34 let stream = ctx.default_stream();
35
36 let ptx = compile_ptx(PTX_SRC).unwrap();
37 let module = ctx.load_module(ptx)?;
38 let f = module.load_function("my_custom_kernel")?;
39
40 // try changing some of these values to see a device assert
41 let thing = MyCoolRustStruct {
42 a: 1.0,
43 b: 2.34,
44 c: 57,
45 d: 420,
46 };
47
48 let mut builder = stream.launch_builder(&f);
49 // since MyCoolRustStruct implements DeviceRepr, we can pass it to launch.
50 builder.arg(&thing);
51 unsafe { builder.launch(LaunchConfig::for_num_elems(1)) }?;
52
53 Ok(())
54}
More examples
Hide additional examples
examples/03-launch-kernel.rs (line 24)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 // You can load a function from a pre-compiled PTX like so:
11 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
12
13 // and then load a function from it:
14 let f = module.load_function("sin_kernel").unwrap();
15
16 let a_host = [1.0, 2.0, 3.0];
17
18 let a_dev = stream.memcpy_stod(&a_host)?;
19 let mut b_dev = a_dev.clone();
20
21 // we use a buidler pattern to launch kernels.
22 let n = 3i32;
23 let cfg = LaunchConfig::for_num_elems(n as u32);
24 let mut launch_args = stream.launch_builder(&f);
25 launch_args.arg(&mut b_dev);
26 launch_args.arg(&a_dev);
27 launch_args.arg(&n);
28 unsafe { launch_args.launch(cfg) }?;
29
30 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
31 let b_host = stream.memcpy_dtov(&b_dev)?;
32
33 println!("Found {b_host:?}");
34 println!("Expected {:?}", a_host.map(f32::sin));
35 assert_eq!(&a_host, a_host_2.as_slice());
36
37 Ok(())
38}
examples/matmul-kernel.rs (line 46)
22fn main() -> Result<(), DriverError> {
23 let start = std::time::Instant::now();
24
25 let ptx = compile_ptx(PTX_SRC).unwrap();
26 println!("Compilation succeeded in {:?}", start.elapsed());
27
28 let ctx = CudaContext::new(0)?;
29 let stream = ctx.default_stream();
30 println!("Built in {:?}", start.elapsed());
31
32 let module = ctx.load_module(ptx)?;
33 let f = module.load_function("matmul")?;
34 println!("Loaded in {:?}", start.elapsed());
35
36 let a_host = [1.0f32, 2.0, 3.0, 4.0];
37 let b_host = [1.0f32, 2.0, 3.0, 4.0];
38 let mut c_host = [0.0f32; 4];
39
40 let a_dev = stream.memcpy_stod(&a_host)?;
41 let b_dev = stream.memcpy_stod(&b_host)?;
42 let mut c_dev = stream.memcpy_stod(&c_host)?;
43
44 println!("Copied in {:?}", start.elapsed());
45
46 let mut builder = stream.launch_builder(&f);
47 builder.arg(&a_dev);
48 builder.arg(&b_dev);
49 builder.arg(&mut c_dev);
50 builder.arg(&2i32);
51 let cfg = LaunchConfig {
52 block_dim: (2, 2, 1),
53 grid_dim: (1, 1, 1),
54 shared_mem_bytes: 0,
55 };
56 unsafe { builder.launch(cfg) }?;
57
58 stream.memcpy_dtoh(&c_dev, &mut c_host)?;
59 println!("Found {:?} in {:?}", c_host, start.elapsed());
60 Ok(())
61}
examples/04-streams.rs (line 25)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
11 let f = module.load_function("sin_kernel")?;
12
13 let n = 3i32;
14 let a_host = [1.0, 2.0, 3.0];
15 let a_dev = stream.memcpy_stod(&a_host)?;
16 let mut b_dev = stream.alloc_zeros::(n as usize)?;
17
18 // we can safely create a second stream using [CudaStream::fork()].
19 // This synchronizes with the source stream, so
20 // the memcpy_vtod & alloc_zeros above will complete before
21 // work on this stream can start.
22 let stream2 = stream.fork()?;
23
24 // now we launch this work on the other stream
25 let mut builder = stream2.launch_builder(&f);
26 builder.arg(&mut b_dev); // NOTE: tells cudarc that we are mutating this.
27 builder.arg(&a_dev); // NOTE: tells cudarc that we are reading from this slice
28 builder.arg(&n);
29 unsafe { builder.launch(LaunchConfig::for_num_elems(n as u32)) }?;
30
31 // cudarc automatically manages multi stream synchronization,
32 // so even though we launched the above on a separate stream,
33 // doing this device to host transfer will still properly synchronize.
34 // a_dev doesn't need to synchronize at all since we specified it is just
35 // being read from.
36 // b_dev DOES need to be synchronized, because it was mutated on a different stream.
37 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
38 let b_host = stream.memcpy_dtov(&b_dev)?;
39
40 println!("Found {b_host:?}");
41 println!("Expected {:?}", a_host.map(f32::sin));
42 assert_eq!(&a_host, a_host_2.as_slice());
43
44 Ok(())
45}
examples/06-threading.rs (line 27)
12fn main() -> Result<(), DriverError> {
13 {
14 // Option 1: sharing ctx & module between threads
15 thread::scope(|s| {
16 let ptx = compile_ptx(KERNEL_SRC).unwrap();
17 let ctx = CudaContext::new(0)?;
18 let module = ctx.load_module(ptx)?;
19 for i in 0..10i32 {
20 let thread_ctx = ctx.clone();
21 let thread_module = module.clone();
22 s.spawn(move || {
23 let stream = thread_ctx.default_stream();
24 let f = thread_module.load_function("hello_world")?;
25 unsafe {
26 stream
27 .launch_builder(&f)
28 .arg(&i)
29 .launch(LaunchConfig::for_num_elems(1))
30 }
31 });
32 }
33 Ok(())
34 })?;
35 }
36
37 {
38 // Option 2: initializing different context in each
39 // Note that this will still schedule to the same stream since we are using the
40 // default stream here on the same device.
41 thread::scope(move |s| {
42 for i in 0..10i32 {
43 s.spawn(move || {
44 let ptx = compile_ptx(KERNEL_SRC).unwrap();
45 let ctx = CudaContext::new(0)?;
46 let module = ctx.load_module(ptx)?;
47 let stream = ctx.default_stream();
48 let f = module.load_function("hello_world")?;
49 unsafe {
50 stream
51 .launch_builder(&f)
52 .arg(&i)
53 .launch(LaunchConfig::for_num_elems(1))
54 }
55 });
56 }
57 Ok(())
58 })?;
59 }
60
61 Ok(())
62}
Trait Implementations
Source
impl Debug for CudaStream
Source
fn fmt(&self, f: &mut Formatter<'_>) -> Result
Formats the value using the given formatter. Read more
Source
impl Drop for CudaStream
Source
fn drop(&mut self)
Executes the destructor for this type. Read more
Source
impl PartialEq for CudaStream
Source
fn eq(&self, other: &CudaStream) -> bool
Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source
fn ne(&self, other: &Rhs) -> bool
Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source
impl Eq for CudaStream
Source
impl Send for CudaStream
Source
impl StructuralPartialEq for CudaStream
Source
impl Sync for CudaStream
Auto Trait Implementations
impl Freeze for CudaStream
impl RefUnwindSafe for CudaStream
impl Unpin for CudaStream
impl UnwindSafe for CudaStream
Blanket Implementations
Source
impl Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl Borrow for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl BorrowMut for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl From for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source impl<T, U> Into for T where U: From, Source fn into(self) -> U Calls U::from(self).
That is, this conversion is whatever the implementation of From for U chooses to do.
Source impl<T, U> TryFrom for T where U: Into, 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>::Error> Performs the conversion. Source impl<T, U> TryInto for T where U: TryFrom, Source type Error = <U as TryFrom>::Error The type returned in the event of a conversion error. Source fn try_into(self) -> Result<U, <U as TryFrom>::Error> Performs the conversion. Source impl<V, T> VZip for T where V: MultiLane,
pub struct CudaView<'a, T> { /* private fields */ } &[T] on a cuda device. An immutable sub-view into a CudaSlice created by CudaSlice::as_view()/CudaSlice::slice().
Implementations Source impl CudaView<'_, T> Source pub fn len(&self) -> usize The number of elements T in this view.
Source pub fn is_empty(&self) -> bool Source impl<'a, T> CudaView<'a, T> Source pub fn slice(&self, bounds: impl RangeBounds) -> Self Creates a CudaView at the specified offset from the start of self.
Panics if range.start >= self.len.
Example let mut slice = stream.alloc_zeros::(100).unwrap(); let mut view = slice.slice(0..50); let mut view2 = view.slice(0..25); do_something(&view); Source pub fn try_slice(&self, bounds: impl RangeBounds) -> Option Fallible version of CudaView::slice
Source
pub unsafe fn transmute(&self, len: usize) -> Option<CudaView<'a, S>>
Reinterprets the slice of memory into a different type. len is the number of elements of the new type S that are expected. If not enough bytes are allocated in self for the view, then this returns None.
Safety This is unsafe because not the memory for the view may not be a valid interpretation for the type S.
Source pub fn split_at(&self, mid: usize) -> (Self, Self) Source pub fn try_split_at(&self, mid: usize) -> Option<(Self, Self)> Fallible version of CudaSlice::split_at.
Returns None if mid > self.len.
Trait Implementations Source impl<'a, T: Debug> Debug for CudaView<'a, T> Source fn fmt(&self, f: &mut Formatter<'>) -> Result Formats the value using the given formatter. Read more Source impl DevicePtr for CudaView<', T> Source fn device_ptr<'a>( &'a self, stream: &'a CudaStream, ) -> (CUdeviceptr, SyncOnDrop<'a>) Retrieve the device pointer with the intent to read the device memory associated with it. Read more Source impl DeviceSlice for CudaView<'_, T> Source fn len(&self) -> usize Source fn stream(&self) -> &Arc Source fn num_bytes(&self) -> usize Source fn is_empty(&self) -> bool Source impl<'a, 'b: 'a, 'c: 'b, T> PushKernelArg<&'b CudaView<'c, T>> for LaunchArgs<'a> Source fn arg(&mut self, arg: &'b CudaView<'c, T>) -> &mut Self Auto Trait Implementations impl<'a, T> Freeze for CudaView<'a, T> impl<'a, T> RefUnwindSafe for CudaView<'a, T> where T: RefUnwindSafe, impl<'a, T> Send for CudaView<'a, T> where T: Sync, impl<'a, T> Sync for CudaView<'a, T> where T: Sync, impl<'a, T> Unpin for CudaView<'a, T> impl<'a, T> UnwindSafe for CudaView<'a, T> where T: RefUnwindSafe, Blanket Implementations Source impl Any for T where T: 'static + ?Sized, Source fn type_id(&self) -> TypeId Gets the TypeId of self. Read more Source impl Borrow for T where T: ?Sized, Source fn borrow(&self) -> &T Immutably borrows from an owned value. Read more Source impl BorrowMut for T where T: ?Sized, Source fn borrow_mut(&mut self) -> &mut T Mutably borrows from an owned value. Read more Source impl From for T Source fn from(t: T) -> T Returns the argument unchanged.
Source impl<T, U> Into for T where U: From, Source fn into(self) -> U Calls U::from(self).
That is, this conversion is whatever the implementation of From for U chooses to do.
Source impl<T, U> TryFrom for T where U: Into, 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>::Error> Performs the conversion. Source impl<T, U> TryInto for T where U: TryFrom, Source type Error = <U as TryFrom>::Error The type returned in the event of a conversion error. Source fn try_into(self) -> Result<U, <U as TryFrom>::Error> Performs the conversion. Source impl<V, T> VZip for T where V: MultiLane,
pub struct CudaViewMut<'a, T> { /* private fields */ } &mut [T] on a cuda device. A mutable sub-view into a CudaSlice created by CudaSlice::as_view_mut()/CudaSlice::slice_mut().
Implementations Source impl CudaViewMut<'_, T> Source pub fn len(&self) -> usize Number of elements T that are in this view.
Source pub fn is_empty(&self) -> bool Source pub fn as_view(&self) -> CudaView<'_, T> Downgrade this to a &[T]
Source impl<'a, T> CudaViewMut<'a, T> Source pub fn slice<'b: 'a>( &'b self, bounds: impl RangeBounds, ) -> CudaView<'a, T> Creates a CudaView at the specified offset from the start of self.
Panics if range and 0...self.len() are not overlapping.
Example let mut slice = stream.alloc_zeros::(100).unwrap(); let mut view = slice.slice_mut(0..50); let mut view2 = view.slice_mut(0..25); do_something(&mut view2); One cannot slice twice into the same CudaViewMut:
ⓘ let mut slice = stream.alloc_zeros::(100).unwrap(); let mut view = slice.slice_mut(0..50); // cannot borrow twice from same view let mut view1 = slice.slice_mut(0..25); let mut view2 = slice.slice_mut(25..50); do_something(view1, view2); If you need non-overlapping mutable views into a CudaViewMut, you can use CudaViewMut::split_at_mut().
Source pub fn try_slice<'b: 'a>( &'b self, bounds: impl RangeBounds, ) -> Option<CudaView<'a, T>> Fallible version of CudaViewMut::slice
Source
pub unsafe fn transmute(&self, len: usize) -> Option<CudaView<'a, S>>
Reinterprets the slice of memory into a different type. len is the number of elements of the new type S that are expected. If not enough bytes are allocated in self for the view, then this returns None.
Safety This is unsafe because not the memory for the view may not be a valid interpretation for the type S.
Source pub fn slice_mut(&mut self, bounds: impl RangeBounds) -> Self Creates a CudaViewMut at the specified offset from the start of self.
Panics if range and 0...self.len() are not overlapping.
Source pub fn try_slice_mut(&mut self, bounds: impl RangeBounds) -> Option Fallible version of CudaViewMut::slice_mut
Source pub fn split_at_mut(&mut self, mid: usize) -> (Self, Self) Splits the CudaViewMut into two at the given index.
Panics if mid > self.len.
This method can be used to create non-overlapping mutable views into a CudaViewMut.
let mut slice = stream.alloc_zeros::(100).unwrap(); let mut view = slice.slice_mut(0..50); // split the view into two non-overlapping, mutable views let (mut view1, mut view2) = view.split_at_mut(25); do_something(view1, view2); Source pub fn try_split_at_mut(&mut self, mid: usize) -> Option<(Self, Self)> Fallible version of CudaViewMut::split_at_mut.
Returns None if mid > self.len
Source
pub unsafe fn transmute_mut(
&mut self,
len: usize,
) -> Option<CudaViewMut<'a, S>>
Reinterprets the slice of memory into a different type. len is the number of elements of the new type S that are expected. If not enough bytes are allocated in self for the view, then this returns None.
Safety This is unsafe because not the memory for the view may not be a valid interpretation for the type S.
Trait Implementations Source impl<'a, T: Debug> Debug for CudaViewMut<'a, T> Source fn fmt(&self, f: &mut Formatter<'>) -> Result Formats the value using the given formatter. Read more Source impl DevicePtr for CudaViewMut<', T> Source fn device_ptr<'a>( &'a self, stream: &'a CudaStream, ) -> (CUdeviceptr, SyncOnDrop<'a>) Retrieve the device pointer with the intent to read the device memory associated with it. Read more Source impl DevicePtrMut for CudaViewMut<', T> Source fn device_ptr_mut<'a>( &'a mut self, stream: &'a CudaStream, ) -> (CUdeviceptr, SyncOnDrop<'a>) Retrieve the device pointer with the intent to modify the device memory associated with it. Read more Source impl DeviceSlice for CudaViewMut<', T> Source fn len(&self) -> usize Source fn stream(&self) -> &Arc Source fn num_bytes(&self) -> usize Source fn is_empty(&self) -> bool Source impl<'a, 'b: 'a, 'c: 'b, T> PushKernelArg<&'b mut CudaViewMut<'c, T>> for LaunchArgs<'a> Source fn arg(&mut self, arg: &'b mut CudaViewMut<'c, T>) -> &mut Self Auto Trait Implementations impl<'a, T> Freeze for CudaViewMut<'a, T> impl<'a, T> RefUnwindSafe for CudaViewMut<'a, T> where T: RefUnwindSafe, impl<'a, T> Send for CudaViewMut<'a, T> where T: Send, impl<'a, T> Sync for CudaViewMut<'a, T> where T: Sync, impl<'a, T> Unpin for CudaViewMut<'a, T> impl<'a, T> !UnwindSafe for CudaViewMut<'a, T> Blanket Implementations Source impl Any for T where T: 'static + ?Sized, Source fn type_id(&self) -> TypeId Gets the TypeId of self. Read more Source impl Borrow for T where T: ?Sized, Source fn borrow(&self) -> &T Immutably borrows from an owned value. Read more Source impl BorrowMut for T where T: ?Sized, Source fn borrow_mut(&mut self) -> &mut T Mutably borrows from an owned value. Read more Source impl From for T Source fn from(t: T) -> T Returns the argument unchanged.
Source impl<T, U> Into for T where U: From, Source fn into(self) -> U Calls U::from(self).
That is, this conversion is whatever the implementation of From for U chooses to do.
Source impl<T, U> TryFrom for T where U: Into, 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>::Error> Performs the conversion. Source impl<T, U> TryInto for T where U: TryFrom, Source type Error = <U as TryFrom>::Error The type returned in the event of a conversion error. Source fn try_into(self) -> Result<U, <U as TryFrom>::Error> Performs the conversion. Source impl<V, T> VZip for T where V: MultiLane,
pub struct ExternalMemory { /* private fields */ } An abstraction for imported external memory.
This struct can be created via CudaContext::import_external_memory(). The imported external memory will be destroyed when this struct is dropped.
Implementations Source impl ExternalMemory Source pub fn map_all(self) -> Result<MappedBuffer, DriverError> Map the whole external memory to get mapped buffer.
Source pub fn map_range(self, range: Range) -> Result<MappedBuffer, DriverError> Map a range of the external memory to a mapped buffer.
Only one mapped buffer is allowed at a time. This is more restrictive than it necessarily needs to be, but it makes enforcing safety easier.
Panics This function will panic if the range is invalid, such as when the start or end is larger than the size.
Trait Implementations Source impl Debug for ExternalMemory Source fn fmt(&self, f: &mut Formatter<'_>) -> Result Formats the value using the given formatter. Read more Source impl Drop for ExternalMemory Source fn drop(&mut self) Executes the destructor for this type. Read more Auto Trait Implementations impl Freeze for ExternalMemory impl RefUnwindSafe for ExternalMemory impl !Send for ExternalMemory impl !Sync for ExternalMemory impl Unpin for ExternalMemory impl UnwindSafe for ExternalMemory Blanket Implementations Source impl Any for T where T: 'static + ?Sized, Source fn type_id(&self) -> TypeId Gets the TypeId of self. Read more Source impl Borrow for T where T: ?Sized, Source fn borrow(&self) -> &T Immutably borrows from an owned value. Read more Source impl BorrowMut for T where T: ?Sized, Source fn borrow_mut(&mut self) -> &mut T Mutably borrows from an owned value. Read more Source impl From for T Source fn from(t: T) -> T Returns the argument unchanged.
Source impl<T, U> Into for T where U: From, Source fn into(self) -> U Calls U::from(self).
That is, this conversion is whatever the implementation of From for U chooses to do.
Source impl<T, U> TryFrom for T where U: Into, 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>::Error> Performs the conversion. Source impl<T, U> TryInto for T where U: TryFrom, Source type Error = <U as TryFrom>::Error The type returned in the event of a conversion error. Source fn try_into(self) -> Result<U, <U as TryFrom>::Error> Performs the conversion. Source impl<V, T> VZip for T where V: MultiLane,
pub struct LaunchArgs<'a> { /* private fields */ } The kernel launch builder. Instantiate with CudaStream::launch_builder(), and then launch the kernel with LaunchArgs::launch()
Anything added as a kernel argument with LaunchArgs::arg() must either:
Implement DeviceRepr Add a custom implementation of impl<'a> PushKernelArg for LaunchArgs<'a>, where T is your type. Implementations Source impl LaunchArgs<'_> Source pub fn record_kernel_launch(&mut self, flags: CUevent_flags) -> &mut Self Calling this will make LaunchArgs::launch() and LaunchArgs::launch_cooperative() return 2 CudaEvents that recorded before and after the kernel is submitted.
Source pub unsafe fn launch( &mut self, cfg: LaunchConfig, ) -> Result<Option<(CudaEvent, CudaEvent)>, DriverError> Submits the configuration CudaFunction to execute asychronously on the configured device stream.
Safety This is generally unsafe for two main reasons:
We can’t guarantee that the arguments are valid for the configured CudaFunction. We don’t know if the types are correct, if the arguments are in the correct order, if the types are representable in CUDA, etc. We can’t guarantee that the cuda kernel follows the mutability of the arguments configured with LaunchArgs::arg(). For instance, you can pass a reference to a CudaSlice, which on rust side can’t be mutated, but on cuda side the kernel can mutate it. CudaFunction can access memory outside of limits. Handling asynchronous mutation All CudaSlice/CudaView/CudaViewMut contain 2 events that record when the data associated with them are read from/written to.
The PushKernelArg implementation of these adds these events to LaunchArgs, so when LaunchArgs::launch() is called, we properly do multi stream synchronization.
So in practice it is not possible to have multiple kernels concurrently modify device data while using the safe api.
Handling use after free Since LaunchArgs::launch() properly records reads/writes for CudaSlice/CudaView/CudaViewMut, and the drop implementation of CudaSlice waits on those events to finish, we will never encounter a use after free situation.
Examples found in repository?
examples/05-device-repr.rs (line 51)
32fn main() -> Result<(), DriverError> {
33 let ctx = CudaContext::new(0)?;
34 let stream = ctx.default_stream();
35
36 let ptx = compile_ptx(PTX_SRC).unwrap();
37 let module = ctx.load_module(ptx)?;
38 let f = module.load_function("my_custom_kernel")?;
39
40 // try changing some of these values to see a device assert
41 let thing = MyCoolRustStruct {
42 a: 1.0,
43 b: 2.34,
44 c: 57,
45 d: 420,
46 };
47
48 let mut builder = stream.launch_builder(&f);
49 // since MyCoolRustStruct implements DeviceRepr, we can pass it to launch.
50 builder.arg(&thing);
51 unsafe { builder.launch(LaunchConfig::for_num_elems(1)) }?;
52
53 Ok(())
54}
More examples
Hide additional examples
examples/03-launch-kernel.rs (line 28)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 // You can load a function from a pre-compiled PTX like so:
11 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
12
13 // and then load a function from it:
14 let f = module.load_function("sin_kernel").unwrap();
15
16 let a_host = [1.0, 2.0, 3.0];
17
18 let a_dev = stream.memcpy_stod(&a_host)?;
19 let mut b_dev = a_dev.clone();
20
21 // we use a buidler pattern to launch kernels.
22 let n = 3i32;
23 let cfg = LaunchConfig::for_num_elems(n as u32);
24 let mut launch_args = stream.launch_builder(&f);
25 launch_args.arg(&mut b_dev);
26 launch_args.arg(&a_dev);
27 launch_args.arg(&n);
28 unsafe { launch_args.launch(cfg) }?;
29
30 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
31 let b_host = stream.memcpy_dtov(&b_dev)?;
32
33 println!("Found {b_host:?}");
34 println!("Expected {:?}", a_host.map(f32::sin));
35 assert_eq!(&a_host, a_host_2.as_slice());
36
37 Ok(())
38}
examples/matmul-kernel.rs (line 56)
22fn main() -> Result<(), DriverError> {
23 let start = std::time::Instant::now();
24
25 let ptx = compile_ptx(PTX_SRC).unwrap();
26 println!("Compilation succeeded in {:?}", start.elapsed());
27
28 let ctx = CudaContext::new(0)?;
29 let stream = ctx.default_stream();
30 println!("Built in {:?}", start.elapsed());
31
32 let module = ctx.load_module(ptx)?;
33 let f = module.load_function("matmul")?;
34 println!("Loaded in {:?}", start.elapsed());
35
36 let a_host = [1.0f32, 2.0, 3.0, 4.0];
37 let b_host = [1.0f32, 2.0, 3.0, 4.0];
38 let mut c_host = [0.0f32; 4];
39
40 let a_dev = stream.memcpy_stod(&a_host)?;
41 let b_dev = stream.memcpy_stod(&b_host)?;
42 let mut c_dev = stream.memcpy_stod(&c_host)?;
43
44 println!("Copied in {:?}", start.elapsed());
45
46 let mut builder = stream.launch_builder(&f);
47 builder.arg(&a_dev);
48 builder.arg(&b_dev);
49 builder.arg(&mut c_dev);
50 builder.arg(&2i32);
51 let cfg = LaunchConfig {
52 block_dim: (2, 2, 1),
53 grid_dim: (1, 1, 1),
54 shared_mem_bytes: 0,
55 };
56 unsafe { builder.launch(cfg) }?;
57
58 stream.memcpy_dtoh(&c_dev, &mut c_host)?;
59 println!("Found {:?} in {:?}", c_host, start.elapsed());
60 Ok(())
61}
examples/04-streams.rs (line 29)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
11 let f = module.load_function("sin_kernel")?;
12
13 let n = 3i32;
14 let a_host = [1.0, 2.0, 3.0];
15 let a_dev = stream.memcpy_stod(&a_host)?;
16 let mut b_dev = stream.alloc_zeros::(n as usize)?;
17
18 // we can safely create a second stream using [CudaStream::fork()].
19 // This synchronizes with the source stream, so
20 // the memcpy_vtod & alloc_zeros above will complete before
21 // work on this stream can start.
22 let stream2 = stream.fork()?;
23
24 // now we launch this work on the other stream
25 let mut builder = stream2.launch_builder(&f);
26 builder.arg(&mut b_dev); // NOTE: tells cudarc that we are mutating this.
27 builder.arg(&a_dev); // NOTE: tells cudarc that we are reading from this slice
28 builder.arg(&n);
29 unsafe { builder.launch(LaunchConfig::for_num_elems(n as u32)) }?;
30
31 // cudarc automatically manages multi stream synchronization,
32 // so even though we launched the above on a separate stream,
33 // doing this device to host transfer will still properly synchronize.
34 // a_dev doesn't need to synchronize at all since we specified it is just
35 // being read from.
36 // b_dev DOES need to be synchronized, because it was mutated on a different stream.
37 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
38 let b_host = stream.memcpy_dtov(&b_dev)?;
39
40 println!("Found {b_host:?}");
41 println!("Expected {:?}", a_host.map(f32::sin));
42 assert_eq!(&a_host, a_host_2.as_slice());
43
44 Ok(())
45}
examples/06-threading.rs (line 29)
12fn main() -> Result<(), DriverError> {
13 {
14 // Option 1: sharing ctx & module between threads
15 thread::scope(|s| {
16 let ptx = compile_ptx(KERNEL_SRC).unwrap();
17 let ctx = CudaContext::new(0)?;
18 let module = ctx.load_module(ptx)?;
19 for i in 0..10i32 {
20 let thread_ctx = ctx.clone();
21 let thread_module = module.clone();
22 s.spawn(move || {
23 let stream = thread_ctx.default_stream();
24 let f = thread_module.load_function("hello_world")?;
25 unsafe {
26 stream
27 .launch_builder(&f)
28 .arg(&i)
29 .launch(LaunchConfig::for_num_elems(1))
30 }
31 });
32 }
33 Ok(())
34 })?;
35 }
36
37 {
38 // Option 2: initializing different context in each
39 // Note that this will still schedule to the same stream since we are using the
40 // default stream here on the same device.
41 thread::scope(move |s| {
42 for i in 0..10i32 {
43 s.spawn(move || {
44 let ptx = compile_ptx(KERNEL_SRC).unwrap();
45 let ctx = CudaContext::new(0)?;
46 let module = ctx.load_module(ptx)?;
47 let stream = ctx.default_stream();
48 let f = module.load_function("hello_world")?;
49 unsafe {
50 stream
51 .launch_builder(&f)
52 .arg(&i)
53 .launch(LaunchConfig::for_num_elems(1))
54 }
55 });
56 }
57 Ok(())
58 })?;
59 }
60
61 Ok(())
62}
Source
pub unsafe fn launch_cooperative(
&mut self,
cfg: LaunchConfig,
) -> Result<Option<(CudaEvent, CudaEvent)>, DriverError>
Launch a cooperative kernel.
Safety See LaunchArgs::launch()
Trait Implementations Source impl<'a> Debug for LaunchArgs<'a> Source fn fmt(&self, f: &mut Formatter<'_>) -> Result Formats the value using the given formatter. Read more Source impl<'a, 'b: 'a, T> PushKernelArg<&'b CudaSlice> for LaunchArgs<'a> Source fn arg(&mut self, arg: &'b CudaSlice) -> &mut Self Source impl<'a, 'b: 'a, 'c: 'b, T> PushKernelArg<&'b CudaView<'c, T>> for LaunchArgs<'a> Source fn arg(&mut self, arg: &'b CudaView<'c, T>) -> &mut Self Source impl<'a, 'b: 'a, T: DeviceRepr> PushKernelArg<&'b T> for LaunchArgs<'a> Source fn arg(&mut self, arg: &'b T) -> &mut Self Source impl<'a, 'b: 'a, T> PushKernelArg<&'b UnifiedSlice> for LaunchArgs<'a> Source fn arg(&mut self, arg: &'b UnifiedSlice) -> &mut Self Source impl<'a, 'b: 'a, T> PushKernelArg<&'b mut CudaSlice> for LaunchArgs<'a> Source fn arg(&mut self, arg: &'b mut CudaSlice) -> &mut Self Source impl<'a, 'b: 'a, 'c: 'b, T> PushKernelArg<&'b mut CudaViewMut<'c, T>> for LaunchArgs<'a> Source fn arg(&mut self, arg: &'b mut CudaViewMut<'c, T>) -> &mut Self Source impl<'a, 'b: 'a, T> PushKernelArg<&'b mut UnifiedSlice> for LaunchArgs<'a> Source fn arg(&mut self, arg: &'b mut UnifiedSlice) -> &mut Self Auto Trait Implementations impl<'a> Freeze for LaunchArgs<'a> impl<'a> RefUnwindSafe for LaunchArgs<'a> impl<'a> !Send for LaunchArgs<'a> impl<'a> !Sync for LaunchArgs<'a> impl<'a> Unpin for LaunchArgs<'a> impl<'a> UnwindSafe for LaunchArgs<'a> Blanket Implementations Source impl Any for T where T: 'static + ?Sized, Source fn type_id(&self) -> TypeId Gets the TypeId of self. Read more Source impl Borrow for T where T: ?Sized, Source fn borrow(&self) -> &T Immutably borrows from an owned value. Read more Source impl BorrowMut for T where T: ?Sized, Source fn borrow_mut(&mut self) -> &mut T Mutably borrows from an owned value. Read more Source impl From for T Source fn from(t: T) -> T Returns the argument unchanged.
Source impl<T, U> Into for T where U: From, Source fn into(self) -> U Calls U::from(self).
That is, this conversion is whatever the implementation of From for U chooses to do.
Source impl<T, U> TryFrom for T where U: Into, 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>::Error> Performs the conversion. Source impl<T, U> TryInto for T where U: TryFrom, Source type Error = <U as TryFrom>::Error The type returned in the event of a conversion error. Source fn try_into(self) -> Result<U, <U as TryFrom>::Error> Performs the conversion. Source impl<V, T> VZip for T where V: MultiLane,
pub struct LaunchConfig { pub grid_dim: (u32, u32, u32), pub block_dim: (u32, u32, u32), pub shared_mem_bytes: u32, } Configuration for result::launch_kernel
See cuda docs for description of each parameter.
Fields grid_dim: (u32, u32, u32) (width, height, depth) of grid in blocks
block_dim: (u32, u32, u32) (x, y, z) dimension of each thread block
shared_mem_bytes: u32 Dynamic shared-memory size per thread block in bytes
Implementations Source impl LaunchConfig Source pub fn for_num_elems(n: u32) -> Self Creates a LaunchConfig with:
block_dim == 1024
grid_dim == (n + 1023) / 1024
shared_mem_bytes == 0
Examples found in repository?
examples/05-device-repr.rs (line 51)
32fn main() -> Result<(), DriverError> {
33 let ctx = CudaContext::new(0)?;
34 let stream = ctx.default_stream();
35
36 let ptx = compile_ptx(PTX_SRC).unwrap();
37 let module = ctx.load_module(ptx)?;
38 let f = module.load_function("my_custom_kernel")?;
39
40 // try changing some of these values to see a device assert
41 let thing = MyCoolRustStruct {
42 a: 1.0,
43 b: 2.34,
44 c: 57,
45 d: 420,
46 };
47
48 let mut builder = stream.launch_builder(&f);
49 // since MyCoolRustStruct implements DeviceRepr, we can pass it to launch.
50 builder.arg(&thing);
51 unsafe { builder.launch(LaunchConfig::for_num_elems(1)) }?;
52
53 Ok(())
54}
More examples
Hide additional examples
examples/03-launch-kernel.rs (line 23)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 // You can load a function from a pre-compiled PTX like so:
11 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
12
13 // and then load a function from it:
14 let f = module.load_function("sin_kernel").unwrap();
15
16 let a_host = [1.0, 2.0, 3.0];
17
18 let a_dev = stream.memcpy_stod(&a_host)?;
19 let mut b_dev = a_dev.clone();
20
21 // we use a buidler pattern to launch kernels.
22 let n = 3i32;
23 let cfg = LaunchConfig::for_num_elems(n as u32);
24 let mut launch_args = stream.launch_builder(&f);
25 launch_args.arg(&mut b_dev);
26 launch_args.arg(&a_dev);
27 launch_args.arg(&n);
28 unsafe { launch_args.launch(cfg) }?;
29
30 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
31 let b_host = stream.memcpy_dtov(&b_dev)?;
32
33 println!("Found {b_host:?}");
34 println!("Expected {:?}", a_host.map(f32::sin));
35 assert_eq!(&a_host, a_host_2.as_slice());
36
37 Ok(())
38}
examples/04-streams.rs (line 29)
6fn main() -> Result<(), DriverError> {
7 let ctx = CudaContext::new(0)?;
8 let stream = ctx.default_stream();
9
10 let module = ctx.load_module(Ptx::from_file("./examples/sin.ptx"))?;
11 let f = module.load_function("sin_kernel")?;
12
13 let n = 3i32;
14 let a_host = [1.0, 2.0, 3.0];
15 let a_dev = stream.memcpy_stod(&a_host)?;
16 let mut b_dev = stream.alloc_zeros::(n as usize)?;
17
18 // we can safely create a second stream using [CudaStream::fork()].
19 // This synchronizes with the source stream, so
20 // the memcpy_vtod & alloc_zeros above will complete before
21 // work on this stream can start.
22 let stream2 = stream.fork()?;
23
24 // now we launch this work on the other stream
25 let mut builder = stream2.launch_builder(&f);
26 builder.arg(&mut b_dev); // NOTE: tells cudarc that we are mutating this.
27 builder.arg(&a_dev); // NOTE: tells cudarc that we are reading from this slice
28 builder.arg(&n);
29 unsafe { builder.launch(LaunchConfig::for_num_elems(n as u32)) }?;
30
31 // cudarc automatically manages multi stream synchronization,
32 // so even though we launched the above on a separate stream,
33 // doing this device to host transfer will still properly synchronize.
34 // a_dev doesn't need to synchronize at all since we specified it is just
35 // being read from.
36 // b_dev DOES need to be synchronized, because it was mutated on a different stream.
37 let a_host_2 = stream.memcpy_dtov(&a_dev)?;
38 let b_host = stream.memcpy_dtov(&b_dev)?;
39
40 println!("Found {b_host:?}");
41 println!("Expected {:?}", a_host.map(f32::sin));
42 assert_eq!(&a_host, a_host_2.as_slice());
43
44 Ok(())
45}
examples/06-threading.rs (line 29)
12fn main() -> Result<(), DriverError> {
13 {
14 // Option 1: sharing ctx & module between threads
15 thread::scope(|s| {
16 let ptx = compile_ptx(KERNEL_SRC).unwrap();
17 let ctx = CudaContext::new(0)?;
18 let module = ctx.load_module(ptx)?;
19 for i in 0..10i32 {
20 let thread_ctx = ctx.clone();
21 let thread_module = module.clone();
22 s.spawn(move || {
23 let stream = thread_ctx.default_stream();
24 let f = thread_module.load_function("hello_world")?;
25 unsafe {
26 stream
27 .launch_builder(&f)
28 .arg(&i)
29 .launch(LaunchConfig::for_num_elems(1))
30 }
31 });
32 }
33 Ok(())
34 })?;
35 }
36
37 {
38 // Option 2: initializing different context in each
39 // Note that this will still schedule to the same stream since we are using the
40 // default stream here on the same device.
41 thread::scope(move |s| {
42 for i in 0..10i32 {
43 s.spawn(move || {
44 let ptx = compile_ptx(KERNEL_SRC).unwrap();
45 let ctx = CudaContext::new(0)?;
46 let module = ctx.load_module(ptx)?;
47 let stream = ctx.default_stream();
48 let f = module.load_function("hello_world")?;
49 unsafe {
50 stream
51 .launch_builder(&f)
52 .arg(&i)
53 .launch(LaunchConfig::for_num_elems(1))
54 }
55 });
56 }
57 Ok(())
58 })?;
59 }
60
61 Ok(())
62}
Trait Implementations
Source
impl Clone for LaunchConfig
Source
fn clone(&self) -> LaunchConfig
Returns a duplicate of the value. Read more
1.0.0 · Source
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from source. Read more
Source
impl Debug for LaunchConfig
Source
fn fmt(&self, f: &mut Formatter<'_>) -> Result
Formats the value using the given formatter. Read more
Source
impl Copy for LaunchConfig
Auto Trait Implementations
impl Freeze for LaunchConfig
impl RefUnwindSafe for LaunchConfig
impl Send for LaunchConfig
impl Sync for LaunchConfig
impl Unpin for LaunchConfig
impl UnwindSafe for LaunchConfig
Blanket Implementations
Source
impl Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl Borrow for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl BorrowMut for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl CloneToUninit for T
where
T: Clone,
Source
unsafe fn clone_to_uninit(&self, dest: *mut u8)
🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source
impl From for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source impl<T, U> Into for T where U: From, Source fn into(self) -> U Calls U::from(self).
That is, this conversion is whatever the implementation of From for U chooses to do.
Source impl ToOwned for T where T: Clone, Source type Owned = T The resulting type after obtaining ownership. Source fn to_owned(&self) -> T Creates owned data from borrowed data, usually by cloning. Read more Source fn clone_into(&self, target: &mut T) Uses borrowed data to replace owned data, usually by cloning. Read more Source impl<T, U> TryFrom for T where U: Into, 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>::Error> Performs the conversion. Source impl<T, U> TryInto for T where U: TryFrom, Source type Error = <U as TryFrom>::Error The type returned in the event of a conversion error. Source fn try_into(self) -> Result<U, <U as TryFrom>::Error> Performs the conversion. Source impl<V, T> VZip for T where V: MultiLane,
pub struct MappedBuffer { /* private fields */ } An abstraction for a mapped buffer for some external memory.
This struct can be created via ExternalMemory::map_range or ExternalMemory::map_all. The underlying mapped buffer will be freed when this struct is dropped.
Trait Implementations Source impl Debug for MappedBuffer Source fn fmt(&self, f: &mut Formatter<'_>) -> Result Formats the value using the given formatter. Read more Source impl DevicePtr for MappedBuffer Source fn device_ptr<'a>( &'a self, stream: &'a CudaStream, ) -> (CUdeviceptr, SyncOnDrop<'a>) Retrieve the device pointer with the intent to read the device memory associated with it. Read more Source impl DeviceSlice for MappedBuffer Source fn len(&self) -> usize Source fn stream(&self) -> &Arc Source fn num_bytes(&self) -> usize Source fn is_empty(&self) -> bool Source impl Drop for MappedBuffer Source fn drop(&mut self) Executes the destructor for this type. Read more Auto Trait Implementations impl Freeze for MappedBuffer impl RefUnwindSafe for MappedBuffer impl !Send for MappedBuffer impl !Sync for MappedBuffer impl Unpin for MappedBuffer impl UnwindSafe for MappedBuffer Blanket Implementations Source impl Any for T where T: 'static + ?Sized, Source fn type_id(&self) -> TypeId Gets the TypeId of self. Read more Source impl Borrow for T where T: ?Sized, Source fn borrow(&self) -> &T Immutably borrows from an owned value. Read more Source impl BorrowMut for T where T: ?Sized, Source fn borrow_mut(&mut self) -> &mut T Mutably borrows from an owned value. Read more Source impl From for T Source fn from(t: T) -> T Returns the argument unchanged.
Source impl<T, U> Into for T where U: From, Source fn into(self) -> U Calls U::from(self).
That is, this conversion is whatever the implementation of From for U chooses to do.
Source impl<T, U> TryFrom for T where U: Into, 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>::Error> Performs the conversion. Source impl<T, U> TryInto for T where U: TryFrom, Source type Error = <U as TryFrom>::Error The type returned in the event of a conversion error. Source fn try_into(self) -> Result<U, <U as TryFrom>::Error> Performs the conversion. Source impl<V, T> VZip for T where V: MultiLane,
pub struct PinnedHostSlice { /* private fields */ } Rust side data that the cuda driver knows is pinned. This is different than Pin<Vec> mainly because cuda driver manages this memory and ensures it is page locked.
Allocate this with CudaContext::alloc_pinned(), and do device copies with CudaStream::memcpy_stod()/CudaStream::memcpy_htod()/CudaStream::memcpy_dtoh()
Implementations Source impl PinnedHostSlice Source pub fn context(&self) -> &Arc The context this was created in.
Source pub fn len(&self) -> usize The number of elements T in this slice.
Source pub fn num_bytes(&self) -> usize The number of bytes in this slice.
Source pub fn is_empty(&self) -> bool Source impl<T: ValidAsZeroBits> PinnedHostSlice Source pub fn as_ptr(&self) -> Result<*const T, DriverError> Waits for any scheduled work to complete and then returns a refernce to the host side data.
Source pub fn as_mut_ptr(&mut self) -> Result<*mut T, DriverError> Waits for any scheduled work to complete and then returns a refernce to the host side data.
Source pub fn as_slice(&self) -> Result<&[T], DriverError> Waits for any scheduled work to complete and then returns a refernce to the host side data.
Source pub fn as_mut_slice(&mut self) -> Result<&mut [T], DriverError> Waits for any scheduled work to complete and then returns a refernce to the host side data.
Trait Implementations Source impl<T: Debug> Debug for PinnedHostSlice Source fn fmt(&self, f: &mut Formatter<'_>) -> Result Formats the value using the given formatter. Read more Source impl Drop for PinnedHostSlice Source fn drop(&mut self) Executes the destructor for this type. Read more Source impl HostSlice for PinnedHostSlice Source fn len(&self) -> usize Source unsafe fn stream_synced_slice<'a>( &'a self, stream: &'a CudaStream, ) -> (&'a [T], SyncOnDrop<'a>) Safety Read more Source unsafe fn stream_synced_mut_slice<'a>( &'a mut self, stream: &'a CudaStream, ) -> (&'a mut [T], SyncOnDrop<'a>) Safety Read more Source fn is_empty(&self) -> bool Source impl Send for PinnedHostSlice Source impl Sync for PinnedHostSlice Auto Trait Implementations impl Freeze for PinnedHostSlice impl RefUnwindSafe for PinnedHostSlice where T: RefUnwindSafe, impl Unpin for PinnedHostSlice impl UnwindSafe for PinnedHostSlice where T: RefUnwindSafe, Blanket Implementations Source§ impl Any for T where T: 'static + ?Sized, Source fn type_id(&self) -> TypeId Gets the TypeId of self. Read more Source impl Borrow for T where T: ?Sized, Source fn borrow(&self) -> &T Immutably borrows from an owned value. Read more Source impl BorrowMut for T where T: ?Sized, Source fn borrow_mut(&mut self) -> &mut T Mutably borrows from an owned value. Read more Source impl From for T Source fn from(t: T) -> T Returns the argument unchanged.
Source impl<T, U> Into for T where U: From, Source fn into(self) -> U Calls U::from(self).
That is, this conversion is whatever the implementation of From for U chooses to do.
Source impl<T, U> TryFrom for T where U: Into, 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>::Error> Performs the conversion. Source impl<T, U> TryInto for T where U: TryFrom, Source type Error = <U as TryFrom>::Error The type returned in the event of a conversion error. Source fn try_into(self) -> Result<U, <U as TryFrom>::Error> Performs the conversion. Source impl<V, T> VZip for T where V: MultiLane,
pub struct Profiler; Calls profiler_start() in Profiler::new(), and profiler_stop() in Drop.
Implementations Source impl Profiler Source pub fn new() -> Result<Self, DriverError> Enables profile collection by the active profiling tool for the current context. If profiling is already enabled, then Profiler::new() has no effect. More info in Cuda docs
use cudarc::driver::{Profiler};
{ let profiler = Profiler::new()?; // Hotpath // Profiler stops on drop } // Now check your results // nsys profile -c cudaProfilerApi /path/to/bin // And this will profile only the hotpath. Trait Implementations Source impl Default for Profiler Source fn default() -> Profiler Returns the “default value” for a type. Read more Source impl Drop for Profiler Source fn drop(&mut self) Executes the destructor for this type. Read more Auto Trait Implementations impl Freeze for Profiler impl RefUnwindSafe for Profiler impl Send for Profiler impl Sync for Profiler impl Unpin for Profiler impl UnwindSafe for Profiler Blanket Implementations Source impl Any for T where T: 'static + ?Sized, Source fn type_id(&self) -> TypeId Gets the TypeId of self. Read more Source impl Borrow for T where T: ?Sized, Source fn borrow(&self) -> &T Immutably borrows from an owned value. Read more Source impl BorrowMut for T where T: ?Sized, Source fn borrow_mut(&mut self) -> &mut T Mutably borrows from an owned value. Read more Source impl From for T Source fn from(t: T) -> T Returns the argument unchanged.
Source impl<T, U> Into for T where U: From, Source fn into(self) -> U Calls U::from(self).
That is, this conversion is whatever the implementation of From for U chooses to do.
Source impl<T, U> TryFrom for T where U: Into, 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>::Error> Performs the conversion. Source impl<T, U> TryInto for T where U: TryFrom, Source type Error = <U as TryFrom>::Error The type returned in the event of a conversion error. Source fn try_into(self) -> Result<U, <U as TryFrom>::Error> Performs the conversion. Source impl<V, T> VZip for T where V: MultiLane,