Skip to main content

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}