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