nvml_wrapper/
device.rs

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