Skip to main content

singe_nvml/
unit.rs

1#[allow(unused_imports)]
2use crate::error::Status;
3
4use std::{mem::MaybeUninit, ptr};
5
6use singe_nvml_sys as sys;
7
8use crate::{
9    device::Device,
10    error::Result,
11    try_ffi,
12    types::{
13        FanState, LedState, PsuInfo, UnitFanInfo, UnitFanSpeeds, UnitInfo, UnitTemperature,
14        UnitTemperatureType,
15    },
16};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19#[repr(transparent)]
20pub struct Unit(sys::nvmlUnit_t);
21
22impl Unit {
23    pub const unsafe fn from_raw(handle: sys::nvmlUnit_t) -> Self {
24        Self(handle)
25    }
26
27    pub const fn as_raw(self) -> sys::nvmlUnit_t {
28        self.0
29    }
30
31    pub const fn is_null(self) -> bool {
32        self.0.is_null()
33    }
34
35    /// Returns the static information associated with a unit.
36    ///
37    /// For S-class products.
38    ///
39    /// Returns the static unit information reported by NVML.
40    ///
41    /// # Errors
42    ///
43    /// Returns an error if the unit handle or output argument is invalid, or if
44    /// NVML has not been initialized.
45    pub fn info(self) -> Result<UnitInfo> {
46        unsafe {
47            let mut info = MaybeUninit::<sys::nvmlUnitInfo_t>::uninit();
48            try_ffi!(sys::nvmlUnitGetUnitInfo(self.0, info.as_mut_ptr()))?;
49            Ok(info.assume_init().into())
50        }
51    }
52
53    /// Returns the LED state associated with this unit.
54    ///
55    /// For S-class products.
56    ///
57    /// Returns the LED state reported by NVML.
58    ///
59    /// # Errors
60    ///
61    /// Returns an error if the unit handle or output argument is invalid, if this
62    /// is not an S-class product, if NVML has not been initialized, or if NVML
63    /// reports an unexpected failure.
64    pub fn led_state(self) -> Result<LedState> {
65        unsafe {
66            let mut state = MaybeUninit::<sys::nvmlLedState_t>::uninit();
67            try_ffi!(sys::nvmlUnitGetLedState(self.0, state.as_mut_ptr()))?;
68            Ok(state.assume_init().into())
69        }
70    }
71
72    /// Returns the PSU stats for the unit.
73    ///
74    /// For S-class products.
75    ///
76    /// Returns the PSU information reported by NVML.
77    ///
78    /// # Errors
79    ///
80    /// Returns an error if the unit handle or output argument is invalid, if this
81    /// is not an S-class product, if NVML has not been initialized, or if NVML
82    /// reports an unexpected failure.
83    pub fn psu_info(self) -> Result<PsuInfo> {
84        unsafe {
85            let mut info = MaybeUninit::<sys::nvmlPSUInfo_t>::uninit();
86            try_ffi!(sys::nvmlUnitGetPsuInfo(self.0, info.as_mut_ptr()))?;
87            Ok(info.assume_init().into())
88        }
89    }
90
91    /// Returns the temperature readings for the unit, in degrees C.
92    ///
93    /// For S-class products.
94    ///
95    /// Depending on the product, readings may be available for intake (type=0), exhaust (type=1) and board (type=2).
96    ///
97    /// # Errors
98    ///
99    /// Returns an error if the unit handle, temperature type, or output argument is
100    /// invalid, if this is not an S-class product, if NVML has not been initialized,
101    /// or if NVML reports an unexpected failure.
102    pub fn temperature(self, kind: UnitTemperatureType) -> Result<UnitTemperature> {
103        let mut temperature = 0;
104        unsafe {
105            try_ffi!(sys::nvmlUnitGetTemperature(
106                self.0,
107                kind.into(),
108                &raw mut temperature,
109            ))?;
110        }
111        Ok(UnitTemperature { kind, temperature })
112    }
113
114    /// Returns the fan speed readings for the unit.
115    ///
116    /// For S-class products.
117    ///
118    /// Returns the fan speed information reported by NVML.
119    ///
120    /// # Errors
121    ///
122    /// Returns an error if the unit handle or output argument is invalid, if this
123    /// is not an S-class product, if NVML has not been initialized, or if NVML
124    /// reports an unexpected failure.
125    pub fn fan_speeds(self) -> Result<UnitFanSpeeds> {
126        let mut fan_speeds = sys::nvmlUnitFanSpeeds_t::default();
127        unsafe {
128            try_ffi!(sys::nvmlUnitGetFanSpeedInfo(self.0, &raw mut fan_speeds))?;
129        }
130        let fans = fan_speeds.fans[..fan_speeds.count as usize]
131            .iter()
132            .copied()
133            .map(|fan| UnitFanInfo {
134                speed: fan.speed,
135                state: FanState::from(fan.state),
136            })
137            .collect();
138        Ok(UnitFanSpeeds { fans })
139    }
140
141    /// Returns the set of GPU devices that are attached to the specified unit.
142    ///
143    /// For S-class products.
144    ///
145    /// This wrapper queries the device count internally and returns attached devices as a [`Vec`].
146    ///
147    /// # Errors
148    ///
149    /// Returns an error if the internal device buffer is too small, if the unit
150    /// handle or query arguments are invalid, if NVML has not been initialized, or
151    /// if NVML reports an unexpected failure.
152    pub fn devices(self) -> Result<Vec<Device>> {
153        let mut count = 0;
154        let status = unsafe { sys::nvmlUnitGetDevices(self.0, &raw mut count, ptr::null_mut()) };
155        if status == sys::nvmlReturn_t::NVML_SUCCESS && count == 0 {
156            return Ok(Vec::new());
157        }
158        if status != sys::nvmlReturn_t::NVML_ERROR_INSUFFICIENT_SIZE {
159            return Err(status.into());
160        }
161
162        let mut devices = vec![ptr::null_mut(); count as usize];
163        unsafe {
164            try_ffi!(sys::nvmlUnitGetDevices(
165                self.0,
166                &raw mut count,
167                devices.as_mut_ptr()
168            ))?;
169        }
170        devices.truncate(count as usize);
171        Ok(devices
172            .into_iter()
173            .map(|handle| unsafe { Device::from_raw(handle) })
174            .collect())
175    }
176}