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