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