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