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}