Skip to main content

nvml_wrapper/
device.rs

1#[cfg(target_os = "linux")]
2use crate::EventSet;
3use crate::GpmSample;
4use crate::NvLink;
5use crate::Nvml;
6
7use crate::bitmasks::device::ThrottleReasons;
8#[cfg(target_os = "linux")]
9use crate::bitmasks::event::EventTypes;
10#[cfg(target_os = "windows")]
11use crate::bitmasks::Behavior;
12
13use crate::enum_wrappers::{bool_from_state, device::*, state_from_bool};
14
15use crate::enums::device::{
16    BusType, DeviceArchitecture, FanControlPolicy, GpuLockedClocksSetting, PcieLinkMaxSpeed,
17    PowerSource,
18};
19#[cfg(target_os = "linux")]
20use crate::error::NvmlErrorWithSource;
21use crate::error::{nvml_sym, nvml_try, Bits, NvmlError};
22
23use crate::ffi::bindings::*;
24
25use crate::struct_wrappers::device::*;
26use crate::structs::device::*;
27
28use crate::vgpu::VgpuType;
29
30#[cfg(target_os = "linux")]
31use std::convert::TryInto;
32#[cfg(target_os = "linux")]
33use std::os::raw::c_ulong;
34use std::{
35    convert::TryFrom,
36    ffi::CStr,
37    mem,
38    os::raw::{c_int, c_uint, c_ulonglong},
39    ptr,
40};
41
42use static_assertions::assert_impl_all;
43
44/**
45Struct that represents a device on the system.
46
47Obtain a `Device` with the various methods available to you on the `Nvml`
48struct.
49
50Lifetimes are used to enforce that each `Device` instance cannot be used after
51the `Nvml` instance it was obtained from is dropped:
52
53```compile_fail
54use nvml_wrapper::Nvml;
55# use nvml_wrapper::error::*;
56
57# fn main() -> Result<(), NvmlError> {
58let nvml = Nvml::init()?;
59let device = nvml.device_by_index(0)?;
60
61drop(nvml);
62
63// This won't compile
64device.fan_speed(0)?;
65# Ok(())
66# }
67```
68
69This means you shouldn't have to worry about calls to `Device` methods returning
70`Uninitialized` errors.
71*/
72#[derive(Debug)]
73pub struct Device<'nvml> {
74    device: nvmlDevice_t,
75    nvml: &'nvml Nvml,
76}
77
78unsafe impl Send for Device<'_> {}
79unsafe impl Sync for Device<'_> {}
80
81assert_impl_all!(Device: Send, Sync);
82
83impl<'nvml> Device<'nvml> {
84    /**
85    Create a new `Device` wrapper.
86
87    You will most likely never need to call this; see the methods available to you
88    on the `Nvml` struct to get one.
89
90    # Safety
91
92    It is your responsibility to ensure that the given `nvmlDevice_t` pointer
93    is valid.
94    */
95    // Clippy bug, see https://github.com/rust-lang/rust-clippy/issues/5593
96    #[allow(clippy::missing_safety_doc)]
97    pub unsafe fn new(device: nvmlDevice_t, nvml: &'nvml Nvml) -> Self {
98        Self { device, nvml }
99    }
100
101    /// Access the `Nvml` reference this struct wraps
102    pub fn nvml(&self) -> &'nvml Nvml {
103        self.nvml
104    }
105
106    /// Get the raw device handle contained in this struct
107    ///
108    /// Sometimes necessary for C interop.
109    ///
110    /// # Safety
111    ///
112    /// This is unsafe to prevent it from being used without care.
113    pub unsafe fn handle(&self) -> nvmlDevice_t {
114        self.device
115    }
116
117    /**
118    Clear all affinity bindings for the calling thread.
119
120    Note that this was changed as of version 8.0; older versions cleared affinity for
121    the calling process and all children.
122
123    # Errors
124
125    * `Uninitialized`, if the library has not been successfully initialized
126    * `InvalidArg`, if this `Device` is invalid
127    * `Unknown`, on any unexpected error
128
129    # Device Support
130
131    Supports Kepler or newer fully supported devices.
132
133    # Platform Support
134
135    Only supports Linux.
136    */
137    // Checked against local
138    // Tested (no-run)
139    #[cfg(target_os = "linux")]
140    #[doc(alias = "nvmlDeviceClearCpuAffinity")]
141    pub fn clear_cpu_affinity(&mut self) -> Result<(), NvmlError> {
142        let sym = nvml_sym(self.nvml.lib.nvmlDeviceClearCpuAffinity.as_ref())?;
143
144        unsafe { nvml_try(sym(self.device)) }
145    }
146
147    /**
148    Gets the root/admin permissions for the target API.
149
150    Only root users are able to call functions belonging to restricted APIs. See
151    the documentation for the `RestrictedApi` enum for a list of those functions.
152
153    Non-root users can be granted access to these APIs through use of
154    `.set_api_restricted()`.
155
156    # Errors
157
158    * `Uninitialized`, if the library has not been successfully initialized
159    * `InvalidArg`, if this `Device` is invalid or the apiType is invalid (may occur if
160    * the C lib changes dramatically?)
161    * `NotSupported`, if this query is not supported by this `Device` or this `Device`
162    * does not support the feature that is being queried (e.g. enabling/disabling auto
163    * boosted clocks is not supported by this `Device`).
164    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
165    * `UnexpectedVariant`, for which you can read the docs for
166    * `Unknown`, on any unexpected error
167
168    # Device Support
169
170    Supports all _fully supported_ products.
171    */
172    // Checked against local
173    // Tested (except for AutoBoostedClocks)
174    #[doc(alias = "nvmlDeviceGetAPIRestriction")]
175    pub fn is_api_restricted(&self, api: Api) -> Result<bool, NvmlError> {
176        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetAPIRestriction.as_ref())?;
177
178        unsafe {
179            let mut restricted_state: nvmlEnableState_t = mem::zeroed();
180
181            nvml_try(sym(self.device, api.as_c(), &mut restricted_state))?;
182
183            bool_from_state(restricted_state)
184        }
185    }
186
187    /**
188    Gets the current clock setting that all applications will use unless an overspec
189    situation occurs.
190
191    This setting can be changed using `.set_applications_clocks()`.
192
193    # Errors
194
195    * `Uninitialized`, if the library has not been successfully initialized
196    * `InvalidArg`, if this `Device` is invalid or the clockType is invalid (may occur
197    * if the C lib changes dramatically?)
198    * `NotSupported`, if this `Device` does not support this feature
199    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
200    * `Unknown`, on any unexpected error
201
202    # Device Support
203
204    Supports Kepler or newer fully supported devices.
205    */
206    // Checked against local
207    // Tested
208    #[doc(alias = "nvmlDeviceGetApplicationsClock")]
209    pub fn applications_clock(&self, clock_type: Clock) -> Result<u32, NvmlError> {
210        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetApplicationsClock.as_ref())?;
211
212        unsafe {
213            let mut clock: c_uint = mem::zeroed();
214
215            nvml_try(sym(self.device, clock_type.as_c(), &mut clock))?;
216
217            Ok(clock)
218        }
219    }
220
221    /**
222    Gets the current and default state of auto boosted clocks.
223
224    Auto boosted clocks are enabled by default on some hardware, allowing the GPU to run
225    as fast as thermals will allow it to.
226
227    On Pascal and newer hardware, auto boosted clocks are controlled through application
228    clocks. Use `.set_applications_clocks()` and `.reset_applications_clocks()` to control
229    auto boost behavior.
230
231    # Errors
232
233    * `Uninitialized`, if the library has not been successfully initialized
234    * `InvalidArg`, if this `Device` is invalid
235    * `NotSupported`, if this `Device` does not support auto boosted clocks
236    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
237    * `UnexpectedVariant`, for which you can read the docs for
238    * `Unknown`, on any unexpected error
239
240    # Device Support
241
242    Supports Kepler or newer fully supported devices.
243    */
244    // Checked against local
245    // Tested on machines other than my own
246    #[doc(alias = "nvmlDeviceGetAutoBoostedClocksEnabled")]
247    pub fn auto_boosted_clocks_enabled(&self) -> Result<AutoBoostClocksEnabledInfo, NvmlError> {
248        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetAutoBoostedClocksEnabled.as_ref())?;
249
250        unsafe {
251            let mut is_enabled: nvmlEnableState_t = mem::zeroed();
252            let mut is_enabled_default: nvmlEnableState_t = mem::zeroed();
253
254            nvml_try(sym(self.device, &mut is_enabled, &mut is_enabled_default))?;
255
256            Ok(AutoBoostClocksEnabledInfo {
257                is_enabled: bool_from_state(is_enabled)?,
258                is_enabled_default: bool_from_state(is_enabled_default)?,
259            })
260        }
261    }
262
263    /**
264    Gets the total, available and used size of BAR1 memory.
265
266    BAR1 memory is used to map the FB (device memory) so that it can be directly accessed
267    by the CPU or by 3rd party devices (peer-to-peer on the PCIe bus).
268
269    # Errors
270
271    * `Uninitialized`, if the library has not been successfully initialized
272    * `InvalidArg`, if this `Device` is invalid
273    * `NotSupported`, if this `Device` does not support this query
274    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
275    * `Unknown`, on any unexpected error
276
277    # Device Support
278
279    Supports Kepler or newer fully supported devices.
280    */
281    // Checked against local
282    // Tested
283    #[doc(alias = "nvmlDeviceGetBAR1MemoryInfo")]
284    pub fn bar1_memory_info(&self) -> Result<BAR1MemoryInfo, NvmlError> {
285        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetBAR1MemoryInfo.as_ref())?;
286
287        unsafe {
288            let mut mem_info: nvmlBAR1Memory_t = mem::zeroed();
289            nvml_try(sym(self.device, &mut mem_info))?;
290
291            Ok(mem_info.into())
292        }
293    }
294
295    /**
296    Gets the NUMA nodes physically close to the GPU.
297
298    Main goal is to facilitate memory placement optimisations for multi CPU/GPU settings.
299    Node (set) size needs to be something like `<Number of nodes> / (std::mem::size_of::<c_ulong>() / 8) + 1`
300
301    # Errors
302
303    * `Uninitialized`, if the library has not been successfully initialized
304    * `InvalidArg`, if this `Device` is invalid
305    * `NotSupported`, if this `Device` does not support this query
306    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
307    * `Unknown`, on any unexpected error
308    */
309    // Checked against local
310    // Tested
311    #[cfg(target_os = "linux")]
312    #[doc(alias = "nvmlDeviceGetMemoryAffinity")]
313    pub fn memory_affinity(
314        &self,
315        size: usize,
316        scope: nvmlAffinityScope_t,
317    ) -> Result<Vec<c_ulong>, NvmlError> {
318        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetMemoryAffinity.as_ref())?;
319
320        unsafe {
321            if size == 0 {
322                return Err(NvmlError::InsufficientSize(Some(1)));
323            }
324
325            let mut affinities: Vec<c_ulong> = vec![0; size];
326
327            nvml_try(sym(
328                self.device,
329                size as c_uint,
330                affinities.as_mut_ptr(),
331                scope,
332            ))?;
333
334            Ok(affinities)
335        }
336    }
337
338    /**
339    Gets the board ID for this `Device`, from 0-N.
340
341    Devices with the same boardID indicate GPUs connected to the same PLX. Use in
342    conjunction with `.is_multi_gpu_board()` to determine if they are on the same
343    board as well.
344
345    The boardID returned is a unique ID for the current config. Uniqueness and
346    ordering across reboots and system configs is not guaranteed (i.e if a Tesla
347    K40c returns 0x100 and the two GPUs on a Tesla K10 in the same system return
348    0x200, it is not guaranteed that they will always return those values. They will,
349    however, always be different from each other).
350
351    # Errors
352
353    * `Uninitialized`, if the library has not been successfully initialized
354    * `InvalidArg`, if this `Device` is invalid
355    * `NotSupported`, if this `Device` does not support this feature
356    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
357    * `Unknown`, on any unexpected error
358
359    # Device Support
360
361    Supports Fermi or newer fully supported devices.
362    */
363    // Checked against local
364    // Tested
365    #[doc(alias = "nvmlDeviceGetBoardId")]
366    pub fn board_id(&self) -> Result<u32, NvmlError> {
367        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetBoardId.as_ref())?;
368
369        unsafe {
370            let mut id: c_uint = mem::zeroed();
371            nvml_try(sym(self.device, &mut id))?;
372
373            Ok(id)
374        }
375    }
376
377    /**
378    Gets the NUMA node ID for this `Device` (if within a NUMA node).
379
380    It is possible to identify the NUMA node id for a given Device
381    so ww can optimise a CPU thread to be pinned within the same node
382    for example
383
384    # Errors
385
386    * `Uninitialized`, if the library has not been successfully initialized
387    * `InvalidArg`, if this `Device` is invalid
388    * `NotSupported`, if this `Device` does not support this feature
389    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
390    * `Unknown`, on any unexpected error
391    */
392    #[doc(alias = "nvmlDeviceGetNumaNodeId")]
393    pub fn numa_node_id(&self) -> Result<u32, NvmlError> {
394        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetNumaNodeId.as_ref())?;
395
396        unsafe {
397            let mut id: c_uint = mem::zeroed();
398            nvml_try(sym(self.device, &mut id))?;
399
400            Ok(id)
401        }
402    }
403
404    /**
405    Gets the brand of this `Device`.
406
407    See the `Brand` enum for documentation of possible values.
408
409    # Errors
410
411    * `Uninitialized`, if the library has not been successfully initialized
412    * `InvalidArg`, if this `Device` is invalid
413    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
414    * `UnexpectedVariant`, check that error's docs for more info
415    * `Unknown`, on any unexpected error
416    */
417    // Checked against local nvml.h
418    // Tested
419    #[doc(alias = "nvmlDeviceGetBrand")]
420    pub fn brand(&self) -> Result<Brand, NvmlError> {
421        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetBrand.as_ref())?;
422
423        unsafe {
424            let mut brand: nvmlBrandType_t = mem::zeroed();
425            nvml_try(sym(self.device, &mut brand))?;
426
427            Brand::try_from(brand)
428        }
429    }
430
431    /**
432    Gets bridge chip information for all bridge chips on the board.
433
434    Only applicable to multi-GPU devices.
435
436    # Errors
437
438    * `Uninitialized`, if the library has not been successfully initialized
439    * `InvalidArg`, if this `Device` is invalid
440    * `NotSupported`, if this `Device` does not support this feature
441    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
442    * `UnexpectedVariant`, for which you can read the docs for
443    * `Unknown`, on any unexpected error
444
445    # Device Support
446
447    Supports all _fully supported_ devices.
448    */
449    // Checked against local
450    // Tested on machines other than my own
451    #[doc(alias = "nvmlDeviceGetBridgeChipInfo")]
452    pub fn bridge_chip_info(&self) -> Result<BridgeChipHierarchy, NvmlError> {
453        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetBridgeChipInfo.as_ref())?;
454
455        unsafe {
456            let mut info: nvmlBridgeChipHierarchy_t = mem::zeroed();
457            nvml_try(sym(self.device, &mut info))?;
458
459            BridgeChipHierarchy::try_from(info)
460        }
461    }
462
463    /**
464    Gets this `Device`'s current clock speed for the given `Clock` type and `ClockId`.
465
466    # Errors
467
468    * `Uninitialized`, if the library has not been successfully initialized
469    * `InvalidArg`, if this `Device` is invalid or `clock_type` is invalid (shouldn't occur?)
470    * `NotSupported`, if this `Device` does not support this feature
471    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
472    * `Unknown`, on any unexpected error
473
474    # Device Support
475
476    Supports Kepler and newer fully supported devices.
477    */
478    // Checked against local
479    // Tested (except for CustomerMaxBoost)
480    #[doc(alias = "nvmlDeviceGetClock")]
481    pub fn clock(&self, clock_type: Clock, clock_id: ClockId) -> Result<u32, NvmlError> {
482        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetClock.as_ref())?;
483
484        unsafe {
485            let mut clock: c_uint = mem::zeroed();
486
487            nvml_try(sym(
488                self.device,
489                clock_type.as_c(),
490                clock_id.as_c(),
491                &mut clock,
492            ))?;
493
494            Ok(clock)
495        }
496    }
497
498    /**
499    Gets this `Device`'s customer-defined maximum boost clock speed for the
500    given `Clock` type.
501
502    # Errors
503
504    * `Uninitialized`, if the library has not been successfully initialized
505    * `InvalidArg`, if this `Device` is invalid or `clock_type` is invalid (shouldn't occur?)
506    * `NotSupported`, if this `Device` or the `clock_type` on this `Device`
507    * does not support this feature
508    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
509    * `Unknown`, on any unexpected error
510
511    # Device Support
512
513    Supports Pascal and newer fully supported devices.
514    */
515    // Checked against local
516    // Tested on machines other than my own
517    #[doc(alias = "nvmlDeviceGetMaxCustomerBoostClock")]
518    pub fn max_customer_boost_clock(&self, clock_type: Clock) -> Result<u32, NvmlError> {
519        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetMaxCustomerBoostClock.as_ref())?;
520
521        unsafe {
522            let mut clock: c_uint = mem::zeroed();
523
524            nvml_try(sym(self.device, clock_type.as_c(), &mut clock))?;
525
526            Ok(clock)
527        }
528    }
529
530    /**
531    Gets the current compute mode for this `Device`.
532
533    # Errors
534
535    * `Uninitialized`, if the library has not been successfully initialized
536    * `InvalidArg`, if this `Device` is invalid
537    * `NotSupported`, if this `Device` does not support this feature
538    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
539    * `UnexpectedVariant`, check that error's docs for more info
540    * `Unknown`, on any unexpected error
541    */
542    // Checked against local
543    // Tested
544    #[doc(alias = "nvmlDeviceGetComputeMode")]
545    pub fn compute_mode(&self) -> Result<ComputeMode, NvmlError> {
546        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetComputeMode.as_ref())?;
547
548        unsafe {
549            let mut mode: nvmlComputeMode_t = mem::zeroed();
550            nvml_try(sym(self.device, &mut mode))?;
551
552            ComputeMode::try_from(mode)
553        }
554    }
555
556    /**
557    Gets the CUDA compute capability of this `Device`.
558
559    The returned version numbers are the same as those returned by
560    `cuDeviceGetAttribute()` from the CUDA API.
561
562    # Errors
563
564    * `Uninitialized`, if the library has not been successfully initialized
565    * `InvalidArg`, if this `Device` is invalid
566    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
567    * `Unknown`, on any unexpected error
568    */
569    #[doc(alias = "nvmlDeviceGetCudaComputeCapability")]
570    pub fn cuda_compute_capability(&self) -> Result<CudaComputeCapability, NvmlError> {
571        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetCudaComputeCapability.as_ref())?;
572
573        unsafe {
574            let mut major: c_int = mem::zeroed();
575            let mut minor: c_int = mem::zeroed();
576
577            nvml_try(sym(self.device, &mut major, &mut minor))?;
578
579            Ok(CudaComputeCapability { major, minor })
580        }
581    }
582
583    /**
584    Gets this `Device`'s current clock speed for the given `Clock` type.
585
586    # Errors
587
588    * `Uninitialized`, if the library has not been successfully initialized
589    * `InvalidArg`, if this `Device` is invalid
590    * `NotSupported`, if this `Device` cannot report the specified clock
591    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
592    * `Unknown`, on any unexpected error
593
594    # Device Support
595
596    Supports Fermi or newer fully supported devices.
597    */
598    // Checked against local
599    // Tested
600    #[doc(alias = "nvmlDeviceGetClockInfo")]
601    pub fn clock_info(&self, clock_type: Clock) -> Result<u32, NvmlError> {
602        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetClockInfo.as_ref())?;
603
604        unsafe {
605            let mut clock: c_uint = mem::zeroed();
606
607            nvml_try(sym(self.device, clock_type.as_c(), &mut clock))?;
608
609            Ok(clock)
610        }
611    }
612
613    /**
614    Gets information about processes with a compute context running on this `Device`.
615
616    This only returns information about running compute processes (such as a CUDA application
617    with an active context). Graphics applications (OpenGL, DirectX) won't be listed by this
618    function.
619
620    # Errors
621
622    * `Uninitialized`, if the library has not been successfully initialized
623    * `InvalidArg`, if this `Device` is invalid
624    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
625    * `Unknown`, on any unexpected error
626    */
627    // Tested
628    #[doc(alias = "nvmlDeviceGetComputeRunningProcesses_v3")]
629    pub fn running_compute_processes(&self) -> Result<Vec<ProcessInfo>, NvmlError> {
630        let sym = nvml_sym(
631            self.nvml
632                .lib
633                .nvmlDeviceGetComputeRunningProcesses_v3
634                .as_ref(),
635        )?;
636
637        unsafe {
638            let mut count: c_uint = match self.running_compute_processes_count()? {
639                0 => return Ok(vec![]),
640                value => value,
641            };
642            // Add a bit of headroom in case more processes are launched in
643            // between the above call to get the expected count and the time we
644            // actually make the call to get data below.
645            count += 5;
646            let mut processes: Vec<nvmlProcessInfo_t> = vec![mem::zeroed(); count as usize];
647
648            nvml_try(sym(self.device, &mut count, processes.as_mut_ptr()))?;
649
650            processes.truncate(count as usize);
651            Ok(processes.into_iter().map(ProcessInfo::from).collect())
652        }
653    }
654
655    fn mps_running_compute_processes_count(&self) -> Result<c_uint, NvmlError> {
656        let sym = nvml_sym(
657            self.nvml
658                .lib
659                .nvmlDeviceGetMPSComputeRunningProcesses_v3
660                .as_ref(),
661        )?;
662
663        unsafe {
664            let mut len: c_uint = 0;
665
666            match sym(self.device, &mut len, ptr::null_mut()) {
667                nvmlReturn_enum_NVML_ERROR_INSUFFICIENT_SIZE => Ok(len),
668                another_attempt => nvml_try(another_attempt).map(|_| 0),
669            }
670        }
671    }
672
673    /**
674    Gets information about processes with a compute context running on this `Device`.
675    Note that processes list can differ between the accounting call and the list gathering
676
677    # Errors
678
679    * `Uninitialized`, if the library has not been successfully initialized
680    * `InvalidArg`, if this `Device` is invalid
681    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
682    * `Unknown`, on any unexpected error
683
684    # Device Support
685
686    Supports Volta or newer fully supported devices.
687    */
688    #[doc(alias = "nvmlDeviceGetMPSComputeRunningProcesses_v3")]
689    pub fn mps_running_compute_processes(&self) -> Result<Vec<ProcessInfo>, NvmlError> {
690        let sym = nvml_sym(
691            self.nvml
692                .lib
693                .nvmlDeviceGetMPSComputeRunningProcesses_v3
694                .as_ref(),
695        )?;
696
697        unsafe {
698            let mut len: c_uint = match self.mps_running_compute_processes_count()? {
699                0 => return Ok(vec![]),
700                value => value,
701            };
702
703            let mut processes: Vec<nvmlProcessInfo_t> = Vec::with_capacity(len as usize);
704
705            nvml_try(sym(self.device, &mut len, processes.as_mut_ptr()))?;
706
707            processes.set_len(len as usize);
708            Ok(processes.into_iter().map(ProcessInfo::from).collect())
709        }
710    }
711
712    /**
713    Gets the number of processes with a compute context running on this `Device`.
714
715    This only returns the count of running compute processes (such as a CUDA application
716    with an active context). Graphics applications (OpenGL, DirectX) won't be counted by this
717    function.
718
719    # Errors
720
721    * `Uninitialized`, if the library has not been successfully initialized
722    * `InvalidArg`, if this `Device` is invalid
723    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
724    * `Unknown`, on any unexpected error
725    */
726    // Tested as part of `.running_compute_processes()`
727    #[doc(alias = "nvmlDeviceGetComputeRunningProcesses_v3")]
728    pub fn running_compute_processes_count(&self) -> Result<u32, NvmlError> {
729        let sym = nvml_sym(
730            self.nvml
731                .lib
732                .nvmlDeviceGetComputeRunningProcesses_v3
733                .as_ref(),
734        )?;
735
736        unsafe {
737            // Indicates that we want the count
738            let mut count: c_uint = 0;
739
740            // Passing null doesn't mean we want the count, it's just allowed
741            match sym(self.device, &mut count, ptr::null_mut()) {
742                nvmlReturn_enum_NVML_ERROR_INSUFFICIENT_SIZE => Ok(count),
743                // If success, return 0; otherwise, return error
744                other => nvml_try(other).map(|_| 0),
745            }
746        }
747    }
748
749    /**
750    Gets information about processes with a compute context running on this `Device`.
751
752    This only returns information about running compute processes (such as a CUDA application
753    with an active context). Graphics applications (OpenGL, DirectX) won't be listed by this
754    function.
755
756    # Errors
757
758    * `Uninitialized`, if the library has not been successfully initialized
759    * `InvalidArg`, if this `Device` is invalid
760    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
761    * `Unknown`, on any unexpected error
762    */
763    #[doc(alias = "nvmlDeviceGetComputeRunningProcesses_v2")]
764    #[cfg(feature = "legacy-functions")]
765    pub fn running_compute_processes_v2(&self) -> Result<Vec<ProcessInfo>, NvmlError> {
766        let sym = nvml_sym(
767            self.nvml
768                .lib
769                .nvmlDeviceGetComputeRunningProcesses_v2
770                .as_ref(),
771        )?;
772
773        unsafe {
774            let mut count: c_uint = match self.running_compute_processes_count_v2()? {
775                0 => return Ok(vec![]),
776                value => value,
777            };
778            // Add a bit of headroom in case more processes are launched in
779            // between the above call to get the expected count and the time we
780            // actually make the call to get data below.
781            count += 5;
782            let mut processes: Vec<nvmlProcessInfo_v2_t> = vec![mem::zeroed(); count as usize];
783
784            nvml_try(sym(self.device, &mut count, processes.as_mut_ptr()))?;
785
786            processes.truncate(count as usize);
787            Ok(processes.into_iter().map(ProcessInfo::from).collect())
788        }
789    }
790
791    /**
792    Gets the number of processes with a compute context running on this `Device`.
793
794    This only returns the count of running compute processes (such as a CUDA application
795    with an active context). Graphics applications (OpenGL, DirectX) won't be counted by this
796    function.
797
798    # Errors
799
800    * `Uninitialized`, if the library has not been successfully initialized
801    * `InvalidArg`, if this `Device` is invalid
802    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
803    * `Unknown`, on any unexpected error
804    */
805    #[doc(alias = "nvmlDeviceGetComputeRunningProcesses_v2")]
806    #[cfg(feature = "legacy-functions")]
807    pub fn running_compute_processes_count_v2(&self) -> Result<u32, NvmlError> {
808        let sym = nvml_sym(
809            self.nvml
810                .lib
811                .nvmlDeviceGetComputeRunningProcesses_v2
812                .as_ref(),
813        )?;
814
815        unsafe {
816            // Indicates that we want the count
817            let mut count: c_uint = 0;
818
819            // Passing null doesn't mean we want the count, it's just allowed
820            match sym(self.device, &mut count, ptr::null_mut()) {
821                nvmlReturn_enum_NVML_ERROR_INSUFFICIENT_SIZE => Ok(count),
822                // If success, return 0; otherwise, return error
823                other => nvml_try(other).map(|_| 0),
824            }
825        }
826    }
827
828    /**
829    Gets a vector of bitmasks with the ideal CPU affinity for this `Device`.
830
831    The results are sized to `size`. For example, if processors 0, 1, 32, and 33 are
832    ideal for this `Device` and `size` == 2, result\[0\] = 0x3, result\[1\] = 0x3.
833
834    64 CPUs per unsigned long on 64-bit machines, 32 on 32-bit machines.
835
836    # Errors
837
838    * `Uninitialized`, if the library has not been successfully initialized
839    * `InvalidArg`, if this `Device` is invalid
840    * `InsufficientSize`, if the passed-in `size` is 0 (must be > 0)
841    * `NotSupported`, if this `Device` does not support this feature
842    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
843    * `Unknown`, on any unexpected error
844
845    # Device Support
846
847    Supports Kepler or newer fully supported devices.
848
849    # Platform Support
850
851    Only supports Linux.
852    */
853    // Checked against local
854    // Tested
855    // TODO: Should we trim zeros here or leave it to the caller?
856    #[cfg(target_os = "linux")]
857    #[doc(alias = "nvmlDeviceGetCpuAffinity")]
858    pub fn cpu_affinity(&self, size: usize) -> Result<Vec<c_ulong>, NvmlError> {
859        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetCpuAffinity.as_ref())?;
860
861        unsafe {
862            if size == 0 {
863                // Return an error containing the minimum size that can be passed.
864                return Err(NvmlError::InsufficientSize(Some(1)));
865            }
866
867            let mut affinities: Vec<c_ulong> = vec![mem::zeroed(); size];
868
869            nvml_try(sym(self.device, size as c_uint, affinities.as_mut_ptr()))?;
870
871            Ok(affinities)
872        }
873    }
874
875    /**
876    Checks simultaneously if confidential compute is enabled, if the device is in a production environment,
877    and if the device is accepting client requests.
878    # Errors
879    * `Uninitialized`, if the library has not been successfully initialized
880    * `NotSupported`, if this query is not supported by the device
881    * `InvalidArg`, if confidential compute state is invalid
882    */
883    pub fn check_confidential_compute_status(&self) -> Result<bool, NvmlError> {
884        let cc_state_sym = nvml_sym(self.nvml.lib.nvmlSystemGetConfComputeState.as_ref())?;
885        let cc_gpus_ready_sym = nvml_sym(
886            self.nvml
887                .lib
888                .nvmlSystemGetConfComputeGpusReadyState
889                .as_ref(),
890        )?;
891
892        unsafe {
893            let mut state: nvmlConfComputeSystemState_t = mem::zeroed();
894            nvml_try(cc_state_sym(&mut state))?;
895
896            let is_cc_enabled = state.ccFeature == NVML_CC_SYSTEM_FEATURE_ENABLED;
897            let is_prod_environment = state.environment == NVML_CC_SYSTEM_ENVIRONMENT_PROD;
898
899            let mut cc_gpus_ready: std::os::raw::c_uint = 0;
900            nvml_try(cc_gpus_ready_sym(&mut cc_gpus_ready))?;
901            let is_accepting_client_requests =
902                cc_gpus_ready == NVML_CC_ACCEPTING_CLIENT_REQUESTS_TRUE;
903
904            Ok(is_cc_enabled && is_prod_environment && is_accepting_client_requests)
905        }
906    }
907
908    /**
909    Gets the confidential compute state for this `Device`.
910    # Errors
911    * `Uninitialized`, if the library has not been successfully initialized
912    * `InvalidArg`, if device is invalid or memory is NULL
913    * `NotSupported`, if this query is not supported by the device
914    */
915    #[doc(alias = "nvmlDeviceGetConfComputeGpusReadyState")]
916    pub fn get_confidential_compute_state(&self) -> Result<bool, NvmlError> {
917        let sym = nvml_sym(
918            self.nvml
919                .lib
920                .nvmlSystemGetConfComputeGpusReadyState
921                .as_ref(),
922        )?;
923
924        unsafe {
925            let mut is_accepting_work: u32 = 0;
926            nvml_try(sym(&mut is_accepting_work))?;
927            Ok(is_accepting_work == NVML_CC_ACCEPTING_CLIENT_REQUESTS_TRUE)
928        }
929    }
930
931    /**
932    Sets the confidential compute state for this `Device`.
933    # Errors
934    * `Uninitialized`, if the library has not been successfully initialized
935    * `InvalidArg`, if device is invalid or memory is NULL
936    * `NotSupported`, if this query is not supported by the device
937    */
938    #[doc(alias = "nvmlDeviceSetConfComputeState")]
939    pub fn set_confidential_compute_state(&self, is_accepting_work: bool) -> Result<(), NvmlError> {
940        let sym = nvml_sym(
941            self.nvml
942                .lib
943                .nvmlSystemSetConfComputeGpusReadyState
944                .as_ref(),
945        )?;
946
947        unsafe {
948            nvml_try(sym(is_accepting_work as u32))?;
949            Ok(())
950        }
951    }
952
953    /**
954    Gets the confidential compute state for this `Device`.
955    # Errors
956
957    * `Uninitialized`, if the library has not been successfully initialized
958    * `InvalidArg`, if device is invalid or counters is NULL
959    * `NotSupported`, if the device does not support this feature
960    * `GpuLost`, if the target GPU has fallen off the bus or is otherwise inaccessible
961    * `ArgumentVersionMismatch`, if the provided version is invalid/unsupported
962    * `Unknown`, on any unexpected error
963    */
964    #[doc(alias = "nvmlDeviceSetConfComputeSettings")]
965    pub fn is_cc_enabled(&self) -> Result<bool, NvmlError> {
966        let sym = nvml_sym(self.nvml.lib.nvmlSystemGetConfComputeSettings.as_ref())?;
967
968        unsafe {
969            let mut settings: nvmlSystemConfComputeSettings_t = mem::zeroed();
970            // Implements NVML_STRUCT_VERSION(SystemConfComputeSettings, 1), as detailed in nvml.h
971            settings.version = (std::mem::size_of::<nvmlSystemConfComputeSettings_v1_t>()
972                | (1_usize << 24_usize)) as u32;
973            nvml_try(sym(&mut settings))?;
974            Ok(settings.ccFeature == NVML_CC_SYSTEM_FEATURE_ENABLED)
975        }
976    }
977
978    /**
979    Gets the confidential compute state for this `Device`.
980    # Errors
981
982    * `Uninitialized`, if the library has not been successfully initialized
983    * `InvalidArg`, if device is invalid or counters is NULL
984    * `NotSupported`, if the device does not support this feature
985    * `GpuLost`, if the target GPU has fallen off the bus or is otherwise inaccessible
986    * `ArgumentVersionMismatch`, if the provided version is invalid/unsupported
987    * `Unknown`, on any unexpected error
988    */
989    #[doc(alias = "nvmlSystemGetConfComputeSettings")]
990    pub fn is_multi_gpu_protected_pcie_enabled(&self) -> Result<bool, NvmlError> {
991        let sym = nvml_sym(self.nvml.lib.nvmlSystemGetConfComputeSettings.as_ref())?;
992
993        unsafe {
994            let mut settings: nvmlSystemConfComputeSettings_t = mem::zeroed();
995            // Implements NVML_STRUCT_VERSION(SystemConfComputeSettings, 1), as detailed in nvml.h
996            settings.version = (std::mem::size_of::<nvmlSystemConfComputeSettings_v1_t>()
997                | (1_usize << 24_usize)) as u32;
998            nvml_try(sym(&mut settings))?;
999            Ok(settings.multiGpuMode == NVML_CC_SYSTEM_MULTIGPU_PROTECTED_PCIE)
1000        }
1001    }
1002
1003    /**
1004    Gets the confidential compute state for this `Device`.
1005    # Errors
1006
1007    * `Uninitialized`, if the library has not been successfully initialized
1008    * `InvalidArg`, if device is invalid or counters is NULL
1009    * `NotSupported`, if the device does not support this feature
1010    * `GpuLost`, if the target GPU has fallen off the bus or is otherwise inaccessible
1011    * `ArgumentVersionMismatch`, if the provided version is invalid/unsupported
1012    * `Unknown`, on any unexpected error
1013    */
1014    #[doc(alias = "nvmlSystemGetConfComputeSettings")]
1015    pub fn is_cc_dev_mode_enabled(&self) -> Result<bool, NvmlError> {
1016        let sym = nvml_sym(self.nvml.lib.nvmlSystemGetConfComputeSettings.as_ref())?;
1017
1018        unsafe {
1019            let mut settings: nvmlSystemConfComputeSettings_t = mem::zeroed();
1020            // Implements NVML_STRUCT_VERSION(SystemConfComputeSettings, 1), as detailed in nvml.h
1021            settings.version = (std::mem::size_of::<nvmlSystemConfComputeSettings_v1_t>()
1022                | (1_usize << 24_usize)) as u32;
1023            nvml_try(sym(&mut settings))?;
1024            Ok(settings.devToolsMode == NVML_CC_SYSTEM_DEVTOOLS_MODE_ON)
1025        }
1026    }
1027
1028    /**
1029    Gets the confidential compute capabilities for this `Device`.
1030    # Errors
1031    * `Uninitialized`, if the library has not been successfully initialized
1032    * `InvalidArg`, if device is invalid or memory is NULL
1033    * `NotSupported`, if this query is not supported by the device
1034    */
1035    pub fn get_confidential_compute_capabilities(
1036        &self,
1037    ) -> Result<ConfidentialComputeCapabilities, NvmlError> {
1038        let sym = nvml_sym(self.nvml.lib.nvmlSystemGetConfComputeCapabilities.as_ref())?;
1039
1040        unsafe {
1041            let mut capabilities: nvmlConfComputeSystemCaps_t = mem::zeroed();
1042            nvml_try(sym(&mut capabilities))?;
1043
1044            let cpu_caps = match capabilities.cpuCaps {
1045                NVML_CC_SYSTEM_CPU_CAPS_NONE => ConfidentialComputeCpuCapabilities::None,
1046                NVML_CC_SYSTEM_CPU_CAPS_AMD_SEV => ConfidentialComputeCpuCapabilities::AmdSev,
1047                NVML_CC_SYSTEM_CPU_CAPS_INTEL_TDX => ConfidentialComputeCpuCapabilities::IntelTdx,
1048                _ => return Err(NvmlError::Unknown),
1049            };
1050
1051            let gpus_caps = match capabilities.gpusCaps {
1052                NVML_CC_SYSTEM_GPUS_CC_CAPABLE => ConfidentialComputeGpuCapabilities::Capable,
1053                NVML_CC_SYSTEM_GPUS_CC_NOT_CAPABLE => {
1054                    ConfidentialComputeGpuCapabilities::NotCapable
1055                }
1056                _ => return Err(NvmlError::Unknown),
1057            };
1058
1059            Ok(ConfidentialComputeCapabilities {
1060                cpu_caps,
1061                gpus_caps,
1062            })
1063        }
1064    }
1065
1066    /**
1067    Fetches the confidential compute attestation report for this [`Device`].
1068
1069    This method retrieves a comprehensive attestation report from the device, which includes:
1070    - A 32-byte nonce
1071    - The attestation report size (as big-endian bytes)
1072    - The attestation report data (up to 8192 bytes)
1073    - A flag indicating if CEC attestation is present (as big-endian bytes)
1074    - The CEC attestation report size (as big-endian bytes)
1075    - The CEC attestation report data (up to 4096 bytes)
1076
1077    The returned vector contains all these components concatenated together in the order listed above.
1078
1079    # Errors
1080
1081    * `Uninitialized`, if the library has not been successfully initialized
1082    * `InvalidArg`, if device is invalid or memory is NULL
1083    * `NotSupported`, if this query is not supported by the device
1084    * `Unknown`, on any unexpected error
1085    */
1086    #[doc(alias = "nvmlDeviceGetAttestationReport")]
1087    pub fn confidential_compute_gpu_attestation_report(
1088        &self,
1089        nonce: [u8; NVML_CC_GPU_CEC_NONCE_SIZE as usize],
1090    ) -> Result<ConfidentialComputeGpuAttestationReport, NvmlError> {
1091        let sym = nvml_sym(
1092            self.nvml
1093                .lib
1094                .nvmlDeviceGetConfComputeGpuAttestationReport
1095                .as_ref(),
1096        )?;
1097
1098        unsafe {
1099            let mut report: nvmlConfComputeGpuAttestationReport_st = mem::zeroed();
1100            report.nonce = nonce;
1101
1102            nvml_try(sym(self.device, &mut report))?;
1103
1104            let is_cec_attestation_report_present = report.isCecAttestationReportPresent == 1;
1105            Ok(ConfidentialComputeGpuAttestationReport {
1106                attestation_report_size: report.attestationReportSize,
1107                attestation_report: report.attestationReport
1108                    [..report.attestationReportSize as usize]
1109                    .to_vec(),
1110                is_cec_attestation_report_present,
1111                cec_attestation_report_size: report.cecAttestationReportSize,
1112                cec_attestation_report: report.cecAttestationReport
1113                    [..report.cecAttestationReportSize as usize]
1114                    .to_vec(),
1115            })
1116        }
1117    }
1118
1119    /**
1120    Gets the confidential compute GPU certificate for this `Device`.
1121
1122    # Errors
1123
1124    * `Uninitialized` if the library has not been successfully initialized
1125    * `InvalidArg` if device is invalid or memory is NULL
1126    * `NotSupported` if this query is not supported by the device
1127    * `Unknown` on any unexpected error
1128    */
1129    pub fn confidential_compute_gpu_certificate(
1130        &self,
1131    ) -> Result<ConfidentialComputeGpuCertificate, NvmlError> {
1132        let sym = nvml_sym(
1133            self.nvml
1134                .lib
1135                .nvmlDeviceGetConfComputeGpuCertificate
1136                .as_ref(),
1137        )?;
1138
1139        unsafe {
1140            let mut certificate_chain: nvmlConfComputeGpuCertificate_t = mem::zeroed();
1141            nvml_try(sym(self.device, &mut certificate_chain))?;
1142
1143            Ok(ConfidentialComputeGpuCertificate {
1144                cert_chain_size: certificate_chain.certChainSize,
1145                attestation_cert_chain_size: certificate_chain.attestationCertChainSize,
1146                cert_chain: certificate_chain.certChain[..certificate_chain.certChainSize as usize]
1147                    .to_vec(),
1148                attestation_cert_chain: certificate_chain.attestationCertChain
1149                    [..certificate_chain.attestationCertChainSize as usize]
1150                    .to_vec(),
1151            })
1152        }
1153    }
1154
1155    /**
1156    Gets the current PCIe link generation.
1157
1158    # Errors
1159
1160    * `Uninitialized`, if the library has not been successfully initialized
1161    * `InvalidArg`, if this `Device` is invalid
1162    * `NotSupported`, if PCIe link information is not available
1163    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1164    * `Unknown`, on any unexpected error
1165
1166    # Device Support
1167
1168    Supports Fermi or newer fully supported devices.
1169    */
1170    // Checked against local
1171    // Tested
1172    #[doc(alias = "nvmlDeviceGetCurrPcieLinkGeneration")]
1173    pub fn current_pcie_link_gen(&self) -> Result<u32, NvmlError> {
1174        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetCurrPcieLinkGeneration.as_ref())?;
1175
1176        unsafe {
1177            let mut link_gen: c_uint = mem::zeroed();
1178
1179            nvml_try(sym(self.device, &mut link_gen))?;
1180
1181            Ok(link_gen)
1182        }
1183    }
1184
1185    /**
1186    Gets the current PCIe link width.
1187
1188    # Errors
1189
1190    * `Uninitialized`, if the library has not been successfully initialized
1191    * `InvalidArg`, if this `Device` is invalid
1192    * `NotSupported`, if PCIe link information is not available
1193    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1194    * `Unknown`, on any unexpected error
1195
1196    # Device Support
1197
1198    Supports Fermi or newer fully supported devices.
1199    */
1200    // Checked against local
1201    // Tested
1202    #[doc(alias = "nvmlDeviceGetCurrPcieLinkWidth")]
1203    pub fn current_pcie_link_width(&self) -> Result<u32, NvmlError> {
1204        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetCurrPcieLinkWidth.as_ref())?;
1205
1206        unsafe {
1207            let mut link_width: c_uint = mem::zeroed();
1208            nvml_try(sym(self.device, &mut link_width))?;
1209
1210            Ok(link_width)
1211        }
1212    }
1213
1214    /**
1215    Gets the current utilization and sampling size (sampling size in μs) for the Decoder.
1216
1217    # Errors
1218
1219    * `Uninitialized`, if the library has not been successfully initialized
1220    * `InvalidArg`, if this `Device` is invalid
1221    * `NotSupported`, if this `Device` does not support this feature
1222    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1223    * `Unknown`, on any unexpected error
1224
1225    # Device Support
1226
1227    Supports Kepler or newer fully supported devices.
1228    */
1229    // Checked against local
1230    // Tested
1231    #[doc(alias = "nvmlDeviceGetDecoderUtilization")]
1232    pub fn decoder_utilization(&self) -> Result<UtilizationInfo, NvmlError> {
1233        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetDecoderUtilization.as_ref())?;
1234
1235        unsafe {
1236            let mut utilization: c_uint = mem::zeroed();
1237            let mut sampling_period: c_uint = mem::zeroed();
1238
1239            nvml_try(sym(self.device, &mut utilization, &mut sampling_period))?;
1240
1241            Ok(UtilizationInfo {
1242                utilization,
1243                sampling_period,
1244            })
1245        }
1246    }
1247
1248    /**
1249    Gets global statistics for active frame buffer capture sessions on this `Device`.
1250
1251    # Errors
1252
1253    * `Uninitialized`, if the library has not been successfully initialized
1254    * `NotSupported`, if this `Device` does not support this feature
1255    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1256    * `Unknown`, on any unexpected error
1257
1258    # Device Support
1259
1260    Supports Maxwell or newer fully supported devices.
1261    */
1262    // tested
1263    #[doc(alias = "nvmlDeviceGetFBCStats")]
1264    pub fn fbc_stats(&self) -> Result<FbcStats, NvmlError> {
1265        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetFBCStats.as_ref())?;
1266
1267        unsafe {
1268            let mut fbc_stats: nvmlFBCStats_t = mem::zeroed();
1269            nvml_try(sym(self.device, &mut fbc_stats))?;
1270
1271            Ok(fbc_stats.into())
1272        }
1273    }
1274
1275    /**
1276    Gets information about active frame buffer capture sessions on this `Device`.
1277
1278    Note that information such as the horizontal and vertical resolutions, the
1279    average FPS, and the average latency will be zero if no frames have been
1280    captured since a session was started.
1281
1282    # Errors
1283
1284    * `UnexpectedVariant`, for which you can read the docs for
1285    * `IncorrectBits`, if bits are found in a session's info flags that don't
1286      match the flags in this wrapper
1287    * `Uninitialized`, if the library has not been successfully initialized
1288    * `NotSupported`, if this `Device` does not support this feature
1289    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1290    * `Unknown`, on any unexpected error
1291
1292    # Device Support
1293
1294    Supports Maxwell or newer fully supported devices.
1295    */
1296    // tested
1297    #[doc(alias = "nvmlDeviceGetFBCSessions")]
1298    pub fn fbc_sessions_info(&self) -> Result<Vec<FbcSessionInfo>, NvmlError> {
1299        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetFBCSessions.as_ref())?;
1300
1301        unsafe {
1302            let mut count: c_uint = match self.fbc_session_count()? {
1303                0 => return Ok(vec![]),
1304                value => value,
1305            };
1306            let mut info: Vec<nvmlFBCSessionInfo_t> = vec![mem::zeroed(); count as usize];
1307
1308            nvml_try(sym(self.device, &mut count, info.as_mut_ptr()))?;
1309
1310            info.into_iter().map(FbcSessionInfo::try_from).collect()
1311        }
1312    }
1313
1314    /**
1315    Gets the number of active frame buffer capture sessions on this `Device`.
1316
1317    # Errors
1318
1319    * `Uninitialized`, if the library has not been successfully initialized
1320    * `InvalidArg`, if this `Device` is invalid
1321    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1322    * `Unknown`, on any unexpected error
1323    */
1324    // tested as part of the above
1325    #[doc(alias = "nvmlDeviceGetFBCSessions")]
1326    pub fn fbc_session_count(&self) -> Result<u32, NvmlError> {
1327        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetFBCSessions.as_ref())?;
1328
1329        unsafe {
1330            let mut count: c_uint = 0;
1331
1332            nvml_try(sym(self.device, &mut count, ptr::null_mut()))?;
1333
1334            Ok(count)
1335        }
1336    }
1337
1338    /**
1339    Gets GPU device hardware attributes
1340
1341    DeviceAttributes represents compute capabilities, Streaming MultiProcessor
1342    capacity, slices allocated to a given GPU, decoding/encoding supported,
1343    available memory for these GPU operations
1344
1345    # Errors
1346    * `Uninitialized`, if the library has not been successfully initialized
1347    * `InvalidArg`, if this `Device` is invalid
1348    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1349    * `Unknown`, on any unexpected error
1350    */
1351    #[doc(alias = "nvmlDeviceGetAttributes_v2")]
1352    pub fn attributes(&self) -> Result<DeviceAttributes, NvmlError> {
1353        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetAttributes_v2.as_ref())?;
1354
1355        unsafe {
1356            let mut attrs: nvmlDeviceAttributes_t = mem::zeroed();
1357            nvml_try(sym(self.device, &mut attrs))?;
1358
1359            Ok(attrs.into())
1360        }
1361    }
1362
1363    /**
1364    Gets the default applications clock that this `Device` boots with or defaults to after
1365    `reset_applications_clocks()`.
1366
1367    # Errors
1368
1369    * `Uninitialized`, if the library has not been successfully initialized
1370    * `InvalidArg`, if this `Device` is invalid
1371    * `NotSupported`, if this `Device` does not support this feature
1372    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1373    * `Unknown`, on any unexpected error
1374
1375    # Device Support
1376
1377    Supports Kepler or newer fully supported devices.
1378    */
1379    // Checked against local
1380    // Tested
1381    #[doc(alias = "nvmlDeviceGetDefaultApplicationsClock")]
1382    pub fn default_applications_clock(&self, clock_type: Clock) -> Result<u32, NvmlError> {
1383        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetDefaultApplicationsClock.as_ref())?;
1384
1385        unsafe {
1386            let mut clock: c_uint = mem::zeroed();
1387
1388            nvml_try(sym(self.device, clock_type.as_c(), &mut clock))?;
1389
1390            Ok(clock)
1391        }
1392    }
1393
1394    /// Not documenting this because it's deprecated. Read NVIDIA's docs if you
1395    /// must use it.
1396    #[deprecated(note = "use `Device.memory_error_counter()`")]
1397    #[doc(alias = "nvmlDeviceGetDetailedEccErrors")]
1398    pub fn detailed_ecc_errors(
1399        &self,
1400        error_type: MemoryError,
1401        counter_type: EccCounter,
1402    ) -> Result<EccErrorCounts, NvmlError> {
1403        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetDetailedEccErrors.as_ref())?;
1404
1405        unsafe {
1406            let mut counts: nvmlEccErrorCounts_t = mem::zeroed();
1407
1408            nvml_try(sym(
1409                self.device,
1410                error_type.as_c(),
1411                counter_type.as_c(),
1412                &mut counts,
1413            ))?;
1414
1415            Ok(counts.into())
1416        }
1417    }
1418
1419    /**
1420    Gets the display active state for this `Device`.
1421
1422    This method indicates whether a display is initialized on this `Device`.
1423    For example, whether or not an X Server is attached to this device and
1424    has allocated memory for the screen.
1425
1426    A display can be active even when no monitor is physically attached to this `Device`.
1427
1428    # Errors
1429
1430    * `Uninitialized`, if the library has not been successfully initialized
1431    * `InvalidArg`, if this `Device` is invalid
1432    * `NotSupported`, if this `Device` does not support this feature
1433    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1434    * `UnexpectedVariant`, for which you can read the docs for
1435    * `Unknown`, on any unexpected error
1436    */
1437    // Checked against local
1438    // Tested
1439    #[doc(alias = "nvmlDeviceGetDisplayActive")]
1440    pub fn is_display_active(&self) -> Result<bool, NvmlError> {
1441        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetDisplayActive.as_ref())?;
1442
1443        unsafe {
1444            let mut state: nvmlEnableState_t = mem::zeroed();
1445            nvml_try(sym(self.device, &mut state))?;
1446
1447            bool_from_state(state)
1448        }
1449    }
1450
1451    /**
1452    Gets whether a physical display is currently connected to any of this `Device`'s
1453    connectors.
1454
1455    This calls the C function `nvmlDeviceGetDisplayMode`.
1456
1457    # Errors
1458
1459    * `Uninitialized`, if the library has not been successfully initialized
1460    * `InvalidArg`, if this `Device` is invalid
1461    * `NotSupported`, if this `Device` does not support this feature
1462    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1463    * `UnexpectedVariant`, for which you can read the docs for
1464    * `Unknown`, on any unexpected error
1465    */
1466    // Checked against local
1467    // Tested
1468    #[doc(alias = "nvmlDeviceGetDisplayMode")]
1469    pub fn is_display_connected(&self) -> Result<bool, NvmlError> {
1470        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetDisplayMode.as_ref())?;
1471
1472        unsafe {
1473            let mut state: nvmlEnableState_t = mem::zeroed();
1474            nvml_try(sym(self.device, &mut state))?;
1475
1476            bool_from_state(state)
1477        }
1478    }
1479
1480    /**
1481    Gets the current and pending driver model for this `Device`.
1482
1483    On Windows, the device driver can run in either WDDM or WDM (TCC) modes.
1484    If a display is attached to the device it must run in WDDM mode. TCC mode
1485    is preferred if a display is not attached.
1486
1487    # Errors
1488
1489    * `Uninitialized`, if the library has not been successfully initialized
1490    * `InvalidArg`, if this `Device` is invalid
1491    * `NotSupported`, if the platform is not Windows
1492    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1493    * `UnexpectedVariant`, for which you can read the docs for
1494    * `Unknown`, on any unexpected error
1495
1496    # Device Support
1497
1498    Supports Fermi and newer fully supported devices.
1499
1500    # Platform Support
1501
1502    Only supports Windows.
1503    */
1504    // Checked against local
1505    // Tested
1506    #[cfg(target_os = "windows")]
1507    #[doc(alias = "nvmlDeviceGetDriverModel")]
1508    pub fn driver_model(&self) -> Result<DriverModelState, NvmlError> {
1509        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetDriverModel.as_ref())?;
1510
1511        unsafe {
1512            let mut current: nvmlDriverModel_t = mem::zeroed();
1513            let mut pending: nvmlDriverModel_t = mem::zeroed();
1514
1515            nvml_try(sym(self.device, &mut current, &mut pending))?;
1516
1517            Ok(DriverModelState {
1518                current: DriverModel::try_from(current)?,
1519                pending: DriverModel::try_from(pending)?,
1520            })
1521        }
1522    }
1523
1524    /**
1525    Get the current and pending ECC modes for this `Device`.
1526
1527    Changing ECC modes requires a reboot. The "pending" ECC mode refers to the target
1528    mode following the next reboot.
1529
1530    # Errors
1531
1532    * `Uninitialized`, if the library has not been successfully initialized
1533    * `InvalidArg`, if this `Device` is invalid
1534    * `NotSupported`, if this `Device` does not support this feature
1535    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1536    * `UnexpectedVariant`, for which you can read the docs for
1537    * `Unknown`, on any unexpected error
1538
1539    # Device Support
1540
1541    Supports Fermi and newer fully supported devices. Only applicable to devices with
1542    ECC. Requires `InfoRom::ECC` version 1.0 or higher.
1543    */
1544    // Checked against local
1545    // Tested on machines other than my own
1546    #[doc(alias = "nvmlDeviceGetEccMode")]
1547    pub fn is_ecc_enabled(&self) -> Result<EccModeState, NvmlError> {
1548        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetEccMode.as_ref())?;
1549
1550        unsafe {
1551            let mut current: nvmlEnableState_t = mem::zeroed();
1552            let mut pending: nvmlEnableState_t = mem::zeroed();
1553
1554            nvml_try(sym(self.device, &mut current, &mut pending))?;
1555
1556            Ok(EccModeState {
1557                currently_enabled: bool_from_state(current)?,
1558                pending_enabled: bool_from_state(pending)?,
1559            })
1560        }
1561    }
1562
1563    /**
1564    Gets the current utilization and sampling size (sampling size in μs) for the Encoder.
1565
1566    # Errors
1567
1568    * `Uninitialized`, if the library has not been successfully initialized
1569    * `InvalidArg`, if this `Device` is invalid
1570    * `NotSupported`, if this `Device` does not support this feature
1571    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1572    * `Unknown`, on any unexpected error
1573
1574    # Device Support
1575
1576    Supports Kepler or newer fully supported devices.
1577    */
1578    // Checked against local
1579    // Tested
1580    #[doc(alias = "nvmlDeviceGetEncoderUtilization")]
1581    pub fn encoder_utilization(&self) -> Result<UtilizationInfo, NvmlError> {
1582        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetEncoderUtilization.as_ref())?;
1583
1584        unsafe {
1585            let mut utilization: c_uint = mem::zeroed();
1586            let mut sampling_period: c_uint = mem::zeroed();
1587
1588            nvml_try(sym(self.device, &mut utilization, &mut sampling_period))?;
1589
1590            Ok(UtilizationInfo {
1591                utilization,
1592                sampling_period,
1593            })
1594        }
1595    }
1596
1597    /**
1598    Gets the current capacity of this device's encoder in macroblocks per second.
1599
1600    # Errors
1601
1602    * `Uninitialized`, if the library has not been successfully initialized
1603    * `InvalidArg`, if this device is invalid
1604    * `NotSupported`, if this `Device` does not support the given `for_type`
1605    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1606    * `Unknown`, on any unexpected error
1607
1608    # Device Support
1609
1610    Supports Maxwell or newer fully supported devices.
1611    */
1612    // Tested
1613    #[doc(alias = "nvmlDeviceGetEncoderCapacity")]
1614    pub fn encoder_capacity(&self, for_type: EncoderType) -> Result<u32, NvmlError> {
1615        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetEncoderCapacity.as_ref())?;
1616
1617        unsafe {
1618            let mut capacity: c_uint = mem::zeroed();
1619
1620            nvml_try(sym(self.device, for_type.as_c(), &mut capacity))?;
1621
1622            Ok(capacity)
1623        }
1624    }
1625
1626    /**
1627    Gets the current encoder stats for this device.
1628
1629    # Errors
1630
1631    * `Uninitialized`, if the library has not been successfully initialized
1632    * `InvalidArg`, if this device is invalid
1633    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1634    * `Unknown`, on any unexpected error
1635
1636    # Device Support
1637
1638    Supports Maxwell or newer fully supported devices.
1639    */
1640    // Tested
1641    #[doc(alias = "nvmlDeviceGetEncoderStats")]
1642    pub fn encoder_stats(&self) -> Result<EncoderStats, NvmlError> {
1643        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetEncoderStats.as_ref())?;
1644
1645        unsafe {
1646            let mut session_count: c_uint = mem::zeroed();
1647            let mut average_fps: c_uint = mem::zeroed();
1648            let mut average_latency: c_uint = mem::zeroed();
1649
1650            nvml_try(sym(
1651                self.device,
1652                &mut session_count,
1653                &mut average_fps,
1654                &mut average_latency,
1655            ))?;
1656
1657            Ok(EncoderStats {
1658                session_count,
1659                average_fps,
1660                average_latency,
1661            })
1662        }
1663    }
1664
1665    /**
1666    Gets information about active encoder sessions on this device.
1667
1668    # Errors
1669
1670    * `Uninitialized`, if the library has not been successfully initialized
1671    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1672    * `UnexpectedVariant`, if an enum variant not defined in this wrapper gets
1673    * returned in a field of an `EncoderSessionInfo` struct
1674    * `Unknown`, on any unexpected error
1675
1676    # Device Support
1677
1678    Supports Maxwell or newer fully supported devices.
1679    */
1680    // Tested
1681    // TODO: Test this with an active session and make sure it works
1682    #[doc(alias = "nvmlDeviceGetEncoderSessions")]
1683    pub fn encoder_sessions(&self) -> Result<Vec<EncoderSessionInfo>, NvmlError> {
1684        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetEncoderSessions.as_ref())?;
1685
1686        unsafe {
1687            let mut count = match self.encoder_sessions_count()? {
1688                0 => return Ok(vec![]),
1689                value => value,
1690            };
1691            let mut sessions: Vec<nvmlEncoderSessionInfo_t> = vec![mem::zeroed(); count as usize];
1692
1693            nvml_try(sym(self.device, &mut count, sessions.as_mut_ptr()))?;
1694
1695            sessions.truncate(count as usize);
1696            sessions
1697                .into_iter()
1698                .map(EncoderSessionInfo::try_from)
1699                .collect::<Result<_, NvmlError>>()
1700        }
1701    }
1702
1703    /**
1704    Gets the number of active encoder sessions on this device.
1705
1706    # Errors
1707
1708    * `Uninitialized`, if the library has not been successfully initialized
1709    * `InvalidArg`, if this `Device` is invalid
1710    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1711    * `Unknown`, on any unexpected error
1712    */
1713    // tested as part of the above
1714    fn encoder_sessions_count(&self) -> Result<u32, NvmlError> {
1715        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetEncoderSessions.as_ref())?;
1716
1717        unsafe {
1718            let mut count: c_uint = 0;
1719
1720            nvml_try(sym(self.device, &mut count, ptr::null_mut()))?;
1721
1722            Ok(count)
1723        }
1724    }
1725
1726    /**
1727    Gets the effective power limit in milliwatts that the driver enforces after taking
1728    into account all limiters.
1729
1730    Note: This can be different from the `.power_management_limit()` if other limits
1731    are set elswhere. This includes the out-of-band power limit interface.
1732
1733    # Errors
1734
1735    * `Uninitialized`, if the library has not been successfully initialized
1736    * `InvalidArg`, if this `Device` is invalid
1737    * `NotSupported`, if this `Device` does not support this feature
1738    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1739    * `Unknown`, on any unexpected error
1740
1741    # Device Support
1742
1743    Supports Kepler or newer fully supported devices.
1744    */
1745    // Checked against local
1746    // Tested
1747    #[doc(alias = "nvmlDeviceGetEnforcedPowerLimit")]
1748    pub fn enforced_power_limit(&self) -> Result<u32, NvmlError> {
1749        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetEnforcedPowerLimit.as_ref())?;
1750
1751        unsafe {
1752            let mut limit: c_uint = mem::zeroed();
1753            nvml_try(sym(self.device, &mut limit))?;
1754
1755            Ok(limit)
1756        }
1757    }
1758
1759    /**
1760    Gets the GPU clock frequency offset value.
1761
1762    # Errors
1763
1764    * `Uninitialized`, if the library has not been successfully initialized
1765    * `InvalidArg`, if this `Device` is invalid
1766    * `NotSupported`, if this `Device` does not support this feature
1767    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1768    * `UnexpectedVariant`, for which you can read the docs for
1769    * `Unknown`, on any unexpected error
1770
1771    # Device Support
1772
1773    Supports all discrete products with unlocked overclocking capabilities.
1774    */
1775    // Checked against local
1776    // Tested (no-run)
1777    #[doc(alias = "nvmlDeviceGetGpcClkVfOffset")]
1778    pub fn gpc_clock_vf_offset(&self) -> Result<i32, NvmlError> {
1779        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetGpcClkVfOffset.as_ref())?;
1780
1781        unsafe {
1782            let mut offset: c_int = mem::zeroed();
1783            nvml_try(sym(self.device, &mut offset))?;
1784
1785            Ok(offset)
1786        }
1787    }
1788
1789    /**
1790    Sets the GPU clock frequency offset value.
1791
1792    # Errors
1793
1794    * `Uninitialized`, if the library has not been successfully initialized
1795    * `InvalidArg`, if this `Device` is invalid
1796    * `NotSupported`, if this `Device` does not support this feature
1797    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1798    * `UnexpectedVariant`, for which you can read the docs for
1799    * `Unknown`, on any unexpected error
1800
1801    # Device Support
1802
1803    Supports all discrete products with unlocked overclocking capabilities.
1804    */
1805    // Checked against local
1806    // Tested (no-run)
1807    #[doc(alias = "nvmlDeviceGetGpcClkVfOffset")]
1808    pub fn set_gpc_clock_vf_offset(&self, offset: i32) -> Result<(), NvmlError> {
1809        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetGpcClkVfOffset.as_ref())?;
1810
1811        unsafe { nvml_try(sym(self.device, offset)) }
1812    }
1813
1814    /**
1815    Gets the memory clock frequency offset value.
1816
1817    # Errors
1818
1819    * `Uninitialized`, if the library has not been successfully initialized
1820    * `InvalidArg`, if this `Device` is invalid
1821    * `NotSupported`, if this `Device` does not support this feature
1822    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1823    * `UnexpectedVariant`, for which you can read the docs for
1824    * `Unknown`, on any unexpected error
1825
1826    # Device Support
1827
1828    Supports all discrete products with unlocked overclocking capabilities.
1829    */
1830    // Checked against local
1831    // Tested (no-run)
1832    #[doc(alias = "nvmlDeviceGetGpcMemClkVfOffset")]
1833    pub fn mem_clock_vf_offset(&self) -> Result<i32, NvmlError> {
1834        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetMemClkVfOffset.as_ref())?;
1835
1836        unsafe {
1837            let mut offset: c_int = mem::zeroed();
1838            nvml_try(sym(self.device, &mut offset))?;
1839
1840            Ok(offset)
1841        }
1842    }
1843
1844    /**
1845    Sets the memory clock frequency offset value.
1846
1847    # Errors
1848
1849    * `Uninitialized`, if the library has not been successfully initialized
1850    * `InvalidArg`, if this `Device` is invalid
1851    * `NotSupported`, if this `Device` does not support this feature
1852    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1853    * `UnexpectedVariant`, for which you can read the docs for
1854    * `Unknown`, on any unexpected error
1855
1856    # Device Support
1857
1858    Supports all discrete products with unlocked overclocking capabilities.
1859    */
1860    // Checked against local
1861    // Tested (no-run)
1862    #[doc(alias = "nvmlDeviceSetGpcMemClkVfOffset")]
1863    pub fn set_mem_clock_vf_offset(&self, offset: i32) -> Result<(), NvmlError> {
1864        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetMemClkVfOffset.as_ref())?;
1865
1866        unsafe { nvml_try(sym(self.device, offset)) }
1867    }
1868
1869    /**
1870    Gets the intended operating speed of the specified fan as a percentage of the
1871    maximum fan speed (100%).
1872
1873    Note: The reported speed is the intended fan speed. If the fan is physically blocked
1874    and unable to spin, the output will not match the actual fan speed.
1875
1876    You can determine valid fan indices using [`Self::num_fans()`].
1877
1878    # Errors
1879
1880    * `Uninitialized`, if the library has not been successfully initialized
1881    * `InvalidArg`, if this `Device` is invalid or `fan_idx` is invalid
1882    * `NotSupported`, if this `Device` does not have a fan or is newer than Maxwell
1883    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1884    * `Unknown`, on any unexpected error
1885
1886    # Device Support
1887
1888    Supports all discrete products with dedicated fans.
1889    */
1890    // Checked against local
1891    // Tested
1892    #[doc(alias = "nvmlDeviceGetFanSpeed_v2")]
1893    pub fn fan_speed(&self, fan_idx: u32) -> Result<u32, NvmlError> {
1894        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetFanSpeed_v2.as_ref())?;
1895
1896        unsafe {
1897            let mut speed: c_uint = mem::zeroed();
1898            nvml_try(sym(self.device, fan_idx, &mut speed))?;
1899
1900            Ok(speed)
1901        }
1902    }
1903
1904    /**
1905    Retrieves the intended operating speed in rotations per minute (RPM) of the
1906    device's specified fan.
1907
1908    Note: The reported speed is the intended fan speed. If the fan is physically
1909    blocked and unable to spin, the output will not match the actual fan speed.
1910
1911    ...
1912    You can determine valid fan indices using [`Self::num_fans()`].
1913
1914    # Errors
1915
1916    * `Uninitialized`, if the library has not been successfully initialized
1917    * `InvalidArg`, if this `Device` is invalid or `fan_idx` is invalid
1918    * `NotSupported`, if this `Device` does not have a fan or is newer than Maxwell
1919    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1920    * `Unknown`, on any unexpected error
1921
1922    # Device Support
1923
1924    For Maxwell or newer fully supported devices.
1925
1926    For all discrete products with dedicated fans.
1927    */
1928    // Checked against local
1929    // Tested
1930    #[doc(alias = "nvmlDeviceGetFanSpeedRPM")]
1931    pub fn fan_speed_rpm(&self, fan_idx: u32) -> Result<u32, NvmlError> {
1932        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetFanSpeedRPM.as_ref())?;
1933
1934        unsafe {
1935            let mut fan_speed: nvmlFanSpeedInfo_t = mem::zeroed();
1936            // Implements NVML_STRUCT_VERSION(FanSpeedInfo, 1), as detailed in nvml.h
1937            fan_speed.version =
1938                (std::mem::size_of::<nvmlFanSpeedInfo_v1_t>() | (1_usize << 24_usize)) as u32;
1939            fan_speed.fan = fan_idx;
1940            nvml_try(sym(self.device, &mut fan_speed))?;
1941
1942            Ok(fan_speed.speed)
1943        }
1944    }
1945
1946    /**
1947    Retrieves the min and max fan speed that user can set for the GPU fan.
1948
1949    Returns a (min, max) tuple.
1950
1951    # Errors
1952
1953    * `Uninitialized`, if the library has not been successfully initialized
1954    * `InvalidArg`, if this `Device` is invalid
1955    * `NotSupported`, if this `Device` does not have fans
1956    * `Unknown`, on any unexpected error
1957
1958    # Device Support
1959
1960    For all cuda-capable discrete products with fans
1961    */
1962    // Checked against local
1963    // Tested
1964    #[doc(alias = "nvmlDeviceGetMinMaxFanSpeed")]
1965    pub fn min_max_fan_speed(&self) -> Result<(u32, u32), NvmlError> {
1966        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetMinMaxFanSpeed.as_ref())?;
1967
1968        unsafe {
1969            let mut min = mem::zeroed();
1970            let mut max = mem::zeroed();
1971            nvml_try(sym(self.device, &mut min, &mut max))?;
1972            Ok((min, max))
1973        }
1974    }
1975
1976    /**
1977    Gets current fan control policy.
1978
1979    You can determine valid fan indices using [`Self::num_fans()`].
1980
1981    # Errors
1982
1983    * `Uninitialized`, if the library has not been successfully initialized
1984    * `InvalidArg`, if this `Device` is invalid or `fan_idx` is invalid
1985    * `NotSupported`, if this `Device` does not have a fan
1986    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
1987    * `UnexpectedVariant`, for which you can read the docs for
1988    * `Unknown`, on any unexpected error
1989
1990    # Device Support
1991
1992    Supports Maxwell or newer fully supported discrete devices with fans.
1993     */
1994    #[doc(alias = "nvmlGetFanControlPolicy_v2")]
1995    pub fn fan_control_policy(&self, fan_idx: u32) -> Result<FanControlPolicy, NvmlError> {
1996        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetFanControlPolicy_v2.as_ref())?;
1997
1998        unsafe {
1999            let mut policy: nvmlFanControlPolicy_t = mem::zeroed();
2000            nvml_try(sym(self.device, fan_idx, &mut policy))?;
2001
2002            FanControlPolicy::try_from(policy)
2003        }
2004    }
2005
2006    /**
2007    Sets fan control policy.
2008
2009    You can determine valid fan indices using [`Self::num_fans()`].
2010
2011    # Errors
2012
2013    * `Uninitialized`, if the library has not been successfully initialized
2014    * `InvalidArg`, if this `Device` is invalid or `fan_idx` is invalid
2015    * `NotSupported`, if this `Device` does not have a fan
2016    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2017    * `UnexpectedVariant`, for which you can read the docs for
2018    * `Unknown`, on any unexpected error
2019
2020    # Device Support
2021
2022    Supports Maxwell or newer fully supported discrete devices with fans.
2023     */
2024    #[doc(alias = "nvmlDeviceSetFanControlPolicy")]
2025    pub fn set_fan_control_policy(
2026        &mut self,
2027        fan_idx: u32,
2028        policy: FanControlPolicy,
2029    ) -> Result<(), NvmlError> {
2030        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetFanControlPolicy.as_ref())?;
2031
2032        unsafe { nvml_try(sym(self.device, fan_idx, policy.as_c())) }
2033    }
2034
2035    /**
2036    Sets the speed of a specified fan.
2037
2038    WARNING: This function changes the fan control policy to manual. It means that YOU have to monitor the temperature and adjust the fan speed accordingly.
2039    If you set the fan speed too low you can burn your GPU! Use [`Device::set_default_fan_speed`] to restore default control policy.
2040
2041    You can determine valid fan indices using [`Self::num_fans()`].
2042
2043    # Errors
2044
2045    * `Uninitialized`, if the library has not been successfully initialized
2046    * `InvalidArg`, if this `Device` is invalid or `fan_idx` is invalid
2047    * `NotSupported`, if this `Device` does not have a fan
2048    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2049    * `UnexpectedVariant`, for which you can read the docs for
2050    * `Unknown`, on any unexpected error
2051
2052    # Device Support
2053
2054    Supports Maxwell or newer fully supported discrete devices with fans.
2055     */
2056    #[doc(alias = "nvmlDeviceSetFanSpeed_v2")]
2057    pub fn set_fan_speed(&mut self, fan_idx: u32, speed: u32) -> Result<(), NvmlError> {
2058        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetFanSpeed_v2.as_ref())?;
2059
2060        unsafe { nvml_try(sym(self.device, fan_idx, speed)) }
2061    }
2062
2063    /**
2064    Sets the the fan control policy to default.
2065
2066    You can determine valid fan indices using [`Self::num_fans()`].
2067
2068    # Errors
2069
2070    * `Uninitialized`, if the library has not been successfully initialized
2071    * `InvalidArg`, if this `Device` is invalid or `fan_idx` is invalid
2072    * `NotSupported`, if this `Device` does not have a fan
2073    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2074    * `UnexpectedVariant`, for which you can read the docs for
2075    * `Unknown`, on any unexpected error
2076
2077    # Device Support
2078
2079    Supports Maxwell or newer fully supported discrete devices with fans.
2080     */
2081    #[doc(alias = "nvmlDeviceSetDefaultFanSpeed_v2")]
2082    pub fn set_default_fan_speed(&mut self, fan_idx: u32) -> Result<(), NvmlError> {
2083        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetDefaultFanSpeed_v2.as_ref())?;
2084
2085        unsafe { nvml_try(sym(self.device, fan_idx)) }
2086    }
2087
2088    /**
2089    Gets the number of fans on this [`Device`].
2090
2091    # Errors
2092
2093    * `Uninitialized`, if the library has not been successfully initialized
2094    * `NotSupported`, if this `Device` does not have a fan
2095    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2096    * `Unknown`, on any unexpected error
2097
2098    # Device Support
2099
2100    Supports all discrete products with dedicated fans.
2101    */
2102    #[doc(alias = "nvmlDeviceGetNumFans")]
2103    pub fn num_fans(&self) -> Result<u32, NvmlError> {
2104        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetNumFans.as_ref())?;
2105
2106        unsafe {
2107            let mut count: c_uint = mem::zeroed();
2108            nvml_try(sym(self.device, &mut count))?;
2109
2110            Ok(count)
2111        }
2112    }
2113
2114    /**
2115    Gets the current GPU operation mode and the pending one (that it will switch to
2116    after a reboot).
2117
2118    # Errors
2119
2120    * `Uninitialized`, if the library has not been successfully initialized
2121    * `InvalidArg`, if this `Device` is invalid
2122    * `NotSupported`, if this `Device` does not support this feature
2123    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2124    * `UnexpectedVariant`, for which you can read the docs for
2125    * `Unknown`, on any unexpected error
2126
2127    # Device Support
2128
2129    Supports GK110 M-class and X-class Tesla products from the Kepler family. Modes `LowDP`
2130    and `AllOn` are supported on fully supported GeForce products. Not supported
2131    on Quadro and Tesla C-class products.
2132    */
2133    // Checked against local
2134    // Tested on machines other than my own
2135    #[doc(alias = "nvmlDeviceGetGpuOperationMode")]
2136    pub fn gpu_operation_mode(&self) -> Result<OperationModeState, NvmlError> {
2137        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetGpuOperationMode.as_ref())?;
2138
2139        unsafe {
2140            let mut current: nvmlGpuOperationMode_t = mem::zeroed();
2141            let mut pending: nvmlGpuOperationMode_t = mem::zeroed();
2142
2143            nvml_try(sym(self.device, &mut current, &mut pending))?;
2144
2145            Ok(OperationModeState {
2146                current: OperationMode::try_from(current)?,
2147                pending: OperationMode::try_from(pending)?,
2148            })
2149        }
2150    }
2151
2152    /**
2153    Gets information about processes with a graphics context running on this `Device`.
2154
2155    This only returns information about graphics based processes (OpenGL, DirectX, etc.).
2156
2157    # Errors
2158
2159    * `Uninitialized`, if the library has not been successfully initialized
2160    * `InvalidArg`, if this `Device` is invalid
2161    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2162    * `Unknown`, on any unexpected error
2163    */
2164    // Tested
2165    #[doc(alias = "nvmlDeviceGetGraphicsRunningProcesses_v3")]
2166    pub fn running_graphics_processes(&self) -> Result<Vec<ProcessInfo>, NvmlError> {
2167        let sym = nvml_sym(
2168            self.nvml
2169                .lib
2170                .nvmlDeviceGetGraphicsRunningProcesses_v3
2171                .as_ref(),
2172        )?;
2173
2174        unsafe {
2175            let mut count: c_uint = match self.running_graphics_processes_count()? {
2176                0 => return Ok(vec![]),
2177                value => value,
2178            };
2179            // Add a bit of headroom in case more processes are launched in
2180            // between the above call to get the expected count and the time we
2181            // actually make the call to get data below.
2182            count += 5;
2183            let mut processes: Vec<nvmlProcessInfo_t> = vec![mem::zeroed(); count as usize];
2184
2185            nvml_try(sym(self.device, &mut count, processes.as_mut_ptr()))?;
2186            processes.truncate(count as usize);
2187
2188            Ok(processes.into_iter().map(ProcessInfo::from).collect())
2189        }
2190    }
2191
2192    /**
2193    Gets the number of processes with a graphics context running on this `Device`.
2194
2195    This only returns the count of graphics based processes (OpenGL, DirectX).
2196
2197    # Errors
2198
2199    * `Uninitialized`, if the library has not been successfully initialized
2200    * `InvalidArg`, if this `Device` is invalid
2201    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2202    * `UnexpectedVariant`, for which you can read the docs for
2203    * `Unknown`, on any unexpected error
2204    */
2205    // Tested as part of `.running_graphics_processes()`
2206    #[doc(alias = "nvmlDeviceGetGraphicsRunningProcesses_v3")]
2207    pub fn running_graphics_processes_count(&self) -> Result<u32, NvmlError> {
2208        let sym = nvml_sym(
2209            self.nvml
2210                .lib
2211                .nvmlDeviceGetGraphicsRunningProcesses_v3
2212                .as_ref(),
2213        )?;
2214
2215        unsafe {
2216            // Indicates that we want the count
2217            let mut count: c_uint = 0;
2218
2219            // Passing null doesn't indicate that we want the count. It's just allowed.
2220            match sym(self.device, &mut count, ptr::null_mut()) {
2221                nvmlReturn_enum_NVML_ERROR_INSUFFICIENT_SIZE => Ok(count),
2222                // If success, return 0; otherwise, return error
2223                other => nvml_try(other).map(|_| 0),
2224            }
2225        }
2226    }
2227
2228    /**
2229    Gets information about processes with a graphics context running on this `Device`.
2230
2231    This only returns information about graphics based processes (OpenGL, DirectX, etc.).
2232
2233    # Errors
2234
2235    * `Uninitialized`, if the library has not been successfully initialized
2236    * `InvalidArg`, if this `Device` is invalid
2237    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2238    * `Unknown`, on any unexpected error
2239    */
2240    #[doc(alias = "nvmlDeviceGetGraphicsRunningProcesses_v2")]
2241    #[cfg(feature = "legacy-functions")]
2242    pub fn running_graphics_processes_v2(&self) -> Result<Vec<ProcessInfo>, NvmlError> {
2243        let sym = nvml_sym(
2244            self.nvml
2245                .lib
2246                .nvmlDeviceGetGraphicsRunningProcesses_v2
2247                .as_ref(),
2248        )?;
2249
2250        unsafe {
2251            let mut count: c_uint = match self.running_graphics_processes_count_v2()? {
2252                0 => return Ok(vec![]),
2253                value => value,
2254            };
2255            // Add a bit of headroom in case more processes are launched in
2256            // between the above call to get the expected count and the time we
2257            // actually make the call to get data below.
2258            count += 5;
2259            let mut processes: Vec<nvmlProcessInfo_v2_t> = vec![mem::zeroed(); count as usize];
2260
2261            nvml_try(sym(self.device, &mut count, processes.as_mut_ptr()))?;
2262            processes.truncate(count as usize);
2263
2264            Ok(processes.into_iter().map(ProcessInfo::from).collect())
2265        }
2266    }
2267
2268    /**
2269    Gets the number of processes with a graphics context running on this `Device`.
2270
2271    This only returns the count of graphics based processes (OpenGL, DirectX).
2272
2273    # Errors
2274
2275    * `Uninitialized`, if the library has not been successfully initialized
2276    * `InvalidArg`, if this `Device` is invalid
2277    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2278    * `UnexpectedVariant`, for which you can read the docs for
2279    * `Unknown`, on any unexpected error
2280    */
2281    #[doc(alias = "nvmlDeviceGetGraphicsRunningProcesses_v2")]
2282    #[cfg(feature = "legacy-functions")]
2283    pub fn running_graphics_processes_count_v2(&self) -> Result<u32, NvmlError> {
2284        let sym = nvml_sym(
2285            self.nvml
2286                .lib
2287                .nvmlDeviceGetGraphicsRunningProcesses_v2
2288                .as_ref(),
2289        )?;
2290
2291        unsafe {
2292            // Indicates that we want the count
2293            let mut count: c_uint = 0;
2294
2295            // Passing null doesn't indicate that we want the count. It's just allowed.
2296            match sym(self.device, &mut count, ptr::null_mut()) {
2297                nvmlReturn_enum_NVML_ERROR_INSUFFICIENT_SIZE => Ok(count),
2298                // If success, return 0; otherwise, return error
2299                other => nvml_try(other).map(|_| 0),
2300            }
2301        }
2302    }
2303
2304    /**
2305    Gets utilization stats for relevant currently running processes.
2306
2307    Utilization stats are returned for processes that had a non-zero utilization stat
2308    at some point during the target sample period. Passing `None` as the
2309    `last_seen_timestamp` will target all samples that the driver has buffered; passing
2310    a timestamp retrieved from a previous query will target samples taken since that
2311    timestamp.
2312
2313    # Errors
2314
2315    * `Uninitialized`, if the library has not been successfully initialized
2316    * `InvalidArg`, if this `Device` is invalid
2317    * `NotSupported`, if this `Device` does not support this feature
2318    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2319    * `Unknown`, on any unexpected error
2320
2321    # Device Support
2322
2323    Supports Maxwell or newer fully supported devices.
2324    */
2325    #[doc(alias = "nvmlDeviceGetProcessUtilization")]
2326    pub fn process_utilization_stats<T>(
2327        &self,
2328        last_seen_timestamp: T,
2329    ) -> Result<Vec<ProcessUtilizationSample>, NvmlError>
2330    where
2331        T: Into<Option<u64>>,
2332    {
2333        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetProcessUtilization.as_ref())?;
2334
2335        unsafe {
2336            let last_seen_timestamp = last_seen_timestamp.into().unwrap_or(0);
2337            let mut count = match self.process_utilization_stats_count(last_seen_timestamp)? {
2338                0 => return Ok(vec![]),
2339                v => v,
2340            };
2341            let mut utilization_samples: Vec<nvmlProcessUtilizationSample_t> =
2342                vec![mem::zeroed(); count as usize];
2343
2344            nvml_try(sym(
2345                self.device,
2346                utilization_samples.as_mut_ptr(),
2347                &mut count,
2348                last_seen_timestamp,
2349            ))?;
2350            utilization_samples.truncate(count as usize);
2351
2352            Ok(utilization_samples
2353                .into_iter()
2354                .map(ProcessUtilizationSample::from)
2355                .collect())
2356        }
2357    }
2358
2359    fn process_utilization_stats_count(
2360        &self,
2361        last_seen_timestamp: u64,
2362    ) -> Result<c_uint, NvmlError> {
2363        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetProcessUtilization.as_ref())?;
2364
2365        unsafe {
2366            let mut count: c_uint = 0;
2367
2368            match sym(
2369                self.device,
2370                ptr::null_mut(),
2371                &mut count,
2372                last_seen_timestamp,
2373            ) {
2374                // Despite being undocumented, this appears to be the correct behavior
2375                nvmlReturn_enum_NVML_ERROR_INSUFFICIENT_SIZE => Ok(count),
2376                other => nvml_try(other).map(|_| 0),
2377            }
2378        }
2379    }
2380
2381    /**
2382    Gets the NVML index of this `Device`.
2383
2384    Keep in mind that the order in which NVML enumerates devices has no guarantees of
2385    consistency between reboots. Also, the NVML index may not correlate with other APIs,
2386    such as the CUDA device index.
2387
2388    # Errors
2389
2390    * `Uninitialized`, if the library has not been successfully initialized
2391    * `InvalidArg`, if this `Device` is invalid
2392    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2393    */
2394    // Checked against local
2395    // Tested
2396    #[doc(alias = "nvmlDeviceGetIndex")]
2397    pub fn index(&self) -> Result<u32, NvmlError> {
2398        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetIndex.as_ref())?;
2399
2400        unsafe {
2401            let mut index: c_uint = mem::zeroed();
2402            nvml_try(sym(self.device, &mut index))?;
2403
2404            Ok(index)
2405        }
2406    }
2407
2408    /**
2409    Gets the checksum of the config stored in this `Device`'s infoROM.
2410
2411    Can be used to make sure that two GPUs have the exact same configuration.
2412    The current checksum takes into account configuration stored in PWR and ECC
2413    infoROM objects. The checksum can change between driver released or when the
2414    user changes the configuration (e.g. disabling/enabling ECC).
2415
2416    # Errors
2417
2418    * `CorruptedInfoROM`, if this `Device`'s checksum couldn't be retrieved due to infoROM corruption
2419    * `Uninitialized`, if the library has not been successfully initialized
2420    * `NotSupported`, if this `Device` does not support this feature
2421    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2422    * `Unknown`, on any unexpected error
2423
2424    # Device Support
2425
2426    Supports all devices with an infoROM.
2427    */
2428    // Checked against local
2429    // Tested on machines other than my own
2430    #[doc(alias = "nvmlDeviceGetInforomConfigurationChecksum")]
2431    pub fn config_checksum(&self) -> Result<u32, NvmlError> {
2432        let sym = nvml_sym(
2433            self.nvml
2434                .lib
2435                .nvmlDeviceGetInforomConfigurationChecksum
2436                .as_ref(),
2437        )?;
2438
2439        unsafe {
2440            let mut checksum: c_uint = mem::zeroed();
2441
2442            nvml_try(sym(self.device, &mut checksum))?;
2443
2444            Ok(checksum)
2445        }
2446    }
2447
2448    /**
2449    Gets the global infoROM image version.
2450
2451    This image version, just like the VBIOS version, uniquely describes the exact version
2452    of the infoROM flashed on the board, in contrast to the infoROM object version which
2453    is only an indicator of supported features.
2454
2455    # Errors
2456
2457    * `Uninitialized`, if the library has not been successfully initialized
2458    * `InvalidArg`, if this `Device` is invalid
2459    * `NotSupported`, if this `Device` does not have an infoROM
2460    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2461    * `Utf8Error`, if the string obtained from the C function is not valid Utf8
2462    * `Unknown`, on any unexpected error
2463
2464    # Device Support
2465
2466    Supports all devices with an infoROM.
2467    */
2468    // Checked against local
2469    // Tested on machines other than my own
2470    #[doc(alias = "nvmlDeviceGetInforomImageVersion")]
2471    pub fn info_rom_image_version(&self) -> Result<String, NvmlError> {
2472        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetInforomImageVersion.as_ref())?;
2473
2474        unsafe {
2475            let mut version_vec = vec![0; NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE as usize];
2476
2477            nvml_try(sym(
2478                self.device,
2479                version_vec.as_mut_ptr(),
2480                NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE,
2481            ))?;
2482
2483            let version_raw = CStr::from_ptr(version_vec.as_ptr());
2484            Ok(version_raw.to_str()?.into())
2485        }
2486    }
2487
2488    /**
2489    Gets the version information for this `Device`'s infoROM object, for the passed in
2490    object type.
2491
2492    # Errors
2493
2494    * `Uninitialized`, if the library has not been successfully initialized
2495    * `InvalidArg`, if this `Device` is invalid
2496    * `NotSupported`, if this `Device` does not have an infoROM
2497    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2498    * `Utf8Error`, if the string obtained from the C function is not valid UTF-8
2499    * `Unknown`, on any unexpected error
2500
2501    # Device Support
2502
2503    Supports all devices with an infoROM.
2504
2505    Fermi and higher parts have non-volatile on-board memory for persisting device info,
2506    such as aggregate ECC counts. The version of the data structures in this memory may
2507    change from time to time.
2508    */
2509    // Checked against local
2510    // Tested on machines other than my own
2511    #[doc(alias = "nvmlDeviceGetInforomVersion")]
2512    pub fn info_rom_version(&self, object: InfoRom) -> Result<String, NvmlError> {
2513        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetInforomVersion.as_ref())?;
2514
2515        unsafe {
2516            let mut version_vec = vec![0; NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE as usize];
2517
2518            nvml_try(sym(
2519                self.device,
2520                object.as_c(),
2521                version_vec.as_mut_ptr(),
2522                NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE,
2523            ))?;
2524
2525            let version_raw = CStr::from_ptr(version_vec.as_ptr());
2526            Ok(version_raw.to_str()?.into())
2527        }
2528    }
2529
2530    /**
2531    Gets the maximum clock speeds for this `Device`.
2532
2533    # Errors
2534
2535    * `Uninitialized`, if the library has not been successfully initialized
2536    * `InvalidArg`, if this `Device` is invalid
2537    * `NotSupported`, if this `Device` cannot report the specified `Clock`
2538    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2539    * `Unknown`, on any unexpected error
2540
2541    # Device Support
2542
2543    Supports Fermi and newer fully supported devices.
2544
2545    Note: On GPUs from the Fermi family, current P0 (Performance state 0?) clocks
2546    (reported by `.clock_info()`) can differ from max clocks by a few MHz.
2547    */
2548    // Checked against local
2549    // Tested
2550    #[doc(alias = "nvmlDeviceGetMaxClockInfo")]
2551    pub fn max_clock_info(&self, clock_type: Clock) -> Result<u32, NvmlError> {
2552        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetMaxClockInfo.as_ref())?;
2553
2554        unsafe {
2555            let mut clock: c_uint = mem::zeroed();
2556
2557            nvml_try(sym(self.device, clock_type.as_c(), &mut clock))?;
2558
2559            Ok(clock)
2560        }
2561    }
2562
2563    /**
2564    Gets the max PCIe link generation possible with this `Device` and system.
2565
2566    For a gen 2 PCIe device attached to a gen 1 PCIe bus, the max link generation
2567    this function will report is generation 1.
2568
2569    # Errors
2570
2571    * `Uninitialized`, if the library has not been successfully initialized
2572    * `InvalidArg`, if this `Device` is invalid
2573    * `NotSupported`, if PCIe link information is not available
2574    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2575    * `Unknown`, on any unexpected error
2576
2577    # Device Support
2578
2579    Supports Fermi and newer fully supported devices.
2580    */
2581    // Checked against local
2582    // Tested
2583    #[doc(alias = "nvmlDeviceGetMaxPcieLinkGeneration")]
2584    pub fn max_pcie_link_gen(&self) -> Result<u32, NvmlError> {
2585        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetMaxPcieLinkGeneration.as_ref())?;
2586
2587        unsafe {
2588            let mut max_gen: c_uint = mem::zeroed();
2589
2590            nvml_try(sym(self.device, &mut max_gen))?;
2591
2592            Ok(max_gen)
2593        }
2594    }
2595
2596    /**
2597    Gets the maximum PCIe link width possible with this `Device` and system.
2598
2599    For a device with a 16x PCie bus width attached to an 8x PCIe system bus,
2600    this method will report a max link width of 8.
2601
2602    # Errors
2603
2604    * `Uninitialized`, if the library has not been successfully initialized
2605    * `InvalidArg`, if this `Device` is invalid
2606    * `NotSupported`, if PCIe link information is not available
2607    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2608    * `Unknown`, on any unexpected error
2609
2610    # Device Support
2611
2612    Supports Fermi and newer fully supported devices.
2613    */
2614    // Checked against local
2615    // Tested
2616    #[doc(alias = "nvmlDeviceGetMaxPcieLinkWidth")]
2617    pub fn max_pcie_link_width(&self) -> Result<u32, NvmlError> {
2618        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetMaxPcieLinkWidth.as_ref())?;
2619
2620        unsafe {
2621            let mut max_width: c_uint = mem::zeroed();
2622            nvml_try(sym(self.device, &mut max_width))?;
2623
2624            Ok(max_width)
2625        }
2626    }
2627
2628    /**
2629    Gets the requested memory error counter for this `Device`.
2630
2631    Only applicable to devices with ECC. Requires ECC mode to be enabled.
2632
2633    # Errors
2634
2635    * `Uninitialized`, if the library has not been successfully initialized
2636    * `InvalidArg`, if `error_type`, `counter_type`, or `location` is invalid (shouldn't occur?)
2637    * `NotSupported`, if this `Device` does not support ECC error reporting for the specified
2638    * memory
2639    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2640    * `Unknown`, on any unexpected error
2641
2642    # Device Support
2643
2644    Supports Fermi and newer fully supported devices. Requires `InfoRom::ECC` version
2645    2.0 or higher to report aggregate location-based memory error counts. Requires
2646    `InfoRom::ECC version 1.0 or higher to report all other memory error counts.
2647    */
2648    // Checked against local
2649    // Tested on machines other than my own
2650    #[doc(alias = "nvmlDeviceGetMemoryErrorCounter")]
2651    pub fn memory_error_counter(
2652        &self,
2653        error_type: MemoryError,
2654        counter_type: EccCounter,
2655        location: MemoryLocation,
2656    ) -> Result<u64, NvmlError> {
2657        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetMemoryErrorCounter.as_ref())?;
2658
2659        unsafe {
2660            let mut count: c_ulonglong = mem::zeroed();
2661
2662            nvml_try(sym(
2663                self.device,
2664                error_type.as_c(),
2665                counter_type.as_c(),
2666                location.as_c(),
2667                &mut count,
2668            ))?;
2669
2670            Ok(count)
2671        }
2672    }
2673
2674    /**
2675    Gets the amount of used, free and total memory available on this `Device`, in bytes.
2676
2677    Note that enabling ECC reduces the amount of total available memory due to the
2678    extra required parity bits.
2679
2680    Also note that on Windows, most device memory is allocated and managed on startup
2681    by Windows.
2682
2683    Under Linux and Windows TCC (no physical display connected), the reported amount
2684    of used memory is equal to the sum of memory allocated by all active channels on
2685    this `Device`.
2686
2687    # Errors
2688
2689    * `Uninitialized`, if the library has not been successfully initialized
2690    * `InvalidArg`, if this `Device` is invalid
2691    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2692    * `Unknown`, on any unexpected error
2693    */
2694    // Checked against local
2695    // Tested
2696    #[doc(alias = "nvmlDeviceGetMemoryInfo")]
2697    pub fn memory_info(&self) -> Result<MemoryInfo, NvmlError> {
2698        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetMemoryInfo_v2.as_ref())?;
2699
2700        unsafe {
2701            let mut info: nvmlMemory_v2_t = mem::zeroed();
2702
2703            // Implements NVML_STRUCT_VERSION(Memory, 2), as detailed in nvml.h (https://github.com/NVIDIA/nvidia-settings/issues/78)
2704            info.version = (std::mem::size_of::<nvmlMemory_v2_t>() | (2_usize << 24_usize)) as u32;
2705            nvml_try(sym(self.device, &mut info))?;
2706
2707            Ok(info.into())
2708        }
2709    }
2710
2711    /**
2712    Gets the minor number for this `Device`.
2713
2714    The minor number is such that the NVIDIA device node file for each GPU will
2715    have the form `/dev/nvidia[minor number]`.
2716
2717    # Errors
2718
2719    * `Uninitialized`, if the library has not been successfully initialized
2720    * `InvalidArg`, if this `Device` is invalid
2721    * `NotSupported`, if this query is not supported by this `Device`
2722    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2723    * `Unknown`, on any unexpected error
2724
2725    # Platform Support
2726
2727    Only supports Linux.
2728    */
2729    // Checked against local
2730    // Tested
2731    #[cfg(target_os = "linux")]
2732    #[doc(alias = "nvmlDeviceGetMinorNumber")]
2733    pub fn minor_number(&self) -> Result<u32, NvmlError> {
2734        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetMinorNumber.as_ref())?;
2735
2736        unsafe {
2737            let mut number: c_uint = mem::zeroed();
2738            nvml_try(sym(self.device, &mut number))?;
2739
2740            Ok(number)
2741        }
2742    }
2743
2744    /**
2745    Identifies whether or not this `Device` is on a multi-GPU board.
2746
2747    # Errors
2748
2749    * `Uninitialized`, if the library has not been successfully initialized
2750    * `InvalidArg`, if this `Device` is invalid
2751    * `NotSupported`, if this `Device` does not support this feature
2752    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2753    * `Unknown`, on any unexpected error
2754
2755    # Device Support
2756
2757    Supports Fermi or newer fully supported devices.
2758    */
2759    // Checked against local
2760    // Tested
2761    #[doc(alias = "nvmlDeviceGetMultiGpuBoard")]
2762    pub fn is_multi_gpu_board(&self) -> Result<bool, NvmlError> {
2763        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetMultiGpuBoard.as_ref())?;
2764
2765        unsafe {
2766            let mut int_bool: c_uint = mem::zeroed();
2767            nvml_try(sym(self.device, &mut int_bool))?;
2768
2769            match int_bool {
2770                0 => Ok(false),
2771                _ => Ok(true),
2772            }
2773        }
2774    }
2775
2776    /**
2777     Get Gpu instance profile info for a give profile.
2778    # Errors
2779
2780    * `Uninitialized`, if the library has not been successfully initialized
2781    * `InvalidArg`, if this `Device` is invalid
2782    * `NotSupported`, if this `Device` does not support this feature
2783    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2784    * `Unknown`, on any unexpected error
2785
2786    # Platform Support
2787
2788    Only supports Linux.
2789
2790    # Device Support
2791
2792    Supports Ampere and newer fully supported devices.
2793    */
2794    #[cfg(target_os = "linux")]
2795    #[doc(alias = "nvmlDeviceGetGpuInstanceProfileInfo")]
2796    pub fn profile_info(&self, profile: u32) -> Result<ProfileInfo, NvmlError> {
2797        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetGpuInstanceProfileInfo.as_ref())?;
2798
2799        unsafe {
2800            let mut info: nvmlGpuInstanceProfileInfo_t = mem::zeroed();
2801            nvml_try(sym(self.device, profile, &mut info))?;
2802
2803            Ok(info.into())
2804        }
2805    }
2806
2807    /**
2808     Get GPU instance placements. A placement is a given location of a GPU in a device.
2809
2810    # Errors
2811
2812    * `Uninitialized`, if the library has not been successfully initialized
2813    * `InvalidArg`, if this `Device` is invalid
2814    * `NotSupported`, if this `Device` does not support this feature
2815    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2816    * `Unknown`, on any unexpected error
2817
2818    # Platform Support
2819
2820    Only supports Linux.
2821
2822    # Device Support
2823
2824    Supports Ampere and newer fully supported devices.
2825    */
2826    #[cfg(target_os = "linux")]
2827    #[doc(alias = "nvmlDeviceGetGpuInstancePossiblePlacements_v2")]
2828    pub fn possible_placements(
2829        &self,
2830        profile: u32,
2831    ) -> Result<Vec<GpuInstancePlacement>, NvmlError> {
2832        let sym = nvml_sym(
2833            self.nvml
2834                .lib
2835                .nvmlDeviceGetGpuInstancePossiblePlacements_v2
2836                .as_ref(),
2837        )?;
2838
2839        unsafe {
2840            let mut count: c_uint = 0;
2841            nvml_try(sym(self.device, profile, ptr::null_mut(), &mut count))?;
2842            let mut placements: Vec<nvmlGpuInstancePlacement_t> =
2843                Vec::with_capacity(count as usize);
2844
2845            nvml_try(sym(
2846                self.device,
2847                profile,
2848                placements.as_mut_ptr(),
2849                &mut count,
2850            ))?;
2851
2852            Ok(placements
2853                .into_iter()
2854                .map(GpuInstancePlacement::from)
2855                .collect())
2856        }
2857    }
2858
2859    /**
2860    Checks if the `Device`supports multi partitioned GPU feature and if enabled.
2861    Not to confuse with `is_multi_gpu_board`, MIG is a single GPU
2862    being able to be split into isolated instances, a sort of "NUMA" for GPU.
2863    If the `Device` supports MIG, we can have its current mode (enabled/disabled)
2864    and, if set, its pending mode for the next system reboot.
2865    # Errors
2866
2867    * `Uninitialized`, if the library has not been successfully initialized
2868    * `InvalidArg`, if this `Device` is invalid
2869    * `NotSupported`, if this `Device` does not support this feature
2870    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2871    * `Unknown`, on any unexpected error
2872    */
2873    #[doc(alias = "nvmlDeviceGetMigMode")]
2874    pub fn mig_mode(&self) -> Result<MigMode, NvmlError> {
2875        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetMigMode.as_ref())?;
2876
2877        unsafe {
2878            let mut mode: MigMode = mem::zeroed();
2879            nvml_try(sym(self.device, &mut mode.current, &mut mode.pending))?;
2880
2881            Ok(mode)
2882        }
2883    }
2884
2885    /**
2886    Set the Device MIG mode ; even if the GPU supports this feature,
2887    the setting can still fail (e.g. device still in use).
2888    # Errors
2889
2890    * `Uninitialized`, if the library has not been successfully initialized
2891    * `InvalidArg`, if this `Device` is invalid
2892    * `NotSupported`, if this `Device` does not support this feature
2893    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2894    * `Unknown`, on any unexpected error
2895    */
2896    #[doc(alias = "nvmlDeviceSetMigMode")]
2897    pub fn set_mig_mode(&self, m: bool) -> Result<u32, NvmlError> {
2898        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetMigMode.as_ref())?;
2899
2900        unsafe {
2901            let mode: c_uint = match m {
2902                true => NVML_DEVICE_MIG_ENABLE,
2903                false => NVML_DEVICE_MIG_DISABLE,
2904            };
2905            let mut status: c_uint = 0;
2906
2907            nvml_try(sym(self.device, mode, &mut status))?;
2908            Ok(status)
2909        }
2910    }
2911
2912    /**
2913     Gets the MIG device handle from `index` on a parent physical GPU
2914     # Errors
2915
2916    * `Uninitialized`, if the library has not been successfully initialized
2917    * `InvalidArg`, if this `Device` is invalid
2918    * `NotSupported`, if this `Device` does not support this feature
2919    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2920    * `Unknown`, on any unexpected error
2921    */
2922    #[doc(alias = "nvmlDeviceGetMigDeviceHandleByIndex")]
2923    pub fn mig_device_by_index(&self, index: u32) -> Result<Device<'nvml>, NvmlError> {
2924        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetMigDeviceHandleByIndex.as_ref())?;
2925
2926        unsafe {
2927            let mut parent: nvmlDevice_t = mem::zeroed();
2928            nvml_try(sym(self.device, index, &mut parent))?;
2929
2930            Ok(Device::new(parent, self.nvml))
2931        }
2932    }
2933
2934    /**
2935     Gets the parent device from the MiG device handle
2936     # Errors
2937
2938    * `Uninitialized`, if the library has not been successfully initialized
2939    * `InvalidArg`, if this `Device` is invalid
2940    * `NotSupported`, if this `Device` does not support this feature
2941    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2942    * `Unknown`, on any unexpected error
2943    */
2944    #[doc(alias = "nvmlDeviceGetDeviceHandleFromMigDeviceHandle")]
2945    pub fn mig_parent_device(&self) -> Result<Device<'nvml>, NvmlError> {
2946        let sym = nvml_sym(
2947            self.nvml
2948                .lib
2949                .nvmlDeviceGetDeviceHandleFromMigDeviceHandle
2950                .as_ref(),
2951        )?;
2952
2953        unsafe {
2954            let mut parent: nvmlDevice_t = mem::zeroed();
2955            nvml_try(sym(self.device, &mut parent))?;
2956
2957            Ok(Device::new(parent, self.nvml))
2958        }
2959    }
2960
2961    /**
2962     Gets the maximum number of MIG devices on a physical GPU
2963     # Errors
2964
2965    * `Uninitialized`, if the library has not been successfully initialized
2966    * `InvalidArg`, if this `Device` is invalid
2967    * `NotSupported`, if this `Device` does not support this feature
2968    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2969    * `Unknown`, on any unexpected error
2970    */
2971    #[doc(alias = "nvmlDeviceGetMaxMigDeviceCount")]
2972    pub fn mig_device_count(&self) -> Result<u32, NvmlError> {
2973        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetMaxMigDeviceCount.as_ref())?;
2974
2975        unsafe {
2976            let mut count: c_uint = 0;
2977            nvml_try(sym(self.device, &mut count))?;
2978
2979            Ok(count)
2980        }
2981    }
2982
2983    /**
2984     Determines if the current device is of MIG type
2985     # Errors
2986
2987    * `Uninitialized`, if the library has not been successfully initialized
2988    * `InvalidArg`, if this `Device` is invalid
2989    * `NotSupported`, if this `Device` does not support this feature
2990    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
2991    * `Unknown`, on any unexpected error
2992    */
2993    pub fn mig_is_mig_device_handle(&self) -> Result<bool, NvmlError> {
2994        let sym = nvml_sym(self.nvml.lib.nvmlDeviceIsMigDeviceHandle.as_ref())?;
2995
2996        unsafe {
2997            let mut mig_handle: c_uint = 0;
2998            nvml_try(sym(self.device, &mut mig_handle))?;
2999
3000            Ok(mig_handle > 0)
3001        }
3002    }
3003
3004    /**
3005    The name of this `Device`, e.g. "Tesla C2070".
3006
3007    The name is an alphanumeric string that denotes a particular product.
3008
3009    # Errors
3010
3011    * `Uninitialized`, if the library has not been successfully initialized
3012    * `InvalidArg`, if this `Device` is invalid
3013    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3014    * `Utf8Error`, if the string obtained from the C function is not valid Utf8
3015    * `Unknown`, on any unexpected error
3016    */
3017    // Checked against local
3018    // Tested
3019    #[doc(alias = "nvmlDeviceGetName")]
3020    pub fn name(&self) -> Result<String, NvmlError> {
3021        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetName.as_ref())?;
3022
3023        unsafe {
3024            let mut name_vec = vec![0; NVML_DEVICE_NAME_V2_BUFFER_SIZE as usize];
3025
3026            nvml_try(sym(
3027                self.device,
3028                name_vec.as_mut_ptr(),
3029                NVML_DEVICE_NAME_V2_BUFFER_SIZE,
3030            ))?;
3031
3032            let name_raw = CStr::from_ptr(name_vec.as_ptr());
3033            Ok(name_raw.to_str()?.into())
3034        }
3035    }
3036
3037    /**
3038    Gets the PCI attributes of this `Device`.
3039
3040    See `PciInfo` for details about the returned attributes.
3041
3042    # Errors
3043
3044    * `Uninitialized`, if the library has not been successfully initialized
3045    * `InvalidArg`, if this `Device` is invalid
3046    * `GpuLost`, if the GPU has fallen off the bus or is otherwise inaccessible
3047    * `Utf8Error`, if a string obtained from the C function is not valid Utf8
3048    * `Unknown`, on any unexpected error
3049    */
3050    // Checked against local
3051    // Tested
3052    #[doc(alias = "nvmlDeviceGetPciInfo_v3")]
3053    pub fn pci_info(&self) -> Result<PciInfo, NvmlError> {
3054        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetPciInfo_v3.as_ref())?;
3055
3056        unsafe {
3057            let mut pci_info: nvmlPciInfo_t = mem::zeroed();
3058            nvml_try(sym(self.device, &mut pci_info))?;
3059
3060            PciInfo::try_from(pci_info, true)
3061        }
3062    }
3063
3064    /**
3065    Gets the PCIe replay counter.
3066
3067    # Errors
3068
3069    * `Uninitialized`, if the library has not been successfully initialized
3070    * `InvalidArg`, if this `Device` is invalid
3071    * `NotSupported`, if this `Device` does not support this feature
3072    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3073    * `Unknown`, on any unexpected error
3074
3075    # Device Support
3076
3077    Supports Kepler or newer fully supported devices.
3078    */
3079    // Checked against local
3080    // Tested
3081    #[doc(alias = "nvmlDeviceGetPcieReplayCounter")]
3082    pub fn pcie_replay_counter(&self) -> Result<u32, NvmlError> {
3083        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetPcieReplayCounter.as_ref())?;
3084
3085        unsafe {
3086            let mut value: c_uint = mem::zeroed();
3087            nvml_try(sym(self.device, &mut value))?;
3088
3089            Ok(value)
3090        }
3091    }
3092
3093    /**
3094    Gets PCIe utilization information in KB/s.
3095
3096    The function called within this method is querying a byte counter over a 20ms
3097    interval and thus is the PCIE throughput over that interval.
3098
3099    # Errors
3100
3101    * `Uninitialized`, if the library has not been successfully initialized
3102    * `InvalidArg`, if this `Device` is invalid or `counter` is invalid (shouldn't occur?)
3103    * `NotSupported`, if this `Device` does not support this feature
3104    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3105    * `Unknown`, on any unexpected error
3106
3107    # Device Support
3108
3109    Supports Maxwell and newer fully supported devices.
3110
3111    # Environment Support
3112
3113    This method is not supported on virtual machines running vGPUs.
3114    */
3115    // Checked against local
3116    // Tested
3117    #[doc(alias = "nvmlDeviceGetPcieThroughput")]
3118    pub fn pcie_throughput(&self, counter: PcieUtilCounter) -> Result<u32, NvmlError> {
3119        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetPcieThroughput.as_ref())?;
3120
3121        unsafe {
3122            let mut throughput: c_uint = mem::zeroed();
3123
3124            nvml_try(sym(self.device, counter.as_c(), &mut throughput))?;
3125
3126            Ok(throughput)
3127        }
3128    }
3129
3130    /**
3131    Gets the current performance state for this `Device`. 0 == max, 15 == min.
3132
3133    # Errors
3134
3135    * `Uninitialized`, if the library has not been successfully initialized
3136    * `InvalidArg`, if this `Device` is invalid
3137    * `NotSupported`, if this `Device` does not support this feature
3138    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3139    * `UnexpectedVariant`, for which you can read the docs for
3140    * `Unknown`, on any unexpected error
3141
3142    # Device Support
3143
3144    Supports Fermi or newer fully supported devices.
3145    */
3146    // Checked against local
3147    // Tested
3148    #[doc(alias = "nvmlDeviceGetPerformanceState")]
3149    pub fn performance_state(&self) -> Result<PerformanceState, NvmlError> {
3150        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetPerformanceState.as_ref())?;
3151
3152        unsafe {
3153            let mut state: nvmlPstates_t = mem::zeroed();
3154            nvml_try(sym(self.device, &mut state))?;
3155
3156            PerformanceState::try_from(state)
3157        }
3158    }
3159
3160    /**
3161    Gets whether or not persistent mode is enabled for this `Device`.
3162
3163    When driver persistence mode is enabled the driver software is not torn down
3164    when the last client disconnects. This feature is disabled by default.
3165
3166    # Errors
3167
3168    * `Uninitialized`, if the library has not been successfully initialized
3169    * `InvalidArg`, if this `Device` is invalid
3170    * `NotSupported`, if this `Device` does not support this feature
3171    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3172    * `UnexpectedVariant`, for which you can read the docs for
3173    * `Unknown`, on any unexpected error
3174
3175    # Platform Support
3176
3177    Only supports Linux.
3178    */
3179    // Checked against local
3180    // Tested
3181    #[cfg(target_os = "linux")]
3182    #[doc(alias = "nvmlDeviceGetPersistenceMode")]
3183    pub fn is_in_persistent_mode(&self) -> Result<bool, NvmlError> {
3184        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetPersistenceMode.as_ref())?;
3185
3186        unsafe {
3187            let mut state: nvmlEnableState_t = mem::zeroed();
3188            nvml_try(sym(self.device, &mut state))?;
3189
3190            bool_from_state(state)
3191        }
3192    }
3193
3194    /**
3195    Gets the default power management limit for this `Device`, in milliwatts.
3196
3197    This is the limit that this `Device` boots with.
3198
3199    # Errors
3200
3201    * `Uninitialized`, if the library has not been successfully initialized
3202    * `InvalidArg`, if this `Device` is invalid
3203    * `NotSupported`, if this `Device` does not support this feature
3204    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3205    * `Unknown`, on any unexpected error
3206
3207    # Device Support
3208
3209    Supports Kepler or newer fully supported devices.
3210    */
3211    // Checked against local
3212    // Tested
3213    #[doc(alias = "nvmlDeviceGetPowerManagementDefaultLimit")]
3214    pub fn power_management_limit_default(&self) -> Result<u32, NvmlError> {
3215        let sym = nvml_sym(
3216            self.nvml
3217                .lib
3218                .nvmlDeviceGetPowerManagementDefaultLimit
3219                .as_ref(),
3220        )?;
3221
3222        unsafe {
3223            let mut limit: c_uint = mem::zeroed();
3224            nvml_try(sym(self.device, &mut limit))?;
3225
3226            Ok(limit)
3227        }
3228    }
3229
3230    /**
3231    Gets the power management limit associated with this `Device`.
3232
3233    The power limit defines the upper boundary for the card's power draw. If the card's
3234    total power draw reaches this limit, the power management algorithm kicks in.
3235
3236    # Errors
3237
3238    * `Uninitialized`, if the library has not been successfully initialized
3239    * `InvalidArg`, if this `Device` is invalid
3240    * `NotSupported`, if this `Device` does not support this feature
3241    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3242    * `Unknown`, on any unexpected error
3243
3244    # Device Support
3245
3246    Supports Fermi or newer fully supported devices.
3247
3248    This reading is only supported if power management mode is supported. See
3249    `.is_power_management_algo_active()`. Yes, it's deprecated, but that's what
3250    NVIDIA's docs said to see.
3251    */
3252    // Checked against local
3253    // Tested
3254    #[doc(alias = "nvmlDeviceGetPowerManagementLimit")]
3255    pub fn power_management_limit(&self) -> Result<u32, NvmlError> {
3256        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetPowerManagementLimit.as_ref())?;
3257
3258        unsafe {
3259            let mut limit: c_uint = mem::zeroed();
3260            nvml_try(sym(self.device, &mut limit))?;
3261
3262            Ok(limit)
3263        }
3264    }
3265
3266    /**
3267    Gets information about possible power management limit values for this `Device`, in milliwatts.
3268
3269    # Errors
3270
3271    * `Uninitialized`, if the library has not been successfully initialized
3272    * `InvalidArg`, if this `Device` is invalid
3273    * `NotSupported`, if this `Device` does not support this feature
3274    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3275    * `Unknown`, on any unexpected error
3276
3277    # Device Support
3278
3279    Supports Kepler or newer fully supported devices.
3280    */
3281    // Checked against local
3282    // Tested
3283    #[doc(alias = "nvmlDeviceGetPowerManagementLimitConstraints")]
3284    pub fn power_management_limit_constraints(
3285        &self,
3286    ) -> Result<PowerManagementConstraints, NvmlError> {
3287        let sym = nvml_sym(
3288            self.nvml
3289                .lib
3290                .nvmlDeviceGetPowerManagementLimitConstraints
3291                .as_ref(),
3292        )?;
3293
3294        unsafe {
3295            let mut min_limit: c_uint = mem::zeroed();
3296            let mut max_limit: c_uint = mem::zeroed();
3297
3298            nvml_try(sym(self.device, &mut min_limit, &mut max_limit))?;
3299
3300            Ok(PowerManagementConstraints {
3301                min_limit,
3302                max_limit,
3303            })
3304        }
3305    }
3306
3307    /// Not documenting this because it's deprecated. Read NVIDIA's docs if you
3308    /// must use it.
3309    // Tested
3310    #[deprecated(note = "NVIDIA states that \"this API has been deprecated.\"")]
3311    #[doc(alias = "nvmlDeviceGetPowerManagementMode")]
3312    pub fn is_power_management_algo_active(&self) -> Result<bool, NvmlError> {
3313        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetPowerManagementMode.as_ref())?;
3314
3315        unsafe {
3316            let mut state: nvmlEnableState_t = mem::zeroed();
3317            nvml_try(sym(self.device, &mut state))?;
3318
3319            bool_from_state(state)
3320        }
3321    }
3322
3323    /// Not documenting this because it's deprecated. Read NVIDIA's docs if you
3324    /// must use it.
3325    // Tested
3326    #[deprecated(note = "use `.performance_state()`.")]
3327    #[doc(alias = "nvmlDeviceGetPowerState")]
3328    pub fn power_state(&self) -> Result<PerformanceState, NvmlError> {
3329        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetPowerState.as_ref())?;
3330
3331        unsafe {
3332            let mut state: nvmlPstates_t = mem::zeroed();
3333            nvml_try(sym(self.device, &mut state))?;
3334
3335            PerformanceState::try_from(state)
3336        }
3337    }
3338
3339    /**
3340    Gets the power usage for this GPU and its associated circuitry (memory) in milliwatts.
3341
3342    # Errors
3343
3344    * `Uninitialized`, if the library has not been successfully initialized
3345    * `InvalidArg`, if this `Device` is invalid
3346    * `NotSupported`, if this `Device` does not support power readings
3347    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3348    * `Unknown`, on any unexpected error
3349
3350    # Device Support
3351
3352    Supports Fermi and newer fully supported devices.
3353
3354    This reading is accurate to within +/- 5% of current power draw on Fermi and Kepler GPUs.
3355    It is only supported if power management mode is supported. See `.is_power_management_algo_active()`.
3356    Yes, that is deprecated, but that's what NVIDIA's docs say to see.
3357    */
3358    // Checked against local
3359    // Tested
3360    #[doc(alias = "nvmlDeviceGetPowerUsage")]
3361    pub fn power_usage(&self) -> Result<u32, NvmlError> {
3362        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetPowerUsage.as_ref())?;
3363
3364        unsafe {
3365            let mut usage: c_uint = mem::zeroed();
3366            nvml_try(sym(self.device, &mut usage))?;
3367
3368            Ok(usage)
3369        }
3370    }
3371
3372    /**
3373    Gets this device's total energy consumption in millijoules (mJ) since the last
3374    driver reload.
3375
3376    # Errors
3377
3378    * `Uninitialized`, if the library has not been successfully initialized
3379    * `InvalidArg`, if this `Device` is invalid
3380    * `NotSupported`, if this `Device` does not support energy readings
3381    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3382    * `Unknown`, on any unexpected error
3383
3384    # Device Support
3385
3386    Supports Volta and newer fully supported devices.
3387    */
3388    #[doc(alias = "nvmlDeviceGetTotalEnergyConsumption")]
3389    pub fn total_energy_consumption(&self) -> Result<u64, NvmlError> {
3390        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetTotalEnergyConsumption.as_ref())?;
3391
3392        unsafe {
3393            let mut total: c_ulonglong = mem::zeroed();
3394            nvml_try(sym(self.device, &mut total))?;
3395
3396            Ok(total)
3397        }
3398    }
3399
3400    /**
3401    Gets the list of retired pages filtered by `cause`, including pages pending retirement.
3402
3403    **I cannot verify that this method will work because the call within is not supported
3404    on my dev machine**. Please **verify for yourself** that it works before you use it.
3405    If you are able to test it on your machine, please let me know if it works; if it
3406    doesn't, I would love a PR.
3407
3408    # Errors
3409
3410    * `Uninitialized`, if the library has not been successfully initialized
3411    * `InvalidArg`, if this `Device` is invalid
3412    * `NotSupported`, if this `Device` doesn't support this feature
3413    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3414    * `Unknown`, on any unexpected error
3415
3416    # Device Support
3417
3418    Supports Kepler and newer fully supported devices.
3419    */
3420    // Checked against local
3421    // Tested on machines other than my own
3422    #[doc(alias = "nvmlDeviceGetRetiredPages_v2")]
3423    pub fn retired_pages(&self, cause: RetirementCause) -> Result<Vec<RetiredPage>, NvmlError> {
3424        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetRetiredPages_v2.as_ref())?;
3425
3426        unsafe {
3427            let mut count = match self.retired_pages_count(&cause)? {
3428                0 => return Ok(vec![]),
3429                value => value,
3430            };
3431            let mut addresses: Vec<c_ulonglong> = vec![mem::zeroed(); count as usize];
3432            let mut timestamps: Vec<c_ulonglong> = vec![mem::zeroed(); count as usize];
3433
3434            nvml_try(sym(
3435                self.device,
3436                cause.as_c(),
3437                &mut count,
3438                addresses.as_mut_ptr(),
3439                timestamps.as_mut_ptr(),
3440            ))?;
3441
3442            Ok(addresses
3443                .into_iter()
3444                .zip(timestamps)
3445                .map(|(address, timestamp)| RetiredPage { address, timestamp })
3446                .collect())
3447        }
3448    }
3449
3450    // Helper for the above function. Returns # of samples that can be queried.
3451    fn retired_pages_count(&self, cause: &RetirementCause) -> Result<c_uint, NvmlError> {
3452        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetRetiredPages.as_ref())?;
3453
3454        unsafe {
3455            let mut count: c_uint = 0;
3456
3457            nvml_try(sym(
3458                self.device,
3459                cause.as_c(),
3460                &mut count,
3461                // All NVIDIA says is that this
3462                // can't be null.
3463                &mut mem::zeroed(),
3464            ))?;
3465
3466            Ok(count)
3467        }
3468    }
3469
3470    /**
3471    Gets whether there are pages pending retirement (they need a reboot to fully retire).
3472
3473    # Errors
3474
3475    * `Uninitialized`, if the library has not been successfully initialized
3476    * `InvalidArg`, if this `Device` is invalid
3477    * `NotSupported`, if this `Device` doesn't support this feature
3478    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3479    * `UnexpectedVariant`, for which you can read the docs for
3480    * `Unknown`, on any unexpected error
3481
3482    # Device Support
3483
3484    Supports Kepler and newer fully supported devices.
3485    */
3486    // Checked against local
3487    // Tested on machines other than my own
3488    #[doc(alias = "nvmlDeviceGetRetiredPagesPendingStatus")]
3489    pub fn are_pages_pending_retired(&self) -> Result<bool, NvmlError> {
3490        let sym = nvml_sym(
3491            self.nvml
3492                .lib
3493                .nvmlDeviceGetRetiredPagesPendingStatus
3494                .as_ref(),
3495        )?;
3496
3497        unsafe {
3498            let mut state: nvmlEnableState_t = mem::zeroed();
3499
3500            nvml_try(sym(self.device, &mut state))?;
3501
3502            bool_from_state(state)
3503        }
3504    }
3505
3506    /**
3507    Gets recent samples for this `Device`.
3508
3509    `last_seen_timestamp` represents the CPU timestamp in μs. Passing in `None`
3510    will fetch all samples maintained in the underlying buffer; you can
3511    alternatively pass in a timestamp retrieved from the date of the previous
3512    query in order to obtain more recent samples.
3513
3514    The advantage of using this method for samples in contrast to polling via
3515    existing methods is to get higher frequency data at a lower polling cost.
3516
3517    # Errors
3518
3519    * `Uninitialized`, if the library has not been successfully initialized
3520    * `InvalidArg`, if this `Device` is invalid
3521    * `NotSupported`, if this query is not supported by this `Device`
3522    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3523    * `NotFound`, if sample entries are not found
3524    * `UnexpectedVariant`, check that error's docs for more info
3525    * `Unknown`, on any unexpected error
3526
3527    # Device Support
3528
3529    Supports Kepler and newer fully supported devices.
3530
3531    # Examples
3532
3533    ```
3534    # use nvml_wrapper::Nvml;
3535    # use nvml_wrapper::error::*;
3536    # fn main() -> Result<(), NvmlError> {
3537    # match test() {
3538    # Err(NvmlError::NotFound) => Ok(()),
3539    # other => other,
3540    # }
3541    # }
3542    # fn test() -> Result<(), NvmlError> {
3543    # let nvml = Nvml::init()?;
3544    # let device = nvml.device_by_index(0)?;
3545    use nvml_wrapper::enum_wrappers::device::Sampling;
3546
3547    // Passing `None` indicates that we want all `Power` samples in the sample buffer
3548    let power_samples = device.samples(Sampling::Power, None)?;
3549
3550    // Take the first sample from the vector, if it exists...
3551    if let Some(sample) = power_samples.get(0) {
3552        // ...and now we can get all `ProcessorClock` samples that exist with a later
3553        // timestamp than the `Power` sample.
3554        let newer_clock_samples = device.samples(Sampling::ProcessorClock, sample.timestamp)?;
3555    }
3556    # Ok(())
3557    # }
3558    ```
3559    */
3560    // Checked against local
3561    // Tested
3562    #[doc(alias = "nvmlDeviceGetSamples")]
3563    pub fn samples<T>(
3564        &self,
3565        sample_type: Sampling,
3566        last_seen_timestamp: T,
3567    ) -> Result<Vec<Sample>, NvmlError>
3568    where
3569        T: Into<Option<u64>>,
3570    {
3571        let timestamp = last_seen_timestamp.into().unwrap_or(0);
3572        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetSamples.as_ref())?;
3573
3574        unsafe {
3575            let mut val_type: nvmlValueType_t = mem::zeroed();
3576            let count = match self.samples_count(&sample_type, timestamp)? {
3577                0 => return Ok(vec![]),
3578                value => value,
3579            };
3580            let mut samples: Vec<nvmlSample_t> = vec![mem::zeroed(); count as usize];
3581            let mut new_count = count;
3582
3583            nvml_try(sym(
3584                self.device,
3585                sample_type.as_c(),
3586                timestamp,
3587                &mut val_type,
3588                &mut new_count,
3589                samples.as_mut_ptr(),
3590            ))?;
3591
3592            let val_type_rust = SampleValueType::try_from(val_type)?;
3593            Ok(samples
3594                .into_iter()
3595                .take(new_count as usize)
3596                .map(|s| Sample::from_tag_and_struct(&val_type_rust, s))
3597                .collect())
3598        }
3599    }
3600
3601    // Helper for the above function. Returns # of samples that can be queried.
3602    fn samples_count(&self, sample_type: &Sampling, timestamp: u64) -> Result<c_uint, NvmlError> {
3603        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetSamples.as_ref())?;
3604
3605        unsafe {
3606            let mut val_type: nvmlValueType_t = mem::zeroed();
3607            let mut count: c_uint = mem::zeroed();
3608
3609            nvml_try(sym(
3610                self.device,
3611                sample_type.as_c(),
3612                timestamp,
3613                &mut val_type,
3614                &mut count,
3615                // Indicates that we want the count
3616                ptr::null_mut(),
3617            ))?;
3618
3619            Ok(count)
3620        }
3621    }
3622
3623    /**
3624    Get values for the given slice of `FieldId`s.
3625
3626    NVIDIA's docs say that if any of the `FieldId`s are populated by the same driver
3627    call, the samples for those IDs will be populated by a single call instead of
3628    a call per ID. It would appear, then, that this is essentially a "batch-request"
3629    API path for better performance.
3630
3631    There are too many field ID constants defined in the header to reasonably
3632    wrap them with an enum in this crate. Instead, I've re-exported the defined
3633    ID constants at `nvml_wrapper::sys_exports::field_id::*`; stick those
3634    constants in `FieldId`s for use with this function.
3635
3636    # Errors
3637
3638    ## Outer `Result`
3639
3640    * `InvalidArg`, if `id_slice` has a length of zero
3641
3642    ## Inner `Result`
3643
3644    * `UnexpectedVariant`, check that error's docs for more info
3645
3646    # Device Support
3647
3648    Device support varies per `FieldId` that you pass in.
3649    */
3650    // TODO: Example
3651    #[doc(alias = "nvmlDeviceGetFieldValues")]
3652    pub fn field_values_for(
3653        &self,
3654        id_slice: &[FieldId],
3655    ) -> Result<Vec<Result<FieldValueSample, NvmlError>>, NvmlError> {
3656        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetFieldValues.as_ref())?;
3657
3658        unsafe {
3659            let values_count = id_slice.len();
3660            let mut field_values: Vec<nvmlFieldValue_t> = Vec::with_capacity(values_count);
3661
3662            for id in id_slice.iter() {
3663                let mut raw: nvmlFieldValue_t = mem::zeroed();
3664                raw.fieldId = id.0;
3665
3666                field_values.push(raw);
3667            }
3668
3669            nvml_try(sym(
3670                self.device,
3671                values_count as i32,
3672                field_values.as_mut_ptr(),
3673            ))?;
3674
3675            Ok(field_values
3676                .into_iter()
3677                .map(FieldValueSample::try_from)
3678                .collect())
3679        }
3680    }
3681
3682    /**
3683    Gets the globally unique board serial number associated with this `Device`'s board
3684    as an alphanumeric string.
3685
3686    This serial number matches the serial number tag that is physically attached to the board.
3687
3688    # Errors
3689
3690    * `Uninitialized`, if the library has not been successfully initialized
3691    * `InvalidArg`, if this `Device` is invalid
3692    * `NotSupported`, if this `Device` doesn't support this feature
3693    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3694    * `Utf8Error`, if the string obtained from the C function is not valid Utf8
3695    * `Unknown`, on any unexpected error
3696
3697    # Device Support
3698
3699    Supports all products with an infoROM.
3700    */
3701    // Checked against local
3702    // Tested on machines other than my own
3703    #[doc(alias = "nvmlDeviceGetSerial")]
3704    pub fn serial(&self) -> Result<String, NvmlError> {
3705        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetSerial.as_ref())?;
3706
3707        unsafe {
3708            let mut serial_vec = vec![0; NVML_DEVICE_SERIAL_BUFFER_SIZE as usize];
3709
3710            nvml_try(sym(
3711                self.device,
3712                serial_vec.as_mut_ptr(),
3713                NVML_DEVICE_SERIAL_BUFFER_SIZE,
3714            ))?;
3715
3716            let serial_raw = CStr::from_ptr(serial_vec.as_ptr());
3717            Ok(serial_raw.to_str()?.into())
3718        }
3719    }
3720
3721    /**
3722    Gets the board part number for this `Device`.
3723
3724    The board part number is programmed into the board's infoROM.
3725
3726    # Errors
3727
3728    * `Uninitialized`, if the library has not been successfully initialized
3729    * `NotSupported`, if the necessary VBIOS fields have not been filled
3730    * `GpuLost`, if the target GPU has fellen off the bus or is otherwise inaccessible
3731    * `Utf8Error`, if the string obtained from the C function is not valid Utf8
3732    * `Unknown`, on any unexpected error
3733    */
3734    // Checked against local
3735    // Tested on machines other than my own
3736    #[doc(alias = "nvmlDeviceGetBoardPartNumber")]
3737    pub fn board_part_number(&self) -> Result<String, NvmlError> {
3738        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetBoardPartNumber.as_ref())?;
3739
3740        unsafe {
3741            let mut part_num_vec = vec![0; NVML_DEVICE_PART_NUMBER_BUFFER_SIZE as usize];
3742
3743            nvml_try(sym(
3744                self.device,
3745                part_num_vec.as_mut_ptr(),
3746                NVML_DEVICE_PART_NUMBER_BUFFER_SIZE,
3747            ))?;
3748
3749            let part_num_raw = CStr::from_ptr(part_num_vec.as_ptr());
3750            Ok(part_num_raw.to_str()?.into())
3751        }
3752    }
3753
3754    /**
3755    Gets current throttling reasons.
3756
3757    Note that multiple reasons can be affecting clocks at once.
3758
3759    The returned bitmask is created via the `ThrottleReasons::from_bits_truncate`
3760    method, meaning that any bits that don't correspond to flags present in this
3761    version of the wrapper will be dropped.
3762
3763    # Errors
3764
3765    * `Uninitialized`, if the library has not been successfully initialized
3766    * `NotSupported`, if this `Device` does not support this feature
3767    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3768    * `Unknown`, on any unexpected error
3769
3770    # Device Support
3771
3772    Supports all _fully supported_ devices.
3773    */
3774    // Checked against local.
3775    // Tested
3776    #[doc(alias = "nvmlDeviceGetCurrentClocksThrottleReasons")]
3777    pub fn current_throttle_reasons(&self) -> Result<ThrottleReasons, NvmlError> {
3778        Ok(ThrottleReasons::from_bits_truncate(
3779            self.current_throttle_reasons_raw()?,
3780        ))
3781    }
3782
3783    /**
3784    Gets current throttling reasons, erroring if any bits correspond to
3785    non-present flags.
3786
3787    Note that multiple reasons can be affecting clocks at once.
3788
3789    # Errors
3790
3791    * `Uninitialized`, if the library has not been successfully initialized
3792    * `IncorrectBits`, if NVML returns any bits that do not correspond to flags in
3793    * `ThrottleReasons`
3794    * `NotSupported`, if this `Device` does not support this feature
3795    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3796    * `Unknown`, on any unexpected error
3797
3798    # Device Support
3799
3800    Supports all _fully supported_ devices.
3801    */
3802    // Checked against local.
3803    // Tested
3804    pub fn current_throttle_reasons_strict(&self) -> Result<ThrottleReasons, NvmlError> {
3805        let reasons = self.current_throttle_reasons_raw()?;
3806
3807        ThrottleReasons::from_bits(reasons).ok_or(NvmlError::IncorrectBits(Bits::U64(reasons)))
3808    }
3809
3810    // Helper for the above methods.
3811    fn current_throttle_reasons_raw(&self) -> Result<c_ulonglong, NvmlError> {
3812        let sym = nvml_sym(
3813            self.nvml
3814                .lib
3815                .nvmlDeviceGetCurrentClocksThrottleReasons
3816                .as_ref(),
3817        )?;
3818
3819        unsafe {
3820            let mut reasons: c_ulonglong = mem::zeroed();
3821
3822            nvml_try(sym(self.device, &mut reasons))?;
3823
3824            Ok(reasons)
3825        }
3826    }
3827
3828    /**
3829    Gets a bitmask of the supported throttle reasons.
3830
3831    These reasons can be returned by `.current_throttle_reasons()`.
3832
3833    The returned bitmask is created via the `ThrottleReasons::from_bits_truncate`
3834    method, meaning that any bits that don't correspond to flags present in this
3835    version of the wrapper will be dropped.
3836
3837    # Errors
3838
3839    * `Uninitialized`, if the library has not been successfully initialized
3840    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3841    * `Unknown`, on any unexpected error
3842
3843    # Device Support
3844
3845    Supports all _fully supported_ devices.
3846
3847    # Environment Support
3848
3849    This method is not supported on virtual machines running vGPUs.
3850    */
3851    // Checked against local
3852    // Tested
3853    #[doc(alias = "nvmlDeviceGetSupportedClocksThrottleReasons")]
3854    pub fn supported_throttle_reasons(&self) -> Result<ThrottleReasons, NvmlError> {
3855        Ok(ThrottleReasons::from_bits_truncate(
3856            self.supported_throttle_reasons_raw()?,
3857        ))
3858    }
3859
3860    /**
3861    Gets a bitmask of the supported throttle reasons, erroring if any bits
3862    correspond to non-present flags.
3863
3864    These reasons can be returned by `.current_throttle_reasons()`.
3865
3866    # Errors
3867
3868    * `Uninitialized`, if the library has not been successfully initialized
3869    * `IncorrectBits`, if NVML returns any bits that do not correspond to flags in
3870      `ThrottleReasons`
3871    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3872    * `Unknown`, on any unexpected error
3873
3874    # Device Support
3875
3876    Supports all _fully supported_ devices.
3877
3878    # Environment Support
3879
3880    This method is not supported on virtual machines running vGPUs.
3881    */
3882    // Checked against local
3883    // Tested
3884    pub fn supported_throttle_reasons_strict(&self) -> Result<ThrottleReasons, NvmlError> {
3885        let reasons = self.supported_throttle_reasons_raw()?;
3886
3887        ThrottleReasons::from_bits(reasons).ok_or(NvmlError::IncorrectBits(Bits::U64(reasons)))
3888    }
3889
3890    // Helper for the above methods.
3891    fn supported_throttle_reasons_raw(&self) -> Result<c_ulonglong, NvmlError> {
3892        let sym = nvml_sym(
3893            self.nvml
3894                .lib
3895                .nvmlDeviceGetSupportedClocksThrottleReasons
3896                .as_ref(),
3897        )?;
3898        unsafe {
3899            let mut reasons: c_ulonglong = mem::zeroed();
3900
3901            nvml_try(sym(self.device, &mut reasons))?;
3902
3903            Ok(reasons)
3904        }
3905    }
3906
3907    /**
3908    Gets a `Vec` of possible graphics clocks that can be used as an arg for
3909    `set_applications_clocks()`.
3910
3911    # Errors
3912
3913    * `Uninitialized`, if the library has not been successfully initialized
3914    * `NotFound`, if the specified `for_mem_clock` is not a supported frequency
3915    * `InvalidArg`, if this `Device` is invalid
3916    * `NotSupported`, if this `Device` doesn't support this feature
3917    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3918    * `Unknown`, on any unexpected error
3919
3920    # Device Support
3921
3922    Supports Kepler and newer fully supported devices.
3923    */
3924    // Checked against local
3925    // Tested
3926    #[doc(alias = "nvmlDeviceGetSupportedGraphicsClocks")]
3927    pub fn supported_graphics_clocks(&self, for_mem_clock: u32) -> Result<Vec<u32>, NvmlError> {
3928        match self.supported_graphics_clocks_manual(for_mem_clock, 128) {
3929            Err(NvmlError::InsufficientSize(Some(s))) =>
3930            // `s` is the required size for the call; make the call a second time
3931            {
3932                self.supported_graphics_clocks_manual(for_mem_clock, s)
3933            }
3934            value => value,
3935        }
3936    }
3937
3938    // Removes code duplication in the above function.
3939    fn supported_graphics_clocks_manual(
3940        &self,
3941        for_mem_clock: u32,
3942        size: usize,
3943    ) -> Result<Vec<u32>, NvmlError> {
3944        let mut items: Vec<c_uint> = vec![0; size];
3945        let mut count = size as c_uint;
3946
3947        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetSupportedGraphicsClocks.as_ref())?;
3948
3949        unsafe {
3950            match sym(self.device, for_mem_clock, &mut count, items.as_mut_ptr()) {
3951                // `count` is now the size that is required. Return it in the error.
3952                nvmlReturn_enum_NVML_ERROR_INSUFFICIENT_SIZE => {
3953                    return Err(NvmlError::InsufficientSize(Some(count as usize)))
3954                }
3955                value => nvml_try(value)?,
3956            }
3957        }
3958
3959        items.truncate(count as usize);
3960        Ok(items)
3961    }
3962
3963    /**
3964    Gets a `Vec` of possible memory clocks that can be used as an arg for
3965    `set_applications_clocks()`.
3966
3967    # Errors
3968
3969    * `Uninitialized`, if the library has not been successfully initialized
3970    * `InvalidArg`, if this `Device` is invalid
3971    * `NotSupported`, if this `Device` doesn't support this feature
3972    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
3973    * `Unknown`, on any unexpected error
3974
3975    # Device Support
3976
3977    Supports Kepler and newer fully supported devices.
3978    */
3979    // Checked against local
3980    // Tested
3981    #[doc(alias = "nvmlDeviceGetSupportedMemoryClocks")]
3982    pub fn supported_memory_clocks(&self) -> Result<Vec<u32>, NvmlError> {
3983        match self.supported_memory_clocks_manual(16) {
3984            Err(NvmlError::InsufficientSize(Some(s))) => {
3985                // `s` is the required size for the call; make the call a second time
3986                self.supported_memory_clocks_manual(s)
3987            }
3988            value => value,
3989        }
3990    }
3991
3992    // Removes code duplication in the above function.
3993    fn supported_memory_clocks_manual(&self, size: usize) -> Result<Vec<u32>, NvmlError> {
3994        let mut items: Vec<c_uint> = vec![0; size];
3995        let mut count = size as c_uint;
3996
3997        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetSupportedMemoryClocks.as_ref())?;
3998
3999        unsafe {
4000            match sym(self.device, &mut count, items.as_mut_ptr()) {
4001                // `count` is now the size that is required. Return it in the error.
4002                nvmlReturn_enum_NVML_ERROR_INSUFFICIENT_SIZE => {
4003                    return Err(NvmlError::InsufficientSize(Some(count as usize)))
4004                }
4005                value => nvml_try(value)?,
4006            }
4007        }
4008
4009        items.truncate(count as usize);
4010        Ok(items)
4011    }
4012
4013    /**
4014    Gets the current temperature readings for the given sensor, in °C.
4015
4016    # Errors
4017
4018    * `Uninitialized`, if the library has not been successfully initialized
4019    * `InvalidArg`, if this `Device` is invalid or `sensor` is invalid (shouldn't occur?)
4020    * `NotSupported`, if this `Device` does not have the specified sensor
4021    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4022    * `Unknown`, on any unexpected error
4023    */
4024    // Checked against local
4025    // Tested
4026    #[doc(alias = "nvmlDeviceGetTemperature")]
4027    pub fn temperature(&self, sensor: TemperatureSensor) -> Result<u32, NvmlError> {
4028        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetTemperature.as_ref())?;
4029
4030        unsafe {
4031            let mut temp: c_uint = mem::zeroed();
4032
4033            nvml_try(sym(self.device, sensor.as_c(), &mut temp))?;
4034
4035            Ok(temp)
4036        }
4037    }
4038
4039    /**
4040    Gets the temperature threshold for this `Device` and the specified `threshold_type`, in °C.
4041
4042    # Errors
4043
4044    * `Uninitialized`, if the library has not been successfully initialized
4045    * `InvalidArg`, if this `Device` is invalid or `threshold_type` is invalid (shouldn't occur?)
4046    * `NotSupported`, if this `Device` does not have a temperature sensor or is unsupported
4047    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4048    * `Unknown`, on any unexpected error
4049
4050    # Device Support
4051
4052    Supports Kepler and newer fully supported devices.
4053    */
4054    // Checked against local
4055    // Tested
4056    #[doc(alias = "nvmlDeviceGetTemperatureThreshold")]
4057    pub fn temperature_threshold(
4058        &self,
4059        threshold_type: TemperatureThreshold,
4060    ) -> Result<u32, NvmlError> {
4061        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetTemperatureThreshold.as_ref())?;
4062
4063        unsafe {
4064            let mut temp: c_uint = mem::zeroed();
4065
4066            nvml_try(sym(self.device, threshold_type.as_c(), &mut temp))?;
4067
4068            Ok(temp)
4069        }
4070    }
4071
4072    /**
4073    Set the temperature threshold for this `Device` and the specified `threshold_type` and
4074    with the given temperature.
4075
4076    # Errors
4077
4078    * `Uninitialized`, if the library has not been successfully initialized
4079    * `InvalidArg`, if this `Device` is invalid or `threshold_type` is invalid (shouldn't occur?)
4080    * `NotSupported`, if this `Device` does not have a temperature sensor or is unsupported
4081    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4082    * `Unknown`, on any unexpected error
4083
4084    # Device Support
4085
4086    Supports Kepler and newer fully supported devices.
4087    */
4088    // Checked against local
4089    // Tested
4090    #[doc(alias = "nvmlDeviceSetTemperatureThreshold")]
4091    pub fn set_temperature_threshold(
4092        &self,
4093        threshold_type: TemperatureThreshold,
4094        temp: i32,
4095    ) -> Result<(), NvmlError> {
4096        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetTemperatureThreshold.as_ref())?;
4097
4098        unsafe {
4099            let mut t = temp;
4100            nvml_try(sym(self.device, threshold_type.as_c(), &mut t))
4101        }
4102    }
4103
4104    /**
4105    Gets the common ancestor for two devices.
4106
4107    # Errors
4108
4109    * `InvalidArg`, if either `Device` is invalid
4110    * `NotSupported`, if this `Device` or the OS does not support this feature
4111    * `UnexpectedVariant`, for which you can read the docs for
4112    * `Unknown`, an error has occurred in the underlying topology discovery
4113
4114    # Platform Support
4115
4116    Only supports Linux.
4117    */
4118    // Checked against local
4119    // Tested
4120    #[cfg(target_os = "linux")]
4121    #[doc(alias = "nvmlDeviceGetTopologyCommonAncestor")]
4122    pub fn topology_common_ancestor(
4123        &self,
4124        other_device: Device,
4125    ) -> Result<TopologyLevel, NvmlError> {
4126        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetTopologyCommonAncestor.as_ref())?;
4127
4128        unsafe {
4129            let mut level: nvmlGpuTopologyLevel_t = mem::zeroed();
4130
4131            nvml_try(sym(self.device, other_device.device, &mut level))?;
4132
4133            TopologyLevel::try_from(level)
4134        }
4135    }
4136
4137    /**
4138    Gets the set of GPUs that are nearest to this `Device` at a specific interconnectivity level.
4139
4140    # Errors
4141
4142    * `InvalidArg`, if this `Device` is invalid or `level` is invalid (shouldn't occur?)
4143    * `NotSupported`, if this `Device` or the OS does not support this feature
4144    * `Unknown`, an error has occurred in the underlying topology discovery
4145
4146    # Platform Support
4147
4148    Only supports Linux.
4149    */
4150    // Checked against local
4151    // Tested
4152    #[cfg(target_os = "linux")]
4153    #[doc(alias = "nvmlDeviceGetTopologyNearestGpus")]
4154    pub fn topology_nearest_gpus(
4155        &self,
4156        level: TopologyLevel,
4157    ) -> Result<Vec<Device<'nvml>>, NvmlError> {
4158        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetTopologyNearestGpus.as_ref())?;
4159
4160        unsafe {
4161            let mut count = match self.top_nearest_gpus_count(&level)? {
4162                0 => return Ok(vec![]),
4163                value => value,
4164            };
4165            let mut gpus: Vec<nvmlDevice_t> = vec![mem::zeroed(); count as usize];
4166
4167            nvml_try(sym(
4168                self.device,
4169                level.as_c(),
4170                &mut count,
4171                gpus.as_mut_ptr(),
4172            ))?;
4173
4174            Ok(gpus
4175                .into_iter()
4176                .map(|d| Device::new(d, self.nvml))
4177                .collect())
4178        }
4179    }
4180
4181    // Helper for the above function. Returns # of GPUs in the set.
4182    #[cfg(target_os = "linux")]
4183    fn top_nearest_gpus_count(&self, level: &TopologyLevel) -> Result<c_uint, NvmlError> {
4184        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetTopologyNearestGpus.as_ref())?;
4185
4186        unsafe {
4187            let mut count: c_uint = 0;
4188
4189            nvml_try(sym(
4190                self.device,
4191                level.as_c(),
4192                &mut count,
4193                // Passing null (I assume?)
4194                // indicates that we want the
4195                // GPU count
4196                ptr::null_mut(),
4197            ))?;
4198
4199            Ok(count)
4200        }
4201    }
4202
4203    /**
4204    Gets the total ECC error counts for this `Device`.
4205
4206    Only applicable to devices with ECC. The total error count is the sum of errors across
4207    each of the separate memory systems, i.e. the total set of errors across the entire device.
4208
4209    # Errors
4210
4211    * `Uninitialized`, if the library has not been successfully initialized
4212    * `InvalidArg`, if this `Device` is invalid or either enum is invalid (shouldn't occur?)
4213    * `NotSupported`, if this `Device` does not support this feature
4214    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4215    * `Unknown`, on any unexpected error
4216
4217    # Device Support
4218
4219    Supports Fermi and newer fully supported devices. Requires `InfoRom::ECC` version 1.0
4220    or higher. Requires ECC mode to be enabled.
4221    */
4222    // Checked against local
4223    // Tested on machines other than my own
4224    #[doc(alias = "nvmlDeviceGetTotalEccErrors")]
4225    pub fn total_ecc_errors(
4226        &self,
4227        error_type: MemoryError,
4228        counter_type: EccCounter,
4229    ) -> Result<u64, NvmlError> {
4230        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetTotalEccErrors.as_ref())?;
4231
4232        unsafe {
4233            let mut count: c_ulonglong = mem::zeroed();
4234
4235            nvml_try(sym(
4236                self.device,
4237                error_type.as_c(),
4238                counter_type.as_c(),
4239                &mut count,
4240            ))?;
4241
4242            Ok(count)
4243        }
4244    }
4245
4246    /**
4247    Gets the globally unique immutable UUID associated with this `Device` as a 5 part
4248    hexadecimal string.
4249
4250    This UUID augments the immutable, board serial identifier. It is a globally unique
4251    identifier and is the _only_ available identifier for pre-Fermi-architecture products.
4252    It does NOT correspond to any identifier printed on the board.
4253
4254    # Errors
4255
4256    * `Uninitialized`, if the library has not been successfully initialized
4257    * `InvalidArg`, if this `Device` is invalid
4258    * `NotSupported`, if this `Device` does not support this feature
4259    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4260    * `Utf8Error`, if the string obtained from the C function is not valid Utf8
4261    * `Unknown`, on any unexpected error
4262
4263    # Examples
4264
4265    The UUID can be used to compare two `Device`s and find out if they represent
4266    the same physical device:
4267
4268    ```no_run
4269    # use nvml_wrapper::Nvml;
4270    # use nvml_wrapper::error::*;
4271    # fn main() -> Result<(), NvmlError> {
4272    # let nvml = Nvml::init()?;
4273    # let device1 = nvml.device_by_index(0)?;
4274    # let device2 = nvml.device_by_index(1)?;
4275    if device1.uuid()? == device2.uuid()? {
4276        println!("`device1` represents the same physical device that `device2` does.");
4277    }
4278    # Ok(())
4279    # }
4280    ```
4281    */
4282    // Checked against local
4283    // Tested
4284    #[doc(alias = "nvmlDeviceGetUUID")]
4285    pub fn uuid(&self) -> Result<String, NvmlError> {
4286        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetUUID.as_ref())?;
4287
4288        unsafe {
4289            let mut uuid_vec = vec![0; NVML_DEVICE_UUID_V2_BUFFER_SIZE as usize];
4290
4291            nvml_try(sym(
4292                self.device,
4293                uuid_vec.as_mut_ptr(),
4294                NVML_DEVICE_UUID_V2_BUFFER_SIZE,
4295            ))?;
4296
4297            let uuid_raw = CStr::from_ptr(uuid_vec.as_ptr());
4298            Ok(uuid_raw.to_str()?.into())
4299        }
4300    }
4301
4302    /**
4303    Gets the current utilization rates for this `Device`'s major subsystems.
4304
4305    Note: During driver initialization when ECC is enabled, one can see high GPU
4306    and memory utilization readings. This is caused by the ECC memory scrubbing
4307    mechanism that is performed during driver initialization.
4308
4309    # Errors
4310
4311    * `Uninitialized`, if the library has not been successfully initialized
4312    * `InvalidArg`, if this `Device` is invalid
4313    * `NotSupported`, if this `Device` does not support this feature
4314    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4315    * `Unknown`, on any unexpected error
4316
4317    # Device Support
4318
4319    Supports Fermi and newer fully supported devices.
4320    */
4321    // Checked against local
4322    // Tested
4323    #[doc(alias = "nvmlDeviceGetUtilizationRates")]
4324    pub fn utilization_rates(&self) -> Result<Utilization, NvmlError> {
4325        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetUtilizationRates.as_ref())?;
4326
4327        unsafe {
4328            let mut utilization: nvmlUtilization_t = mem::zeroed();
4329            nvml_try(sym(self.device, &mut utilization))?;
4330
4331            Ok(utilization.into())
4332        }
4333    }
4334
4335    /**
4336    Gets the VBIOS version of this `Device`.
4337
4338    The VBIOS version may change from time to time.
4339
4340    # Errors
4341
4342    * `Uninitialized`, if the library has not been successfully initialized
4343    * `InvalidArg`, if this `Device` is invalid
4344    * `NotSupported`, if this `Device` does not support this feature
4345    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4346    * `Utf8Error`, if the string obtained from the C function is not valid UTF-8
4347    * `Unknown`, on any unexpected error
4348    */
4349    // Checked against local
4350    // Tested
4351    #[doc(alias = "nvmlDeviceGetVbiosVersion")]
4352    pub fn vbios_version(&self) -> Result<String, NvmlError> {
4353        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetVbiosVersion.as_ref())?;
4354
4355        unsafe {
4356            let mut version_vec = vec![0; NVML_DEVICE_VBIOS_VERSION_BUFFER_SIZE as usize];
4357
4358            nvml_try(sym(
4359                self.device,
4360                version_vec.as_mut_ptr(),
4361                NVML_DEVICE_VBIOS_VERSION_BUFFER_SIZE,
4362            ))?;
4363
4364            let version_raw = CStr::from_ptr(version_vec.as_ptr());
4365            Ok(version_raw.to_str()?.into())
4366        }
4367    }
4368
4369    /**
4370    Gets the duration of time during which this `Device` was throttled (lower than the
4371    requested clocks) due to power or thermal constraints.
4372
4373    This is important to users who are trying to understand if their GPUs throttle at any
4374    point while running applications. The difference in violation times at two different
4375    reference times gives the indication of a GPU throttling event.
4376
4377    Violation for thermal capping is not supported at this time.
4378
4379    # Errors
4380
4381    * `Uninitialized`, if the library has not been successfully initialized
4382    * `InvalidArg`, if this `Device` is invalid or `perf_policy` is invalid (shouldn't occur?)
4383    * `NotSupported`, if this query is not supported by this `Device`
4384    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4385
4386    # Device Support
4387
4388    Supports Kepler or newer fully supported devices.
4389    */
4390    // Checked against local
4391    // Tested
4392    #[doc(alias = "nvmlDeviceGetViolationStatus")]
4393    pub fn violation_status(
4394        &self,
4395        perf_policy: PerformancePolicy,
4396    ) -> Result<ViolationTime, NvmlError> {
4397        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetViolationStatus.as_ref())?;
4398        unsafe {
4399            let mut viol_time: nvmlViolationTime_t = mem::zeroed();
4400
4401            nvml_try(sym(self.device, perf_policy.as_c(), &mut viol_time))?;
4402
4403            Ok(viol_time.into())
4404        }
4405    }
4406
4407    /**
4408    Gets the interrupt number for this [`Device`].
4409
4410    # Errors
4411
4412    * `Uninitialized`, if the library has not been successfully initialized
4413    * `NotSupported`, if this query is not supported by this `Device`
4414    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4415    */
4416    #[doc(alias = "nvmlDeviceGetIrqNum")]
4417    pub fn irq_num(&self) -> Result<u32, NvmlError> {
4418        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetIrqNum.as_ref())?;
4419
4420        let irq_num = unsafe {
4421            let mut irq_num: c_uint = mem::zeroed();
4422
4423            nvml_try(sym(self.device, &mut irq_num))?;
4424
4425            irq_num
4426        };
4427
4428        Ok(irq_num)
4429    }
4430
4431    /**
4432    Gets the core count for this [`Device`].
4433
4434    The cores represented in the count here are commonly referred to as
4435    "CUDA cores".
4436
4437    # Errors
4438
4439    * `Uninitialized`, if the library has not been successfully initialized
4440    * `NotSupported`, if this query is not supported by this `Device`
4441    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4442    */
4443    #[doc(alias = "nvmlDeviceGetNumGpuCores")]
4444    pub fn num_cores(&self) -> Result<u32, NvmlError> {
4445        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetNumGpuCores.as_ref())?;
4446
4447        unsafe {
4448            let mut count: c_uint = mem::zeroed();
4449
4450            nvml_try(sym(self.device, &mut count))?;
4451
4452            Ok(count)
4453        }
4454    }
4455
4456    /**
4457    Gets the status for a given p2p capability index between this [`Device`] and another given [`Device`].
4458
4459    # Errors
4460
4461    * `Uninitialized`, if the library has not been successfully initialized
4462    * `InvalidArg`, if device1 or device2 or p2p_index is invalid
4463    * `Unknown`, on any unexpected error
4464    */
4465    #[doc(alias = "nvmlDeviceGetP2PStatus")]
4466    pub fn p2p_status(
4467        &self,
4468        device2: &Device,
4469        p2p_index: P2pCapabilitiesIndex,
4470    ) -> Result<P2pStatus, NvmlError> {
4471        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetP2PStatus.as_ref())?;
4472
4473        let status_c = unsafe {
4474            let mut status: nvmlGpuP2PStatus_t = mem::zeroed();
4475            let device2 = device2.device;
4476
4477            nvml_try(sym(self.device, device2, p2p_index as u32, &mut status))?;
4478
4479            status
4480        };
4481
4482        P2pStatus::try_from(status_c)
4483    }
4484
4485    /**
4486    Gets the power source of this [`Device`].
4487
4488    # Errors
4489
4490    * `Uninitialized`, if the library has not been successfully initialized
4491    * `NotSupported`, if this query is not supported by this `Device`
4492    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4493    */
4494    #[doc(alias = "nvmlDeviceGetPowerSource")]
4495    pub fn power_source(&self) -> Result<PowerSource, NvmlError> {
4496        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetPowerSource.as_ref())?;
4497
4498        let power_source_c = unsafe {
4499            let mut power_source: nvmlPowerSource_t = mem::zeroed();
4500
4501            nvml_try(sym(self.device, &mut power_source))?;
4502
4503            power_source
4504        };
4505
4506        PowerSource::try_from(power_source_c)
4507    }
4508
4509    /**
4510    Gets the memory bus width of this [`Device`].
4511
4512    The returned value is in bits (i.e. 320 for a 320-bit bus width).
4513
4514    # Errors
4515
4516    * `Uninitialized`, if the library has not been successfully initialized
4517    * `NotSupported`, if this query is not supported by this `Device`
4518    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4519    */
4520    #[doc(alias = "nvmlDeviceGetMemoryBusWidth")]
4521    pub fn memory_bus_width(&self) -> Result<u32, NvmlError> {
4522        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetMemoryBusWidth.as_ref())?;
4523
4524        let memory_bus_width = unsafe {
4525            let mut memory_bus_width: c_uint = mem::zeroed();
4526
4527            nvml_try(sym(self.device, &mut memory_bus_width))?;
4528
4529            memory_bus_width
4530        };
4531
4532        Ok(memory_bus_width)
4533    }
4534
4535    /**
4536    Gets the max PCIe link speed for this [`Device`].
4537
4538    # Errors
4539
4540    * `Uninitialized`, if the library has not been successfully initialized
4541    * `NotSupported`, if this query is not supported by this `Device`
4542    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4543    */
4544    #[doc(alias = "nvmlDeviceGetPcieLinkMaxSpeed")]
4545    pub fn max_pcie_link_speed(&self) -> Result<PcieLinkMaxSpeed, NvmlError> {
4546        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetPcieLinkMaxSpeed.as_ref())?;
4547
4548        let pcie_link_max_speed_c = unsafe {
4549            let mut pcie_link_max_speed: c_uint = mem::zeroed();
4550
4551            nvml_try(sym(self.device, &mut pcie_link_max_speed))?;
4552
4553            pcie_link_max_speed
4554        };
4555
4556        PcieLinkMaxSpeed::try_from(pcie_link_max_speed_c)
4557    }
4558
4559    /**
4560    Gets the current PCIe link speed for this [`Device`].
4561
4562    NVML docs say the returned value is in "MBPS". Looking at the output of
4563    this function, however, seems to imply it actually returns the transfer
4564    rate per lane of the PCIe link in MT/s, not the combined multi-lane
4565    throughput. See [`PcieLinkMaxSpeed`] for the same discussion.
4566
4567    For example, on my machine currently:
4568
4569    > Right now the device is connected via a PCIe gen 4 x16 interface and
4570    > `pcie_link_speed()` returns 16000
4571
4572    This lines up with the "transfer rate per lane numbers" listed at
4573    <https://en.wikipedia.org/wiki/PCI_Express>. PCIe gen 4 provides 16.0 GT/s.
4574    Also, checking my machine at a different moment yields:
4575
4576    > Right now the device is connected via a PCIe gen 2 x16 interface and
4577    > `pcie_link_speed()` returns 5000
4578
4579    Which again lines up with the table on the page above; PCIe gen 2 provides
4580    5.0 GT/s.
4581
4582    # Errors
4583
4584    * `Uninitialized`, if the library has not been successfully initialized
4585    * `NotSupported`, if this query is not supported by this `Device`
4586    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4587    */
4588    #[doc(alias = "nvmlDeviceGetPcieSpeed")]
4589    pub fn pcie_link_speed(&self) -> Result<u32, NvmlError> {
4590        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetPcieSpeed.as_ref())?;
4591
4592        let pcie_speed_c = unsafe {
4593            let mut pcie_speed: c_uint = mem::zeroed();
4594
4595            nvml_try(sym(self.device, &mut pcie_speed))?;
4596
4597            pcie_speed
4598        };
4599
4600        Ok(pcie_speed_c)
4601    }
4602
4603    /**
4604    Gets the type of bus by which this [`Device`] is connected.
4605
4606    # Errors
4607
4608    * `Uninitialized`, if the library has not been successfully initialized
4609    */
4610    #[doc(alias = "nvmlDeviceGetBusType")]
4611    pub fn bus_type(&self) -> Result<BusType, NvmlError> {
4612        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetBusType.as_ref())?;
4613
4614        let bus_type_c = unsafe {
4615            let mut bus_type: nvmlBusType_t = mem::zeroed();
4616
4617            nvml_try(sym(self.device, &mut bus_type))?;
4618
4619            bus_type
4620        };
4621
4622        BusType::try_from(bus_type_c)
4623    }
4624
4625    /**
4626    Gets the architecture of this [`Device`].
4627
4628    # Errors
4629
4630    * `Uninitialized`, if the library has not been successfully initialized
4631    */
4632    #[doc(alias = "nvmlDeviceGetArchitecture")]
4633    pub fn architecture(&self) -> Result<DeviceArchitecture, NvmlError> {
4634        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetArchitecture.as_ref())?;
4635
4636        let architecture_c = unsafe {
4637            let mut architecture: nvmlDeviceArchitecture_t = mem::zeroed();
4638
4639            nvml_try(sym(self.device, &mut architecture))?;
4640
4641            architecture
4642        };
4643
4644        DeviceArchitecture::try_from(architecture_c)
4645    }
4646
4647    /**
4648    Checks if this `Device` and the passed-in device are on the same physical board.
4649
4650    # Errors
4651
4652    * `Uninitialized`, if the library has not been successfully initialized
4653    * `InvalidArg`, if either `Device` is invalid
4654    * `NotSupported`, if this check is not supported by this `Device`
4655    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4656    * `Unknown`, on any unexpected error
4657    */
4658    // Checked against local
4659    // Tested
4660    #[doc(alias = "nvmlDeviceOnSameBoard")]
4661    pub fn is_on_same_board_as(&self, other_device: &Device) -> Result<bool, NvmlError> {
4662        let sym = nvml_sym(self.nvml.lib.nvmlDeviceOnSameBoard.as_ref())?;
4663
4664        unsafe {
4665            let mut bool_int: c_int = mem::zeroed();
4666
4667            nvml_try(sym(self.device, other_device.handle(), &mut bool_int))?;
4668
4669            #[allow(clippy::match_like_matches_macro)]
4670            Ok(match bool_int {
4671                0 => false,
4672                _ => true,
4673            })
4674        }
4675    }
4676
4677    /**
4678    Resets the application clock to the default value.
4679
4680    This is the applications clock that will be used after a system reboot or a driver
4681    reload. The default value is a constant, but the current value be changed with
4682    `.set_applications_clocks()`.
4683
4684    On Pascal and newer hardware, if clocks were previously locked with
4685    `.set_applications_clocks()`, this call will unlock clocks. This returns clocks
4686    to their default behavior of automatically boosting above base clocks as
4687    thermal limits allow.
4688
4689    # Errors
4690
4691    * `Uninitialized`, if the library has not been successfully initialized
4692    * `InvalidArg`, if the `Device` is invalid
4693    * `NotSupported`, if this `Device` does not support this feature
4694    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4695    * `Unknown`, on any unexpected error
4696
4697    # Device Support
4698
4699    Supports Fermi and newer non-GeForce fully supported devices and Maxwell or newer
4700    GeForce devices.
4701    */
4702    // Checked against local
4703    // Tested (no-run)
4704    #[doc(alias = "nvmlDeviceResetApplicationsClocks")]
4705    pub fn reset_applications_clocks(&mut self) -> Result<(), NvmlError> {
4706        let sym = nvml_sym(self.nvml.lib.nvmlDeviceResetApplicationsClocks.as_ref())?;
4707
4708        unsafe { nvml_try(sym(self.device)) }
4709    }
4710
4711    /**
4712    Try to set the current state of auto boosted clocks on this `Device`.
4713
4714    Auto boosted clocks are enabled by default on some hardware, allowing the GPU to run
4715    as fast as thermals will allow it to. Auto boosted clocks should be disabled if fixed
4716    clock rates are desired.
4717
4718    On Pascal and newer hardware, auto boosted clocks are controlled through application
4719    clocks. Use `.set_applications_clocks()` and `.reset_applications_clocks()` to control
4720    auto boost behavior.
4721
4722    Non-root users may use this API by default, but access can be restricted by root using
4723    `.set_api_restriction()`.
4724
4725    Note: persistence mode is required to modify the curent auto boost settings and
4726    therefore must be enabled.
4727
4728    # Errors
4729
4730    * `Uninitialized`, if the library has not been successfully initialized
4731    * `InvalidArg`, if the `Device` is invalid
4732    * `NotSupported`, if this `Device` does not support auto boosted clocks
4733    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4734    * `Unknown`, on any unexpected error
4735
4736    Not sure why nothing is said about `NoPermission`.
4737
4738    # Device Support
4739
4740    Supports Kepler and newer fully supported devices.
4741    */
4742    // Checked against local
4743    // Tested (no-run)
4744    #[doc(alias = "nvmlDeviceSetAutoBoostedClocksEnabled")]
4745    pub fn set_auto_boosted_clocks(&mut self, enabled: bool) -> Result<(), NvmlError> {
4746        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetAutoBoostedClocksEnabled.as_ref())?;
4747
4748        unsafe { nvml_try(sym(self.device, state_from_bool(enabled))) }
4749    }
4750
4751    /**
4752    Sets the ideal affinity for the calling thread and `Device` based on the guidelines given in
4753    `.cpu_affinity()`.
4754
4755    Currently supports up to 64 processors.
4756
4757    # Errors
4758
4759    * `Uninitialized`, if the library has not been successfully initialized
4760    * `InvalidArg`, if the `Device` is invalid
4761    * `NotSupported`, if this `Device` does not support this feature
4762    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4763    * `Unknown`, on any unexpected error
4764
4765    # Device Support
4766
4767    Supports Kepler and newer fully supported devices.
4768
4769    # Platform Support
4770
4771    Only supports Linux.
4772    */
4773    // Checked against local
4774    // Tested (no-run)
4775    #[cfg(target_os = "linux")]
4776    #[doc(alias = "nvmlDeviceSetCpuAffinity")]
4777    pub fn set_cpu_affinity(&mut self) -> Result<(), NvmlError> {
4778        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetCpuAffinity.as_ref())?;
4779
4780        unsafe { nvml_try(sym(self.device)) }
4781    }
4782
4783    /**
4784    Gets a vector of bitmasks with the ideal CPU affinity for this `Device` within the specified `scope`,
4785    the latter being NUMA node or processor socket (`NVML_AFFINITY_SCOPE_NODE` and `NVML_AFFINITY_SCOPE_SOCKET`).
4786
4787    Beyond this, the outcome and meaning are similar to `cpu_affinity`
4788
4789    # Errors
4790
4791    * `Uninitialized`, if the library has not been successfully initialized
4792    * `InvalidArg`, if this `Device` is invalid
4793    * `InsufficientSize`, if the passed-in `size` is 0 (must be > 0)
4794    * `NotSupported`, if this `Device` does not support this feature
4795    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4796    * `Unknown`, on any unexpected error
4797
4798    # Device Support
4799
4800    Supports Kepler or newer fully supported devices.
4801
4802    # Platform Support
4803
4804    Only supports Linux.
4805
4806    */
4807    #[cfg(target_os = "linux")]
4808    #[doc(alias = "nvmlDeviceGetCpuAffinityWithinScope")]
4809    pub fn cpu_affinity_within_scope(
4810        &self,
4811        size: usize,
4812        scope: nvmlAffinityScope_t,
4813    ) -> Result<Vec<c_ulong>, NvmlError> {
4814        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetCpuAffinityWithinScope.as_ref())?;
4815
4816        unsafe {
4817            if size == 0 {
4818                // Return an error containing the minimum size that can be passed.
4819                return Err(NvmlError::InsufficientSize(Some(1)));
4820            }
4821
4822            let mut affinities: Vec<c_ulong> = vec![mem::zeroed(); size];
4823
4824            nvml_try(sym(
4825                self.device,
4826                size as c_uint,
4827                affinities.as_mut_ptr(),
4828                scope,
4829            ))?;
4830
4831            Ok(affinities)
4832        }
4833    }
4834
4835    /**
4836    Try to set the default state of auto boosted clocks on this `Device`.
4837
4838    This is the default state that auto boosted clocks will return to when no compute
4839    processes (e.g. CUDA application with an active context) are running.
4840
4841    Requires root/admin permissions.
4842
4843    Auto boosted clocks are enabled by default on some hardware, allowing the GPU to run
4844    as fast as thermals will allow it to. Auto boosted clocks should be disabled if fixed
4845    clock rates are desired.
4846
4847    On Pascal and newer hardware, auto boosted clocks are controlled through application
4848    clocks. Use `.set_applications_clocks()` and `.reset_applications_clocks()` to control
4849    auto boost behavior.
4850
4851    # Errors
4852
4853    * `Uninitialized`, if the library has not been successfully initialized
4854    * `NoPermission`, if the calling user does not have permission to change the default state
4855    * `InvalidArg`, if the `Device` is invalid
4856    * `NotSupported`, if this `Device` does not support auto boosted clocks
4857    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4858    * `Unknown`, on any unexpected error
4859
4860    # Device Support
4861
4862    Supports Kepler or newer non-GeForce fully supported devices and Maxwell or newer
4863    GeForce devices.
4864    */
4865    // Checked against local
4866    // Tested (no-run)
4867    #[doc(alias = "nvmlDeviceSetDefaultAutoBoostedClocksEnabled")]
4868    pub fn set_auto_boosted_clocks_default(&mut self, enabled: bool) -> Result<(), NvmlError> {
4869        let sym = nvml_sym(
4870            self.nvml
4871                .lib
4872                .nvmlDeviceSetDefaultAutoBoostedClocksEnabled
4873                .as_ref(),
4874        )?;
4875
4876        unsafe {
4877            // Passing 0 because NVIDIA says flags are not supported yet
4878            nvml_try(sym(self.device, state_from_bool(enabled), 0))
4879        }
4880    }
4881
4882    /**
4883    Reads the infoROM from this `Device`'s flash and verifies the checksum.
4884
4885    # Errors
4886
4887    * `Uninitialized`, if the library has not been successfully initialized
4888    * `CorruptedInfoROM`, if this `Device`'s infoROM is corrupted
4889    * `NotSupported`, if this `Device` does not support this feature
4890    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
4891    * `Unknown`, on any unexpected error
4892
4893    Not sure why `InvalidArg` is not mentioned.
4894
4895    # Device Support
4896
4897    Supports all devices with an infoROM.
4898    */
4899    // Checked against local
4900    // Tested on machines other than my own
4901    #[doc(alias = "nvmlDeviceValidateInforom")]
4902    pub fn validate_info_rom(&self) -> Result<(), NvmlError> {
4903        let sym = nvml_sym(self.nvml.lib.nvmlDeviceValidateInforom.as_ref())?;
4904
4905        unsafe { nvml_try(sym(self.device)) }
4906    }
4907
4908    // Wrappers for things from Accounting Statistics now
4909
4910    /**
4911    Clears accounting information about all processes that have already terminated.
4912
4913    Requires root/admin permissions.
4914
4915    # Errors
4916
4917    * `Uninitialized`, if the library has not been successfully initialized
4918    * `InvalidArg`, if the `Device` is invalid
4919    * `NotSupported`, if this `Device` does not support this feature
4920    * `NoPermission`, if the user doesn't have permission to perform this operation
4921    * `Unknown`, on any unexpected error
4922
4923    # Device Support
4924
4925    Supports Kepler and newer fully supported devices.
4926    */
4927    // Checked against local
4928    // Tested (no-run)
4929    #[doc(alias = "nvmlDeviceClearAccountingPids")]
4930    pub fn clear_accounting_pids(&mut self) -> Result<(), NvmlError> {
4931        let sym = nvml_sym(self.nvml.lib.nvmlDeviceClearAccountingPids.as_ref())?;
4932
4933        unsafe { nvml_try(sym(self.device)) }
4934    }
4935
4936    /**
4937    Gets the number of processes that the circular buffer with accounting PIDs can hold
4938    (in number of elements).
4939
4940    This is the max number of processes that accounting information will be stored for
4941    before the oldest process information will get overwritten by information
4942    about new processes.
4943
4944    # Errors
4945
4946    * `Uninitialized`, if the library has not been successfully initialized
4947    * `InvalidArg`, if the `Device` is invalid
4948    * `NotSupported`, if this `Device` does not support this feature or accounting mode
4949      is disabled
4950    * `Unknown`, on any unexpected error
4951
4952    # Device Support
4953
4954    Supports Kepler and newer fully supported devices.
4955    */
4956    // Checked against local
4957    // Tested
4958    #[doc(alias = "nvmlDeviceGetAccountingBufferSize")]
4959    pub fn accounting_buffer_size(&self) -> Result<u32, NvmlError> {
4960        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetAccountingBufferSize.as_ref())?;
4961
4962        unsafe {
4963            let mut count: c_uint = mem::zeroed();
4964            nvml_try(sym(self.device, &mut count))?;
4965
4966            Ok(count)
4967        }
4968    }
4969
4970    /**
4971    Gets whether or not per-process accounting mode is enabled.
4972
4973    # Errors
4974
4975    * `Uninitialized`, if the library has not been successfully initialized
4976    * `InvalidArg`, if the `Device` is invalid
4977    * `NotSupported`, if this `Device` does not support this feature
4978    * `UnexpectedVariant`, for which you can read the docs for
4979    * `Unknown`, on any unexpected error
4980
4981    # Device Support
4982
4983    Supports Kepler and newer fully supported devices.
4984    */
4985    // Checked against local
4986    // Tested
4987    #[doc(alias = "nvmlDeviceGetAccountingMode")]
4988    pub fn is_accounting_enabled(&self) -> Result<bool, NvmlError> {
4989        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetAccountingMode.as_ref())?;
4990
4991        unsafe {
4992            let mut state: nvmlEnableState_t = mem::zeroed();
4993            nvml_try(sym(self.device, &mut state))?;
4994
4995            bool_from_state(state)
4996        }
4997    }
4998
4999    /**
5000    Gets the list of processes that can be queried for accounting stats.
5001
5002    The list of processes returned can be in running or terminated state. Note that
5003    in the case of a PID collision some processes might not be accessible before
5004    the circular buffer is full.
5005
5006    # Errors
5007
5008    * `Uninitialized`, if the library has not been successfully initialized
5009    * `InvalidArg`, if the `Device` is invalid
5010    * `NotSupported`, if this `Device` does not support this feature or accounting
5011      mode is disabled
5012    * `Unknown`, on any unexpected error
5013    */
5014    // Checked against local
5015    // Tested
5016    #[doc(alias = "nvmlDeviceGetAccountingPids")]
5017    pub fn accounting_pids(&self) -> Result<Vec<u32>, NvmlError> {
5018        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetAccountingPids.as_ref())?;
5019
5020        unsafe {
5021            let mut count = match self.accounting_pids_count()? {
5022                0 => return Ok(vec![]),
5023                value => value,
5024            };
5025            let mut pids: Vec<c_uint> = vec![mem::zeroed(); count as usize];
5026
5027            nvml_try(sym(self.device, &mut count, pids.as_mut_ptr()))?;
5028
5029            Ok(pids)
5030        }
5031    }
5032
5033    // Helper function for the above.
5034    fn accounting_pids_count(&self) -> Result<c_uint, NvmlError> {
5035        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetAccountingPids.as_ref())?;
5036
5037        unsafe {
5038            // Indicates that we want the count
5039            let mut count: c_uint = 0;
5040
5041            // Null also indicates that we want the count
5042            match sym(self.device, &mut count, ptr::null_mut()) {
5043                // List is empty
5044                nvmlReturn_enum_NVML_SUCCESS => Ok(0),
5045                // Count is set to pids count
5046                nvmlReturn_enum_NVML_ERROR_INSUFFICIENT_SIZE => Ok(count),
5047                // We know this is an error
5048                other => nvml_try(other).map(|_| 0),
5049            }
5050        }
5051    }
5052
5053    /**
5054    Gets a process's accounting stats.
5055
5056    Accounting stats capture GPU utilization and other statistics across the lifetime
5057    of a process. Accounting stats can be queried during the lifetime of the process
5058    and after its termination. The `time` field in `AccountingStats` is reported as
5059    zero during the lifetime of the process and updated to the actual running time
5060    after its termination.
5061
5062    Accounting stats are kept in a circular buffer; newly created processes overwrite
5063    information regarding old processes.
5064
5065    Note:
5066    * Accounting mode needs to be on. See `.is_accounting_enabled()`.
5067    * Only compute and graphics applications stats can be queried. Monitoring
5068      applications can't be queried since they don't contribute to GPU utilization.
5069    * If a PID collision occurs, the stats of the latest process (the one that
5070      terminated last) will be reported.
5071
5072    # Errors
5073
5074    * `Uninitialized`, if the library has not been successfully initialized
5075    * `InvalidArg`, if the `Device` is invalid
5076    * `NotFound`, if the process stats were not found
5077    * `NotSupported`, if this `Device` does not support this feature or accounting
5078      mode is disabled
5079    * `Unknown`, on any unexpected error
5080
5081    # Device Support
5082
5083    Suports Kepler and newer fully supported devices.
5084
5085    # Warning
5086
5087    On Kepler devices, per-process stats are accurate _only if_ there's one process
5088    running on this `Device`.
5089    */
5090    // Checked against local
5091    // Tested (for error)
5092    #[doc(alias = "nvmlDeviceGetAccountingStats")]
5093    pub fn accounting_stats_for(&self, process_id: u32) -> Result<AccountingStats, NvmlError> {
5094        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetAccountingStats.as_ref())?;
5095
5096        unsafe {
5097            let mut stats: nvmlAccountingStats_t = mem::zeroed();
5098
5099            nvml_try(sym(self.device, process_id, &mut stats))?;
5100
5101            Ok(stats.into())
5102        }
5103    }
5104
5105    /**
5106    Enables or disables per-process accounting.
5107
5108    Requires root/admin permissions.
5109
5110    Note:
5111    * This setting is not persistent and will default to disabled after the driver
5112      unloads. Enable persistence mode to be sure the setting doesn't switch off
5113      to disabled.
5114    * Enabling accounting mode has no negative impact on GPU performance.
5115    * Disabling accounting clears accounting information for all PIDs
5116
5117    # Errors
5118
5119    * `Uninitialized`, if the library has not been successfully initialized
5120    * `InvalidArg`, if the `Device` is invalid
5121    * `NotSupported`, if this `Device` does not support this feature
5122    * `NoPermission`, if the user doesn't have permission to perform this operation
5123    * `Unknown`, on any unexpected error
5124
5125    # Device Support
5126
5127    Supports Kepler and newer fully supported devices.
5128    */
5129    // Checked against local
5130    // Tested (no-run)
5131    #[doc(alias = "nvmlDeviceSetAccountingMode")]
5132    pub fn set_accounting(&mut self, enabled: bool) -> Result<(), NvmlError> {
5133        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetAccountingMode.as_ref())?;
5134
5135        unsafe { nvml_try(sym(self.device, state_from_bool(enabled))) }
5136    }
5137
5138    // Device commands starting here
5139
5140    /**
5141    Clears the ECC error and other memory error counts for this `Device`.
5142
5143    Sets all of the specified ECC counters to 0, including both detailed and total counts.
5144    This operation takes effect immediately.
5145
5146    Requires root/admin permissions and ECC mode to be enabled.
5147
5148    # Errors
5149
5150    * `Uninitialized`, if the library has not been successfully initialized
5151    * `InvalidArg`, if the `Device` is invalid or `counter_type` is invalid (shouldn't occur?)
5152    * `NotSupported`, if this `Device` does not support this feature
5153    * `NoPermission`, if the user doesn't have permission to perform this operation
5154    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
5155    * `Unknown`, on any unexpected error
5156
5157    # Device Support
5158
5159    Supports Kepler and newer fully supported devices. Only applicable to devices with
5160    ECC. Requires `InfoRom::ECC` version 2.0 or higher to clear aggregate
5161    location-based ECC counts. Requires `InfoRom::ECC` version 1.0 or higher to
5162    clear all other ECC counts.
5163    */
5164    // Checked against local
5165    // Tested (no-run)
5166    #[doc(alias = "nvmlDeviceClearEccErrorCounts")]
5167    pub fn clear_ecc_error_counts(&mut self, counter_type: EccCounter) -> Result<(), NvmlError> {
5168        let sym = nvml_sym(self.nvml.lib.nvmlDeviceClearEccErrorCounts.as_ref())?;
5169
5170        unsafe { nvml_try(sym(self.device, counter_type.as_c())) }
5171    }
5172
5173    /**
5174    Changes the root/admin restrictions on certain APIs.
5175
5176    This method can be used by a root/admin user to give non root/admin users access
5177    to certain otherwise-restricted APIs. The new setting lasts for the lifetime of
5178    the NVIDIA driver; it is not persistent. See `.is_api_restricted()` to query
5179    current settings.
5180
5181    # Errors
5182
5183    * `Uninitialized`, if the library has not been successfully initialized
5184    * `InvalidArg`, if the `Device` is invalid or `api_type` is invalid (shouldn't occur?)
5185    * `NotSupported`, if this `Device` does not support changing API restrictions or
5186      this `Device` does not support the feature that API restrictions are being set for
5187      (e.g. enabling/disabling auto boosted clocks is not supported by this `Device`).
5188    * `NoPermission`, if the user doesn't have permission to perform this operation
5189    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
5190    * `Unknown`, on any unexpected error
5191
5192    # Device Support
5193
5194    Supports Kepler and newer fully supported devices.
5195    */
5196    // Checked against local
5197    // Tested (no-run)
5198    #[doc(alias = "nvmlDeviceSetAPIRestriction")]
5199    pub fn set_api_restricted(&mut self, api_type: Api, restricted: bool) -> Result<(), NvmlError> {
5200        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetAPIRestriction.as_ref())?;
5201
5202        unsafe {
5203            nvml_try(sym(
5204                self.device,
5205                api_type.as_c(),
5206                state_from_bool(restricted),
5207            ))
5208        }
5209    }
5210
5211    /**
5212    Sets clocks that applications will lock to.
5213
5214    Sets the clocks that compute and graphics applications will be running at. e.g.
5215    CUDA driver requests these clocks during context creation which means this
5216    property defines clocks at which CUDA applications will be running unless some
5217    overspec event occurs (e.g. over power, over thermal or external HW brake).
5218
5219    Can be used as a setting to request constant performance. Requires root/admin
5220    permissions.
5221
5222    On Pascal and newer hardware, this will automatically disable automatic boosting
5223    of clocks. On K80 and newer Kepler and Maxwell GPUs, users desiring fixed performance
5224    should also call `.set_auto_boosted_clocks(false)` to prevent clocks from automatically
5225    boosting above the clock value being set here.
5226
5227    You can determine valid `mem_clock` and `graphics_clock` arg values via
5228    [`Self::supported_memory_clocks()`] and [`Self::supported_graphics_clocks()`].
5229
5230    Note that after a system reboot or driver reload applications clocks go back
5231    to their default value.
5232
5233    See also [`Self::set_mem_locked_clocks()`].
5234
5235    # Errors
5236
5237    * `Uninitialized`, if the library has not been successfully initialized
5238    * `InvalidArg`, if the `Device` is invalid or the clocks are not a valid combo
5239    * `NotSupported`, if this `Device` does not support this feature
5240    * `NoPermission`, if the user doesn't have permission to perform this operation
5241    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
5242    * `Unknown`, on any unexpected error
5243
5244    # Device Support
5245
5246    Supports Kepler and newer non-GeForce fully supported devices and Maxwell or newer
5247    GeForce devices.
5248    */
5249    // Checked against local
5250    // Tested (no-run)
5251    #[doc(alias = "nvmlDeviceSetApplicationsClocks")]
5252    pub fn set_applications_clocks(
5253        &mut self,
5254        mem_clock: u32,
5255        graphics_clock: u32,
5256    ) -> Result<(), NvmlError> {
5257        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetApplicationsClocks.as_ref())?;
5258
5259        unsafe { nvml_try(sym(self.device, mem_clock, graphics_clock)) }
5260    }
5261
5262    /**
5263    Sets the compute mode for this `Device`.
5264
5265    The compute mode determines whether a GPU can be used for compute operations
5266    and whether it can be shared across contexts.
5267
5268    This operation takes effect immediately. Under Linux it is not persistent
5269    across reboots and always resets to `Default`. Under Windows it is
5270    persistent.
5271
5272    Under Windows, compute mode may only be set to `Default` when running in WDDM
5273    (physical display connected).
5274
5275    Requires root/admin permissions.
5276
5277    # Errors
5278
5279    * `Uninitialized`, if the library has not been successfully initialized
5280    * `InvalidArg`, if the `Device` is invalid or `mode` is invalid (shouldn't occur?)
5281    * `NotSupported`, if this `Device` does not support this feature
5282    * `NoPermission`, if the user doesn't have permission to perform this operation
5283    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
5284    * `Unknown`, on any unexpected error
5285    */
5286    // Checked against local
5287    // Tested (no-run)
5288    #[doc(alias = "nvmlDeviceSetComputeMode")]
5289    pub fn set_compute_mode(&mut self, mode: ComputeMode) -> Result<(), NvmlError> {
5290        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetComputeMode.as_ref())?;
5291
5292        unsafe { nvml_try(sym(self.device, mode.as_c())) }
5293    }
5294
5295    /**
5296    Sets the driver model for this `Device`.
5297
5298    This operation takes effect after the next reboot. The model may only be
5299    set to WDDM when running in DEFAULT compute mode. Changing the model to
5300    WDDM is not supported when the GPU doesn't support graphics acceleration
5301    or will not support it after a reboot.
5302
5303    On Windows platforms the device driver can run in either WDDM or WDM (TCC)
5304    mode. If a physical display is attached to a device it must run in WDDM mode.
5305
5306    It is possible to force the change to WDM (TCC) while the display is still
5307    attached with a `Behavior` of `FORCE`. This should only be done if the host
5308    is subsequently powered down and the display is detached from this `Device`
5309    before the next reboot.
5310
5311    Requires root/admin permissions.
5312
5313    # Errors
5314
5315    * `Uninitialized`, if the library has not been successfully initialized
5316    * `InvalidArg`, if the `Device` is invalid or `model` is invalid (shouldn't occur?)
5317    * `NotSupported`, if this `Device` does not support this feature
5318    * `NoPermission`, if the user doesn't have permission to perform this operation
5319    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
5320    * `Unknown`, on any unexpected error
5321
5322    # Device Support
5323
5324    Supports Fermi and newer fully supported devices.
5325
5326    # Platform Support
5327
5328    Only supports Windows.
5329
5330    # Examples
5331
5332    ```no_run
5333    # use nvml_wrapper::Nvml;
5334    # use nvml_wrapper::error::*;
5335    # fn test() -> Result<(), NvmlError> {
5336    # let nvml = Nvml::init()?;
5337    # let mut device = nvml.device_by_index(0)?;
5338    use nvml_wrapper::bitmasks::Behavior;
5339    use nvml_wrapper::enum_wrappers::device::DriverModel;
5340
5341    device.set_driver_model(DriverModel::WDM, Behavior::DEFAULT)?;
5342
5343    // Force the change to WDM (TCC)
5344    device.set_driver_model(DriverModel::WDM, Behavior::FORCE)?;
5345    # Ok(())
5346    # }
5347    ```
5348    */
5349    // Checked against local
5350    // Tested (no-run)
5351    #[cfg(target_os = "windows")]
5352    #[doc(alias = "nvmlDeviceSetDriverModel")]
5353    pub fn set_driver_model(
5354        &mut self,
5355        model: DriverModel,
5356        flags: Behavior,
5357    ) -> Result<(), NvmlError> {
5358        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetDriverModel.as_ref())?;
5359
5360        unsafe { nvml_try(sym(self.device, model.as_c(), flags.bits())) }
5361    }
5362
5363    /**
5364    Lock this `Device`'s clocks to a specific frequency range.
5365
5366    This setting supercedes application clock values and takes effect regardless
5367    of whether or not any CUDA apps are running. It can be used to request constant
5368    performance.
5369
5370    After a system reboot or a driver reload the clocks go back to their default
5371    values.
5372
5373    Requires root/admin permissions.
5374
5375    # Errors
5376
5377    * `Uninitialized`, if the library has not been successfully initialized
5378    * `InvalidArg`, if the provided minimum and maximum clocks are not a valid combo
5379    * `NotSupported`, if this `Device` does not support this feature
5380    * `NoPermission`, if the user doesn't have permission to perform this operation
5381    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
5382    * `Unknown`, on any unexpected error
5383
5384    # Device Support
5385
5386    Supports Volta and newer fully supported devices.
5387    */
5388    // Tested (no-run)
5389    #[doc(alias = "nvmlDeviceSetGpuLockedClocks")]
5390    pub fn set_gpu_locked_clocks(
5391        &mut self,
5392        setting: GpuLockedClocksSetting,
5393    ) -> Result<(), NvmlError> {
5394        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetGpuLockedClocks.as_ref())?;
5395
5396        let (min_clock_mhz, max_clock_mhz) = setting.into_min_and_max_clocks();
5397
5398        unsafe { nvml_try(sym(self.device, min_clock_mhz, max_clock_mhz)) }
5399    }
5400
5401    /**
5402    Reset this [`Device`]'s clocks to their default values.
5403
5404    This resets to the same values that would be used after a reboot or driver
5405    reload (defaults to idle clocks but can be configured via
5406    [`Self::set_applications_clocks()`]).
5407
5408    # Errors
5409
5410    * `Uninitialized`, if the library has not been successfully initialized
5411    * `NotSupported`, if this `Device` does not support this feature
5412    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
5413    * `Unknown`, on any unexpected error
5414
5415    # Device Support
5416
5417    Supports Volta and newer fully supported devices.
5418    */
5419    // Tested (no-run)
5420    #[doc(alias = "nvmlDeviceResetGpuLockedClocks")]
5421    pub fn reset_gpu_locked_clocks(&mut self) -> Result<(), NvmlError> {
5422        let sym = nvml_sym(self.nvml.lib.nvmlDeviceResetGpuLockedClocks.as_ref())?;
5423
5424        unsafe { nvml_try(sym(self.device)) }
5425    }
5426
5427    /**
5428    Lock this [`Device`]'s memory clocks to a specific frequency range.
5429
5430    This setting supercedes application clock values and takes effect regardless
5431    of whether or not any CUDA apps are running. It can be used to request
5432    constant performance. See also [`Self::set_applications_clocks()`].
5433
5434    After a system reboot or a driver reload the clocks go back to their default
5435    values. See also [`Self::reset_mem_locked_clocks()`].
5436
5437    You can use [`Self::supported_memory_clocks()`] to determine valid
5438    frequency combinations to pass into this call.
5439
5440    # Device Support
5441
5442    Supports Ampere and newer fully supported devices.
5443    */
5444    // Tested (no-run)
5445    #[doc(alias = "nvmlDeviceSetMemoryLockedClocks")]
5446    pub fn set_mem_locked_clocks(
5447        &mut self,
5448        min_clock_mhz: u32,
5449        max_clock_mhz: u32,
5450    ) -> Result<(), NvmlError> {
5451        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetMemoryLockedClocks.as_ref())?;
5452
5453        unsafe { nvml_try(sym(self.device, min_clock_mhz, max_clock_mhz)) }
5454    }
5455
5456    /**
5457    Reset this [`Device`]'s memory clocks to their default values.
5458
5459    This resets to the same values that would be used after a reboot or driver
5460    reload (defaults to idle clocks but can be configured via
5461    [`Self::set_applications_clocks()`]).
5462
5463    # Errors
5464
5465    * `Uninitialized`, if the library has not been successfully initialized
5466    * `NotSupported`, if this `Device` does not support this feature
5467    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
5468    * `Unknown`, on any unexpected error
5469
5470    # Device Support
5471
5472    Supports Ampere and newer fully supported devices.
5473    */
5474    // Tested (no-run)
5475    #[doc(alias = "nvmlDeviceResetMemoryLockedClocks")]
5476    pub fn reset_mem_locked_clocks(&mut self) -> Result<(), NvmlError> {
5477        let sym = nvml_sym(self.nvml.lib.nvmlDeviceResetMemoryLockedClocks.as_ref())?;
5478
5479        unsafe { nvml_try(sym(self.device)) }
5480    }
5481
5482    /**
5483    Set whether or not ECC mode is enabled for this `Device`.
5484
5485    Requires root/admin permissions. Only applicable to devices with ECC.
5486
5487    This operation takes effect after the next reboot.
5488
5489    # Errors
5490
5491    * `Uninitialized`, if the library has not been successfully initialized
5492    * `InvalidArg`, if the `Device` is invalid
5493    * `NotSupported`, if this `Device` does not support this feature
5494    * `NoPermission`, if the user doesn't have permission to perform this operation
5495    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
5496    * `Unknown`, on any unexpected error
5497
5498    # Device Support
5499
5500    Supports Kepler and newer fully supported devices. Requires `InfoRom::ECC` version
5501    1.0 or higher.
5502    */
5503    // Checked against local
5504    // Tested (no-run)
5505    #[doc(alias = "nvmlDeviceSetEccMode")]
5506    pub fn set_ecc(&mut self, enabled: bool) -> Result<(), NvmlError> {
5507        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetEccMode.as_ref())?;
5508
5509        unsafe { nvml_try(sym(self.device, state_from_bool(enabled))) }
5510    }
5511
5512    /**
5513    Sets the GPU operation mode for this `Device`.
5514
5515    Requires root/admin permissions. Changing GOMs requires a reboot, a requirement
5516    that may be removed in the future.
5517
5518    Compute only GOMs don't support graphics acceleration. Under Windows switching
5519    to these GOMs when the pending driver model is WDDM (physical display attached)
5520    is not supported.
5521
5522    # Errors
5523
5524    * `Uninitialized`, if the library has not been successfully initialized
5525    * `InvalidArg`, if the `Device` is invalid or `mode` is invalid (shouldn't occur?)
5526    * `NotSupported`, if this `Device` does not support GOMs or a specific mode
5527    * `NoPermission`, if the user doesn't have permission to perform this operation
5528    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
5529    * `Unknown`, on any unexpected error
5530
5531    # Device Support
5532
5533    Supports GK110 M-class and X-class Tesla products from the Kepler family. Modes
5534    `LowDP` and `AllOn` are supported on fully supported GeForce products. Not
5535    supported on Quadro and Tesla C-class products.
5536    */
5537    // Checked against local
5538    // Tested (no-run)
5539    #[doc(alias = "nvmlDeviceSetGpuOperationMode")]
5540    pub fn set_gpu_op_mode(&mut self, mode: OperationMode) -> Result<(), NvmlError> {
5541        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetGpuOperationMode.as_ref())?;
5542
5543        unsafe { nvml_try(sym(self.device, mode.as_c())) }
5544    }
5545
5546    /**
5547    Sets the persistence mode for this `Device`.
5548
5549    The persistence mode determines whether the GPU driver software is torn down
5550    after the last client exits.
5551
5552    This operation takes effect immediately and requires root/admin permissions.
5553    It is not persistent across reboots; after each reboot it will default to
5554    disabled.
5555
5556    Note that after disabling persistence on a device that has its own NUMA
5557    memory, this `Device` handle will no longer be valid, and to continue to
5558    interact with the physical device that it represents you will need to
5559    obtain a new `Device` using the methods available on the `Nvml` struct.
5560    This limitation is currently only applicable to devices that have a
5561    coherent NVLink connection to system memory.
5562
5563    # Errors
5564
5565    * `Uninitialized`, if the library has not been successfully initialized
5566    * `InvalidArg`, if the `Device` is invalid
5567    * `NotSupported`, if this `Device` does not support this feature
5568    * `NoPermission`, if the user doesn't have permission to perform this operation
5569    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
5570    * `Unknown`, on any unexpected error
5571
5572    # Platform Support
5573
5574    Only supports Linux.
5575    */
5576    // Checked against local
5577    // Tested (no-run)
5578    #[cfg(target_os = "linux")]
5579    #[doc(alias = "nvmlDeviceSetPersistenceMode")]
5580    pub fn set_persistent(&mut self, enabled: bool) -> Result<(), NvmlError> {
5581        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetPersistenceMode.as_ref())?;
5582
5583        unsafe { nvml_try(sym(self.device, state_from_bool(enabled))) }
5584    }
5585
5586    /**
5587    Sets the power limit for this `Device`, in milliwatts.
5588
5589    This limit is not persistent across reboots or driver unloads. Enable
5590    persistent mode to prevent the driver from unloading when no application
5591    is using this `Device`.
5592
5593    Requires root/admin permissions. See `.power_management_limit_constraints()`
5594    to check the allowed range of values.
5595
5596    # Errors
5597
5598    * `Uninitialized`, if the library has not been successfully initialized
5599    * `InvalidArg`, if the `Device` is invalid or `limit` is out of range
5600    * `NotSupported`, if this `Device` does not support this feature
5601    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
5602    * `Unknown`, on any unexpected error
5603
5604    For some reason NVIDIA does not mention `NoPermission`.
5605
5606    # Device Support
5607
5608    Supports Kepler and newer fully supported devices.
5609    */
5610    // Checked against local
5611    // Tested (no-run)
5612    #[doc(alias = "nvmlDeviceSetPowerManagementLimit")]
5613    pub fn set_power_management_limit(&mut self, limit: u32) -> Result<(), NvmlError> {
5614        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetPowerManagementLimit.as_ref())?;
5615
5616        unsafe { nvml_try(sym(self.device, limit)) }
5617    }
5618
5619    /**
5620    Retrieve min, max and current clock offset of some clock domain for a given PState
5621
5622    # Errors
5623
5624    * `Uninitialized`, if the library has not been successfully initialized
5625    * `InvalidArg`,  If device, type or pstate are invalid or both minClockOffsetMHz and maxClockOffsetMHz are NULL
5626    * `ArgumentVersionMismatch`, if the provided version is invalid/unsupported
5627    * `NotSupported`, if this `Device` does not support this feature
5628
5629    # Device Support
5630
5631    Supports Maxwell and newer fully supported devices.
5632    */
5633    // Checked against local
5634    // Tested
5635    #[doc(alias = "nvmlDeviceGetClockOffsets")]
5636    pub fn clock_offset(
5637        &self,
5638        clock_type: Clock,
5639        power_state: PerformanceState,
5640    ) -> Result<ClockOffset, NvmlError> {
5641        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetClockOffsets.as_ref())?;
5642
5643        unsafe {
5644            // Implements NVML_STRUCT_VERSION(ClockOffset, 1), as detailed in nvml.h
5645            let version =
5646                (std::mem::size_of::<nvmlClockOffset_v1_t>() | (1_usize << 24_usize)) as u32;
5647
5648            let mut clock_offset = nvmlClockOffset_v1_t {
5649                version,
5650                type_: clock_type.as_c(),
5651                pstate: power_state.as_c(),
5652                clockOffsetMHz: mem::zeroed(),
5653                minClockOffsetMHz: mem::zeroed(),
5654                maxClockOffsetMHz: mem::zeroed(),
5655            };
5656            nvml_try(sym(self.device, &mut clock_offset))?;
5657            ClockOffset::try_from(clock_offset)
5658        }
5659    }
5660
5661    /**
5662    Control current clock offset of some clock domain for a given PState
5663
5664    # Errors
5665
5666    * `Uninitialized`, if the library has not been successfully initialized
5667    * `NoPermission`, if the user doesn't have permission to perform this operation
5668    * `InvalidArg`,  If device, type or pstate are invalid or both clockOffsetMHz is out of allowed range
5669    * `ArgumentVersionMismatch`, if the provided version is invalid/unsupported
5670
5671    # Device Support
5672
5673    Supports Maxwell and newer fully supported devices.
5674    */
5675    // Checked against local
5676    // Tested (no-run)
5677    #[doc(alias = "nvmlDeviceSetClockOffsets")]
5678    pub fn set_clock_offset(
5679        &mut self,
5680        clock_type: Clock,
5681        power_state: PerformanceState,
5682        offset: i32,
5683    ) -> Result<(), NvmlError> {
5684        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetClockOffsets.as_ref())?;
5685
5686        unsafe {
5687            // Implements NVML_STRUCT_VERSION(ClockOffset, 1), as detailed in nvml.h
5688            let version =
5689                (std::mem::size_of::<nvmlClockOffset_v1_t>() | (1_usize << 24_usize)) as u32;
5690
5691            let mut clock_offset = nvmlClockOffset_v1_t {
5692                version,
5693                type_: clock_type.as_c(),
5694                pstate: power_state.as_c(),
5695                clockOffsetMHz: offset,
5696                minClockOffsetMHz: 0,
5697                maxClockOffsetMHz: 0,
5698            };
5699            nvml_try(sym(self.device, &mut clock_offset))?;
5700            Ok(())
5701        }
5702    }
5703
5704    /**
5705    Get all supported Performance States (P-States) for the device.
5706    The number of elements in the returned list will never exceed [`NVML_MAX_GPU_PERF_PSTATES`]`.
5707
5708    # Errors
5709
5710    * `InsufficientSize`, if the the container supplied was not large enough to hold the resulting list
5711    * `Uninitialized`, if the library has not been successfully initialized
5712    * `InvalidArg`,  if device or pstates is invalid
5713    * `NotSupported`, if the device does not support performance state readings
5714    * `Unknown`, on any unexpected error
5715    */
5716    // Checked against local
5717    // Tested
5718    #[doc(alias = "nvmlDeviceGetSupportedPerformanceStates")]
5719    pub fn supported_performance_states(&self) -> Result<Vec<PerformanceState>, NvmlError> {
5720        let sym = nvml_sym(
5721            self.nvml
5722                .lib
5723                .nvmlDeviceGetSupportedPerformanceStates
5724                .as_ref(),
5725        )?;
5726
5727        unsafe {
5728            let mut pstates =
5729                [PerformanceState::Unknown.as_c(); NVML_MAX_GPU_PERF_PSTATES as usize];
5730            // The array size passed to `nvmlDeviceGetSupportedPerformanceStates` must be in bytes, not array length
5731            let byte_size = mem::size_of_val(&pstates);
5732
5733            nvml_try(sym(self.device, pstates.as_mut_ptr(), byte_size as u32))?;
5734
5735            pstates
5736                .into_iter()
5737                .take_while(|pstate| *pstate != PerformanceState::Unknown.as_c())
5738                .map(PerformanceState::try_from)
5739                .collect()
5740        }
5741    }
5742
5743    /**
5744    Retrieve min and max clocks of some clock domain for a given PState.
5745
5746    Returns a (min, max) tuple.
5747
5748    # Errors
5749
5750    * `Uninitialized`, if the library has not been successfully initialized
5751    * `InvalidArg`, if device, type or pstate are invalid or both minClockMHz and maxClockMHz are NULL
5752    * `NotSupported`, if the device does not support this feature
5753    */
5754    // Checked against local
5755    // Tested
5756    #[doc(alias = "nvmlDeviceGetMinMaxClockOfPState")]
5757    pub fn min_max_clock_of_pstate(
5758        &self,
5759        clock_type: Clock,
5760        pstate: PerformanceState,
5761    ) -> Result<(u32, u32), NvmlError> {
5762        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetMinMaxClockOfPState.as_ref())?;
5763
5764        unsafe {
5765            let mut min: u32 = mem::zeroed();
5766            let mut max: u32 = mem::zeroed();
5767
5768            nvml_try(sym(
5769                self.device,
5770                clock_type.as_c(),
5771                pstate.as_c(),
5772                &mut min,
5773                &mut max,
5774            ))?;
5775
5776            Ok((min, max))
5777        }
5778    }
5779
5780    // Event handling methods
5781
5782    /**
5783    Starts recording the given `EventTypes` for this `Device` and adding them
5784    to the specified `EventSet`.
5785
5786    Use `.supported_event_types()` to find out which events you can register for
5787    this `Device`.
5788
5789    **Unfortunately, due to the way `error-chain` works, there is no way to
5790    return the set if it is still valid after an error has occurred with the
5791    register call.** The set that you passed in will be freed if any error
5792    occurs and will not be returned to you. This is not desired behavior
5793    and I will fix it as soon as it is possible to do so.
5794
5795    All events that occurred before this call was made will not be recorded.
5796
5797    ECC events are only available on `Device`s with ECC enabled. Power capping events
5798    are only available on `Device`s with power management enabled.
5799
5800    # Errors
5801
5802    * `Uninitialized`, if the library has not been successfully initialized
5803    * `InvalidArg`, if `events` is invalid (shouldn't occur?)
5804    * `NotSupported`, if the platform does not support this feature or some of the
5805      requested event types.
5806    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
5807    * `Unknown`, on any unexpected error. **If this error is returned, the `set` you
5808      passed in has had its resources freed and will not be returned to you**. NVIDIA's
5809      docs say that this error means that the set is in an invalid state.
5810
5811    # Device Support
5812
5813    Supports Fermi and newer fully supported devices.
5814
5815    # Platform Support
5816
5817    Only supports Linux.
5818
5819    # Examples
5820
5821    ```
5822    # use nvml_wrapper::Nvml;
5823    # use nvml_wrapper::error::*;
5824    # fn main() -> Result<(), NvmlErrorWithSource> {
5825    # let nvml = Nvml::init()?;
5826    # let device = nvml.device_by_index(0)?;
5827    use nvml_wrapper::bitmasks::event::EventTypes;
5828
5829    let set = nvml.create_event_set()?;
5830
5831    /*
5832    Register both `CLOCK_CHANGE` and `PSTATE_CHANGE`.
5833
5834    `let set = ...` is a quick way to re-bind the set to the same variable, since
5835    `.register_events()` consumes the set in order to enforce safety and returns it
5836    if everything went well. It does *not* require `set` to be mutable as nothing
5837    is being mutated.
5838    */
5839    let set = device.register_events(
5840        EventTypes::CLOCK_CHANGE |
5841        EventTypes::PSTATE_CHANGE,
5842        set
5843    )?;
5844    # Ok(())
5845    # }
5846    ```
5847    */
5848    // Checked against local
5849    // Tested
5850    // Thanks to Thinkofname for helping resolve lifetime issues
5851    #[cfg(target_os = "linux")]
5852    #[doc(alias = "nvmlDeviceRegisterEvents")]
5853    pub fn register_events(
5854        &self,
5855        events: EventTypes,
5856        set: EventSet<'nvml>,
5857    ) -> Result<EventSet<'nvml>, NvmlErrorWithSource> {
5858        let sym = nvml_sym(self.nvml.lib.nvmlDeviceRegisterEvents.as_ref())?;
5859
5860        unsafe {
5861            match nvml_try(sym(self.device, events.bits(), set.handle())) {
5862                Ok(()) => Ok(set),
5863                Err(NvmlError::Unknown) => {
5864                    // NVIDIA says that if an Unknown error is returned, `set` will
5865                    // be in an undefined state and should be freed.
5866                    if let Err(e) = set.release_events() {
5867                        return Err(NvmlErrorWithSource {
5868                            error: NvmlError::SetReleaseFailed,
5869                            source: Some(e),
5870                        });
5871                    }
5872
5873                    Err(NvmlError::Unknown.into())
5874                }
5875                Err(e) => {
5876                    // TODO: return set here so you can use it again?
5877                    if let Err(e) = set.release_events() {
5878                        return Err(NvmlErrorWithSource {
5879                            error: NvmlError::SetReleaseFailed,
5880                            source: Some(e),
5881                        });
5882                    }
5883
5884                    Err(e.into())
5885                }
5886            }
5887        }
5888    }
5889
5890    /**
5891    Gets the `EventTypes` that this `Device` supports.
5892
5893    The returned bitmask is created via the `EventTypes::from_bits_truncate`
5894    method, meaning that any bits that don't correspond to flags present in this
5895    version of the wrapper will be dropped.
5896
5897    # Errors
5898
5899    * `Uninitialized`, if the library has not been successfully initialized
5900    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
5901    * `Unknown`, on any unexpected error
5902
5903    # Device Support
5904
5905    Supports Fermi and newer fully supported devices.
5906
5907    # Platform Support
5908
5909    Only supports Linux.
5910
5911    # Examples
5912
5913    ```
5914    # use nvml_wrapper::Nvml;
5915    # use nvml_wrapper::error::*;
5916    # fn main() -> Result<(), NvmlError> {
5917    # let nvml = Nvml::init()?;
5918    # let device = nvml.device_by_index(0)?;
5919    use nvml_wrapper::bitmasks::event::EventTypes;
5920
5921    let supported = device.supported_event_types()?;
5922
5923    if supported.contains(EventTypes::CLOCK_CHANGE) {
5924        println!("The `CLOCK_CHANGE` event is supported.");
5925    } else if supported.contains(
5926        EventTypes::SINGLE_BIT_ECC_ERROR |
5927        EventTypes::DOUBLE_BIT_ECC_ERROR
5928    ) {
5929        println!("All ECC error event types are supported.");
5930    }
5931    # Ok(())
5932    # }
5933    ```
5934    */
5935    // Tested
5936    #[cfg(target_os = "linux")]
5937    #[doc(alias = "nvmlDeviceGetSupportedEventTypes")]
5938    pub fn supported_event_types(&self) -> Result<EventTypes, NvmlError> {
5939        Ok(EventTypes::from_bits_truncate(
5940            self.supported_event_types_raw()?,
5941        ))
5942    }
5943
5944    /**
5945    Gets the `EventTypes` that this `Device` supports, erroring if any bits
5946    correspond to non-present flags.
5947
5948    # Errors
5949
5950    * `Uninitialized`, if the library has not been successfully initialized
5951    * `IncorrectBits`, if NVML returns any bits that do not correspond to flags in
5952      `EventTypes`
5953    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
5954    * `Unknown`, on any unexpected error
5955
5956    # Device Support
5957
5958    Supports Fermi and newer fully supported devices.
5959
5960    # Platform Support
5961
5962    Only supports Linux.
5963    */
5964    // Tested
5965    #[cfg(target_os = "linux")]
5966    pub fn supported_event_types_strict(&self) -> Result<EventTypes, NvmlError> {
5967        let ev_types = self.supported_event_types_raw()?;
5968
5969        EventTypes::from_bits(ev_types).ok_or(NvmlError::IncorrectBits(Bits::U64(ev_types)))
5970    }
5971
5972    // Helper for the above methods.
5973    #[cfg(target_os = "linux")]
5974    fn supported_event_types_raw(&self) -> Result<c_ulonglong, NvmlError> {
5975        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetSupportedEventTypes.as_ref())?;
5976
5977        unsafe {
5978            let mut ev_types: c_ulonglong = mem::zeroed();
5979            nvml_try(sym(self.device, &mut ev_types))?;
5980
5981            Ok(ev_types)
5982        }
5983    }
5984
5985    // Drain states
5986
5987    /**
5988    Enable or disable drain state for this `Device`.
5989
5990    If you pass `None` as `pci_info`, `.pci_info()` will be called in order to obtain
5991    `PciInfo` to be used within this method.
5992
5993    Enabling drain state forces this `Device` to no longer accept new incoming requests.
5994    Any new NVML processes will no longer see this `Device`.
5995
5996    Must be called as administrator. Persistence mode for this `Device` must be turned
5997    off before this call is made.
5998
5999    # Errors
6000
6001    * `Uninitialized`, if the library has not been successfully initialized
6002    * `NotSupported`, if this `Device` doesn't support this feature
6003    * `NoPermission`, if the calling process has insufficient permissions to perform
6004      this operation
6005    * `InUse`, if this `Device` has persistence mode turned on
6006    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
6007    * `Unknown`, on any unexpected error
6008
6009    In addition, all of the errors returned by:
6010
6011    * `.pci_info()`
6012    * `PciInfo.try_into()`
6013
6014    # Device Support
6015
6016    Supports Pascal and newer fully supported devices.
6017
6018    Some Kepler devices are also supported (that's all NVIDIA says, no specifics).
6019
6020    # Platform Support
6021
6022    Only supports Linux.
6023
6024    # Examples
6025
6026    ```no_run
6027    # use nvml_wrapper::Nvml;
6028    # use nvml_wrapper::error::*;
6029    # fn test() -> Result<(), NvmlError> {
6030    # let nvml = Nvml::init()?;
6031    # let mut device = nvml.device_by_index(0)?;
6032    // Pass `None`, `.set_drain()` call will grab `PciInfo` for us
6033    device.set_drain(true, None)?;
6034
6035    let pci_info = device.pci_info()?;
6036
6037    // Pass in our own `PciInfo`, call will use it instead
6038    device.set_drain(true, pci_info)?;
6039    # Ok(())
6040    # }
6041    ```
6042    */
6043    // Checked against local
6044    #[cfg(target_os = "linux")]
6045    #[doc(alias = "nvmlDeviceModifyDrainState")]
6046    pub fn set_drain<T: Into<Option<PciInfo>>>(
6047        &mut self,
6048        enabled: bool,
6049        pci_info: T,
6050    ) -> Result<(), NvmlError> {
6051        let pci_info = if let Some(info) = pci_info.into() {
6052            info
6053        } else {
6054            self.pci_info()?
6055        };
6056
6057        let sym = nvml_sym(self.nvml.lib.nvmlDeviceModifyDrainState.as_ref())?;
6058
6059        unsafe { nvml_try(sym(&mut pci_info.try_into()?, state_from_bool(enabled))) }
6060    }
6061
6062    /**
6063    Query the drain state of this `Device`.
6064
6065    If you pass `None` as `pci_info`, `.pci_info()` will be called in order to obtain
6066    `PciInfo` to be used within this method.
6067
6068    # Errors
6069
6070    * `Uninitialized`, if the library has not been successfully initialized
6071    * `NotSupported`, if this `Device` doesn't support this feature
6072    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
6073    * `UnexpectedVariant`, for which you can read the docs for
6074    * `Unknown`, on any unexpected error
6075
6076    In addition, all of the errors returned by:
6077
6078    * `.pci_info()`
6079    * `PciInfo.try_into()`
6080
6081    # Device Support
6082
6083    Supports Pascal and newer fully supported devices.
6084
6085    Some Kepler devices are also supported (that's all NVIDIA says, no specifics).
6086
6087    # Platform Support
6088
6089    Only supports Linux.
6090
6091    # Examples
6092
6093    ```
6094    # use nvml_wrapper::Nvml;
6095    # use nvml_wrapper::error::*;
6096    # fn main() -> Result<(), NvmlError> {
6097    # let nvml = Nvml::init()?;
6098    # let mut device = nvml.device_by_index(0)?;
6099    // Pass `None`, `.is_drain_enabled()` call will grab `PciInfo` for us
6100    device.is_drain_enabled(None)?;
6101
6102    let pci_info = device.pci_info()?;
6103
6104    // Pass in our own `PciInfo`, call will use it instead
6105    device.is_drain_enabled(pci_info)?;
6106    # Ok(())
6107    # }
6108    ```
6109    */
6110    // Checked against local
6111    // Tested
6112    #[cfg(target_os = "linux")]
6113    #[doc(alias = "nvmlDeviceQueryDrainState")]
6114    pub fn is_drain_enabled<T: Into<Option<PciInfo>>>(
6115        &self,
6116        pci_info: T,
6117    ) -> Result<bool, NvmlError> {
6118        let pci_info = if let Some(info) = pci_info.into() {
6119            info
6120        } else {
6121            self.pci_info()?
6122        };
6123
6124        let sym = nvml_sym(self.nvml.lib.nvmlDeviceQueryDrainState.as_ref())?;
6125
6126        unsafe {
6127            let mut state: nvmlEnableState_t = mem::zeroed();
6128
6129            nvml_try(sym(&mut pci_info.try_into()?, &mut state))?;
6130
6131            bool_from_state(state)
6132        }
6133    }
6134
6135    /**
6136    Get the list of performance modes for `Device`
6137
6138    Originally, NVML returns as a list in a form of a single string separated by comma.
6139
6140    # Errors
6141
6142    * `Uninitialized`, if the library has not been successfully initialized
6143    * `NotSupported`, if the platform does not support this feature or some of the
6144      requested event types.
6145    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
6146    * `Unknown`, on any unexpected error. **If this error is returned, the `set` you
6147
6148    # Platform Support
6149
6150    Only supports Linux.
6151    */
6152    // Checked against local
6153    // Tested
6154    #[cfg(target_os = "linux")]
6155    #[doc(alias = "nvmlDeviceGetPerformanceModes")]
6156    pub fn performance_modes(&self) -> Result<(Vec<String>, u32), NvmlError> {
6157        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetPerformanceModes.as_ref())?;
6158
6159        unsafe {
6160            let mut pmodes: nvmlDevicePerfModes_t = mem::zeroed();
6161
6162            nvml_try(sym(self.device, &mut pmodes))?;
6163
6164            let modes_str = CStr::from_ptr(pmodes.str_.as_ptr());
6165            let modes = modes_str.to_str()?;
6166            Ok((
6167                modes.split(';').map(str::to_string).collect(),
6168                pmodes.version,
6169            ))
6170        }
6171    }
6172
6173    /**
6174    Gets the active vGPU instances for `Device`
6175
6176    A list as Vec of vGPU handles is returned to be used with nvmlVgpuInstance* calls.
6177
6178    # Errors
6179
6180    * `Uninitialized`, if the library has not been successfully initialized
6181    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
6182    * `Unknown`, on any unexpected error
6183    * `NotSupported`, if the platform does not support this feature
6184
6185    # Platform Support
6186
6187    Only supports Linux.
6188    */
6189    // Checked against local
6190    // Tested
6191    #[cfg(target_os = "linux")]
6192    #[doc(alias = "nvmlDeviceGetActiveVgpus")]
6193    pub fn active_vgpus(&self) -> Result<Vec<nvmlVgpuInstance_t>, NvmlError> {
6194        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetActiveVgpus.as_ref())?;
6195
6196        unsafe {
6197            let mut count: u32 = 0;
6198
6199            nvml_try(sym(self.device, std::ptr::null_mut(), &mut count))?;
6200            let mut arr: Vec<nvmlVgpuInstance_t> = vec![0; count as usize];
6201            nvml_try(sym(self.device, arr.as_mut_ptr(), &mut count))?;
6202
6203            Ok(arr)
6204        }
6205    }
6206
6207    /**
6208    Get the list of process ids running on a given vGPU instance for stats purpose
6209
6210    # Errors
6211
6212    * `Uninitialized`, if the library has not been successfully initialized
6213    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
6214    * `Unknown`, on any unexpected error
6215    * `NotSupported`, if the platform does not support this feature
6216
6217    # Platform Support
6218
6219    For Maxwell or newer fully supported devices
6220    */
6221    #[doc(alias = "nvmlVgpuInstanceGetAccountingPids")]
6222    pub fn vgpu_accounting_pids(
6223        &self,
6224        instance: nvmlVgpuInstance_t,
6225    ) -> Result<Vec<u32>, NvmlError> {
6226        let sym = nvml_sym(self.nvml.lib.nvmlVgpuInstanceGetAccountingPids.as_ref())?;
6227
6228        unsafe {
6229            let mut count: u32 = 0;
6230
6231            nvml_try(sym(instance, &mut count, std::ptr::null_mut()))?;
6232            let mut pids: Vec<u32> = vec![0; count as usize];
6233            nvml_try(sym(instance, &mut count, pids.as_mut_ptr()))?;
6234
6235            Ok(pids)
6236        }
6237    }
6238
6239    /**
6240     Get the stats for a given pid running in the vGPU instance
6241    # Errors
6242
6243    * `Uninitialized`, if the library has not been successfully initialized
6244    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
6245    * `Unknown`, on any unexpected error
6246    * `NotSupported`, if the platform does not support this feature
6247
6248    # Platform Support
6249
6250    For Maxwell or newer fully supported devices
6251    */
6252    #[doc(alias = "nvmlVgpuInstanceGetAccountingStats")]
6253    pub fn vgpu_accounting_instance(
6254        &self,
6255        instance: nvmlVgpuInstance_t,
6256        pid: u32,
6257    ) -> Result<AccountingStats, NvmlError> {
6258        let sym = nvml_sym(self.nvml.lib.nvmlVgpuInstanceGetAccountingStats.as_ref())?;
6259
6260        unsafe {
6261            let mut stats: nvmlAccountingStats_t = mem::zeroed();
6262            nvml_try(sym(instance, pid, &mut stats))?;
6263
6264            Ok(AccountingStats::from(stats))
6265        }
6266    }
6267
6268    /**
6269    Gets the virtualization mode of `Device`
6270
6271    # Errors
6272
6273    * `Uninitialized`, if the library has not been successfully initialized
6274
6275    * `InvalidArg`, if this `Device` is invalid or `clock_type` is invalid (shouldn't occur?)
6276    * `NotSupported`, if this `Device` does not support this feature
6277    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
6278    * `Unknown`, on any unexpected error
6279
6280    # Device support
6281
6282    Supports Kepler and newer fully supported devices.
6283
6284    */
6285    // Checked against local
6286    // Tested
6287    #[cfg(target_os = "linux")]
6288    #[doc(alias = "nvmlDeviceGetVirtualizationMode")]
6289    pub fn virtualization_mode(&self) -> Result<GpuVirtualizationMode, NvmlError> {
6290        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetVirtualizationMode.as_ref())?;
6291
6292        unsafe {
6293            let mut mode: nvmlGpuVirtualizationMode_t = mem::zeroed();
6294
6295            nvml_try(sym(self.device, &mut mode))?;
6296
6297            GpuVirtualizationMode::try_from(mode)
6298        }
6299    }
6300
6301    /**
6302    Removes this `Device` from the view of both NVML and the NVIDIA kernel driver.
6303
6304    If you pass `None` as `pci_info`, `.pci_info()` will be called in order to obtain
6305    `PciInfo` to be used within this method.
6306
6307    This call only works if no other processes are attached. If other processes
6308    are attached when this is called, the `InUse` error will be returned and
6309    this `Device` will return to its original draining state. The only situation
6310    where this can occur is if a process was and is still using this `Device`
6311    before the call to `set_drain()` was made and it was enabled. Note that
6312    persistence mode counts as an attachment to this `Device` and thus must be
6313    disabled prior to this call.
6314
6315    For long-running NVML processes, please note that this will change the
6316    enumeration of current GPUs. As an example, if there are four GPUs present
6317    and the first is removed, the new enumeration will be 0-2. Device handles
6318    for the removed GPU will be invalid.
6319
6320    NVIDIA doesn't provide much documentation about the `gpu_state` and `link_state`
6321    parameters, so you're on your own there. It does say that the `gpu_state`
6322    controls whether or not this `Device` should be removed from the kernel.
6323
6324    Must be run as administrator.
6325
6326    # Bad Ergonomics Explanation
6327
6328    Previously the design of `error-chain` made it impossible to return stuff
6329    with generic lifetime parameters. The crate's errors are now based on
6330    `std::error::Error`, so this situation no longer needs to be, but I haven't
6331    made time to re-work it.
6332
6333    # Errors
6334
6335    * `Uninitialized`, if the library has not been successfully initialized
6336    * `NotSupported`, if this `Device` doesn't support this feature
6337    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
6338    * `InUse`, if this `Device` is still in use and cannot be removed
6339
6340    In addition, all of the errors returned by:
6341
6342    * `.pci_info()`
6343    * `PciInfo.try_into()`
6344
6345    # Device Support
6346
6347    Supports Pascal and newer fully supported devices.
6348
6349    Some Kepler devices are also supported (that's all NVIDIA says, no specifics).
6350
6351    # Platform Support
6352
6353    Only supports Linux.
6354
6355    # Examples
6356
6357    How to handle error case:
6358
6359    ```no_run
6360    # use nvml_wrapper::Nvml;
6361    # use nvml_wrapper::error::*;
6362    # use nvml_wrapper::enum_wrappers::device::{DetachGpuState, PcieLinkState};
6363    # fn test() -> Result<(), NvmlError> {
6364    # let nvml = Nvml::init()?;
6365    # let mut device = nvml.device_by_index(0)?;
6366    match device.remove(None, DetachGpuState::Remove, PcieLinkState::ShutDown) {
6367        (Ok(()), None) => println!("Successful call, `Device` removed"),
6368        (Err(e), Some(d)) => println!("Unsuccessful call. `Device`: {:?}", d),
6369        _ => println!("Something else",)
6370    }
6371    # Ok(())
6372    # }
6373    ```
6374    Demonstration of the `pci_info` parameter's use:
6375
6376    ```no_run
6377    # use nvml_wrapper::Nvml;
6378    # use nvml_wrapper::error::*;
6379    # use nvml_wrapper::enum_wrappers::device::{DetachGpuState, PcieLinkState};
6380    # fn test() -> Result<(), NvmlErrorWithSource> {
6381    # let nvml = Nvml::init()?;
6382    # let mut device = nvml.device_by_index(0)?;
6383    // Pass `None`, `.remove()` call will grab `PciInfo` for us
6384    device.remove(None, DetachGpuState::Remove, PcieLinkState::ShutDown).0?;
6385
6386    # let mut device2 = nvml.device_by_index(0)?;
6387    // Different `Device` because `.remove()` consumes the `Device`
6388    let pci_info = device2.pci_info()?;
6389
6390    // Pass in our own `PciInfo`, call will use it instead
6391    device2.remove(pci_info, DetachGpuState::Remove, PcieLinkState::ShutDown).0?;
6392    # Ok(())
6393    # }
6394    ```
6395    */
6396    // Checked against local
6397    // TODO: Fix ergonomics here when possible.
6398    #[cfg(target_os = "linux")]
6399    #[doc(alias = "nvmlDeviceRemoveGpu_v2")]
6400    pub fn remove<T: Into<Option<PciInfo>>>(
6401        self,
6402        pci_info: T,
6403        gpu_state: DetachGpuState,
6404        link_state: PcieLinkState,
6405    ) -> (Result<(), NvmlErrorWithSource>, Option<Device<'nvml>>) {
6406        let pci_info = if let Some(info) = pci_info.into() {
6407            info
6408        } else {
6409            match self.pci_info() {
6410                Ok(info) => info,
6411                Err(error) => {
6412                    return (
6413                        Err(NvmlErrorWithSource {
6414                            error,
6415                            source: Some(NvmlError::GetPciInfoFailed),
6416                        }),
6417                        Some(self),
6418                    )
6419                }
6420            }
6421        };
6422
6423        let mut raw_pci_info = match pci_info.try_into() {
6424            Ok(info) => info,
6425            Err(error) => {
6426                return (
6427                    Err(NvmlErrorWithSource {
6428                        error,
6429                        source: Some(NvmlError::PciInfoToCFailed),
6430                    }),
6431                    Some(self),
6432                )
6433            }
6434        };
6435
6436        let sym = match nvml_sym(self.nvml.lib.nvmlDeviceRemoveGpu_v2.as_ref()) {
6437            Ok(sym) => sym,
6438            Err(error) => {
6439                return (
6440                    Err(NvmlErrorWithSource {
6441                        error,
6442                        source: None,
6443                    }),
6444                    Some(self),
6445                )
6446            }
6447        };
6448
6449        unsafe {
6450            match nvml_try(sym(&mut raw_pci_info, gpu_state.as_c(), link_state.as_c())) {
6451                // `Device` removed; call was successful, no `Device` to return
6452                Ok(()) => (Ok(()), None),
6453                // `Device` has not been removed; unsuccessful call, return `Device`
6454                Err(e) => (Err(e.into()), Some(self)),
6455            }
6456        }
6457    }
6458
6459    /**
6460     Get GSP firmware mode. Whether it is enabled and if it is in default mode.
6461
6462    # Errors
6463
6464    * `Uninitialized`, if the library has not been successfully initialized
6465    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
6466    * `Unknown`, on any unexpected error
6467    * `NotSupported`, if the platform does not support this feature
6468    */
6469    #[doc(alias = "nvmlDeviceGetGspFirmwareMode")]
6470    pub fn gsp_firmware_mode(&self) -> Result<GspFirmwareMode, NvmlError> {
6471        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetGspFirmwareMode.as_ref())?;
6472
6473        unsafe {
6474            let mut enabled: c_uint = 0;
6475            let mut default: c_uint = 0;
6476
6477            nvml_try(sym(self.device, &mut enabled, &mut default))?;
6478
6479            Ok(GspFirmwareMode {
6480                enabled: enabled != 0,
6481                default: default != 0,
6482            })
6483        }
6484    }
6485
6486    /**
6487     Get GSP firmware version.
6488
6489    # Errors
6490
6491    * `Uninitialized`, if the library has not been successfully initialized
6492    * `GpuLost`, if this `Device` has fallen off the bus or is otherwise inaccessible
6493    * `Unknown`, on any unexpected error
6494    * `NotSupported`, if the platform does not support this feature
6495    */
6496    #[doc(alias = "nvmlDeviceGetGspFirmwareVersion")]
6497    pub fn gsp_firmware_version(&self) -> Result<String, NvmlError> {
6498        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetGspFirmwareVersion.as_ref())?;
6499
6500        unsafe {
6501            let mut version = vec![0; 80];
6502
6503            nvml_try(sym(self.device, version.as_mut_ptr()))?;
6504            let raw = CStr::from_ptr(version.as_ptr());
6505
6506            Ok(raw.to_str()?.into())
6507        }
6508    }
6509
6510    // NvLink
6511
6512    /**
6513    Obtain a struct that represents an NvLink.
6514
6515    NVIDIA does not provide any information as to how to obtain a valid NvLink
6516    value, so you're on your own there.
6517    */
6518    pub fn link_wrapper_for(&self, link: u32) -> NvLink<'_, 'nvml> {
6519        NvLink { device: self, link }
6520    }
6521
6522    // vGPU
6523
6524    /// Obtain a list of vGPU type (profiles) supported by the device, if any.
6525    pub fn vgpu_supported_types(&self) -> Result<Vec<VgpuType<'_>>, NvmlError> {
6526        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetSupportedVgpus.as_ref())?;
6527        let mut ids = vec![];
6528
6529        unsafe {
6530            let mut count: c_uint = 0;
6531
6532            match nvml_try(sym(self.device, &mut count, ids.as_mut_ptr())) {
6533                Ok(()) | Err(NvmlError::InsufficientSize(_)) => {}
6534                Err(err) => return Err(err),
6535            }
6536
6537            ids.resize(count as usize, 0);
6538            nvml_try(sym(self.device, &mut count, ids.as_mut_ptr()))?;
6539        }
6540
6541        Ok(ids.into_iter().map(|id| VgpuType::new(self, id)).collect())
6542    }
6543
6544    /// Obtain a list of vGPU type (profiles) creatable on the device, if any.
6545    pub fn vgpu_creatable_types(&self) -> Result<Vec<VgpuType<'_>>, NvmlError> {
6546        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetCreatableVgpus.as_ref())?;
6547        let mut ids = vec![];
6548
6549        unsafe {
6550            let mut count: c_uint = 0;
6551
6552            match nvml_try(sym(self.device, &mut count, ids.as_mut_ptr())) {
6553                Ok(()) | Err(NvmlError::InsufficientSize(_)) => {}
6554                Err(err) => return Err(err),
6555            }
6556
6557            ids.resize(count as usize, 0);
6558            nvml_try(sym(self.device, &mut count, ids.as_mut_ptr()))?;
6559        }
6560
6561        Ok(ids.into_iter().map(|id| VgpuType::new(self, id)).collect())
6562    }
6563
6564    /// Obtain a list of vGPU scheduler capabilities supported by the device, if any.
6565    pub fn vgpu_scheduler_capabilities(&self) -> Result<VgpuSchedulerCapabilities, NvmlError> {
6566        let sym = nvml_sym(
6567            self.nvml
6568                .lib
6569                .nvmlDeviceGetVgpuSchedulerCapabilities
6570                .as_ref(),
6571        )?;
6572
6573        unsafe {
6574            let mut capabilities: nvmlVgpuSchedulerCapabilities_t = mem::zeroed();
6575
6576            nvml_try(sym(self.device, &mut capabilities))?;
6577
6578            Ok(VgpuSchedulerCapabilities::from(capabilities))
6579        }
6580    }
6581
6582    /// Obtain the n log entries (max 200) of the vGPU scheduler, to be called several times if need
6583    /// be.
6584    pub fn vgpu_scheduler_log(&self) -> Result<VgpuSchedulerLog, NvmlError> {
6585        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetVgpuSchedulerLog.as_ref())?;
6586
6587        unsafe {
6588            let mut schedulerlog: nvmlVgpuSchedulerLog_t = mem::zeroed();
6589
6590            nvml_try(sym(self.device, &mut schedulerlog))?;
6591
6592            Ok(VgpuSchedulerLog::from(schedulerlog))
6593        }
6594    }
6595
6596    /// Obtain the vGPU scheduler state of the device
6597    pub fn vgpu_scheduler_state(&self) -> Result<VgpuSchedulerGetState, NvmlError> {
6598        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetVgpuSchedulerState.as_ref())?;
6599
6600        unsafe {
6601            let mut scheduler_state: nvmlVgpuSchedulerGetState_t = mem::zeroed();
6602
6603            nvml_try(sym(self.device, &mut scheduler_state))?;
6604
6605            Ok(VgpuSchedulerGetState::from(scheduler_state))
6606        }
6607    }
6608
6609    /// Set the vGPU scheduler state of the device
6610    pub fn set_vgpu_scheduler_state(
6611        &self,
6612        scheduler_state: VgpuSchedulerSetState,
6613    ) -> Result<(), NvmlError> {
6614        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetVgpuSchedulerState.as_ref())?;
6615
6616        unsafe { nvml_try(sym(self.device, &mut scheduler_state.as_c())) }
6617    }
6618
6619    /// Check if the GPU is on vGPU host mode
6620    pub fn vgpu_host_mode(&self) -> Result<HostVgpuMode, NvmlError> {
6621        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetHostVgpuMode.as_ref())?;
6622
6623        unsafe {
6624            let mut mode: nvmlHostVgpuMode_t = 0;
6625
6626            nvml_try(sym(self.device, &mut mode))?;
6627
6628            HostVgpuMode::try_from(mode)
6629        }
6630    }
6631
6632    /// Query the given vGPU capability
6633    pub fn vgpu_capabilities(&self, cap: VgpuCapability) -> Result<u32, NvmlError> {
6634        let sym = nvml_sym(self.nvml.lib.nvmlDeviceGetVgpuCapabilities.as_ref())?;
6635
6636        unsafe {
6637            let mut res: c_uint = 0;
6638            nvml_try(sym(self.device, cap.as_c(), &mut res))?;
6639
6640            Ok(res)
6641        }
6642    }
6643
6644    pub fn vgpu_set_capabilities(
6645        &self,
6646        cap: VgpuCapability,
6647        enable: bool,
6648    ) -> Result<(), NvmlError> {
6649        let sym = nvml_sym(self.nvml.lib.nvmlDeviceSetVgpuCapabilities.as_ref())?;
6650
6651        unsafe {
6652            let state: nvmlEnableState_t = match enable {
6653                true => nvmlEnableState_enum_NVML_FEATURE_ENABLED,
6654                false => nvmlEnableState_enum_NVML_FEATURE_DISABLED,
6655            };
6656
6657            nvml_try(sym(self.device, cap.as_c(), state))
6658        }
6659    }
6660
6661    // GPM (GPU Performance Monitoring) methods
6662
6663    /**
6664    Queries whether GPM (GPU Performance Monitoring) is supported on this device.
6665
6666    # Errors
6667
6668    * `Uninitialized`, if the library has not been successfully initialized
6669    * `InvalidArg`, if the device is invalid
6670    * `Unknown`, on any unexpected error
6671
6672    # Device Support
6673
6674    Supports Hopper and newer architectures.
6675    */
6676    #[doc(alias = "nvmlGpmQueryDeviceSupport")]
6677    pub fn gpm_support(&self) -> Result<bool, NvmlError> {
6678        let sym = nvml_sym(self.nvml.lib.nvmlGpmQueryDeviceSupport.as_ref())?;
6679
6680        unsafe {
6681            let mut support: nvmlGpmSupport_t = mem::zeroed();
6682            support.version = NVML_GPM_SUPPORT_VERSION;
6683
6684            nvml_try(sym(self.device, &mut support))?;
6685
6686            Ok(support.isSupportedDevice != 0)
6687        }
6688    }
6689
6690    /**
6691    Queries whether GPM streaming is currently enabled on this device.
6692
6693    # Errors
6694
6695    * `Uninitialized`, if the library has not been successfully initialized
6696    * `InvalidArg`, if the device is invalid
6697    * `NotSupported`, if GPM is not supported on this device
6698    * `Unknown`, on any unexpected error
6699
6700    # Device Support
6701
6702    Supports Hopper and newer architectures.
6703    */
6704    #[doc(alias = "nvmlGpmQueryIfStreamingEnabled")]
6705    pub fn gpm_streaming_enabled(&self) -> Result<bool, NvmlError> {
6706        let sym = nvml_sym(self.nvml.lib.nvmlGpmQueryIfStreamingEnabled.as_ref())?;
6707
6708        unsafe {
6709            let mut state: c_uint = 0;
6710            nvml_try(sym(self.device, &mut state))?;
6711
6712            Ok(state != 0)
6713        }
6714    }
6715
6716    /**
6717    Enables or disables GPM streaming on this device.
6718
6719    # Errors
6720
6721    * `Uninitialized`, if the library has not been successfully initialized
6722    * `InvalidArg`, if the device is invalid
6723    * `NotSupported`, if GPM is not supported on this device
6724    * `Unknown`, on any unexpected error
6725
6726    # Device Support
6727
6728    Supports Hopper and newer architectures.
6729    */
6730    #[doc(alias = "nvmlGpmSetStreamingEnabled")]
6731    pub fn set_gpm_streaming_enabled(&self, enabled: bool) -> Result<(), NvmlError> {
6732        let sym = nvml_sym(self.nvml.lib.nvmlGpmSetStreamingEnabled.as_ref())?;
6733
6734        let state: c_uint = if enabled { 1 } else { 0 };
6735
6736        unsafe { nvml_try(sym(self.device, state)) }
6737    }
6738
6739    /**
6740    Allocates a GPM sample and populates it with current GPU performance data.
6741
6742    Take two samples separated by a time interval and pass them to
6743    [`crate::gpm::gpm_metrics_get`] to compute performance metrics for that
6744    interval.
6745
6746    # Errors
6747
6748    * `Uninitialized`, if the library has not been successfully initialized
6749    * `InvalidArg`, if the device is invalid
6750    * `NotSupported`, if GPM is not supported on this device
6751    * `Unknown`, on any unexpected error
6752
6753    # Device Support
6754
6755    Supports Hopper and newer architectures.
6756    */
6757    #[doc(alias = "nvmlGpmSampleGet")]
6758    pub fn gpm_sample(&self) -> Result<GpmSample<'nvml>, NvmlError> {
6759        let sym = nvml_sym(self.nvml.lib.nvmlGpmSampleGet.as_ref())?;
6760
6761        let sample = GpmSample::alloc(self.nvml)?;
6762
6763        unsafe {
6764            nvml_try(sym(self.device, sample.handle()))?;
6765        }
6766
6767        Ok(sample)
6768    }
6769
6770    /**
6771    Allocates a GPM sample and populates it with current performance data
6772    for a specific MIG (Multi-Instance GPU) GPU instance.
6773
6774    Take two samples separated by a time interval and pass them to
6775    [`crate::gpm::gpm_metrics_get`] to compute performance metrics for that
6776    interval.
6777
6778    # Errors
6779
6780    * `Uninitialized`, if the library has not been successfully initialized
6781    * `InvalidArg`, if the device or GPU instance ID is invalid
6782    * `NotSupported`, if GPM is not supported on this device
6783    * `Unknown`, on any unexpected error
6784
6785    # Device Support
6786
6787    Supports Hopper and newer architectures with MIG enabled.
6788    */
6789    #[doc(alias = "nvmlGpmMigSampleGet")]
6790    pub fn gpm_mig_sample(&self, gpu_instance_id: u32) -> Result<GpmSample<'nvml>, NvmlError> {
6791        let sym = nvml_sym(self.nvml.lib.nvmlGpmMigSampleGet.as_ref())?;
6792
6793        let sample = GpmSample::alloc(self.nvml)?;
6794
6795        unsafe {
6796            nvml_try(sym(self.device, gpu_instance_id, sample.handle()))?;
6797        }
6798
6799        Ok(sample)
6800    }
6801}
6802
6803#[cfg(test)]
6804#[deny(unused_mut)]
6805mod test {
6806    #[cfg(target_os = "linux")]
6807    use crate::bitmasks::event::*;
6808    #[cfg(target_os = "windows")]
6809    use crate::bitmasks::Behavior;
6810    use crate::enum_wrappers::device::*;
6811    use crate::enums::device::GpuLockedClocksSetting;
6812    use crate::error::*;
6813    use crate::structs::device::FieldId;
6814    use crate::sys_exports::field_id::*;
6815    use crate::test_utils::*;
6816
6817    // This modifies device state, so we don't want to actually run the test
6818    #[allow(dead_code)]
6819    #[cfg(target_os = "linux")]
6820    fn clear_cpu_affinity() {
6821        let nvml = nvml();
6822        let mut device = device(&nvml);
6823
6824        device.clear_cpu_affinity().unwrap();
6825    }
6826
6827    #[test]
6828    #[ignore = "my machine does not support this call"]
6829    fn is_api_restricted() {
6830        let nvml = nvml();
6831        test_with_device(3, &nvml, |device| {
6832            device.is_api_restricted(Api::ApplicationClocks)?;
6833            device.is_api_restricted(Api::AutoBoostedClocks)
6834        })
6835    }
6836
6837    #[test]
6838    #[ignore = "my machine does not support this call"]
6839    fn applications_clock() {
6840        let nvml = nvml();
6841        test_with_device(3, &nvml, |device| {
6842            let gfx_clock = device.applications_clock(Clock::Graphics)?;
6843            let sm_clock = device.applications_clock(Clock::SM)?;
6844            let mem_clock = device.applications_clock(Clock::Memory)?;
6845            let vid_clock = device.applications_clock(Clock::Video)?;
6846
6847            Ok(format!(
6848                "Graphics Clock: {}, SM Clock: {}, Memory Clock: {}, Video Clock: {}",
6849                gfx_clock, sm_clock, mem_clock, vid_clock
6850            ))
6851        })
6852    }
6853
6854    #[test]
6855    #[ignore = "my machine does not support this call"]
6856    fn auto_boosted_clocks_enabled() {
6857        let nvml = nvml();
6858        test_with_device(3, &nvml, |device| device.auto_boosted_clocks_enabled())
6859    }
6860
6861    #[test]
6862    fn bar1_memory_info() {
6863        let nvml = nvml();
6864        test_with_device(3, &nvml, |device| device.bar1_memory_info())
6865    }
6866
6867    #[cfg(target_os = "linux")]
6868    #[test]
6869    fn memory_affinity() {
6870        let nvml = nvml();
6871        test_with_device(3, &nvml, |device| device.memory_affinity(64, 0))
6872    }
6873
6874    #[test]
6875    fn board_id() {
6876        let nvml = nvml();
6877        test_with_device(3, &nvml, |device| device.board_id())
6878    }
6879
6880    #[test]
6881    fn numa_node_id() {
6882        let nvml = nvml();
6883        test_with_device(3, &nvml, |device| device.numa_node_id())
6884    }
6885
6886    #[test]
6887    fn brand() {
6888        let nvml = nvml();
6889        test_with_device(3, &nvml, |device| device.brand())
6890    }
6891
6892    #[test]
6893    #[ignore = "my machine does not support this call"]
6894    fn bridge_chip_info() {
6895        let nvml = nvml();
6896        test_with_device(3, &nvml, |device| device.bridge_chip_info())
6897    }
6898
6899    #[test]
6900    #[ignore = "my machine does not support this call"]
6901    fn clock() {
6902        let nvml = nvml();
6903        test_with_device(3, &nvml, |device| {
6904            device.clock(Clock::Graphics, ClockId::Current)?;
6905            device.clock(Clock::SM, ClockId::TargetAppClock)?;
6906            device.clock(Clock::Memory, ClockId::DefaultAppClock)?;
6907            device.clock(Clock::Video, ClockId::TargetAppClock)
6908            // My machine does not support CustomerMaxBoost
6909        })
6910    }
6911
6912    #[test]
6913    #[ignore = "my machine does not support this call"]
6914    fn max_customer_boost_clock() {
6915        let nvml = nvml();
6916        test_with_device(3, &nvml, |device| {
6917            device.max_customer_boost_clock(Clock::Graphics)?;
6918            device.max_customer_boost_clock(Clock::SM)?;
6919            device.max_customer_boost_clock(Clock::Memory)?;
6920            device.max_customer_boost_clock(Clock::Video)
6921        })
6922    }
6923
6924    #[test]
6925    fn compute_mode() {
6926        let nvml = nvml();
6927        test_with_device(3, &nvml, |device| device.compute_mode())
6928    }
6929
6930    #[test]
6931    fn clock_info() {
6932        let nvml = nvml();
6933        test_with_device(3, &nvml, |device| {
6934            let gfx_clock = device.clock_info(Clock::Graphics)?;
6935            let sm_clock = device.clock_info(Clock::SM)?;
6936            let mem_clock = device.clock_info(Clock::Memory)?;
6937            let vid_clock = device.clock_info(Clock::Video)?;
6938
6939            Ok(format!(
6940                "Graphics Clock: {}, SM Clock: {}, Memory Clock: {}, Video Clock: {}",
6941                gfx_clock, sm_clock, mem_clock, vid_clock
6942            ))
6943        })
6944    }
6945
6946    #[test]
6947    fn running_compute_processes() {
6948        let nvml = nvml();
6949        test_with_device(3, &nvml, |device| device.running_compute_processes())
6950    }
6951
6952    #[cfg(feature = "legacy-functions")]
6953    #[cfg_attr(feature = "legacy-functions", test)]
6954    fn running_compute_processes_v2() {
6955        let nvml = nvml();
6956        test_with_device(3, &nvml, |device| device.running_compute_processes_v2())
6957    }
6958
6959    #[test]
6960    fn mps_running_compute_processes() {
6961        let nvml = nvml();
6962        test_with_device(3, &nvml, |device| device.mps_running_compute_processes())
6963    }
6964
6965    #[cfg(target_os = "linux")]
6966    #[test]
6967    fn cpu_affinity() {
6968        let nvml = nvml();
6969        test_with_device(3, &nvml, |device| device.cpu_affinity(64))
6970    }
6971
6972    #[cfg(target_os = "linux")]
6973    #[test]
6974    fn cpu_affinity_within_scope() {
6975        let nvml = nvml();
6976        test_with_device(3, &nvml, |device| device.cpu_affinity_within_scope(64, 0))
6977    }
6978
6979    #[test]
6980    fn current_pcie_link_gen() {
6981        let nvml = nvml();
6982        test_with_device(3, &nvml, |device| device.current_pcie_link_gen())
6983    }
6984
6985    #[test]
6986    fn current_pcie_link_width() {
6987        let nvml = nvml();
6988        test_with_device(3, &nvml, |device| device.current_pcie_link_width())
6989    }
6990
6991    #[test]
6992    fn decoder_utilization() {
6993        let nvml = nvml();
6994        test_with_device(3, &nvml, |device| device.decoder_utilization())
6995    }
6996
6997    #[test]
6998    #[ignore = "my machine does not support this call"]
6999    fn default_applications_clock() {
7000        let nvml = nvml();
7001        test_with_device(3, &nvml, |device| {
7002            let gfx_clock = device.default_applications_clock(Clock::Graphics)?;
7003            let sm_clock = device.default_applications_clock(Clock::SM)?;
7004            let mem_clock = device.default_applications_clock(Clock::Memory)?;
7005            let vid_clock = device.default_applications_clock(Clock::Video)?;
7006
7007            Ok(format!(
7008                "Graphics Clock: {}, SM Clock: {}, Memory Clock: {}, Video Clock: {}",
7009                gfx_clock, sm_clock, mem_clock, vid_clock
7010            ))
7011        })
7012    }
7013
7014    #[test]
7015    fn is_display_active() {
7016        let nvml = nvml();
7017        test_with_device(3, &nvml, |device| device.is_display_active())
7018    }
7019
7020    #[test]
7021    fn is_display_connected() {
7022        let nvml = nvml();
7023        test_with_device(3, &nvml, |device| device.is_display_connected())
7024    }
7025
7026    #[cfg(target_os = "windows")]
7027    #[test]
7028    fn driver_model() {
7029        let nvml = nvml();
7030        test_with_device(3, &nvml, |device| device.driver_model())
7031    }
7032
7033    #[test]
7034    #[ignore = "my machine does not support this call"]
7035    fn is_ecc_enabled() {
7036        let nvml = nvml();
7037        test_with_device(3, &nvml, |device| device.is_ecc_enabled())
7038    }
7039
7040    #[test]
7041    fn encoder_utilization() {
7042        let nvml = nvml();
7043        test_with_device(3, &nvml, |device| device.encoder_utilization())
7044    }
7045
7046    #[test]
7047    fn encoder_capacity() {
7048        let nvml = nvml();
7049        test_with_device(3, &nvml, |device| {
7050            device.encoder_capacity(EncoderType::H264)
7051        })
7052    }
7053
7054    #[test]
7055    fn encoder_stats() {
7056        let nvml = nvml();
7057        test_with_device(3, &nvml, |device| device.encoder_stats())
7058    }
7059
7060    #[test]
7061    fn encoder_sessions() {
7062        let nvml = nvml();
7063        test_with_device(3, &nvml, |device| device.encoder_sessions())
7064    }
7065
7066    #[test]
7067    fn fbc_stats() {
7068        let nvml = nvml();
7069        test_with_device(3, &nvml, |device| device.fbc_stats())
7070    }
7071
7072    #[test]
7073    fn fbc_sessions_info() {
7074        let nvml = nvml();
7075        test_with_device(3, &nvml, |device| device.fbc_sessions_info())
7076    }
7077
7078    #[test]
7079    fn enforced_power_limit() {
7080        let nvml = nvml();
7081        test_with_device(3, &nvml, |device| device.enforced_power_limit())
7082    }
7083
7084    #[test]
7085    fn fan_speed() {
7086        let nvml = nvml();
7087        test_with_device(3, &nvml, |device| device.fan_speed(0))
7088    }
7089
7090    #[test]
7091    fn fan_speed_rpm() {
7092        let nvml = nvml();
7093        test_with_device(3, &nvml, |device| device.fan_speed_rpm(0))
7094    }
7095
7096    #[test]
7097    fn min_max_fan_speed() {
7098        let nvml = nvml();
7099        test_with_device(3, &nvml, |device| device.min_max_fan_speed())
7100    }
7101
7102    #[test]
7103    fn num_fans() {
7104        let nvml = nvml();
7105        test_with_device(3, &nvml, |device| device.num_fans())
7106    }
7107
7108    #[test]
7109    #[ignore = "my machine does not support this call"]
7110    fn gpu_operation_mode() {
7111        let nvml = nvml();
7112        test_with_device(3, &nvml, |device| device.gpu_operation_mode())
7113    }
7114
7115    #[test]
7116    fn running_graphics_processes() {
7117        let nvml = nvml();
7118        test_with_device(3, &nvml, |device| device.running_graphics_processes())
7119    }
7120
7121    #[cfg(feature = "legacy-functions")]
7122    #[cfg_attr(feature = "legacy-functions", test)]
7123    fn running_graphics_processes_v2() {
7124        let nvml = nvml();
7125        test_with_device(3, &nvml, |device| device.running_graphics_processes_v2())
7126    }
7127
7128    #[test]
7129    fn process_utilization_stats() {
7130        let nvml = nvml();
7131        test_with_device(3, &nvml, |device| device.process_utilization_stats(None))
7132    }
7133
7134    #[test]
7135    fn index() {
7136        let nvml = nvml();
7137        test_with_device(3, &nvml, |device| device.index())
7138    }
7139
7140    #[test]
7141    #[ignore = "my machine does not support this call"]
7142    fn config_checksum() {
7143        let nvml = nvml();
7144        test_with_device(3, &nvml, |device| device.config_checksum())
7145    }
7146
7147    #[test]
7148    #[ignore = "my machine does not support this call"]
7149    fn info_rom_image_version() {
7150        let nvml = nvml();
7151        test_with_device(3, &nvml, |device| device.info_rom_image_version())
7152    }
7153
7154    #[test]
7155    #[ignore = "my machine does not support this call"]
7156    fn info_rom_version() {
7157        let nvml = nvml();
7158        test_with_device(3, &nvml, |device| {
7159            device.info_rom_version(InfoRom::OEM)?;
7160            device.info_rom_version(InfoRom::ECC)?;
7161            device.info_rom_version(InfoRom::Power)
7162        })
7163    }
7164
7165    #[test]
7166    fn max_clock_info() {
7167        let nvml = nvml();
7168        test_with_device(3, &nvml, |device| {
7169            let gfx_clock = device.max_clock_info(Clock::Graphics)?;
7170            let sm_clock = device.max_clock_info(Clock::SM)?;
7171            let mem_clock = device.max_clock_info(Clock::Memory)?;
7172            let vid_clock = device.max_clock_info(Clock::Video)?;
7173
7174            Ok(format!(
7175                "Graphics Clock: {}, SM Clock: {}, Memory Clock: {}, Video Clock: {}",
7176                gfx_clock, sm_clock, mem_clock, vid_clock
7177            ))
7178        })
7179    }
7180
7181    #[test]
7182    fn max_pcie_link_gen() {
7183        let nvml = nvml();
7184        test_with_device(3, &nvml, |device| device.max_pcie_link_gen())
7185    }
7186
7187    #[test]
7188    fn max_pcie_link_width() {
7189        let nvml = nvml();
7190        test_with_device(3, &nvml, |device| device.max_pcie_link_width())
7191    }
7192
7193    #[test]
7194    #[ignore = "my machine does not support this call"]
7195    fn memory_error_counter() {
7196        let nvml = nvml();
7197        test_with_device(3, &nvml, |device| {
7198            device.memory_error_counter(
7199                MemoryError::Corrected,
7200                EccCounter::Volatile,
7201                MemoryLocation::Device,
7202            )
7203        })
7204    }
7205
7206    #[test]
7207    fn memory_info() {
7208        let nvml = nvml();
7209        test_with_device(3, &nvml, |device| device.memory_info())
7210    }
7211
7212    #[cfg(target_os = "linux")]
7213    #[test]
7214    fn minor_number() {
7215        let nvml = nvml();
7216        test_with_device(3, &nvml, |device| device.minor_number())
7217    }
7218
7219    #[test]
7220    fn is_multi_gpu_board() {
7221        let nvml = nvml();
7222        test_with_device(3, &nvml, |device| device.is_multi_gpu_board())
7223    }
7224
7225    #[cfg(target_os = "linux")]
7226    #[test]
7227    fn possible_placements() {
7228        let nvml = nvml();
7229        test_with_device(3, &nvml, |device| device.possible_placements(0))
7230    }
7231
7232    #[cfg(target_os = "linux")]
7233    #[test]
7234    fn profile_info() {
7235        let nvml = nvml();
7236        test_with_device(3, &nvml, |device| device.profile_info(0))
7237    }
7238
7239    #[test]
7240    fn mig_mode() {
7241        let nvml = nvml();
7242        test_with_device(3, &nvml, |device| device.mig_mode())
7243    }
7244
7245    #[test]
7246    fn set_mig_mode() {
7247        let nvml = nvml();
7248        test_with_device(3, &nvml, |device| device.set_mig_mode(false))
7249    }
7250
7251    #[test]
7252    fn mig_device_by_index() {
7253        let nvml = nvml();
7254        let device = device(&nvml);
7255        test(3, || device.mig_device_by_index(0))
7256    }
7257
7258    #[test]
7259    fn mig_device_count() {
7260        let nvml = nvml();
7261        let device = device(&nvml);
7262        test(3, || device.mig_device_count())
7263    }
7264
7265    #[test]
7266    fn mig_is_mig_device_handle() {
7267        let nvml = nvml();
7268        test_with_device(3, &nvml, |device| device.mig_is_mig_device_handle())
7269    }
7270
7271    #[test]
7272    fn mig_parent_device() {
7273        let nvml = nvml();
7274        let device = device(&nvml);
7275        test(3, || device.mig_parent_device())
7276    }
7277
7278    #[test]
7279    fn name() {
7280        let nvml = nvml();
7281        test_with_device(3, &nvml, |device| device.mig_device_count())
7282    }
7283
7284    #[test]
7285    fn pci_info() {
7286        let nvml = nvml();
7287        test_with_device(3, &nvml, |device| device.pci_info())
7288    }
7289
7290    #[test]
7291    fn pcie_replay_counter() {
7292        let nvml = nvml();
7293        test_with_device(3, &nvml, |device| device.pcie_replay_counter())
7294    }
7295
7296    #[test]
7297    fn pcie_throughput() {
7298        let nvml = nvml();
7299        test_with_device(3, &nvml, |device| {
7300            device.pcie_throughput(PcieUtilCounter::Send)?;
7301            device.pcie_throughput(PcieUtilCounter::Receive)
7302        })
7303    }
7304
7305    #[test]
7306    fn performance_state() {
7307        let nvml = nvml();
7308        test_with_device(3, &nvml, |device| device.performance_state())
7309    }
7310
7311    #[cfg(target_os = "linux")]
7312    #[test]
7313    fn is_in_persistent_mode() {
7314        let nvml = nvml();
7315        test_with_device(3, &nvml, |device| device.is_in_persistent_mode())
7316    }
7317
7318    #[test]
7319    fn power_management_limit_default() {
7320        let nvml = nvml();
7321        test_with_device(3, &nvml, |device| device.power_management_limit_default())
7322    }
7323
7324    #[test]
7325    fn power_management_limit() {
7326        let nvml = nvml();
7327        test_with_device(3, &nvml, |device| device.power_management_limit())
7328    }
7329
7330    #[test]
7331    fn clock_offset() {
7332        let nvml = nvml();
7333        test_with_device(3, &nvml, |device| {
7334            device.clock_offset(Clock::Graphics, PerformanceState::Zero)
7335        });
7336    }
7337
7338    #[test]
7339    fn supported_performance_states() {
7340        let nvml = nvml();
7341        test_with_device(3, &nvml, |device| device.supported_performance_states());
7342    }
7343
7344    #[test]
7345    fn min_max_clock_of_pstate() {
7346        let nvml = nvml();
7347        test_with_device(3, &nvml, |device| {
7348            device.min_max_clock_of_pstate(Clock::Graphics, PerformanceState::Zero)
7349        });
7350    }
7351
7352    #[test]
7353    fn power_management_limit_constraints() {
7354        let nvml = nvml();
7355        test_with_device(3, &nvml, |device| {
7356            device.power_management_limit_constraints()
7357        })
7358    }
7359
7360    #[test]
7361    fn is_power_management_algo_active() {
7362        let nvml = nvml();
7363
7364        #[allow(deprecated)]
7365        test_with_device(3, &nvml, |device| device.is_power_management_algo_active())
7366    }
7367
7368    #[test]
7369    fn power_state() {
7370        let nvml = nvml();
7371
7372        #[allow(deprecated)]
7373        test_with_device(3, &nvml, |device| device.power_state())
7374    }
7375
7376    #[test]
7377    fn power_usage() {
7378        let nvml = nvml();
7379        test_with_device(3, &nvml, |device| device.power_usage())
7380    }
7381
7382    #[test]
7383    #[ignore = "my machine does not support this call"]
7384    fn retired_pages() {
7385        let nvml = nvml();
7386        test_with_device(3, &nvml, |device| {
7387            device.retired_pages(RetirementCause::MultipleSingleBitEccErrors)?;
7388            device.retired_pages(RetirementCause::DoubleBitEccError)
7389        })
7390    }
7391
7392    #[test]
7393    #[ignore = "my machine does not support this call"]
7394    fn are_pages_pending_retired() {
7395        let nvml = nvml();
7396        test_with_device(3, &nvml, |device| device.are_pages_pending_retired())
7397    }
7398
7399    #[test]
7400    #[ignore = "my machine does not support this call"]
7401    fn samples() {
7402        let nvml = nvml();
7403        test_with_device(3, &nvml, |device| {
7404            device.samples(Sampling::ProcessorClock, None)?;
7405            Ok(())
7406        })
7407    }
7408
7409    #[test]
7410    fn gsp_firmware_mode() {
7411        let nvml = nvml();
7412        test_with_device(3, &nvml, |device| device.gsp_firmware_mode())
7413    }
7414
7415    #[test]
7416    fn gsp_firmware_version() {
7417        let nvml = nvml();
7418        test_with_device(3, &nvml, |device| device.gsp_firmware_version())
7419    }
7420
7421    #[test]
7422    fn field_values_for() {
7423        let nvml = nvml();
7424        test_with_device(3, &nvml, |device| {
7425            device.field_values_for(&[
7426                FieldId(NVML_FI_DEV_ECC_CURRENT),
7427                FieldId(NVML_FI_DEV_ECC_PENDING),
7428                FieldId(NVML_FI_DEV_ECC_SBE_VOL_TOTAL),
7429                FieldId(NVML_FI_DEV_ECC_DBE_VOL_TOTAL),
7430                FieldId(NVML_FI_DEV_ECC_SBE_AGG_TOTAL),
7431                FieldId(NVML_FI_DEV_ECC_DBE_AGG_TOTAL),
7432                FieldId(NVML_FI_DEV_ECC_SBE_VOL_L1),
7433                FieldId(NVML_FI_DEV_ECC_DBE_VOL_L1),
7434                FieldId(NVML_FI_DEV_ECC_SBE_VOL_L2),
7435                FieldId(NVML_FI_DEV_ECC_DBE_VOL_L2),
7436                FieldId(NVML_FI_DEV_ECC_SBE_VOL_DEV),
7437                FieldId(NVML_FI_DEV_ECC_DBE_VOL_DEV),
7438                FieldId(NVML_FI_DEV_ECC_SBE_VOL_REG),
7439                FieldId(NVML_FI_DEV_ECC_DBE_VOL_REG),
7440                FieldId(NVML_FI_DEV_ECC_SBE_VOL_TEX),
7441                FieldId(NVML_FI_DEV_ECC_DBE_VOL_TEX),
7442                FieldId(NVML_FI_DEV_ECC_DBE_VOL_CBU),
7443                FieldId(NVML_FI_DEV_ECC_SBE_AGG_L1),
7444                FieldId(NVML_FI_DEV_ECC_DBE_AGG_L1),
7445                FieldId(NVML_FI_DEV_ECC_SBE_AGG_L2),
7446                FieldId(NVML_FI_DEV_ECC_DBE_AGG_L2),
7447                FieldId(NVML_FI_DEV_ECC_SBE_AGG_DEV),
7448                FieldId(NVML_FI_DEV_ECC_DBE_AGG_DEV),
7449                FieldId(NVML_FI_DEV_ECC_SBE_AGG_REG),
7450                FieldId(NVML_FI_DEV_ECC_DBE_AGG_REG),
7451                FieldId(NVML_FI_DEV_ECC_SBE_AGG_TEX),
7452                FieldId(NVML_FI_DEV_ECC_DBE_AGG_TEX),
7453                FieldId(NVML_FI_DEV_ECC_DBE_AGG_CBU),
7454                FieldId(NVML_FI_DEV_PERF_POLICY_POWER),
7455                FieldId(NVML_FI_DEV_PERF_POLICY_THERMAL),
7456                FieldId(NVML_FI_DEV_PERF_POLICY_SYNC_BOOST),
7457                FieldId(NVML_FI_DEV_PERF_POLICY_BOARD_LIMIT),
7458                FieldId(NVML_FI_DEV_PERF_POLICY_LOW_UTILIZATION),
7459                FieldId(NVML_FI_DEV_PERF_POLICY_RELIABILITY),
7460                FieldId(NVML_FI_DEV_PERF_POLICY_TOTAL_APP_CLOCKS),
7461                FieldId(NVML_FI_DEV_PERF_POLICY_TOTAL_BASE_CLOCKS),
7462                FieldId(NVML_FI_DEV_MEMORY_TEMP),
7463                FieldId(NVML_FI_DEV_TOTAL_ENERGY_CONSUMPTION),
7464            ])
7465        })
7466    }
7467
7468    // Passing an empty slice should return an `InvalidArg` error
7469    #[should_panic(expected = "InvalidArg")]
7470    #[test]
7471    fn field_values_for_empty() {
7472        let nvml = nvml();
7473        test_with_device(3, &nvml, |device| device.field_values_for(&[]))
7474    }
7475
7476    #[test]
7477    #[ignore = "my machine does not support this call"]
7478    fn serial() {
7479        let nvml = nvml();
7480        test_with_device(3, &nvml, |device| device.serial())
7481    }
7482
7483    #[test]
7484    #[ignore = "my machine does not support this call"]
7485    fn board_part_number() {
7486        let nvml = nvml();
7487        test_with_device(3, &nvml, |device| device.board_part_number())
7488    }
7489
7490    #[test]
7491    fn current_throttle_reasons() {
7492        let nvml = nvml();
7493        test_with_device(3, &nvml, |device| device.current_throttle_reasons())
7494    }
7495
7496    #[test]
7497    fn current_throttle_reasons_strict() {
7498        let nvml = nvml();
7499        test_with_device(3, &nvml, |device| device.current_throttle_reasons_strict())
7500    }
7501
7502    #[test]
7503    fn supported_throttle_reasons() {
7504        let nvml = nvml();
7505        test_with_device(3, &nvml, |device| device.supported_throttle_reasons())
7506    }
7507
7508    #[test]
7509    fn supported_throttle_reasons_strict() {
7510        let nvml = nvml();
7511        test_with_device(3, &nvml, |device| {
7512            device.supported_throttle_reasons_strict()
7513        })
7514    }
7515
7516    #[test]
7517    #[ignore = "my machine does not support this call"]
7518    fn supported_graphics_clocks() {
7519        let nvml = nvml();
7520        #[allow(unused_variables)]
7521        test_with_device(3, &nvml, |device| {
7522            let supported = device.supported_graphics_clocks(810)?;
7523            Ok(())
7524        })
7525    }
7526
7527    #[test]
7528    #[ignore = "my machine does not support this call"]
7529    fn supported_memory_clocks() {
7530        let nvml = nvml();
7531        #[allow(unused_variables)]
7532        test_with_device(3, &nvml, |device| {
7533            let supported = device.supported_memory_clocks()?;
7534
7535            Ok(())
7536        })
7537    }
7538
7539    #[test]
7540    fn temperature() {
7541        let nvml = nvml();
7542        test_with_device(3, &nvml, |device| {
7543            device.temperature(TemperatureSensor::Gpu)
7544        })
7545    }
7546
7547    #[test]
7548    fn temperature_threshold() {
7549        let nvml = nvml();
7550        test_with_device(3, &nvml, |device| {
7551            let slowdown = device.temperature_threshold(TemperatureThreshold::Slowdown)?;
7552            let shutdown = device.temperature_threshold(TemperatureThreshold::Shutdown)?;
7553
7554            Ok((slowdown, shutdown))
7555        })
7556    }
7557
7558    #[test]
7559    fn set_temperature_threshold() {
7560        let nvml = nvml();
7561        test_with_device(3, &nvml, |device| {
7562            device.set_temperature_threshold(TemperatureThreshold::Slowdown, 0)?;
7563            device.set_temperature_threshold(TemperatureThreshold::Shutdown, 0)
7564        })
7565    }
7566
7567    // I do not have 2 devices
7568    #[ignore = "my machine does not support this call"]
7569    #[cfg(target_os = "linux")]
7570    #[test]
7571    fn topology_common_ancestor() {
7572        let nvml = nvml();
7573        let device1 = device(&nvml);
7574        let device2 = nvml.device_by_index(1).expect("device");
7575
7576        device1
7577            .topology_common_ancestor(device2)
7578            .expect("TopologyLevel");
7579    }
7580
7581    #[cfg(target_os = "linux")]
7582    #[test]
7583    fn topology_nearest_gpus() {
7584        let nvml = nvml();
7585        let device = device(&nvml);
7586        test(3, || device.topology_nearest_gpus(TopologyLevel::System))
7587    }
7588
7589    #[test]
7590    #[ignore = "my machine does not support this call"]
7591    fn total_ecc_errors() {
7592        let nvml = nvml();
7593        test_with_device(3, &nvml, |device| {
7594            device.total_ecc_errors(MemoryError::Corrected, EccCounter::Volatile)
7595        })
7596    }
7597
7598    #[test]
7599    fn uuid() {
7600        let nvml = nvml();
7601        test_with_device(3, &nvml, |device| device.uuid())
7602    }
7603
7604    #[test]
7605    fn utilization_rates() {
7606        let nvml = nvml();
7607        test_with_device(3, &nvml, |device| device.utilization_rates())
7608    }
7609
7610    #[test]
7611    fn vbios_version() {
7612        let nvml = nvml();
7613        test_with_device(3, &nvml, |device| device.vbios_version())
7614    }
7615
7616    #[test]
7617    fn violation_status() {
7618        let nvml = nvml();
7619        test_with_device(3, &nvml, |device| {
7620            device.violation_status(PerformancePolicy::Power)
7621        })
7622    }
7623
7624    #[test]
7625    fn num_cores() {
7626        let nvml = nvml();
7627        test_with_device(3, &nvml, |device| device.num_cores())
7628    }
7629
7630    #[test]
7631    fn irq_num() {
7632        let nvml = nvml();
7633        test_with_device(3, &nvml, |device| device.irq_num())
7634    }
7635
7636    #[test]
7637    fn power_source() {
7638        let nvml = nvml();
7639        test_with_device(3, &nvml, |device| device.power_source())
7640    }
7641
7642    #[test]
7643    fn memory_bus_width() {
7644        let nvml = nvml();
7645        test_with_device(3, &nvml, |device| device.memory_bus_width())
7646    }
7647
7648    #[test]
7649    fn pcie_link_max_speed() {
7650        let nvml = nvml();
7651        test_with_device(3, &nvml, |device| device.max_pcie_link_speed())
7652    }
7653
7654    #[test]
7655    fn bus_type() {
7656        let nvml = nvml();
7657        test_with_device(3, &nvml, |device| device.bus_type())
7658    }
7659
7660    #[test]
7661    fn architecture() {
7662        let nvml = nvml();
7663        test_with_device(3, &nvml, |device| device.architecture())
7664    }
7665
7666    // I do not have 2 devices
7667    #[ignore = "my machine does not support this call"]
7668    #[test]
7669    fn is_on_same_board_as() {
7670        let nvml = nvml();
7671        let device1 = device(&nvml);
7672        let device2 = nvml.device_by_index(1).expect("device");
7673
7674        device1.is_on_same_board_as(&device2).expect("bool");
7675    }
7676
7677    // This modifies device state, so we don't want to actually run the test
7678    #[allow(dead_code)]
7679    fn reset_applications_clocks() {
7680        let nvml = nvml();
7681        let mut device = device(&nvml);
7682
7683        device.reset_applications_clocks().expect("reset clocks")
7684    }
7685
7686    // This modifies device state, so we don't want to actually run the test
7687    #[allow(dead_code)]
7688    fn set_auto_boosted_clocks() {
7689        let nvml = nvml();
7690        let mut device = device(&nvml);
7691
7692        device.set_auto_boosted_clocks(true).expect("set to true")
7693    }
7694
7695    // This modifies device state, so we don't want to actually run the test
7696    #[allow(dead_code)]
7697    #[cfg(target_os = "linux")]
7698    fn set_cpu_affinity() {
7699        let nvml = nvml();
7700        let mut device = device(&nvml);
7701
7702        device.set_cpu_affinity().expect("ideal affinity set")
7703    }
7704
7705    // This modifies device state, so we don't want to actually run the test
7706    #[allow(dead_code)]
7707    fn set_auto_boosted_clocks_default() {
7708        let nvml = nvml();
7709        let mut device = device(&nvml);
7710
7711        device
7712            .set_auto_boosted_clocks_default(true)
7713            .expect("set to true")
7714    }
7715
7716    #[test]
7717    #[ignore = "my machine does not support this call"]
7718    fn validate_info_rom() {
7719        let nvml = nvml();
7720        test_with_device(3, &nvml, |device| device.validate_info_rom())
7721    }
7722
7723    // This modifies device state, so we don't want to actually run the test
7724    #[allow(dead_code)]
7725    fn clear_accounting_pids() {
7726        let nvml = nvml();
7727        let mut device = device(&nvml);
7728
7729        device.clear_accounting_pids().expect("cleared")
7730    }
7731
7732    #[test]
7733    fn accounting_buffer_size() {
7734        let nvml = nvml();
7735        test_with_device(3, &nvml, |device| device.accounting_buffer_size())
7736    }
7737
7738    #[test]
7739    fn is_accounting_enabled() {
7740        let nvml = nvml();
7741        test_with_device(3, &nvml, |device| device.is_accounting_enabled())
7742    }
7743
7744    #[test]
7745    fn accounting_pids() {
7746        let nvml = nvml();
7747        test_with_device(3, &nvml, |device| device.accounting_pids())
7748    }
7749
7750    #[should_panic(expected = "NotFound")]
7751    #[test]
7752    fn accounting_stats_for() {
7753        let nvml = nvml();
7754        test_with_device(3, &nvml, |device| {
7755            let processes = device.running_graphics_processes()?;
7756
7757            // We never enable accounting mode, so this should return a `NotFound` error
7758            match device.accounting_stats_for(processes[0].pid) {
7759                Err(NvmlError::NotFound) => panic!("NotFound"),
7760                other => other,
7761            }
7762        })
7763    }
7764
7765    // This modifies device state, so we don't want to actually run the test
7766    #[allow(dead_code)]
7767    fn set_accounting() {
7768        let nvml = nvml();
7769        let mut device = device(&nvml);
7770
7771        device.set_accounting(true).expect("set to true")
7772    }
7773
7774    // This modifies device state, so we don't want to actually run the test
7775    #[allow(dead_code)]
7776    fn clear_ecc_error_counts() {
7777        let nvml = nvml();
7778        let mut device = device(&nvml);
7779
7780        device
7781            .clear_ecc_error_counts(EccCounter::Aggregate)
7782            .expect("set to true")
7783    }
7784
7785    // This modifies device state, so we don't want to actually run the test
7786    #[allow(dead_code)]
7787    fn set_api_restricted() {
7788        let nvml = nvml();
7789        let mut device = device(&nvml);
7790
7791        device
7792            .set_api_restricted(Api::ApplicationClocks, true)
7793            .expect("set to true")
7794    }
7795
7796    // This modifies device state, so we don't want to actually run the test
7797    #[allow(dead_code)]
7798    fn set_applications_clocks() {
7799        let nvml = nvml();
7800        let mut device = device(&nvml);
7801
7802        device.set_applications_clocks(32, 32).expect("set to true")
7803    }
7804
7805    // This modifies device state, so we don't want to actually run the test
7806    #[allow(dead_code)]
7807    fn set_compute_mode() {
7808        let nvml = nvml();
7809        let mut device = device(&nvml);
7810
7811        device
7812            .set_compute_mode(ComputeMode::Default)
7813            .expect("set to true")
7814    }
7815
7816    // This modifies device state, so we don't want to actually run the test
7817    #[cfg(target_os = "windows")]
7818    #[allow(dead_code)]
7819    fn set_driver_model() {
7820        let nvml = nvml();
7821        let mut device = device(&nvml);
7822
7823        device
7824            .set_driver_model(DriverModel::WDM, Behavior::DEFAULT)
7825            .expect("set to wdm")
7826    }
7827
7828    // This modifies device state, so we don't want to actually run the test
7829    #[allow(dead_code)]
7830    fn set_gpu_locked_clocks() {
7831        let nvml = nvml();
7832        let mut device = device(&nvml);
7833
7834        device
7835            .set_gpu_locked_clocks(GpuLockedClocksSetting::Numeric {
7836                min_clock_mhz: 1048,
7837                max_clock_mhz: 1139,
7838            })
7839            .expect("set to a range")
7840    }
7841
7842    // This modifies device state, so we don't want to actually run the test
7843    #[allow(dead_code)]
7844    fn reset_gpu_locked_clocks() {
7845        let nvml = nvml();
7846        let mut device = device(&nvml);
7847
7848        device.reset_gpu_locked_clocks().expect("clocks reset")
7849    }
7850
7851    // This modifies device state, so we don't want to actually run the test
7852    #[allow(dead_code)]
7853    fn set_mem_locked_clocks() {
7854        let nvml = nvml();
7855        let mut device = device(&nvml);
7856
7857        device
7858            .set_mem_locked_clocks(1048, 1139)
7859            .expect("set to a range")
7860    }
7861
7862    // This modifies device state, so we don't want to actually run the test
7863    #[allow(dead_code)]
7864    fn reset_mem_locked_clocks() {
7865        let nvml = nvml();
7866        let mut device = device(&nvml);
7867
7868        device.reset_mem_locked_clocks().expect("clocks reset")
7869    }
7870
7871    // This modifies device state, so we don't want to actually run the test
7872    #[allow(dead_code)]
7873    fn set_ecc() {
7874        let nvml = nvml();
7875        let mut device = device(&nvml);
7876
7877        device.set_ecc(true).expect("set to true")
7878    }
7879
7880    // This modifies device state, so we don't want to actually run the test
7881    #[allow(dead_code)]
7882    fn set_gpu_op_mode() {
7883        let nvml = nvml();
7884        let mut device = device(&nvml);
7885
7886        device
7887            .set_gpu_op_mode(OperationMode::AllOn)
7888            .expect("set to true")
7889    }
7890
7891    // This modifies device state, so we don't want to actually run the test
7892    #[allow(dead_code)]
7893    #[cfg(target_os = "linux")]
7894    fn set_persistent() {
7895        let nvml = nvml();
7896        let mut device = device(&nvml);
7897
7898        device.set_persistent(true).expect("set to true")
7899    }
7900
7901    // This modifies device state, so we don't want to actually run the test
7902    #[allow(dead_code)]
7903    fn set_power_management_limit() {
7904        let nvml = nvml();
7905        let mut device = device(&nvml);
7906
7907        device
7908            .set_power_management_limit(250000)
7909            .expect("set to true")
7910    }
7911
7912    // This modifies device state, so we don't want to actually run the test
7913    #[allow(dead_code)]
7914    fn set_clock_offset() {
7915        let nvml = nvml();
7916        let mut device = device(&nvml);
7917
7918        device
7919            .set_clock_offset(Clock::Graphics, PerformanceState::Zero, -100)
7920            .expect("set to true")
7921    }
7922
7923    #[cfg(target_os = "linux")]
7924    #[allow(unused_variables)]
7925    #[test]
7926    fn register_events() {
7927        let nvml = nvml();
7928        test_with_device(3, &nvml, |device| {
7929            let set = nvml.create_event_set()?;
7930            let set = device
7931                .register_events(
7932                    EventTypes::PSTATE_CHANGE
7933                        | EventTypes::CRITICAL_XID_ERROR
7934                        | EventTypes::CLOCK_CHANGE,
7935                    set,
7936                )
7937                .map_err(|e| e.error)?;
7938
7939            Ok(())
7940        })
7941    }
7942
7943    #[cfg(target_os = "linux")]
7944    #[test]
7945    fn supported_event_types() {
7946        let nvml = nvml();
7947        test_with_device(3, &nvml, |device| device.supported_event_types())
7948    }
7949
7950    #[cfg(target_os = "linux")]
7951    #[test]
7952    fn supported_event_types_strict() {
7953        let nvml = nvml();
7954        test_with_device(3, &nvml, |device| device.supported_event_types_strict())
7955    }
7956
7957    #[cfg(target_os = "linux")]
7958    #[test]
7959    fn is_drain_enabled() {
7960        let nvml = nvml();
7961        test_with_device(3, &nvml, |device| device.is_drain_enabled(None))
7962    }
7963
7964    #[cfg(target_os = "linux")]
7965    #[test]
7966    fn performance_modes() {
7967        let nvml = nvml();
7968        test_with_device(3, &nvml, |device| device.performance_modes())
7969    }
7970
7971    #[cfg(target_os = "linux")]
7972    #[test]
7973    fn active_vgpus() {
7974        let nvml = nvml();
7975        test_with_device(3, &nvml, |device| device.active_vgpus())
7976    }
7977
7978    #[test]
7979    fn vgpu_accounting_pids() {
7980        let nvml = nvml();
7981        test_with_device(3, &nvml, |device| device.vgpu_accounting_pids(0))
7982    }
7983
7984    #[test]
7985    fn vgpu_accounting_instance() {
7986        let nvml = nvml();
7987        test_with_device(3, &nvml, |device| device.vgpu_accounting_instance(0, 0))
7988    }
7989
7990    #[cfg(target_os = "linux")]
7991    #[test]
7992    fn virtualization_mode() {
7993        let nvml = nvml();
7994        test_with_device(3, &nvml, |device| device.virtualization_mode())
7995    }
7996
7997    #[cfg(target_os = "linux")]
7998    #[test]
7999    fn device_attributes() {
8000        let nvml = nvml();
8001        test_with_device(3, &nvml, |device| device.attributes())
8002    }
8003}