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