Coverage for cuda/core/system/_device.pyx: 84.73%
262 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-03 02:41 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-03 02:41 +0000
1# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2#
3# SPDX-License-Identifier: Apache-2.0
5from __future__ import annotations
7from libc.stdint cimport intptr_t, uint64_t
8from libc.math cimport ceil
10from multiprocessing import cpu_count
11from typing import Iterable, TYPE_CHECKING
12import warnings
14from cuda.bindings import nvml
16from ._nvml_context cimport initialize
17from cuda.core.system.typing import (
18 AddressingMode,
19 AffinityScope,
20 DeviceArch,
21 ClockId,
22 ClocksEventReasons,
23 ClockType,
24 CoolerControl,
25 CoolerTarget,
26 DeviceArch,
27 EventType,
28 FanControlPolicy,
29 FieldId,
30 GpuP2PCapsIndex,
31 GpuP2PStatus,
32 GpuTopologyLevel,
33 InforomObject,
34 TemperatureThresholds,
35 ThermalController,
36 ThermalTarget,
37)
39if TYPE_CHECKING:
40 import cuda.core # no-cython-lint
43cdef object _pstate_to_int(object pstate):
44 if pstate == nvml.Pstates.PSTATE_UNKNOWN: 1afd
45 return None 1ad
46 assert ( 1afd
47 int(pstate) >= 0 and int(pstate) <= 15 1afd
48 ), f"Invalid P-state: {pstate}. Must be between 0 and 15 inclusive, or PSTATE_UNKNOWN."
49 return int(pstate) - int(nvml.Pstates.PSTATE_0) 1afd
52cdef int _pstate_to_enum(int pstate):
53 if pstate < 0 or pstate > 15: 1af
54 raise ValueError(f"Invalid P-state: {pstate}. Must be between 0 and 15 inclusive.")
55 return int(pstate) + int(nvml.Pstates.PSTATE_0) 1f
58include "_clock.pxi"
59include "_cooler.pxi"
60include "_device_attributes.pxi"
61include "_device_utils.pxi"
62include "_event.pxi"
63include "_fan.pxi"
64include "_field_values.pxi"
65include "_inforom.pxi"
66include "_memory.pxi"
67include "_mig.pxi"
68include "_nvlink.pxi"
69include "_pci_info.pxi"
70include "_performance.pxi"
71include "_process.pxi"
72include "_repair_status.pxi"
73include "_temperature.pxi"
74include "_utilization.pxi"
77_ADDRESSING_MODE_MAPPING = {
78 nvml.DeviceAddressingModeType.DEVICE_ADDRESSING_MODE_HMM: AddressingMode.HMM,
79 nvml.DeviceAddressingModeType.DEVICE_ADDRESSING_MODE_ATS: AddressingMode.ATS,
80}
83_AFFINITY_SCOPE_MAPPING = {
84 AffinityScope.NODE: nvml.AffinityScope.NODE,
85 AffinityScope.SOCKET: nvml.AffinityScope.SOCKET,
86}
89_BRAND_TYPE_MAPPING = {
90 nvml.BrandType.BRAND_UNKNOWN: "Unknown",
91 nvml.BrandType.BRAND_QUADRO: "Quadro",
92 nvml.BrandType.BRAND_TESLA: "Tesla",
93 nvml.BrandType.BRAND_NVS: "NVS",
94 nvml.BrandType.BRAND_GRID: "GRID",
95 nvml.BrandType.BRAND_GEFORCE: "GeForce",
96 nvml.BrandType.BRAND_TITAN: "Titan",
97 nvml.BrandType.BRAND_NVIDIA_VAPPS: "NVIDIA vApps",
98 nvml.BrandType.BRAND_NVIDIA_VPC: "NVIDIA VPC",
99 nvml.BrandType.BRAND_NVIDIA_VCS: "NVIDIA VCS",
100 nvml.BrandType.BRAND_NVIDIA_VWS: "NVIDIA VWS",
101 nvml.BrandType.BRAND_NVIDIA_CLOUD_GAMING: "NVIDIA Cloud Gaming",
102 nvml.BrandType.BRAND_NVIDIA_VGAMING: "NVIDIA vGaming",
103 nvml.BrandType.BRAND_QUADRO_RTX: "Quadro RTX",
104 nvml.BrandType.BRAND_NVIDIA_RTX: "NVIDIA RTX",
105 nvml.BrandType.BRAND_NVIDIA: "NVIDIA",
106 nvml.BrandType.BRAND_GEFORCE_RTX: "GeForce RTX",
107 nvml.BrandType.BRAND_TITAN_RTX: "Titan RTX",
108}
111_GPU_P2P_CAPS_INDEX_MAPPING = {
112 GpuP2PCapsIndex.READ: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_READ,
113 GpuP2PCapsIndex.WRITE: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_WRITE,
114 GpuP2PCapsIndex.NVLINK: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_NVLINK,
115 GpuP2PCapsIndex.ATOMICS: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_ATOMICS,
116 GpuP2PCapsIndex.PCI: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_PCI,
117 GpuP2PCapsIndex.PROP: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_PROP,
118 GpuP2PCapsIndex.UNKNOWN: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_UNKNOWN,
119}
122_GPU_P2P_STATUS_MAPPING = {
123 nvml.GpuP2PStatus.P2P_STATUS_OK: GpuP2PStatus.OK,
124 nvml.GpuP2PStatus.P2P_STATUS_CHIPSET_NOT_SUPPORTED: GpuP2PStatus.CHIPSET_NOT_SUPPORTED,
125 nvml.GpuP2PStatus.P2P_STATUS_GPU_NOT_SUPPORTED: GpuP2PStatus.GPU_NOT_SUPPORTED,
126 nvml.GpuP2PStatus.P2P_STATUS_IOH_TOPOLOGY_NOT_SUPPORTED: GpuP2PStatus.IOH_TOPOLOGY_NOT_SUPPORTED,
127 nvml.GpuP2PStatus.P2P_STATUS_DISABLED_BY_REGKEY: GpuP2PStatus.DISABLED_BY_REGKEY,
128 nvml.GpuP2PStatus.P2P_STATUS_NOT_SUPPORTED: GpuP2PStatus.NOT_SUPPORTED,
129 nvml.GpuP2PStatus.P2P_STATUS_UNKNOWN: GpuP2PStatus.UNKNOWN,
130}
133_GPU_TOPOLOGY_LEVEL_MAPPING = {
134 GpuTopologyLevel.INTERNAL: nvml.GpuTopologyLevel.TOPOLOGY_INTERNAL,
135 GpuTopologyLevel.SINGLE: nvml.GpuTopologyLevel.TOPOLOGY_SINGLE,
136 GpuTopologyLevel.MULTIPLE: nvml.GpuTopologyLevel.TOPOLOGY_MULTIPLE,
137 GpuTopologyLevel.HOSTBRIDGE: nvml.GpuTopologyLevel.TOPOLOGY_HOSTBRIDGE,
138 GpuTopologyLevel.NODE: nvml.GpuTopologyLevel.TOPOLOGY_NODE,
139 GpuTopologyLevel.SYSTEM: nvml.GpuTopologyLevel.TOPOLOGY_SYSTEM,
140}
143_GPU_TOPOLOGY_LEVEL_INV_MAPPING = {v: k for k, v in _GPU_TOPOLOGY_LEVEL_MAPPING.items()}
147cdef class Device:
148 """
149 Representation of a device.
151 :class:`cuda.core.system.Device` provides access to various pieces of metadata
152 about devices and their topology, as provided by the NVIDIA Management
153 Library (NVML). To use CUDA with a device, use :class:`cuda.core.Device`.
155 Creating a device instance causes NVML to initialize the target GPU.
156 NVML may initialize additional GPUs if the target GPU is an SLI slave.
158 Parameters
159 ----------
160 index: int, optional
161 Integer representing the CUDA device index to get a handle to. Valid
162 values are between ``0`` and ``cuda.core.system.get_num_devices() - 1``.
164 The order in which devices are enumerated has no guarantees of
165 consistency between reboots. For that reason, it is recommended that
166 devices are looked up by their PCI ids or UUID.
168 uuid: bytes or str, optional
169 UUID of a CUDA device to get a handle to.
171 pci_bus_id: bytes or str, optional
172 PCI bus ID of a CUDA device to get a handle to.
174 Raises
175 ------
176 ValueError
177 If anything other than a single `index`, `uuid` or `pci_bus_id` are specified.
178 """
180 # This is made public for testing purposes only
181 cdef public intptr_t _handle
183 def __init__(
184 self,
185 *,
186 index: int | None = None,
187 uuid: bytes | str | None = None,
188 pci_bus_id: bytes | str | None = None,
189 ) -> None:
190 args = [index, uuid, pci_bus_id] 1sctuefvwpbxyLViRzMloANBCmDOqPEFGgndjHTUIkJQhSr
191 cdef int arg_count = sum(arg is not None for arg in args) 1sctuefvwpbxyLViRzMloANBCmDOqPEFGgndjHTUIkJQhSr
193 if arg_count > 1: 1sctuefvwpbxyLViRzMloANBCmDOqPEFGgndjHTUIkJQhSr
194 raise ValueError("Handle requires only one of `index`, `uuid`, or `pci_bus_id`.") 1V
195 if arg_count == 0: 1sctuefvwpbxyLViRzMloANBCmDOqPEFGgndjHTUIkJQhSr
196 raise ValueError("Handle requires either a device `index`, `uuid`, or `pci_bus_id`.") 1aV
198 initialize() 1sctuefvwpbxyLiRzMloANBCmDOqPEFGgndjHTUIkJQhSr
200 if index is not None: 1sctuefvwpbxyLiRzMloANBCmDOqPEFGgndjHTUIkJQhSr
201 self._handle = nvml.device_get_handle_by_index_v2(index) 1sctuefwpbxyLizMoANBCmDOqPEFGgndjHTUIkJQh
202 elif uuid is not None: 1vRlhSr
203 if isinstance(uuid, bytes): 1vRlSr
204 uuid = uuid.decode("ascii")
205 self._handle = nvml.device_get_handle_by_uuid(uuid) 1vRlSr
206 elif pci_bus_id is not None: 1lh
207 if isinstance(pci_bus_id, bytes): 1lh
208 pci_bus_id = pci_bus_id.decode("ascii")
209 self._handle = nvml.device_get_handle_by_pci_bus_id_v2(pci_bus_id) 1lh
211 #########################################################################
212 # BASIC PROPERTIES
214 @property
215 def index(self) -> int:
216 """
217 The NVML index of this device.
219 Valid indices are derived from the count returned by
220 :meth:`Device.get_device_count`. For example, if ``get_device_count()``
221 returns 2, the valid indices are 0 and 1, corresponding to GPU 0 and GPU
222 1.
224 The order in which NVML enumerates devices has no guarantees of
225 consistency between reboots. For that reason, it is recommended that
226 devices be looked up by their PCI ids or GPU UUID.
228 Note: The NVML index may not correlate with other APIs, such as the CUDA
229 device index.
230 """
231 return nvml.device_get_index(self._handle) 1sctuefvwxyizloACmKDPEFGgndHIJh
233 @property
234 def uuid(self) -> str:
235 """
236 Retrieves the globally unique immutable UUID associated with this
237 device, as a 5 part hexadecimal string, that augments the immutable,
238 board serial identifier.
240 In the upstream NVML C++ API, the UUID includes a ``gpu-`` or ``mig-``
241 prefix. If you need a `uuid` without that prefix (for example, to
242 interact with CUDA), use the `uuid_without_prefix` property.
243 """
244 return nvml.device_get_uuid(self._handle) 1Q
246 @property
247 def uuid_without_prefix(self) -> str:
248 """
249 Retrieves the globally unique immutable UUID associated with this
250 device, as a 5 part hexadecimal string, that augments the immutable,
251 board serial identifier.
253 In the upstream NVML C++ API, the UUID includes a ``gpu-`` or ``mig-``
254 prefix. This property returns it without the prefix, to match the UUIDs
255 used in CUDA. If you need the prefix, use the `uuid` property.
256 """
257 # NVML UUIDs have a `gpu-` or `mig-` prefix. We remove that here.
258 return nvml.device_get_uuid(self._handle)[4:] 1Nkr
260 @property
261 def pci_bus_id(self) -> str:
262 """
263 Retrieves the PCI bus ID of this device.
264 """
265 return self.pci_info.bus_id 1h
267 @property
268 def numa_node_id(self) -> int:
269 """
270 The NUMA node of the given GPU device.
272 This only applies to platforms where the GPUs are NUMA nodes.
273 """
274 return nvml.device_get_numa_node_id(self._handle) 1G
276 @property
277 def arch(self) -> DeviceArch:
278 """
279 :obj:`~DeviceArch` device architecture.
281 For example, a Tesla V100 will report ``DeviceArchitecture.name ==
282 "VOLTA"``, and RTX A6000 will report ``DeviceArchitecture.name ==
283 "AMPERE"``.
284 """
285 arch = nvml.device_get_architecture(self._handle) 1p
286 try: 1p
287 return DeviceArch(arch) 1p
288 except ValueError:
289 return DeviceArch.UNKNOWN
291 @property
292 def name(self) -> str:
293 """
294 Name of the device, e.g.: `"Tesla V100-SXM2-32GB"`
295 """
296 return nvml.device_get_name(self._handle) 1M
298 @property
299 def brand(self) -> str:
300 """
301 The brand of the device.
303 Returns "Unknown" if the brand is unknown.
304 """
305 return _BRAND_TYPE_MAPPING.get(nvml.device_get_brand(self._handle), "Unknown") 1L
307 @property
308 def serial(self) -> str:
309 """
310 Retrieves the globally unique board serial number associated with this
311 device's board.
313 For all products with an InfoROM.
314 """
315 return nvml.device_get_serial(self._handle) 1A
317 @property
318 def module_id(self) -> int:
319 """
320 Get a unique identifier for the device module on the baseboard.
322 This API retrieves a unique identifier for each GPU module that exists
323 on a given baseboard. For non-baseboard products, this ID would always
324 be 0.
325 """
326 return nvml.device_get_module_id(self._handle) 1F
328 @property
329 def minor_number(self) -> int:
330 """
331 The minor number of this device.
333 For Linux only.
335 The minor number is used by the Linux device driver to identify the
336 device node in ``/dev/nvidiaX``.
337 """
338 return nvml.device_get_minor_number(self._handle) 1O
340 @property
341 def is_c2c_enabled(self) -> bool:
342 """
343 Whether the C2C (Chip-to-Chip) mode is enabled for this device.
344 """
345 return bool(nvml.device_get_c2c_mode_info_v(self._handle).is_c2c_enabled) 1u
347 @property
348 def is_persistence_mode_enabled(self) -> bool:
349 """
350 Whether persistence mode is enabled for this device.
352 For Linux only.
353 """
354 return nvml.device_get_persistence_mode(self._handle) == nvml.EnableState.FEATURE_ENABLED 1n
356 @is_persistence_mode_enabled.setter
357 def is_persistence_mode_enabled(self, enabled: bool) -> None:
358 nvml.device_set_persistence_mode( 1n
359 self._handle, 1n
360 nvml.EnableState.FEATURE_ENABLED if enabled else nvml.EnableState.FEATURE_DISABLED 1n
361 )
363 @property
364 def cuda_compute_capability(self) -> tuple[int, int]:
365 """
366 CUDA compute capability of the device, e.g.: `(7, 0)` for a Tesla V100.
368 Returns a tuple `(major, minor)`.
369 """
370 return nvml.device_get_cuda_compute_capability(self._handle) 1R
372 def to_cuda_device(self) -> "cuda.core.Device":
373 """
374 Get the corresponding :class:`cuda.core.Device` (which is used for CUDA
375 access) for this :class:`cuda.core.system.Device` (which is used for
376 NVIDIA Management Library (NVML) access).
378 The devices are mapped to one another by their UUID.
380 Returns
381 -------
382 cuda.core.Device
383 The corresponding CUDA device.
385 Raises
386 ------
387 RuntimeError
388 No corresponding CUDA device is found for this NVML device.
390 For example, on a MIG system, the physical GPU will not have an
391 available CUDA device, since it can not be used directly, even
392 though it can be enumerated from NVML.
393 """
394 from cuda.core import Device as CudaDevice 1k
396 # CUDA does not have an API to get a device by its UUID, so we just
397 # search all the devices for one with a matching UUID.
399 for cuda_device in CudaDevice.get_all_devices(): 1k
400 if cuda_device.uuid == self.uuid_without_prefix: 1k
401 return cuda_device 1k
403 raise RuntimeError("No corresponding CUDA device found for this NVML device.")
405 @classmethod
406 def get_device_count(cls) -> int:
407 """
408 Get the number of available devices.
410 Returns
411 -------
412 int
413 The number of available devices.
414 """
415 initialize() 1WXY
417 return nvml.device_get_count_v2() 1WXY
419 @classmethod
420 def get_all_devices(cls) -> Iterable[Device]:
421 """
422 Query the available device instances.
424 Returns
425 -------
426 Iterator over :obj:`~Device`
427 An iterator over available devices.
428 """
429 initialize() 1sctuefwpxyLizMoANBCmDOqPEFGgndjHIkJQh
431 for device_id in range(nvml.device_get_count_v2()): 1sctuefwpxyLizMoANBCmDOqPEFGgndjHIkJQh
432 yield cls(index=device_id) 1sctuefwpxyLizMoANBCmDOqPEFGgndjHIkJQh
434 #########################################################################
435 # ADDRESSING MODE
437 @property
438 def addressing_mode(self) -> AddressingMode | None:
439 """
440 Get the :obj:`~AddressingMode` of the device.
441 """
442 return _ADDRESSING_MODE_MAPPING.get(nvml.device_get_addressing_mode(self._handle).value, None) 1s
444 #########################################################################
445 # MIG (MULTI-INSTANCE GPU) DEVICES
447 @property
448 def mig(self) -> MigInfo:
449 """
450 Get :obj:`~MigInfo` accessor for MIG (Multi-Instance GPU) information.
452 For Ampere™ or newer fully supported devices.
453 """
454 return MigInfo(self) 1vE
456 #########################################################################
457 # AFFINITY
459 @classmethod
460 def get_all_devices_with_cpu_affinity(cls, cpu_index: int) -> Iterable[Device]:
461 """
462 Retrieve the set of GPUs that have a CPU affinity with the given CPU number.
464 Supported on Linux only.
466 Parameters
467 ----------
468 cpu_index: int
469 The CPU index.
471 Returns
472 -------
473 Iterator of :obj:`~Device`
474 An iterator over available devices.
475 """
476 cdef Device device
477 for handle in nvml.system_get_topology_gpu_set(cpu_index): 1K
478 device = Device.__new__(Device) 1K
479 device._handle = handle 1K
480 yield device 1K
482 def get_memory_affinity(self, scope: AffinityScope | str=AffinityScope.NODE) -> list[int]:
483 """
484 Retrieves a list of indices of NUMA nodes or CPU sockets with the ideal
485 memory affinity for the device.
487 For Kepler™ or newer fully supported devices.
489 Supported on Linux only.
491 If requested scope is not applicable to the target topology, the API
492 will fall back to reporting the memory affinity for the immediate non-I/O
493 ancestor of the device.
495 Parameters
496 ----------
497 scope: AffinityScope | str, optional
498 The scope of the affinity query. Must be one of the values of
499 :class:`AffinityScope`. Default is :attr:`AffinityScope.NODE`.
501 Returns
502 -------
503 list[int]
504 A list of indices of NUMA nodes or CPU sockets with the ideal memory
505 affinity for the device.
506 """
507 try: 1cb
508 scope = _AFFINITY_SCOPE_MAPPING[scope] 1cb
509 except KeyError: 1b
510 raise ValueError( 1b
511 f"Invalid affinity scope: {scope}. " 1b
512 f"Must be one of {list(AffinityScope.__members__.values())}" 1b
513 ) from None 1b
514 return _unpack_bitmask( 1c
515 nvml.device_get_memory_affinity( 1c
516 self._handle, 1c
517 <unsigned int>ceil(cpu_count() / 64), 1c
518 scope, 1c
519 )
520 )
522 def get_cpu_affinity(self, scope: AffinityScope | str=AffinityScope.NODE) -> list[int]:
523 """
524 Retrieves a list of indices of NUMA nodes or CPU sockets with the ideal
525 CPU affinity for the device.
527 For Kepler™ or newer fully supported devices.
529 Supported on Linux only.
531 If requested scope is not applicable to the target topology, the API
532 will fall back to reporting the memory affinity for the immediate non-I/O
533 ancestor of the device.
535 Parameters
536 ----------
537 scope: AffinityScope | str, optional
538 The scope of the affinity query. Must be one of the values of
539 :class:`AffinityScope`. Default is :attr:`AffinityScope.NODE`.
541 Returns
542 -------
543 list[int]
544 A list of indices of NUMA nodes or CPU sockets with the ideal memory
545 affinity for the device.
546 """
547 try: 1cbiK
548 scope = _AFFINITY_SCOPE_MAPPING[scope] 1cbiK
549 except KeyError: 1b
550 raise ValueError( 1b
551 f"Invalid affinity scope: {scope}. " 1b
552 f"Must be one of {list(AffinityScope.__members__.values())}" 1b
553 ) from None 1b
554 return _unpack_bitmask( 1ciK
555 nvml.device_get_cpu_affinity_within_scope( 1ciK
556 self._handle, 1ciK
557 <unsigned int>ceil(cpu_count() / 64), 1ciK
558 scope, 1ciK
559 )
560 )
562 def set_cpu_affinity(self) -> None:
563 """
564 Sets the ideal affinity for the calling thread and device.
566 For Kepler™ or newer fully supported devices.
568 Supported on Linux only.
569 """
570 nvml.device_set_cpu_affinity(self._handle)
572 def clear_cpu_affinity(self) -> None:
573 """
574 Clear all affinity bindings for the calling thread.
576 For Kepler™ or newer fully supported devices.
578 Supported on Linux only.
579 """
580 nvml.device_clear_cpu_affinity(self._handle)
582 #########################################################################
583 # CLOCK
584 # See external class definitions in _clock.pxi
586 def get_clock(self, clock_type: ClockType | str) -> ClockInfo:
587 """
588 :obj:`~_device.ClockInfo` object to get information about and manage a specific clock on a device.
589 """
590 return ClockInfo(self._handle, clock_type) 1f
592 @property
593 def is_auto_boosted_clocks_enabled(self) -> tuple[bool, bool]:
594 """
595 Retrieve the current state of auto boosted clocks on a device.
597 For Kepler™ or newer fully supported devices.
599 Auto Boosted clocks are enabled by default on some hardware, allowing
600 the GPU to run at higher clock rates to maximize performance as thermal
601 limits allow.
603 On Pascal™ and newer hardware, Auto Boosted clocks are controlled
604 through application clocks. Use :meth:`set_application_clocks` and
605 :meth:`reset_application_clocks` to control Auto Boost behavior.
607 Returns
608 -------
609 bool
610 The current state of Auto Boosted clocks
611 bool
612 The default Auto Boosted clocks behavior
614 """
615 current, default = nvml.device_get_auto_boosted_clocks_enabled(self._handle) 1t
616 return current == nvml.EnableState.FEATURE_ENABLED, default == nvml.EnableState.FEATURE_ENABLED
618 @property
619 def current_clock_event_reasons(self) -> list[ClocksEventReasons]:
620 """
621 Retrieves the current :obj:`~ClocksEventReasons`.
623 For all fully supported products.
624 """
625 cdef uint64_t[1] reasons
626 reasons[0] = nvml.device_get_current_clocks_event_reasons(self._handle) 1e
627 output_reasons = [] 1e
628 for reason in _unpack_bitmask(reasons): 1e
629 try:
630 output_reason = _CLOCKS_EVENT_REASONS_MAPPING[1 << reason]
631 except KeyError:
632 raise ValueError(f"Unknown clock event reason bit: {1 << reason}")
633 output_reasons.append(output_reason)
634 return output_reasons 1e
636 @property
637 def supported_clock_event_reasons(self) -> list[ClocksEventReasons]:
638 """
639 Retrieves supported :obj:`~ClocksEventReasons` that can be returned by
640 :meth:`get_current_clock_event_reasons`.
642 For all fully supported products.
644 This method is not supported in virtual machines running virtual GPU (vGPU).
645 """
646 cdef uint64_t[1] reasons
647 reasons[0] = nvml.device_get_supported_clocks_event_reasons(self._handle) 1e
648 output_reasons = [] 1e
649 for reason in _unpack_bitmask(reasons): 1e
650 try: 1e
651 output_reason = _CLOCKS_EVENT_REASONS_MAPPING[1 << reason] 1e
652 except KeyError:
653 raise ValueError(f"Unknown clock event reason bit: {1 << reason}")
654 output_reasons.append(output_reason) 1e
655 return output_reasons 1e
657 ##########################################################################
658 # COOLER
659 # See external class definitions in _cooler.pxi
661 @property
662 def cooler(self) -> CoolerInfo:
663 """
664 :obj:`~_device.CoolerInfo` object with cooler information for the device.
665 """
666 return CoolerInfo(nvml.device_get_cooler_info(self._handle))
668 ##########################################################################
669 # DEVICE ATTRIBUTES
670 # See external class definitions in _device_attributes.pxi
672 @property
673 def attributes(self) -> DeviceAttributes:
674 """
675 :obj:`~_device.DeviceAttributes` object with various device attributes.
677 For Ampere™ or newer fully supported devices. Only available on Linux
678 systems.
679 """
680 return DeviceAttributes(nvml.device_get_attributes_v2(self._handle)) 1x
682 #########################################################################
683 # DISPLAY
685 @property
686 def is_display_connected(self) -> bool:
687 """
688 The display mode for this device.
690 Indicates whether a physical display (e.g. monitor) is currently connected to
691 any of the device's connectors.
692 """
693 return nvml.device_get_display_mode(self._handle) == nvml.EnableState.FEATURE_ENABLED 1B
695 @property
696 def is_display_active(self) -> bool:
697 """
698 The display active status for this device.
700 Indicates whether a display is initialized on the device. For example,
701 whether X Server is attached to this device and has allocated memory for
702 the screen.
704 Display can be active even when no monitor is physically attached.
705 """
706 return nvml.device_get_display_active(self._handle) == nvml.EnableState.FEATURE_ENABLED 1B
708 ##########################################################################
709 # EVENTS
710 # See external class definitions in _event.pxi
712 def register_events(self, events: EventType | str | list[EventType | str]) -> DeviceEvents:
713 """
714 Starts recording events on this device.
716 For Fermi™ or newer fully supported devices. For Linux only.
718 ECC events are available only on ECC-enabled devices (see
719 :meth:`Device.get_total_ecc_errors`). Power capping events are
720 available only on Power Management enabled devices (see
721 :meth:`Device.get_power_management_mode`).
723 This call starts recording of events on specific device. All events
724 that occurred before this call are not recorded. Wait for events using
725 the :meth:`DeviceEvents.wait` method on the result.
727 Examples
728 --------
729 >>> device = Device(index=0)
730 >>> events = device.register_events([
731 ... EventType.XID_CRITICAL_ERROR,
732 ... ])
733 >>> while event := events.wait(timeout_ms=10000):
734 ... print(f"Event {event.event_type} occurred on device {event.device.uuid}")
736 Parameters
737 ----------
738 events: EventType, str, or list of EventType or str
739 The event type or list of event types to register for this device.
741 Returns
742 -------
743 :obj:`~_device.DeviceEvents`
744 An object representing the registered events. Call
745 :meth:`~_device.DeviceEvents.wait` on this object to wait for events.
747 Raises
748 ------
749 :class:`cuda.core.system.NotSupportedError`
750 None of the requested event types are registered.
751 """
752 return DeviceEvents(self._handle, events) 1j
754 def get_supported_event_types(self) -> list[EventType]:
755 """
756 Get the list of event types supported by this device.
758 For Fermi™ or newer fully supported devices. For Linux only (returns an
759 empty list on Windows).
761 Returns
762 -------
763 list[EventType]
764 The list of supported event types.
765 """
766 cdef uint64_t[1] bitmask
767 bitmask[0] = nvml.device_get_supported_event_types(self._handle) 1j
768 events = [] 1j
769 for ev in _unpack_bitmask(bitmask): 1j
770 try: 1j
771 ev_enum = _EVENT_TYPE_MAPPING[1 << ev] 1j
772 except KeyError:
773 raise ValueError(f"Unknown event type bit: {1 << ev}")
774 events.append(ev_enum) 1j
775 return events 1j
777 ##########################################################################
778 # FAN
779 # See external class definitions in _fan.pxi
781 def get_fan(self, fan: int = 0) -> FanInfo:
782 """
783 :obj:`~_device.FanInfo` object to get information and manage a specific fan on a device.
784 """
785 if fan < 0 or fan >= self.num_fans:
786 raise ValueError(f"Fan index {fan} is out of range [0, {self.num_fans})")
787 return FanInfo(self._handle, fan)
789 @property
790 def num_fans(self) -> int:
791 """
792 The number of fans on the device.
793 """
794 return nvml.device_get_num_fans(self._handle) 1wC
796 ##########################################################################
797 # FIELD VALUES
798 # See external class definitions in _field_values.pxi
800 def get_field_values(self, field_ids: list[int | tuple[int, int]]) -> FieldValues:
801 """
802 Get multiple field values from the device.
804 Each value specified can raise its own exception. That exception will
805 be raised when attempting to access the corresponding ``value`` from the
806 returned :obj:`~_device.FieldValues` container.
808 To confirm that there are no exceptions in the entire container, call
809 :meth:`~_device.FieldValues.validate`.
811 Parameters
812 ----------
813 field_ids: list[int | tuple[int, int]]
814 List of field IDs to query.
816 Each item may be either a single value from the :class:`FieldId`
817 enum, or a pair of (:class:`FieldId`, scope ID).
819 Returns
820 -------
821 :obj:`~_device.FieldValues`
822 Container of field values corresponding to the requested field IDs.
823 """
824 # Passing a field_ids array of length 0 raises an InvalidArgumentError,
825 # so avoid that.
826 if len(field_ids) == 0: 1mg
827 return FieldValues(nvml.FieldValue(0)) 1m
829 return FieldValues(nvml.device_get_field_values(self._handle, field_ids)) 1mg
831 def clear_field_values(self, field_ids: list[int | tuple[int, int]]) -> None:
832 """
833 Clear multiple field values from the device.
835 Parameters
836 ----------
837 field_ids: list[int | tuple[int, int]]
838 List of field IDs to clear.
840 Each item may be either a single value from the :class:`FieldId`
841 enum, or a pair of (:class:`FieldId`, scope ID).
842 """
843 # Passing a field_ids array of length 0 raises an InvalidArgumentError,
844 # so avoid that.
845 if len(field_ids) == 0: 1m
846 return
848 nvml.device_clear_field_values(self._handle, field_ids) 1m
850 ##########################################################################
851 # INFOROM
852 # See external class definitions in _inforom.pxi
854 @property
855 def inforom(self) -> InforomInfo:
856 """
857 :obj:`~_device.InforomInfo` object with InfoROM information.
859 For all products with an InfoROM.
860 """
861 return InforomInfo(self) 1D
863 ##########################################################################
864 # MEMORY
865 # See external class definitions in _memory.pxi
867 @property
868 def bar1_memory_info(self) -> BAR1MemoryInfo:
869 """
870 :obj:`~_device.BAR1MemoryInfo` object with BAR1 memory information.
872 BAR1 is used to map the FB (device memory) so that it can be directly
873 accessed by the CPU or by 3rd party devices (peer-to-peer on the PCIE
874 bus).
875 """
876 return BAR1MemoryInfo(nvml.device_get_bar1_memory_info(self._handle)) 1y
878 @property
879 def memory_info(self) -> MemoryInfo:
880 """
881 :obj:`~_device.MemoryInfo` object with memory information.
882 """
883 return MemoryInfo(nvml.device_get_memory_info_v2(self._handle)) 1z
885 ##########################################################################
886 # NVLINK
887 # See external class definitions in _nvlink.pxi
889 def get_nvlink(self, link: int) -> NvlinkInfo:
890 """
891 Get :obj:`~NvlinkInfo` about this device.
893 For devices with NVLink support.
895 .. version-changed:: 1.1.0
896 Any link number not supported by this specific device will raise a `ValueError`.
897 """
898 link_count = self.get_nvlink_count() 1g
899 if link < 0 or link >= link_count: 1g
900 raise ValueError(f"Link index {link} is out of range [0, {link_count})")
901 return NvlinkInfo(self, link) 1g
903 def get_nvlink_count(self) -> int:
904 """
905 Get the number of NVLink links on this device.
907 For devices with NVLink support.
909 .. version-added:: 1.1.0
910 """
911 return self.get_field_values([FieldId.DEV_NVLINK_LINK_COUNT])[0].value 1g
913 def get_nvlinks(self) -> Iterable[NvlinkInfo]:
914 """
915 Get :obj:`~NvlinkInfo` about all NVLink links on this device.
917 For devices with NVLink support.
919 .. version-added:: 1.1.0
920 """
921 for link in range(self.get_nvlink_count()): 1g
922 yield self.get_nvlink(link) 1g
924 ##########################################################################
925 # PCI INFO
926 # See external class definitions in _pci_info.pxi
928 @property
929 def pci_info(self) -> PciInfo:
930 """
931 :obj:`~_device.PciInfo` object with the PCI attributes of this device.
933 Non-physical devices, such as MIG devices, may not have PCI attributes.
934 In that case, this property will raise a `RuntimeError`.
935 """
936 try: 1lokhr
937 pci_info = nvml.device_get_pci_info_ext(self._handle) 1lokhr
938 except nvml.InvalidArgumentError:
939 raise RuntimeError("This device does not have PCI attributes") from None
940 else:
941 return PciInfo(pci_info, self._handle) 1lokhr
943 ##########################################################################
944 # PERFORMANCE
945 # See external class definitions in _performance.pxi
947 @property
948 def performance_state(self) -> int | None:
949 """
950 The current performance state of the device.
952 For Fermi™ or newer fully supported devices.
954 Returns
955 -------
956 int | None
957 The current performance state of the device, as an integer between 0 and 15,
958 where 0 is maximum performance and higher numbers are lower performance.
959 Returns `None` if the performance state is unknown.
960 """
961 return _pstate_to_int(nvml.device_get_performance_state(self._handle)) 1fd
963 @property
964 def dynamic_pstates_info(self) -> GpuDynamicPstatesInfo:
965 """
966 :obj:`~_device.GpuDynamicPstatesInfo` object with performance monitor samples from the associated subdevice.
967 """
968 return GpuDynamicPstatesInfo(nvml.device_get_dynamic_pstates_info(self._handle)) 1d
970 @property
971 def supported_pstates(self) -> list[int]:
972 """
973 Get all supported Performance States (P-States) for the device.
975 The returned list contains a contiguous list of valid P-States supported by
976 the device.
978 Return
979 ------
980 list[int]
981 A list of supported performance state of the device, as an integer
982 between 0 and 15, where 0 is maximum performance and higher numbers
983 are lower performance.
984 """
985 # From nvml.h:
986 # The returned array would contain a contiguous list of valid P-States
987 # supported by the device. If the number of supported P-States is fewer
988 # than the size of the array supplied missing elements would contain \a
989 # NVML_PSTATE_UNKNOWN.
991 pstates = [] 1d
992 for pstate in nvml.device_get_supported_performance_states(self._handle): 1d
993 pstate_value = _pstate_to_int(pstate) 1d
994 if pstate_value is not None: 1d
995 pstates.append(pstate_value) 1d
996 return pstates 1d
998 ##########################################################################
999 # PROCESS
1000 # See external class definitions in _process.pxi
1002 @property
1003 def compute_running_processes(self) -> list[ProcessInfo]:
1004 """
1005 Get information about processes with a compute context on a device
1007 For Fermi™ or newer fully supported devices.
1009 This function returns information only about compute running processes
1010 (e.g. CUDA application which have active context). Any graphics
1011 applications (e.g. using OpenGL, DirectX) won't be listed by this
1012 function.
1014 Keep in mind that information returned by this call is dynamic and the
1015 number of elements might change in time.
1017 In MIG mode, if device handle is provided, the API returns aggregate
1018 information, only if the caller has appropriate privileges. Per-instance
1019 information can be queried by using specific MIG device handles.
1020 Querying per-instance information using MIG device handles is not
1021 supported if the device is in vGPU Host virtualization mode.
1022 """
1023 return [ProcessInfo(self, proc) for proc in nvml.device_get_compute_running_processes_v3(self._handle)] 1vS
1025 ##########################################################################
1026 # REPAIR STATUS
1027 # See external class definitions in _repair_status.pxi
1029 @property
1030 def repair_status(self) -> RepairStatus:
1031 """
1032 :obj:`~_device.RepairStatus` object with TPC/Channel repair status.
1034 For Ampere™ or newer fully supported devices.
1035 """
1036 return RepairStatus(self._handle) 1H
1038 ##########################################################################
1039 # TEMPERATURE
1040 # See external class definitions in _temperature.pxi
1042 @property
1043 def temperature(self) -> Temperature:
1044 """
1045 :obj:`~_device.Temperature` object with temperature information for the device.
1046 """
1047 return Temperature(self._handle) 1TUI
1049 #######################################################################
1050 # TOPOLOGY
1052 def get_topology_nearest_gpus(self, level: GpuTopologyLevel | str) -> Iterable[Device]:
1053 """
1054 Retrieve the GPUs that are nearest to this device at a specific interconnectivity level.
1056 Supported on Linux only.
1058 Parameters
1059 ----------
1060 level: :class:`GpuTopologyLevel`
1061 The topology level.
1063 Returns
1064 -------
1065 Iterable of :class:`Device`
1066 The nearest devices at the given topology level.
1067 """
1068 cdef Device device
1069 try: 1bq
1070 level = _GPU_TOPOLOGY_LEVEL_MAPPING[level] 1bq
1071 except KeyError: 1b
1072 raise ValueError( 1b
1073 f"Invalid topology level: {level}. " 1b
1074 f"Must be one of {list(GpuTopologyLevel.__members__.values())}" 1b
1075 ) from None 1b
1076 for handle in nvml.device_get_topology_nearest_gpus(self._handle, level): 1q
1077 device = Device.__new__(Device)
1078 device._handle = handle
1079 yield device
1081 #######################################################################
1082 # UTILIZATION
1084 @property
1085 def utilization(self) -> Utilization:
1086 """
1087 Retrieves the current :obj:`~Utilization` rates for the device's major
1088 subsystems.
1090 For Fermi™ or newer fully supported devices.
1092 Note: During driver initialization when ECC is enabled one can see high
1093 GPU and Memory Utilization readings. This is caused by ECC Memory
1094 Scrubbing mechanism that is performed during driver initialization.
1096 Note: On MIG-enabled GPUs, querying device utilization rates is not
1097 currently supported.
1099 Returns
1100 -------
1101 Utilization
1102 An object containing the current utilization rates for the device.
1103 """
1104 return Utilization(nvml.device_get_utilization_rates(self._handle)) 1J
1107def get_topology_common_ancestor(device1: Device, device2: Device) -> GpuTopologyLevel:
1108 """
1109 Retrieve the common ancestor for two devices.
1111 For Linux only.
1113 Parameters
1114 ----------
1115 device1: :class:`Device`
1116 The first device.
1117 device2: :class:`Device`
1118 The second device.
1120 Returns
1121 -------
1122 :class:`GpuTopologyLevel`
1123 The common ancestor level of the two devices.
1124 """
1125 return _GPU_TOPOLOGY_LEVEL_INV_MAPPING[
1126 nvml.device_get_topology_common_ancestor(
1127 device1._handle,
1128 device2._handle,
1129 )
1130 ]
1133def get_p2p_status(device1: Device, device2: Device, index: GpuP2PCapsIndex | str) -> GpuP2PStatus:
1134 """
1135 Retrieve the P2P status between two devices.
1137 Parameters
1138 ----------
1139 device1: :class:`Device`
1140 The first device.
1141 device2: :class:`Device`
1142 The second device.
1143 index: :class:`GpuP2PCapsIndex` | str
1144 The P2P capability index being looked for between ``device1`` and ``device2``.
1146 Returns
1147 -------
1148 :class:`GpuP2PStatus`
1149 The P2P status between the two devices.
1150 """
1151 try: 1b
1152 index_enum = _GPU_P2P_CAPS_INDEX_MAPPING[index] 1b
1153 except KeyError: 1b
1154 raise ValueError( 1b
1155 f"Invalid P2P caps index: {index}. " 1b
1156 f"Must be one of {list(GpuP2PCapsIndex.__members__.values())}" 1b
1157 ) from None 1b
1158 return _GPU_P2P_STATUS_MAPPING.get(
1159 nvml.device_get_p2p_status(
1160 device1._handle,
1161 device2._handle,
1162 index_enum,
1163 ),
1164 GpuP2PStatus.UNKNOWN
1165 )
1168__all__ = [
1169 "Device",
1170 "get_p2p_status",
1171 "get_topology_common_ancestor",
1172 "NvlinkInfo",
1173]