Files
rustytorch/cudarc/Driver.md
T
2026-03-04 00:08:42 +00:00

4783 lines
142 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<T> 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<T>> 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<T> and PinnedHostSlice<T>.
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<CudaContext> 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<Self>, 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<f32> = unsafe { stream.alloc::<f32>(10) }?;
9
10 // this will have memory initialized as 0
11 let _: CudaSlice<f64> = stream.alloc_zeros::<f64>(10)?;
12
13 // initialize with slices!
14 let _: CudaSlice<usize> = stream.memcpy_stod(&[0; 10])?;
15 let _: CudaSlice<u32> = 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<dyn std::error::Error>> {
3 use std::fs;
4
5 use cudarc::{cufile::safe::Cufile, driver::CudaContext};
6
7 const N: usize = 100000;
8 let data: Vec<u8> = (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::<u8>(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<f64> = stream.alloc_zeros::<f64>(10)?;
8 let mut b = stream.alloc_zeros::<f64>(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<f64> = 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 gets 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 wont 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 couldnt 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<T>(&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<Self>,
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<Self>) -> Arc<CudaStream>
Gets the default stream for this context (the null ptr stream). Note that contexts 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<f32> = unsafe { stream.alloc::<f32>(10) }?;
9
10 // this will have memory initialized as 0
11 let _: CudaSlice<f64> = stream.alloc_zeros::<f64>(10)?;
12
13 // initialize with slices!
14 let _: CudaSlice<usize> = stream.memcpy_stod(&[0; 10])?;
15 let _: CudaSlice<u32> = 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<dyn std::error::Error>> {
3 use std::fs;
4
5 use cudarc::{cufile::safe::Cufile, driver::CudaContext};
6
7 const N: usize = 100000;
8 let data: Vec<u8> = (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::<u8>(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<f64> = stream.alloc_zeros::<f64>(10)?;
8 let mut b = stream.alloc_zeros::<f64>(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<f64> = 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<Self>) -> Result<Arc<CudaStream>, 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<Self>,
len: usize,
) -> Result<PinnedHostSlice<T>, 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<Self>,
ptx: Ptx,
) -> Result<Arc<CudaModule>, 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::<f32>(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<Self>,
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<Self>,
len: usize,
attach_global: bool,
) -> Result<UnifiedSlice<T>, 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<T> Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl<T> Borrow<T> for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl<T> BorrowMut<T> for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl<T> From<T> for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source
impl<T, U> Into<U> for T
where
U: From<T>,
Source
fn into(self) -> U
Calls U::from(self).
That is, this conversion is whatever the implementation of From<T> for U chooses to do.
Source
impl<T, U> TryFrom<U> for T
where
U: Into<T>,
Source
type Error = Infallible
The type returned in the event of a conversion error.
Source
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
Performs the conversion.
Source
impl<T, U> TryInto<U> for T
where
U: TryFrom<T>,
Source
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
Source
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
Performs the conversion.
Source§
impl<V, T> VZip<V> for T
where
V: MultiLane<T>,
----------------------------
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<CudaContext>
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<T> Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl<T> Borrow<T> for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl<T> BorrowMut<T> for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl<T> From<T> for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source
impl<T, U> Into<U> for T
where
U: From<T>,
Source
fn into(self) -> U
Calls U::from(self).
That is, this conversion is whatever the implementation of From<T> for U chooses to do.
Source
impl<T, U> TryFrom<U> for T
where
U: Into<T>,
Source
type Error = Infallible
The type returned in the event of a conversion error.
Source
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
Performs the conversion.
Source
impl<T, U> TryInto<U> for T
where
U: TryFrom<T>,
Source
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
Source
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
Performs the conversion.
Source
impl<V, T> VZip<V> for T
where
V: MultiLane<T>,
----------------------------
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<T> Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl<T> Borrow<T> for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl<T> BorrowMut<T> for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl<T> 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<T> From<T> for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source
impl<T, U> Into<U> for T
where
U: From<T>,
Source
fn into(self) -> U
Calls U::from(self).
That is, this conversion is whatever the implementation of From<T> for U chooses to do.
Source
impl<T> 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<U> for T
where
U: Into<T>,
Source
type Error = Infallible
The type returned in the event of a conversion error.
Source
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
Performs the conversion.
Source
impl<T, U> TryInto<U> for T
where
U: TryFrom<T>,
Source
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
Source
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
Performs the conversion.
Source
impl<V, T> VZip<V> for T
where
V: MultiLane<T>,
---------------------------------------------------
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<T> Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl<T> Borrow<T> for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl<T> BorrowMut<T> for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl<T> From<T> for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source
impl<T, U> Into<U> for T
where
U: From<T>,
Source
fn into(self) -> U
Calls U::from(self).
That is, this conversion is whatever the implementation of From<T> for U chooses to do.
Source
impl<T, U> TryFrom<U> for T
where
U: Into<T>,
Source
type Error = Infallible
The type returned in the event of a conversion error.
Source
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
Performs the conversion.
Source
impl<T, U> TryInto<U> for T
where
U: TryFrom<T>,
Source
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
Source
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
Performs the conversion.
Source
impl<V, T> VZip<V> for T
where
V: MultiLane<T>,
---------------------------------------------
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<Self>,
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::<f32>(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<T> Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl<T> Borrow<T> for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl<T> BorrowMut<T> for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl<T> From<T> for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source
impl<T, U> Into<U> for T
where
U: From<T>,
Source
fn into(self) -> U
Calls U::from(self).
That is, this conversion is whatever the implementation of From<T> for U chooses to do.
Source
impl<T, U> TryFrom<U> for T
where
U: Into<T>,
Source
type Error = Infallible
The type returned in the event of a conversion error.
Source
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
Performs the conversion.
Source
impl<T, U> TryInto<U> for T
where
U: TryFrom<T>,
Source
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
Source
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
Performs the conversion.
Source
impl<V, T> VZip<V> for T
where
V: MultiLane<T>,
-------------------------------------------------------
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<Self>,
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::<f32>(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<T> Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl<T> Borrow<T> for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl<T> BorrowMut<T> for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl<T> From<T> for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source
impl<T, U> Into<U> for T
where
U: From<T>,
Source
fn into(self) -> U
Calls U::from(self).
That is, this conversion is whatever the implementation of From<T> for U chooses to do.
Source
impl<T, U> TryFrom<U> for T
where
U: Into<T>,
Source
type Error = Infallible
The type returned in the event of a conversion error.
Source
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
Performs the conversion.
Source
impl<T, U> TryInto<U> for T
where
U: TryFrom<T>,
Source
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
Source
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
Performs the conversion.
Source
impl<V, T> VZip<V> for T
where
V: MultiLane<T>,
---------------------------------------------
pub struct CudaSlice<T> { /* private fields */ }
Vec<T> on a cuda device. You can allocate and modify this with CudaStream.
This object is thread safe.
Implementations
Source
impl<T> CudaSlice<T>
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<f64> = stream.alloc_zeros::<f64>(10)?;
8 let mut b = stream.alloc_zeros::<f64>(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<f64> = 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<CudaContext>
The context this belongs to
Source
pub fn stream(&self) -> &Arc<CudaStream>
The stream this object was allocated on and later will be dropped on.
Source
impl<T: DeviceRepr> CudaSlice<T>
Source
pub fn try_clone(&self) -> Result<Self, DriverError>
Allocates copy of self and schedules a device to device copy of memory.
Source
impl<T> CudaSlice<T>
Source
pub fn as_view(&self) -> CudaView<'_, T>
Source
impl<T> CudaSlice<T>
Source
pub fn as_view_mut(&mut self) -> CudaViewMut<'_, T>
Source
impl<T> CudaSlice<T>
Source
pub fn slice(&self, bounds: impl RangeBounds<usize>) -> 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::<u8>(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::<u8>(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<usize>,
) -> Option<CudaView<'_, T>>
Fallible version of CudaSlice::slice().
Source
pub fn slice_mut(
&mut self,
bounds: impl RangeBounds<usize>,
) -> 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::<u8>(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::<u8>(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::<u8>(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<usize>,
) -> Option<CudaViewMut<'_, T>>
Fallible version of CudaSlice::slice_mut
Source
pub unsafe fn transmute<S>(&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<S>(
&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::<u8>(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<T> CudaSlice<T>
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<T>
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<T>
Source
fn fmt(&self, f: &mut Formatter<'_>) -> Result
Formats the value using the given formatter. Read more
Source
impl<T> DevicePtr<T> for CudaSlice<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<T> DevicePtrMut<T> for CudaSlice<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<T> DeviceSlice<T> for CudaSlice<T>
Source
fn len(&self) -> usize
Source
fn stream(&self) -> &Arc<CudaStream>
Source
fn num_bytes(&self) -> usize
Source
fn is_empty(&self) -> bool
Source
impl<T> Drop for CudaSlice<T>
Source
fn drop(&mut self)
Executes the destructor for this type. Read more
Source
impl<'a, 'b: 'a, T> PushKernelArg<&'b CudaSlice<T>> for LaunchArgs<'a>
Source
fn arg(&mut self, arg: &'b CudaSlice<T>) -> &mut Self
Source
impl<'a, 'b: 'a, T> PushKernelArg<&'b mut CudaSlice<T>> for LaunchArgs<'a>
Source
fn arg(&mut self, arg: &'b mut CudaSlice<T>) -> &mut Self
Source
impl<T: Clone + Default + DeviceRepr> TryFrom<CudaSlice<T>> for Vec<T>
Source
type Error = DriverError
The type returned in the event of a conversion error.
Source
fn try_from(value: CudaSlice<T>) -> Result<Self, Self::Error>
Performs the conversion.
Source
impl<T> Send for CudaSlice<T>
Source
impl<T> Sync for CudaSlice<T>
Auto Trait Implementations
impl<T> Freeze for CudaSlice<T>
impl<T> RefUnwindSafe for CudaSlice<T>
where
T: RefUnwindSafe,
impl<T> Unpin for CudaSlice<T>
impl<T> UnwindSafe for CudaSlice<T>
where
T: RefUnwindSafe,
Blanket Implementations
Source
impl<T> Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl<T> Borrow<T> for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl<T> BorrowMut<T> for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl<T> 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<T> From<T> for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source
impl<T, U> Into<U> for T
where
U: From<T>,
Source
fn into(self) -> U
Calls U::from(self).
That is, this conversion is whatever the implementation of From<T> for U chooses to do.
Source
impl<T> 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<U> for T
where
U: Into<T>,
Source
type Error = Infallible
The type returned in the event of a conversion error.
Source
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
Performs the conversion.
Source
impl<T, U> TryInto<U> for T
where
U: TryFrom<T>,
Source
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
Source
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
Performs the conversion.
Source
impl<V, T> VZip<V> for T
where
V: MultiLane<T>,
-------------------------------
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<T>>(
self: &Arc<Self>,
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<T>>(
self: &Arc<Self>,
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<Self>, DriverError>
Creates 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::<f32>(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<CudaContext>
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<T>(self: &Arc<Self>) -> Result<CudaSlice<T>, DriverError>
Allocates an empty CudaSlice with 0 length.
Source
pub unsafe fn alloc<T: DeviceRepr>(
self: &Arc<Self>,
len: usize,
) -> Result<CudaSlice<T>, 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<f32> = unsafe { stream.alloc::<f32>(10) }?;
9
10 // this will have memory initialized as 0
11 let _: CudaSlice<f64> = stream.alloc_zeros::<f64>(10)?;
12
13 // initialize with slices!
14 let _: CudaSlice<usize> = stream.memcpy_stod(&[0; 10])?;
15 let _: CudaSlice<u32> = stream.memcpy_stod(&[1, 2, 3])?;
16
17 Ok(())
18}
Source
pub fn alloc_zeros<T: DeviceRepr + ValidAsZeroBits>(
self: &Arc<Self>,
len: usize,
) -> Result<CudaSlice<T>, DriverError>
Allocates a CudaSlice with len elements of type T. All values are zerod 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<f32> = unsafe { stream.alloc::<f32>(10) }?;
9
10 // this will have memory initialized as 0
11 let _: CudaSlice<f64> = stream.alloc_zeros::<f64>(10)?;
12
13 // initialize with slices!
14 let _: CudaSlice<usize> = stream.memcpy_stod(&[0; 10])?;
15 let _: CudaSlice<u32> = 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<dyn std::error::Error>> {
3 use std::fs;
4
5 use cudarc::{cufile::safe::Cufile, driver::CudaContext};
6
7 const N: usize = 100000;
8 let data: Vec<u8> = (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::<u8>(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<f64> = stream.alloc_zeros::<f64>(10)?;
8 let mut b = stream.alloc_zeros::<f64>(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<f64> = 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::<f32>(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<T>>(
self: &Arc<Self>,
dst: &mut Dst,
) -> Result<(), DriverError>
Sets all the memory in dst to 0. dst can be a CudaSlice or CudaViewMut
Source
pub fn memcpy_stod<T: DeviceRepr, Src: HostSlice<T> + ?Sized>(
self: &Arc<Self>,
src: &Src,
) -> Result<CudaSlice<T>, DriverError>
Copy a [T]/Vec<T>/PinnedHostSlice<T> 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<f32> = unsafe { stream.alloc::<f32>(10) }?;
9
10 // this will have memory initialized as 0
11 let _: CudaSlice<f64> = stream.alloc_zeros::<f64>(10)?;
12
13 // initialize with slices!
14 let _: CudaSlice<usize> = stream.memcpy_stod(&[0; 10])?;
15 let _: CudaSlice<u32> = 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::<f32>(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<T> + ?Sized, Dst: DevicePtrMut<T>>(
self: &Arc<Self>,
src: &Src,
dst: &mut Dst,
) -> Result<(), DriverError>
Copy a [T]/Vec<T>/PinnedHostSlice<T> 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<f64> = stream.alloc_zeros::<f64>(10)?;
8 let mut b = stream.alloc_zeros::<f64>(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<f64> = 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<T>>(
self: &Arc<Self>,
src: &Src,
) -> Result<Vec<T>, DriverError>
Copy a CudaSlice/CudaView to a new Vec<T>.
Examples found in repository?
examples/cufile-copy.rs (line 25)
2fn main() -> Result<(), Box<dyn std::error::Error>> {
3 use std::fs;
4
5 use cudarc::{cufile::safe::Cufile, driver::CudaContext};
6
7 const N: usize = 100000;
8 let data: Vec<u8> = (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::<u8>(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<f64> = stream.alloc_zeros::<f64>(10)?;
8 let mut b = stream.alloc_zeros::<f64>(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<f64> = 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::<f32>(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<T>, Dst: HostSlice<T> + ?Sized>(
self: &Arc<Self>,
src: &Src,
dst: &mut Dst,
) -> Result<(), DriverError>
Copy a CudaSlice/CudaView to a existing [T]/Vec<T>/PinnedHostSlice<T>.
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<f64> = stream.alloc_zeros::<f64>(10)?;
8 let mut b = stream.alloc_zeros::<f64>(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<f64> = 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<T>, Dst: DevicePtrMut<T>>(
self: &Arc<Self>,
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<f64> = stream.alloc_zeros::<f64>(10)?;
8 let mut b = stream.alloc_zeros::<f64>(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<f64> = 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<T>>(
self: &Arc<Self>,
src: &Src,
) -> Result<CudaSlice<T>, DriverError>
Copy a CudaSlice/CudaView to a new CudaSlice.
Source
impl CudaStream
Source
pub unsafe fn upgrade_device_ptr<T>(
self: &Arc<Self>,
cu_device_ptr: CUdeviceptr,
len: usize,
) -> CudaSlice<T>
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<T>() 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<Self>,
flags: CUgraphInstantiate_flags,
) -> Result<Option<CudaGraph>, 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::<f32>(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<T> Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl<T> Borrow<T> for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl<T> BorrowMut<T> for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl<T> From<T> for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source
impl<T, U> Into<U> for T
where
U: From<T>,
Source
fn into(self) -> U
Calls U::from(self).
That is, this conversion is whatever the implementation of From<T> for U chooses to do.
Source
impl<T, U> TryFrom<U> for T
where
U: Into<T>,
Source
type Error = Infallible
The type returned in the event of a conversion error.
Source
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
Performs the conversion.
Source
impl<T, U> TryInto<U> for T
where
U: TryFrom<T>,
Source
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
Source
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
Performs the conversion.
Source
impl<V, T> VZip<V> for T
where
V: MultiLane<T>,
-------------------------------------------
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<T> 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<usize>) -> 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::<u8>(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<usize>) -> Option<Self>
Fallible version of CudaView::slice
Source
pub unsafe fn transmute<S>(&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<T> DevicePtr<T> 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<T> DeviceSlice<T> for CudaView<'_, T>
Source
fn len(&self) -> usize
Source
fn stream(&self) -> &Arc<CudaStream>
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<T> Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl<T> Borrow<T> for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl<T> BorrowMut<T> for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl<T> From<T> for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source
impl<T, U> Into<U> for T
where
U: From<T>,
Source
fn into(self) -> U
Calls U::from(self).
That is, this conversion is whatever the implementation of From<T> for U chooses to do.
Source
impl<T, U> TryFrom<U> for T
where
U: Into<T>,
Source
type Error = Infallible
The type returned in the event of a conversion error.
Source
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
Performs the conversion.
Source
impl<T, U> TryInto<U> for T
where
U: TryFrom<T>,
Source
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
Source
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
Performs the conversion.
Source
impl<V, T> VZip<V> for T
where
V: MultiLane<T>,
------------------------------------------------------
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<T> 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<usize>,
) -> 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::<u8>(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::<u8>(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<usize>,
) -> Option<CudaView<'a, T>>
Fallible version of CudaViewMut::slice
Source
pub unsafe fn transmute<S>(&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<usize>) -> 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<usize>) -> Option<Self>
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::<u8>(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<S>(
&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<T> DevicePtr<T> 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<T> DevicePtrMut<T> 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<T> DeviceSlice<T> for CudaViewMut<'_, T>
Source
fn len(&self) -> usize
Source
fn stream(&self) -> &Arc<CudaStream>
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<T> Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl<T> Borrow<T> for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl<T> BorrowMut<T> for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl<T> From<T> for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source
impl<T, U> Into<U> for T
where
U: From<T>,
Source
fn into(self) -> U
Calls U::from(self).
That is, this conversion is whatever the implementation of From<T> for U chooses to do.
Source
impl<T, U> TryFrom<U> for T
where
U: Into<T>,
Source
type Error = Infallible
The type returned in the event of a conversion error.
Source
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
Performs the conversion.
Source
impl<T, U> TryInto<U> for T
where
U: TryFrom<T>,
Source
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
Source
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
Performs the conversion.
Source
impl<V, T> VZip<V> for T
where
V: MultiLane<T>,
--------------------------------------------------
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<usize>) -> 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<T> Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl<T> Borrow<T> for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl<T> BorrowMut<T> for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl<T> From<T> for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source
impl<T, U> Into<U> for T
where
U: From<T>,
Source
fn into(self) -> U
Calls U::from(self).
That is, this conversion is whatever the implementation of From<T> for U chooses to do.
Source
impl<T, U> TryFrom<U> for T
where
U: Into<T>,
Source
type Error = Infallible
The type returned in the event of a conversion error.
Source
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
Performs the conversion.
Source
impl<T, U> TryInto<U> for T
where
U: TryFrom<T>,
Source
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
Source
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
Performs the conversion.
Source
impl<V, T> VZip<V> for T
where
V: MultiLane<T>,
------------------------------------------------------------
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<T> 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 cant guarantee that the arguments are valid for the configured CudaFunction. We dont know if the types are correct, if the arguments are in the correct order, if the types are representable in CUDA, etc.
We cant 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 cant 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::<f32>(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<T>> for LaunchArgs<'a>
Source
fn arg(&mut self, arg: &'b CudaSlice<T>) -> &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<T>> for LaunchArgs<'a>
Source
fn arg(&mut self, arg: &'b UnifiedSlice<T>) -> &mut Self
Source
impl<'a, 'b: 'a, T> PushKernelArg<&'b mut CudaSlice<T>> for LaunchArgs<'a>
Source
fn arg(&mut self, arg: &'b mut CudaSlice<T>) -> &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<T>> for LaunchArgs<'a>
Source
fn arg(&mut self, arg: &'b mut UnifiedSlice<T>) -> &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<T> Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl<T> Borrow<T> for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl<T> BorrowMut<T> for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl<T> From<T> for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source
impl<T, U> Into<U> for T
where
U: From<T>,
Source
fn into(self) -> U
Calls U::from(self).
That is, this conversion is whatever the implementation of From<T> for U chooses to do.
Source
impl<T, U> TryFrom<U> for T
where
U: Into<T>,
Source
type Error = Infallible
The type returned in the event of a conversion error.
Source
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
Performs the conversion.
Source
impl<T, U> TryInto<U> for T
where
U: TryFrom<T>,
Source
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
Source
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
Performs the conversion.
Source
impl<V, T> VZip<V> for T
where
V: MultiLane<T>,
---------------------------------------------------------------
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::<f32>(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<T> Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl<T> Borrow<T> for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl<T> BorrowMut<T> for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl<T> 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<T> From<T> for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source
impl<T, U> Into<U> for T
where
U: From<T>,
Source
fn into(self) -> U
Calls U::from(self).
That is, this conversion is whatever the implementation of From<T> for U chooses to do.
Source
impl<T> 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<U> for T
where
U: Into<T>,
Source
type Error = Infallible
The type returned in the event of a conversion error.
Source
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
Performs the conversion.
Source
impl<T, U> TryInto<U> for T
where
U: TryFrom<T>,
Source
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
Source
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
Performs the conversion.
Source
impl<V, T> VZip<V> for T
where
V: MultiLane<T>,
--------------------------------------------------------------
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<u8> 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<u8> for MappedBuffer
Source
fn len(&self) -> usize
Source
fn stream(&self) -> &Arc<CudaStream>
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<T> Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl<T> Borrow<T> for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl<T> BorrowMut<T> for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl<T> From<T> for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source
impl<T, U> Into<U> for T
where
U: From<T>,
Source
fn into(self) -> U
Calls U::from(self).
That is, this conversion is whatever the implementation of From<T> for U chooses to do.
Source
impl<T, U> TryFrom<U> for T
where
U: Into<T>,
Source
type Error = Infallible
The type returned in the event of a conversion error.
Source
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
Performs the conversion.
Source
impl<T, U> TryInto<U> for T
where
U: TryFrom<T>,
Source
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
Source
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
Performs the conversion.
Source
impl<V, T> VZip<V> for T
where
V: MultiLane<T>,
----------------------------------------------------------
pub struct PinnedHostSlice<T> { /* private fields */ }
Rust side data that the cuda driver knows is pinned. This is different than Pin<Vec<T>> 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<T> PinnedHostSlice<T>
Source
pub fn context(&self) -> &Arc<CudaContext>
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<T>
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<T>
Source
fn fmt(&self, f: &mut Formatter<'_>) -> Result
Formats the value using the given formatter. Read more
Source
impl<T> Drop for PinnedHostSlice<T>
Source
fn drop(&mut self)
Executes the destructor for this type. Read more
Source
impl<T> HostSlice<T> for PinnedHostSlice<T>
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<T> Send for PinnedHostSlice<T>
Source
impl<T> Sync for PinnedHostSlice<T>
Auto Trait Implementations
impl<T> Freeze for PinnedHostSlice<T>
impl<T> RefUnwindSafe for PinnedHostSlice<T>
where
T: RefUnwindSafe,
impl<T> Unpin for PinnedHostSlice<T>
impl<T> UnwindSafe for PinnedHostSlice<T>
where
T: RefUnwindSafe,
Blanket Implementations
Source§
impl<T> Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl<T> Borrow<T> for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl<T> BorrowMut<T> for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl<T> From<T> for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source
impl<T, U> Into<U> for T
where
U: From<T>,
Source
fn into(self) -> U
Calls U::from(self).
That is, this conversion is whatever the implementation of From<T> for U chooses to do.
Source
impl<T, U> TryFrom<U> for T
where
U: Into<T>,
Source
type Error = Infallible
The type returned in the event of a conversion error.
Source
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
Performs the conversion.
Source
impl<T, U> TryInto<U> for T
where
U: TryFrom<T>,
Source
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
Source
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
Performs the conversion.
Source
impl<V, T> VZip<V> for T
where
V: MultiLane<T>,
----------------------------------------------------------
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<T> Any for T
where
T: 'static + ?Sized,
Source
fn type_id(&self) -> TypeId
Gets the TypeId of self. Read more
Source
impl<T> Borrow<T> for T
where
T: ?Sized,
Source
fn borrow(&self) -> &T
Immutably borrows from an owned value. Read more
Source
impl<T> BorrowMut<T> for T
where
T: ?Sized,
Source
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source
impl<T> From<T> for T
Source
fn from(t: T) -> T
Returns the argument unchanged.
Source
impl<T, U> Into<U> for T
where
U: From<T>,
Source
fn into(self) -> U
Calls U::from(self).
That is, this conversion is whatever the implementation of From<T> for U chooses to do.
Source
impl<T, U> TryFrom<U> for T
where
U: Into<T>,
Source
type Error = Infallible
The type returned in the event of a conversion error.
Source
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
Performs the conversion.
Source
impl<T, U> TryInto<U> for T
where
U: TryFrom<T>,
Source
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
Source
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
Performs the conversion.
Source
impl<V, T> VZip<V> for T
where
V: MultiLane<T>,