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