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