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/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
58/// let _guard = ProfilerGuard::new()?;
59/// // profiling active here …
60/// // dropped → profiler_stop called automatically
61/// # Ok(())
62/// # }
63/// ```
64pub struct ProfilerGuard {
65 active: bool,
66}
67
68impl ProfilerGuard {
69 /// Start profiling and return a guard.
70 ///
71 /// # Errors
72 ///
73 /// Propagates [`profiler_start`] errors.
74 pub fn new() -> CudaRtResult<Self> {
75 profiler_start()?;
76 Ok(Self { active: true })
77 }
78
79 /// Stop profiling early (also called on drop).
80 pub fn stop(&mut self) {
81 if self.active {
82 let _ = profiler_stop();
83 self.active = false;
84 }
85 }
86}
87
88impl Drop for ProfilerGuard {
89 fn drop(&mut self) {
90 self.stop();
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn profiler_start_without_gpu_returns_error() {
100 // Must not panic regardless of GPU presence.
101 let _ = profiler_start();
102 }
103
104 #[test]
105 fn profiler_stop_without_gpu_returns_error() {
106 let _ = profiler_stop();
107 }
108}