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}