Skip to main content

nvml_wrapper/enums/
device.rs

1use std::convert::TryFrom;
2use std::fmt::Display;
3use std::os::raw::c_uint;
4
5use crate::enum_wrappers::device::{ClockLimitId, SampleValueType};
6use crate::error::NvmlError;
7use crate::ffi::bindings::*;
8#[cfg(feature = "serde")]
9use serde_derive::{Deserialize, Serialize};
10
11/// Respresents possible variants for a firmware version.
12#[derive(Debug, Clone, Eq, PartialEq, Hash)]
13#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
14pub enum FirmwareVersion {
15    /// The version is unavailable.
16    Unavailable,
17    Version(u32),
18}
19
20impl From<u32> for FirmwareVersion {
21    fn from(value: u32) -> Self {
22        match value {
23            0 => FirmwareVersion::Unavailable,
24            _ => FirmwareVersion::Version(value),
25        }
26    }
27}
28
29/// Represents possible variants for used GPU memory.
30// Checked
31#[derive(Debug, Clone, Eq, PartialEq, Hash)]
32#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
33pub enum UsedGpuMemory {
34    /// Under WDDM, `NVML_VALUE_NOT_AVAILABLE` is always reported because
35    /// Windows KMD manages all the memory, not the NVIDIA driver.
36    Unavailable,
37    /// Memory used in bytes.
38    Used(u64),
39}
40
41impl From<u64> for UsedGpuMemory {
42    fn from(value: u64) -> Self {
43        let not_available = (NVML_VALUE_NOT_AVAILABLE) as u64;
44
45        match value {
46            v if v == not_available => UsedGpuMemory::Unavailable,
47            _ => UsedGpuMemory::Used(value),
48        }
49    }
50}
51
52/// Represents different types of sample values.
53// Checked against local
54#[derive(Debug, Clone, PartialEq)]
55#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
56pub enum SampleValue {
57    F64(f64),
58    U32(u32),
59    U64(u64),
60    I64(i64),
61}
62
63impl SampleValue {
64    pub fn from_tag_and_union(tag: &SampleValueType, union: nvmlValue_t) -> Self {
65        use self::SampleValueType::*;
66
67        unsafe {
68            match *tag {
69                Double => SampleValue::F64(union.dVal),
70                UnsignedInt => SampleValue::U32(union.uiVal),
71                // Methodology: NVML supports 32-bit Linux. UL is u32 on that platform.
72                // NVML wouldn't return anything larger
73                #[allow(clippy::unnecessary_cast)]
74                UnsignedLong => SampleValue::U32(union.ulVal as u32),
75                UnsignedLongLong => SampleValue::U64(union.ullVal),
76                SignedLongLong => SampleValue::I64(union.sllVal),
77            }
78        }
79    }
80}
81
82/// Represents different types of sample values.
83#[derive(Debug, Clone, Eq, PartialEq, Hash)]
84#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
85pub enum GpuLockedClocksSetting {
86    /// Numeric setting that allows you to explicitly define minimum and
87    /// maximum clock frequencies.
88    Numeric {
89        min_clock_mhz: u32,
90        max_clock_mhz: u32,
91    },
92    /// Symbolic setting that allows you to define lower and upper bounds for
93    /// clock speed with various possibilities.
94    ///
95    /// Not all combinations of `lower_bound` and `upper_bound` are valid.
96    /// Please see the docs for `nvmlDeviceSetGpuLockedClocks` in `nvml.h` to
97    /// learn more.
98    Symbolic {
99        lower_bound: ClockLimitId,
100        upper_bound: ClockLimitId,
101    },
102}
103
104impl GpuLockedClocksSetting {
105    /// Returns `(min_clock_mhz, max_clock_mhz)`.
106    pub fn into_min_and_max_clocks(self) -> (u32, u32) {
107        match self {
108            GpuLockedClocksSetting::Numeric {
109                min_clock_mhz,
110                max_clock_mhz,
111            } => (min_clock_mhz, max_clock_mhz),
112            GpuLockedClocksSetting::Symbolic {
113                lower_bound,
114                upper_bound,
115            } => (lower_bound.as_c(), upper_bound.as_c()),
116        }
117    }
118}
119
120/// Returned by [`crate::Device::bus_type()`].
121// TODO: technically this is an "enum wrapper" but the type on the C side isn't
122// an enum
123#[derive(Debug, Clone, Eq, PartialEq, Hash)]
124#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
125pub enum BusType {
126    /// Unknown bus type.
127    Unknown,
128    /// PCI (Peripheral Component Interconnect) bus type.
129    Pci,
130    /// PCIE (Peripheral Component Interconnect Express) bus type.
131    ///
132    /// This is the most common bus type.
133    Pcie,
134    /// FPCI (Fast Peripheral Component Interconnect) bus type.
135    Fpci,
136    /// AGP (Accelerated Graphics Port) bus type.
137    ///
138    /// This is old and was dropped in favor of PCIE.
139    Agp,
140}
141
142impl BusType {
143    /// Returns the C constant equivalent for the given Rust enum variant.
144    pub fn as_c(&self) -> nvmlBusType_t {
145        match *self {
146            Self::Unknown => NVML_BUS_TYPE_UNKNOWN,
147            Self::Pci => NVML_BUS_TYPE_PCI,
148            Self::Pcie => NVML_BUS_TYPE_PCIE,
149            Self::Fpci => NVML_BUS_TYPE_FPCI,
150            Self::Agp => NVML_BUS_TYPE_AGP,
151        }
152    }
153}
154
155impl TryFrom<nvmlBusType_t> for BusType {
156    type Error = NvmlError;
157
158    fn try_from(data: nvmlBusType_t) -> Result<Self, Self::Error> {
159        match data {
160            NVML_BUS_TYPE_UNKNOWN => Ok(Self::Unknown),
161            NVML_BUS_TYPE_PCI => Ok(Self::Pci),
162            NVML_BUS_TYPE_PCIE => Ok(Self::Pcie),
163            NVML_BUS_TYPE_FPCI => Ok(Self::Fpci),
164            NVML_BUS_TYPE_AGP => Ok(Self::Agp),
165            _ => Err(NvmlError::UnexpectedVariant(data)),
166        }
167    }
168}
169
170/// Returned by [`crate::Device::power_source()`].
171// TODO: technically this is an "enum wrapper" but the type on the C side isn't
172// an enum
173#[derive(Debug, Clone, Eq, PartialEq, Hash)]
174#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
175pub enum PowerSource {
176    /// AC power (receiving power from some external source).
177    Ac,
178    /// Battery power.
179    Battery,
180}
181
182impl PowerSource {
183    /// Returns the C constant equivalent for the given Rust enum variant.
184    pub fn as_c(&self) -> nvmlPowerSource_t {
185        match *self {
186            Self::Ac => NVML_POWER_SOURCE_AC,
187            Self::Battery => NVML_POWER_SOURCE_BATTERY,
188        }
189    }
190}
191
192impl TryFrom<nvmlPowerSource_t> for PowerSource {
193    type Error = NvmlError;
194
195    fn try_from(data: nvmlPowerSource_t) -> Result<Self, Self::Error> {
196        match data {
197            NVML_POWER_SOURCE_AC => Ok(Self::Ac),
198            NVML_POWER_SOURCE_BATTERY => Ok(Self::Battery),
199            _ => Err(NvmlError::UnexpectedVariant(data)),
200        }
201    }
202}
203
204/// PowerMizer mode preference for GPU performance management.
205// TODO: technically this is an "enum wrapper" but the type on the C side isn't
206// an enum
207#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
208#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
209pub enum PowerMizerMode {
210    /// Adjust GPU clocks based on GPU utilization.
211    Adaptive,
212    /// Raise GPU clocks to favor maximum performance, within thermal and other constraints.
213    PreferMaximumPerformance,
214    /// Let the driver choose the performance policy.
215    Auto,
216    /// Lock to GPU base clocks.
217    PreferConsistentPerformance,
218}
219
220impl PowerMizerMode {
221    /// Returns the C constant equivalent for the given Rust enum variant.
222    pub fn as_c(&self) -> c_uint {
223        match *self {
224            Self::Adaptive => NVML_POWER_MIZER_MODE_ADAPTIVE,
225            Self::PreferMaximumPerformance => NVML_POWER_MIZER_MODE_PREFER_MAXIMUM_PERFORMANCE,
226            Self::Auto => NVML_POWER_MIZER_MODE_AUTO,
227            Self::PreferConsistentPerformance => {
228                NVML_POWER_MIZER_MODE_PREFER_CONSISTENT_PERFORMANCE
229            }
230        }
231    }
232}
233
234impl TryFrom<c_uint> for PowerMizerMode {
235    type Error = NvmlError;
236
237    fn try_from(data: c_uint) -> Result<Self, Self::Error> {
238        match data {
239            NVML_POWER_MIZER_MODE_ADAPTIVE => Ok(Self::Adaptive),
240            NVML_POWER_MIZER_MODE_PREFER_MAXIMUM_PERFORMANCE => Ok(Self::PreferMaximumPerformance),
241            NVML_POWER_MIZER_MODE_AUTO => Ok(Self::Auto),
242            NVML_POWER_MIZER_MODE_PREFER_CONSISTENT_PERFORMANCE => {
243                Ok(Self::PreferConsistentPerformance)
244            }
245            _ => Err(NvmlError::UnexpectedVariant(data)),
246        }
247    }
248}
249
250/// Returned by [`crate::Device::architecture()`].
251///
252/// This is the simplified chip architecture of the device.
253// TODO: technically this is an "enum wrapper" but the type on the C side isn't
254// an enum
255#[derive(Debug, Clone, Eq, PartialEq, Hash)]
256#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
257pub enum DeviceArchitecture {
258    /// <https://en.wikipedia.org/wiki/Kepler_(microarchitecture)>
259    Kepler,
260    /// <https://en.wikipedia.org/wiki/Maxwell_(microarchitecture)>
261    Maxwell,
262    /// <https://en.wikipedia.org/wiki/Pascal_(microarchitecture)>
263    Pascal,
264    /// <https://en.wikipedia.org/wiki/Volta_(microarchitecture)>
265    Volta,
266    /// <https://en.wikipedia.org/wiki/Turing_(microarchitecture)>
267    Turing,
268    /// <https://en.wikipedia.org/wiki/Ampere_(microarchitecture)>
269    Ampere,
270    /// <https://en.wikipedia.org/wiki/Ada_Lovelace_(microarchitecture)>
271    Ada,
272    /// <https://en.wikipedia.org/wiki/Hopper_(microarchitecture)>
273    Hopper,
274    /// https://en.wikipedia.org/wiki/Blackwell_(microarchitecture)
275    Blackwell,
276    /// Unknown device architecture (most likely something newer).
277    Unknown,
278}
279
280impl DeviceArchitecture {
281    /// Returns the C constant equivalent for the given Rust enum variant.
282    pub fn as_c(&self) -> nvmlDeviceArchitecture_t {
283        match *self {
284            Self::Kepler => NVML_DEVICE_ARCH_KEPLER,
285            Self::Maxwell => NVML_DEVICE_ARCH_MAXWELL,
286            Self::Pascal => NVML_DEVICE_ARCH_PASCAL,
287            Self::Volta => NVML_DEVICE_ARCH_VOLTA,
288            Self::Turing => NVML_DEVICE_ARCH_TURING,
289            Self::Ampere => NVML_DEVICE_ARCH_AMPERE,
290            Self::Ada => NVML_DEVICE_ARCH_ADA,
291            Self::Hopper => NVML_DEVICE_ARCH_HOPPER,
292            Self::Blackwell => NVML_DEVICE_ARCH_BLACKWELL,
293            Self::Unknown => NVML_DEVICE_ARCH_UNKNOWN,
294        }
295    }
296}
297
298impl TryFrom<nvmlDeviceArchitecture_t> for DeviceArchitecture {
299    type Error = NvmlError;
300
301    fn try_from(data: nvmlDeviceArchitecture_t) -> Result<Self, Self::Error> {
302        match data {
303            NVML_DEVICE_ARCH_KEPLER => Ok(Self::Kepler),
304            NVML_DEVICE_ARCH_MAXWELL => Ok(Self::Maxwell),
305            NVML_DEVICE_ARCH_PASCAL => Ok(Self::Pascal),
306            NVML_DEVICE_ARCH_VOLTA => Ok(Self::Volta),
307            NVML_DEVICE_ARCH_TURING => Ok(Self::Turing),
308            NVML_DEVICE_ARCH_AMPERE => Ok(Self::Ampere),
309            NVML_DEVICE_ARCH_ADA => Ok(Self::Ada),
310            NVML_DEVICE_ARCH_HOPPER => Ok(Self::Hopper),
311            NVML_DEVICE_ARCH_BLACKWELL => Ok(Self::Blackwell),
312            NVML_DEVICE_ARCH_UNKNOWN => Ok(Self::Unknown),
313            _ => Err(NvmlError::UnexpectedVariant(data)),
314        }
315    }
316}
317
318impl Display for DeviceArchitecture {
319    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
320        match self {
321            Self::Kepler => f.write_str("Kepler"),
322            Self::Maxwell => f.write_str("Maxwell"),
323            Self::Pascal => f.write_str("Pascal"),
324            Self::Volta => f.write_str("Volta"),
325            Self::Turing => f.write_str("Turing"),
326            Self::Ampere => f.write_str("Ampere"),
327            Self::Ada => f.write_str("Ada"),
328            Self::Hopper => f.write_str("Hopper"),
329            Self::Blackwell => f.write_str("Blackwell"),
330            Self::Unknown => f.write_str("Unknown"),
331        }
332    }
333}
334
335/// Returned by [`crate::Device::max_pcie_link_speed()`].
336///
337/// Note, the NVML header says these are all MBPS (Megabytes Per Second) but
338/// they don't line up with the throughput numbers on this page:
339/// <https://en.wikipedia.org/wiki/PCI_Express>
340///
341/// They _do_ line up with the "transfer rate per lane" numbers, though. This
342/// would mean they represent transfer speeds rather than throughput, in MT/s.
343///
344/// See also the discussion on [`crate::Device::pcie_link_speed()`].
345// TODO: technically this is an "enum wrapper" but the type on the C side isn't
346// an enum
347#[derive(Debug, Clone, Eq, PartialEq, Hash)]
348#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
349pub enum PcieLinkMaxSpeed {
350    Invalid,
351    MegaTransfersPerSecond2500,
352    MegaTransfersPerSecond5000,
353    MegaTransfersPerSecond8000,
354    MegaTransfersPerSecond16000,
355    MegaTransfersPerSecond32000,
356}
357
358impl PcieLinkMaxSpeed {
359    /// Returns the numerical equivalent for the given enum variant, if valid.
360    pub fn as_integer(&self) -> Option<u32> {
361        Some(match self {
362            PcieLinkMaxSpeed::Invalid => return None,
363            PcieLinkMaxSpeed::MegaTransfersPerSecond2500 => 2500,
364            PcieLinkMaxSpeed::MegaTransfersPerSecond5000 => 5000,
365            PcieLinkMaxSpeed::MegaTransfersPerSecond8000 => 8000,
366            PcieLinkMaxSpeed::MegaTransfersPerSecond16000 => 16000,
367            PcieLinkMaxSpeed::MegaTransfersPerSecond32000 => 32000,
368        })
369    }
370
371    /// Returns the C constant equivalent for the given Rust enum variant.
372    pub fn as_c(&self) -> c_uint {
373        match *self {
374            Self::Invalid => NVML_PCIE_LINK_MAX_SPEED_INVALID,
375            Self::MegaTransfersPerSecond2500 => NVML_PCIE_LINK_MAX_SPEED_2500MBPS,
376            Self::MegaTransfersPerSecond5000 => NVML_PCIE_LINK_MAX_SPEED_5000MBPS,
377            Self::MegaTransfersPerSecond8000 => NVML_PCIE_LINK_MAX_SPEED_8000MBPS,
378            Self::MegaTransfersPerSecond16000 => NVML_PCIE_LINK_MAX_SPEED_16000MBPS,
379            Self::MegaTransfersPerSecond32000 => NVML_PCIE_LINK_MAX_SPEED_32000MBPS,
380        }
381    }
382}
383
384impl TryFrom<c_uint> for PcieLinkMaxSpeed {
385    type Error = NvmlError;
386
387    fn try_from(data: c_uint) -> Result<Self, Self::Error> {
388        match data {
389            NVML_PCIE_LINK_MAX_SPEED_INVALID => Ok(Self::Invalid),
390            NVML_PCIE_LINK_MAX_SPEED_2500MBPS => Ok(Self::MegaTransfersPerSecond2500),
391            NVML_PCIE_LINK_MAX_SPEED_5000MBPS => Ok(Self::MegaTransfersPerSecond5000),
392            NVML_PCIE_LINK_MAX_SPEED_8000MBPS => Ok(Self::MegaTransfersPerSecond8000),
393            NVML_PCIE_LINK_MAX_SPEED_16000MBPS => Ok(Self::MegaTransfersPerSecond16000),
394            NVML_PCIE_LINK_MAX_SPEED_32000MBPS => Ok(Self::MegaTransfersPerSecond32000),
395            _ => Err(NvmlError::UnexpectedVariant(data)),
396        }
397    }
398}
399
400#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
401#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
402#[repr(u32)]
403pub enum FanControlPolicy {
404    TemperatureContinousSw = NVML_FAN_POLICY_TEMPERATURE_CONTINOUS_SW,
405    Manual = NVML_FAN_POLICY_MANUAL,
406}
407
408/// Returned by [`crate::Device::get_fan_control_policy()`].
409///
410/// Policy used for fan control.
411// TODO: technically this is an "enum wrapper" but the type on the C side isn't
412// an enum
413impl FanControlPolicy {
414    pub fn as_c(&self) -> nvmlFanControlPolicy_t {
415        *self as u32
416    }
417}
418
419impl TryFrom<nvmlFanControlPolicy_t> for FanControlPolicy {
420    type Error = NvmlError;
421
422    fn try_from(value: nvmlFanControlPolicy_t) -> Result<Self, Self::Error> {
423        match value {
424            NVML_FAN_POLICY_TEMPERATURE_CONTINOUS_SW => Ok(Self::TemperatureContinousSw),
425            NVML_FAN_POLICY_MANUAL => Ok(Self::Manual),
426            _ => Err(NvmlError::UnexpectedVariant(value)),
427        }
428    }
429}