Skip to main content

nvml_wrapper/
device.rs

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