cuda_std/io.rs
1//! Utilities for printing to stdout from GPU threads.
2//!
3//! CUDA contains a syscall named `vprintf` which provides a way of atomically
4//! printing from GPU threads, this module provides safe wrappers over it.
5//! Printing is atomic, meaning that simultaneous calls from different
6//! threads (which will naturally happen) will not clash with eachother
7//! unlike printing from multiple CPU threads.
8//!
9//! # Important Notes
10//!
11//! Printing output in CUDA is stored inside of a circular buffer which has a fixed size (1mb by default).
12//! If the buffer is filled, old output will be overwritten.
13//!
14//! This buffer is flushed for:
15//! - Kernel launches
16//! - Synchronization (stream/device synchronization)
17//! - Blocking memory copies
18//! - Module load/unload
19//! - Context destruction
20//!
21//! This does NOT include exiting the program, however, because rust uses RAII, unless you leak the
22//! context, output will always be flushed.
23
24extern "C" {
25 // CUDA syscalls implicitly defined by nvvm you can link to.
26
27 #[doc(hidden)]
28 pub fn vprintf(format: *const u8, valist: *const core::ffi::c_void) -> i32;
29
30 #[doc(hidden)]
31 pub fn __assertfail(
32 message: *const u8,
33 file: *const u8,
34 line: u32,
35 function: *const u8,
36 char_size: usize,
37 );
38}
39
40/// Alternative to [`print!`](std::print) which works on CUDA. See [`print`](self) for more info.
41#[macro_export]
42macro_rules! print {
43 ($($arg:tt)*) => {
44 let msg = ::alloc::format!($($arg)*);
45 let cstring = ::alloc::format!("{}\0", msg);
46 unsafe {
47 $crate::io::vprintf(cstring.as_ptr(), ::core::ptr::null_mut());
48 }
49 }
50}
51
52/// Alternative to [`println!`](std::println) which works on CUDA. See [`print`](self) for more info.
53#[macro_export]
54macro_rules! println {
55 () => ($crate::print!("\n"));
56 ($fmt:expr) => ($crate::print!(concat!($fmt, "\n")));
57 ($fmt:expr, $($arg:tt)*) => ($crate::print!(concat!($fmt, "\n"), $($arg)*));
58}
59
60/// Asserts that two expression are equal and returns an `AssertionFailed` error to the application that launched the kernel
61/// if it is not true.
62#[macro_export]
63macro_rules! assert_eq {
64 ($a:expr, $b:expr) => {
65 let _a = $a;
66 let _b = $b;
67
68 if _a != _b {
69 let msg = ::alloc::format!(
70 "\nassertion failed: ({} == {})\nleft : {:?}\nright: {:?}",
71 stringify!($a),
72 stringify!($b),
73 _a,
74 _b
75 );
76
77 unsafe {
78 $crate::io::__assertfail(msg.as_ptr(), file!().as_ptr(), line!(), "".as_ptr(), 1)
79 };
80 }
81 };
82}
83
84/// Asserts that two expression are not equal and returns an `AssertionFailed` error to the application that launched the kernel
85/// if it is not true.
86#[macro_export]
87macro_rules! assert_ne {
88 ($a:expr, $b:expr) => {
89 let _a = $a;
90 let _b = $b;
91
92 if _a == _b {
93 let msg = ::alloc::format!(
94 "\nassertion failed: ({} != {})\nleft : {:?}\nright: {:?}",
95 stringify!($a),
96 stringify!($b),
97 _a,
98 _b
99 );
100
101 unsafe {
102 $crate::io::__assertfail(msg.as_ptr(), file!().as_ptr(), line!(), "".as_ptr(), 1)
103 };
104 }
105 };
106}