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/// # 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}