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