Skip to main content

oxicuda_driver/
profiler.rs

1//! CUDA profiler control.
2//!
3//! Start and stop the CUDA profiler programmatically, or use the
4//! [`ProfilerGuard`] RAII type to scope profiling to a block.
5//!
6//! # Example
7//!
8//! ```rust,no_run
9//! # use oxicuda_driver::profiler;
10//! # fn main() -> Result<(), oxicuda_driver::CudaError> {
11//! {
12//!     let _guard = profiler::ProfilerGuard::start()?;
13//!     // ... GPU work to profile ...
14//! } // profiler stops here
15//! # Ok(())
16//! # }
17//! ```
18
19use crate::error::{CudaError, CudaResult};
20use crate::loader::try_driver;
21
22/// Starts the CUDA profiler (e.g. Nsight Systems / nvprof).
23///
24/// # Errors
25///
26/// Returns [`CudaError::NotSupported`] if the driver lacks `cuProfilerStart`,
27/// or another error on failure.
28pub fn profiler_start() -> CudaResult<()> {
29    let api = try_driver()?;
30    let f = api.cu_profiler_start.ok_or(CudaError::NotSupported)?;
31    crate::cuda_call!(f())
32}
33
34/// Stops the CUDA profiler.
35///
36/// # Errors
37///
38/// Returns [`CudaError::NotSupported`] if the driver lacks `cuProfilerStop`,
39/// or another error on failure.
40pub fn profiler_stop() -> CudaResult<()> {
41    let api = try_driver()?;
42    let f = api.cu_profiler_stop.ok_or(CudaError::NotSupported)?;
43    crate::cuda_call!(f())
44}
45
46/// RAII guard that starts the CUDA profiler on creation and stops it on drop.
47///
48/// This is useful for scoping profiling to a specific block of code.
49/// If the profiler fails to stop on drop, the error is silently ignored
50/// (since `Drop::drop` cannot return errors).
51pub struct ProfilerGuard {
52    _private: (),
53}
54
55impl ProfilerGuard {
56    /// Starts the CUDA profiler and returns a guard that will stop it on drop.
57    ///
58    /// # Errors
59    ///
60    /// Returns an error if `profiler_start()` fails.
61    pub fn start() -> CudaResult<Self> {
62        profiler_start()?;
63        Ok(Self { _private: () })
64    }
65}
66
67impl Drop for ProfilerGuard {
68    fn drop(&mut self) {
69        // Best-effort stop; we cannot propagate errors from Drop.
70        let _ = profiler_stop();
71    }
72}
73
74// ---------------------------------------------------------------------------
75// Tests
76// ---------------------------------------------------------------------------
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn profiler_start_returns_error_without_gpu() {
84        let result = profiler_start();
85        // On macOS or without a GPU driver, this should fail gracefully.
86        let _ = result;
87    }
88
89    #[test]
90    fn profiler_stop_returns_error_without_gpu() {
91        let result = profiler_stop();
92        let _ = result;
93    }
94
95    #[test]
96    fn profiler_guard_does_not_panic_without_gpu() {
97        // start() will fail, so the guard should not be created,
98        // and no panic should occur.
99        let result = ProfilerGuard::start();
100        let _ = result;
101    }
102}