oxicuda_runtime/profiler.rs
1//! CUDA profiler control.
2//!
3//! Implements:
4//! - `cudaProfilerStart`
5//! - `cudaProfilerStop`
6//!
7//! These allow application code to bracket regions of interest for profiling
8//! tools such as Nsight Systems or nvprof.
9
10use oxicuda_driver::loader::try_driver;
11
12use crate::error::{CudaRtError, CudaRtResult};
13
14/// Start the CUDA profiler.
15///
16/// Mirrors `cudaProfilerStart`. Must be paired with [`profiler_stop`].
17///
18/// # Errors
19///
20/// Propagates driver errors (e.g., profiler not initialised).
21pub fn profiler_start() -> CudaRtResult<()> {
22 let api = try_driver().map_err(|_| CudaRtError::DriverNotAvailable)?;
23 // SAFETY: FFI; no user data involved. cu_profiler_start is optional.
24 let f = api.cu_profiler_start.ok_or(CudaRtError::NotSupported)?;
25 let rc = unsafe { f() };
26 if rc != 0 {
27 return Err(CudaRtError::from_code(rc).unwrap_or(CudaRtError::ProfilerDisabled));
28 }
29 Ok(())
30}
31
32/// Stop the CUDA profiler.
33///
34/// Mirrors `cudaProfilerStop`.
35///
36/// # Errors
37///
38/// Propagates driver errors.
39pub fn profiler_stop() -> CudaRtResult<()> {
40 let api = try_driver().map_err(|_| CudaRtError::DriverNotAvailable)?;
41 // SAFETY: FFI. cu_profiler_stop is optional.
42 let f = api.cu_profiler_stop.ok_or(CudaRtError::NotSupported)?;
43 let rc = unsafe { f() };
44 if rc != 0 {
45 return Err(CudaRtError::from_code(rc).unwrap_or(CudaRtError::ProfilerDisabled));
46 }
47 Ok(())
48}
49
50/// RAII guard that calls [`profiler_start`] on construction and
51/// [`profiler_stop`] on drop.
52///
53/// # Example
54///
55/// ```rust,no_run
56/// # use oxicuda_runtime::profiler::ProfilerGuard;
57/// let _guard = ProfilerGuard::new().unwrap();
58/// // profiling active here …
59/// // dropped → profiler_stop called automatically
60/// ```
61pub struct ProfilerGuard {
62 active: bool,
63}
64
65impl ProfilerGuard {
66 /// Start profiling and return a guard.
67 ///
68 /// # Errors
69 ///
70 /// Propagates [`profiler_start`] errors.
71 pub fn new() -> CudaRtResult<Self> {
72 profiler_start()?;
73 Ok(Self { active: true })
74 }
75
76 /// Stop profiling early (also called on drop).
77 pub fn stop(&mut self) {
78 if self.active {
79 let _ = profiler_stop();
80 self.active = false;
81 }
82 }
83}
84
85impl Drop for ProfilerGuard {
86 fn drop(&mut self) {
87 self.stop();
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn profiler_start_without_gpu_returns_error() {
97 // Must not panic regardless of GPU presence.
98 let _ = profiler_start();
99 }
100
101 #[test]
102 fn profiler_stop_without_gpu_returns_error() {
103 let _ = profiler_stop();
104 }
105}