Coverage for cuda/core/system/_device.pyx: 57.68%
267 statements
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-05 01:11 +0000
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-05 01:11 +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: 1gd
45 return None 1d
46 if int(pstate) < 0 or int(pstate) > 15: 1gd
47 raise ValueError(f"Invalid P-state: {pstate}. Must be between 0 and 15 inclusive, or PSTATE_UNKNOWN.")
48 return int(pstate) - int(nvml.Pstates.PSTATE_0) 1gd
51cdef int _pstate_to_enum(int pstate):
52 if pstate < 0 or pstate > 15: 1g
53 raise ValueError(f"Invalid P-state: {pstate}. Must be between 0 and 15 inclusive.")
54 return int(pstate) + int(nvml.Pstates.PSTATE_0) 1g
57include "_clock.pxi"
58include "_cooler.pxi"
59include "_device_attributes.pxi"
60include "_device_utils.pxi"
61include "_event.pxi"
62include "_fan.pxi"
63include "_field_values.pxi"
64include "_inforom.pxi"
65include "_memory.pxi"
66include "_mig.pxi"
67include "_nvlink.pxi"
68include "_pci_info.pxi"
69include "_performance.pxi"
70include "_process.pxi"
71include "_repair_status.pxi"
72include "_temperature.pxi"
73include "_utilization.pxi"
76_ADDRESSING_MODE_MAPPING = {
77 nvml.DeviceAddressingModeType.DEVICE_ADDRESSING_MODE_HMM: AddressingMode.HMM,
78 nvml.DeviceAddressingModeType.DEVICE_ADDRESSING_MODE_ATS: AddressingMode.ATS,
79}
82_AFFINITY_SCOPE_MAPPING = {
83 AffinityScope.NODE: nvml.AffinityScope.NODE,
84 AffinityScope.SOCKET: nvml.AffinityScope.SOCKET,
85}
88_BRAND_TYPE_MAPPING = {
89 nvml.BrandType.BRAND_UNKNOWN: "Unknown",
90 nvml.BrandType.BRAND_QUADRO: "Quadro",
91 nvml.BrandType.BRAND_TESLA: "Tesla",
92 nvml.BrandType.BRAND_NVS: "NVS",
93 nvml.BrandType.BRAND_GRID: "GRID",
94 nvml.BrandType.BRAND_GEFORCE: "GeForce",
95 nvml.BrandType.BRAND_TITAN: "Titan",
96 nvml.BrandType.BRAND_NVIDIA_VAPPS: "NVIDIA vApps",
97 nvml.BrandType.BRAND_NVIDIA_VPC: "NVIDIA VPC",
98 nvml.BrandType.BRAND_NVIDIA_VCS: "NVIDIA VCS",
99 nvml.BrandType.BRAND_NVIDIA_VWS: "NVIDIA VWS",
100 nvml.BrandType.BRAND_NVIDIA_CLOUD_GAMING: "NVIDIA Cloud Gaming",
101 nvml.BrandType.BRAND_NVIDIA_VGAMING: "NVIDIA vGaming",
102 nvml.BrandType.BRAND_QUADRO_RTX: "Quadro RTX",
103 nvml.BrandType.BRAND_NVIDIA_RTX: "NVIDIA RTX",
104 nvml.BrandType.BRAND_NVIDIA: "NVIDIA",
105 nvml.BrandType.BRAND_GEFORCE_RTX: "GeForce RTX",
106 nvml.BrandType.BRAND_TITAN_RTX: "Titan RTX",
107 nvml.BrandType.BRAND_NVIDIA_DLA: "NVIDIA DLA",
108 nvml.BrandType.BRAND_NVIDIA_VGAMEDEV: "NVIDIA vGameDev",
109 nvml.BrandType.BRAND_NVIDIA_NPU: "NVIDIA NPU",
110}
113_GPU_P2P_CAPS_INDEX_MAPPING = {
114 GpuP2PCapsIndex.READ: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_READ,
115 GpuP2PCapsIndex.WRITE: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_WRITE,
116 GpuP2PCapsIndex.NVLINK: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_NVLINK,
117 GpuP2PCapsIndex.ATOMICS: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_ATOMICS,
118 GpuP2PCapsIndex.PCI: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_PCI,
119 GpuP2PCapsIndex.PROP: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_PROP,
120 GpuP2PCapsIndex.UNKNOWN: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_UNKNOWN,
121}
124_GPU_P2P_STATUS_MAPPING = {
125 nvml.GpuP2PStatus.P2P_STATUS_OK: GpuP2PStatus.OK,
126 nvml.GpuP2PStatus.P2P_STATUS_CHIPSET_NOT_SUPPORTED: GpuP2PStatus.CHIPSET_NOT_SUPPORTED,
127 nvml.GpuP2PStatus.P2P_STATUS_GPU_NOT_SUPPORTED: GpuP2PStatus.GPU_NOT_SUPPORTED,
128 nvml.GpuP2PStatus.P2P_STATUS_IOH_TOPOLOGY_NOT_SUPPORTED: GpuP2PStatus.IOH_TOPOLOGY_NOT_SUPPORTED,
129 nvml.GpuP2PStatus.P2P_STATUS_DISABLED_BY_REGKEY: GpuP2PStatus.DISABLED_BY_REGKEY,
130 nvml.GpuP2PStatus.P2P_STATUS_NOT_SUPPORTED: GpuP2PStatus.NOT_SUPPORTED,
131 nvml.GpuP2PStatus.P2P_STATUS_UNKNOWN: GpuP2PStatus.UNKNOWN,
132}
135_GPU_TOPOLOGY_LEVEL_MAPPING = {
136 GpuTopologyLevel.INTERNAL: nvml.GpuTopologyLevel.TOPOLOGY_INTERNAL,
137 GpuTopologyLevel.SINGLE: nvml.GpuTopologyLevel.TOPOLOGY_SINGLE,
138 GpuTopologyLevel.MULTIPLE: nvml.GpuTopologyLevel.TOPOLOGY_MULTIPLE,
139 GpuTopologyLevel.HOSTBRIDGE: nvml.GpuTopologyLevel.TOPOLOGY_HOSTBRIDGE,
140 GpuTopologyLevel.NODE: nvml.GpuTopologyLevel.TOPOLOGY_NODE,
141 GpuTopologyLevel.SYSTEM: nvml.GpuTopologyLevel.TOPOLOGY_SYSTEM,
142}
145_GPU_TOPOLOGY_LEVEL_INV_MAPPING = {v: k for k, v in _GPU_TOPOLOGY_LEVEL_MAPPING.items()}
148cdef class Device:
149 """
150 Representation of a device.
152 :class:`cuda.core.system.Device` provides access to various pieces of metadata
153 about devices and their topology, as provided by the NVIDIA Management
154 Library (NVML). To use CUDA with a device, use :class:`cuda.core.Device`.
156 Creating a device instance causes NVML to initialize the target GPU.
157 NVML may initialize additional GPUs if the target GPU is an SLI slave.
159 Parameters
160 ----------
161 index: int, optional
162 Integer representing the CUDA device index to get a handle to. Valid
163 values are between ``0`` and ``cuda.core.system.get_num_devices() - 1``.
165 The order in which devices are enumerated has no guarantees of
166 consistency between reboots. For that reason, it is recommended that
167 devices are looked up by their PCI ids or UUID.
169 uuid: bytes or str, optional
170 UUID of a CUDA device to get a handle to.
172 pci_bus_id: bytes or str, optional
173 PCI bus ID of a CUDA device to get a handle to.
175 Raises
176 ------
177 ValueError
178 If anything other than a single `index`, `uuid` or `pci_bus_id` are specified.
179 """
181 # This is made public for testing purposes only
182 cdef public intptr_t _handle
184 def __init__(
185 self,
186 *,
187 index: int | None = None,
188 uuid: bytes | str | None = None,
189 pci_bus_id: bytes | str | None = None,
190 ) -> None:
191 args = [index, uuid, pci_bus_id] 1sbtucgvJpawxKVhQyLkqzoAMlBNrOCDEfndiFTUGeHPjRSm
192 cdef int arg_count = sum(arg is not None for arg in args) 1sbtucgvJpawxKVhQyLkqzoAMlBNrOCDEfndiFTUGeHPjRSm
194 if arg_count > 1: 1sbtucgvJpawxKVhQyLkqzoAMlBNrOCDEfndiFTUGeHPjRSm
195 raise ValueError("Handle requires only one of `index`, `uuid`, or `pci_bus_id`.") 1V
196 if arg_count == 0: 1sbtucgvJpawxKVhQyLkqzoAMlBNrOCDEfndiFTUGeHPjRSm
197 raise ValueError("Handle requires either a device `index`, `uuid`, or `pci_bus_id`.") 1V
199 initialize() 1sbtucgvJpawxKhQyLkqzoAMlBNrOCDEfndiFTUGeHPjRSm
201 if index is not None: 1sbtucgvJpawxKhQyLkqzoAMlBNrOCDEfndiFTUGeHPjRSm
202 self._handle = nvml.device_get_handle_by_index_v2(index) 1sbtucgpawxKhyLzoAlBNrOCDEfndiFTUGeHP
203 elif uuid is not None: 1vJQkqMjRSm
204 if isinstance(uuid, bytes): 1vJQkqMjRSm
205 uuid = uuid.decode("ascii")
206 self._handle = nvml.device_get_handle_by_uuid(uuid) 1vJQkqMjRSm
207 elif pci_bus_id is not None: 1kj
208 if isinstance(pci_bus_id, bytes): 1kj
209 pci_bus_id = pci_bus_id.decode("ascii")
210 self._handle = nvml.device_get_handle_by_pci_bus_id_v2(pci_bus_id) 1kj
212 #########################################################################
213 # BASIC PROPERTIES
215 @property
216 def index(self) -> int:
217 """
218 The NVML index of this device.
220 Valid indices are derived from the count returned by
221 :meth:`Device.get_device_count`. For example, if ``get_device_count()``
222 returns 2, the valid indices are 0 and 1, corresponding to GPU 0 and GPU
223 1.
225 The order in which NVML enumerates devices has no guarantees of
226 consistency between reboots. For that reason, it is recommended that
227 devices be looked up by their PCI ids or GPU UUID.
229 Note: The NVML index may not correlate with other APIs, such as the CUDA
230 device index.
231 """
232 return nvml.device_get_index(self._handle) 1sbtucgvJwxhykqzMlIBOCDEfndFGeHj
234 @property
235 def uuid(self) -> str:
236 """
237 Retrieves the globally unique immutable UUID associated with this
238 device, as a 5 part hexadecimal string, that augments the immutable,
239 board serial identifier.
241 Returns the UUID exactly as reported by NVML. It usually includes a
242 ``GPU-``, ``MIG-``, or ``DLA-`` prefix, but some platforms report an
243 unprefixed UUID. To interact with CUDA, use the `uuid_without_prefix`
244 property.
245 """
246 return nvml.device_get_uuid(self._handle) 1oePWXYZm
248 @property
249 def uuid_without_prefix(self) -> str:
250 """
251 Retrieves the globally unique immutable UUID associated with this
252 device, as a 5 part hexadecimal string, that augments the immutable,
253 board serial identifier.
255 Removes a ``GPU-``, ``MIG-``, or ``DLA-`` prefix when present, to match
256 the UUIDs used in CUDA. An already unprefixed UUID is returned
257 unchanged. For the UUID exactly as reported by NVML, use the `uuid`
258 property.
259 """
260 uuid = self.uuid 1oeWXYZm
261 if uuid.startswith(("GPU-", "MIG-", "DLA-")): 1oeWXYZm
262 return uuid[4:] 1oeWXYm
263 return uuid 1Z
265 @property
266 def pci_bus_id(self) -> str:
267 """
268 Retrieves the PCI bus ID of this device.
269 """
270 return self.pci_info.bus_id 1j
272 @property
273 def numa_node_id(self) -> int:
274 """
275 The NUMA node of the given GPU device.
277 This only applies to platforms where the GPUs are NUMA nodes.
278 """
279 return nvml.device_get_numa_node_id(self._handle) 1E
281 @property
282 def arch(self) -> DeviceArch:
283 """
284 :obj:`~DeviceArch` device architecture.
286 For example, a Tesla V100 will report ``DeviceArchitecture.name ==
287 "VOLTA"``, and RTX A6000 will report ``DeviceArchitecture.name ==
288 "AMPERE"``.
289 """
290 arch = nvml.device_get_architecture(self._handle) 1p
291 try: 1p
292 return DeviceArch(arch) 1p
293 except ValueError:
294 return DeviceArch.UNKNOWN
296 @property
297 def name(self) -> str:
298 """
299 Name of the device, e.g.: `"Tesla V100-SXM2-32GB"`
300 """
301 return nvml.device_get_name(self._handle) 1L
303 @property
304 def brand(self) -> str:
305 """
306 The brand of the device.
308 Returns "Unknown" if the brand is unknown.
309 """
310 return _BRAND_TYPE_MAPPING.get(nvml.device_get_brand(self._handle), "Unknown") 1K
312 @property
313 def serial(self) -> str:
314 """
315 Retrieves the globally unique board serial number associated with this
316 device's board.
318 For all products with an InfoROM.
319 """
320 return nvml.device_get_serial(self._handle) 1z
322 @property
323 def module_id(self) -> int:
324 """
325 Get a unique identifier for the device module on the baseboard.
327 This API retrieves a unique identifier for each GPU module that exists
328 on a given baseboard. For non-baseboard products, this ID would always
329 be 0.
330 """
331 return nvml.device_get_module_id(self._handle) 1D
333 @property
334 def minor_number(self) -> int:
335 """
336 The minor number of this device.
338 For Linux only.
340 The minor number is used by the Linux device driver to identify the
341 device node in ``/dev/nvidiaX``.
342 """
343 return nvml.device_get_minor_number(self._handle) 1N
345 @property
346 def is_c2c_enabled(self) -> bool:
347 """
348 Whether the C2C (Chip-to-Chip) mode is enabled for this device.
349 """
350 return bool(nvml.device_get_c2c_mode_info_v(self._handle).is_c2c_enabled) 1u
352 @property
353 def is_persistence_mode_enabled(self) -> bool:
354 """
355 Whether persistence mode is enabled for this device.
357 For Linux only.
358 """
359 return nvml.device_get_persistence_mode(self._handle) == nvml.EnableState.FEATURE_ENABLED 1n
361 @is_persistence_mode_enabled.setter
362 def is_persistence_mode_enabled(self, enabled: bool) -> None:
363 nvml.device_set_persistence_mode( 1n
364 self._handle, 1n
365 nvml.EnableState.FEATURE_ENABLED if enabled else nvml.EnableState.FEATURE_DISABLED 1n
366 )
368 @property
369 def cuda_compute_capability(self) -> tuple[int, int]:
370 """
371 CUDA compute capability of the device, e.g.: `(7, 0)` for a Tesla V100.
373 Returns a tuple `(major, minor)`.
374 """
375 return nvml.device_get_cuda_compute_capability(self._handle) 1Q
377 def to_cuda_device(self) -> "cuda.core.Device":
378 """
379 Get the corresponding :class:`cuda.core.Device` (which is used for CUDA
380 access) for this :class:`cuda.core.system.Device` (which is used for
381 NVIDIA Management Library (NVML) access).
383 The devices are mapped to one another by their UUID.
385 Returns
386 -------
387 cuda.core.Device
388 The corresponding CUDA device.
390 Raises
391 ------
392 RuntimeError
393 No corresponding CUDA device is found for this NVML device.
395 For example, on a MIG system, the physical GPU will not have an
396 available CUDA device, since it can not be used directly, even
397 though it can be enumerated from NVML.
398 """
399 from cuda.core import Device as CudaDevice 1e
401 # CUDA does not have an API to get a device by its UUID, so we just
402 # search all the devices for one with a matching UUID.
404 for cuda_device in CudaDevice.get_all_devices(): 1e
405 if cuda_device.uuid == self.uuid_without_prefix: 1e
406 return cuda_device 1e
408 raise RuntimeError("No corresponding CUDA device found for this NVML device.")
410 @classmethod
411 def get_device_count(cls) -> int:
412 """
413 Get the number of available devices.
415 Returns
416 -------
417 int
418 The number of available devices.
419 """
420 initialize() 1567
422 return nvml.device_get_count_v2() 1567
424 @classmethod
425 def get_all_devices(cls) -> Iterable[Device]:
426 """
427 Query the available device instances.
429 Returns
430 -------
431 Iterator over :obj:`~Device`
432 An iterator over available devices.
433 """
434 initialize() 1sbtucgpwxKhyLzoAlBNrOCDEfndiFGeHP
436 for device_id in range(nvml.device_get_count_v2()): 1sbtucgpwxKhyLzoAlBNrOCDEfndiFGeHP
437 yield cls(index=device_id) 1sbtucgpwxKhyLzoAlBNrOCDEfndiFGeHP
439 #########################################################################
440 # ADDRESSING MODE
442 @property
443 def addressing_mode(self) -> AddressingMode | None:
444 """
445 Get the :obj:`~AddressingMode` of the device.
446 """
447 return _ADDRESSING_MODE_MAPPING.get(nvml.device_get_addressing_mode(self._handle).value, None) 1s
449 #########################################################################
450 # MIG (MULTI-INSTANCE GPU) DEVICES
452 @property
453 def mig(self) -> MigInfo:
454 """
455 Get :obj:`~MigInfo` accessor for MIG (Multi-Instance GPU) information.
457 For Ampere™ or newer fully supported devices.
458 """
459 return MigInfo(self) 1vC
461 #########################################################################
462 # AFFINITY
464 @classmethod
465 def get_all_devices_with_cpu_affinity(cls, cpu_index: int) -> Iterable[Device]:
466 """
467 Retrieve the set of GPUs that have a CPU affinity with the given CPU number.
469 Supported on Linux only.
471 Parameters
472 ----------
473 cpu_index: int
474 The CPU index.
476 Returns
477 -------
478 Iterator of :obj:`~Device`
479 An iterator over available devices.
480 """
481 cdef Device device
482 for handle in nvml.system_get_topology_gpu_set(cpu_index): 1I
483 device = Device.__new__(Device) 1I
484 device._handle = handle 1I
485 yield device 1I
487 def get_memory_affinity(self, scope: AffinityScope | str=AffinityScope.NODE) -> list[int]:
488 """
489 Retrieves a list of indices of NUMA nodes or CPU sockets with the ideal
490 memory affinity for the device.
492 For Kepler™ or newer fully supported devices.
494 Supported on Linux only.
496 If requested scope is not applicable to the target topology, the API
497 will fall back to reporting the memory affinity for the immediate non-I/O
498 ancestor of the device.
500 Parameters
501 ----------
502 scope: AffinityScope | str, optional
503 The scope of the affinity query. Must be one of the values of
504 :class:`AffinityScope`. Default is :attr:`AffinityScope.NODE`.
506 Returns
507 -------
508 list[int]
509 A list of indices of NUMA nodes or CPU sockets with the ideal memory
510 affinity for the device.
511 """
512 try: 1ba
513 scope = _AFFINITY_SCOPE_MAPPING[scope] 1ba
514 except KeyError: 1a
515 raise ValueError( 1a
516 f"Invalid affinity scope: {scope}. " 1a
517 f"Must be one of {list(AffinityScope.__members__.values())}" 1a
518 ) from None 1a
519 return _unpack_bitmask( 1b
520 nvml.device_get_memory_affinity( 1b
521 self._handle, 1b
522 <unsigned int>ceil(cpu_count() / 64), 1b
523 scope, 1b
524 )
525 )
527 def get_cpu_affinity(self, scope: AffinityScope | str=AffinityScope.NODE) -> list[int]:
528 """
529 Retrieves a list of indices of NUMA nodes or CPU sockets with the ideal
530 CPU affinity for the device.
532 For Kepler™ or newer fully supported devices.
534 Supported on Linux only.
536 If requested scope is not applicable to the target topology, the API
537 will fall back to reporting the memory affinity for the immediate non-I/O
538 ancestor of the device.
540 Parameters
541 ----------
542 scope: AffinityScope | str, optional
543 The scope of the affinity query. Must be one of the values of
544 :class:`AffinityScope`. Default is :attr:`AffinityScope.NODE`.
546 Returns
547 -------
548 list[int]
549 A list of indices of NUMA nodes or CPU sockets with the ideal memory
550 affinity for the device.
551 """
552 try: 1bahI
553 scope = _AFFINITY_SCOPE_MAPPING[scope] 1bahI
554 except KeyError: 1a
555 raise ValueError( 1a
556 f"Invalid affinity scope: {scope}. " 1a
557 f"Must be one of {list(AffinityScope.__members__.values())}" 1a
558 ) from None 1a
559 return _unpack_bitmask( 1bhI
560 nvml.device_get_cpu_affinity_within_scope( 1bhI
561 self._handle, 1bhI
562 <unsigned int>ceil(cpu_count() / 64), 1bhI
563 scope, 1bhI
564 )
565 )
567 def set_cpu_affinity(self) -> None:
568 """
569 Sets the ideal affinity for the calling thread and device.
571 For Kepler™ or newer fully supported devices.
573 Supported on Linux only.
574 """
575 nvml.device_set_cpu_affinity(self._handle)
577 def clear_cpu_affinity(self) -> None:
578 """
579 Clear all affinity bindings for the calling thread.
581 For Kepler™ or newer fully supported devices.
583 Supported on Linux only.
584 """
585 nvml.device_clear_cpu_affinity(self._handle)
587 #########################################################################
588 # CLOCK
589 # See external class definitions in _clock.pxi
591 def get_clock(self, clock_type: ClockType | str) -> ClockInfo:
592 """
593 :obj:`~_device.ClockInfo` object to get information about and manage a specific clock on a device.
594 """
595 return ClockInfo(self._handle, clock_type) 1g
597 @property
598 def is_auto_boosted_clocks_enabled(self) -> tuple[bool, bool]:
599 """
600 Retrieve the current state of auto boosted clocks on a device.
602 For Kepler™ or newer fully supported devices.
604 Auto Boosted clocks are enabled by default on some hardware, allowing
605 the GPU to run at higher clock rates to maximize performance as thermal
606 limits allow.
608 On Pascal™ and newer hardware, Auto Boosted clocks are controlled
609 through application clocks. Use :meth:`set_application_clocks` and
610 :meth:`reset_application_clocks` to control Auto Boost behavior.
612 Returns
613 -------
614 bool
615 The current state of Auto Boosted clocks
616 bool
617 The default Auto Boosted clocks behavior
619 """
620 current, default = nvml.device_get_auto_boosted_clocks_enabled(self._handle) 1t
621 return current == nvml.EnableState.FEATURE_ENABLED, default == nvml.EnableState.FEATURE_ENABLED
623 @property
624 def current_clock_event_reasons(self) -> list[ClocksEventReasons]:
625 """
626 Retrieves the current :obj:`~ClocksEventReasons`.
628 For all fully supported products.
629 """
630 cdef uint64_t[1] reasons
631 reasons[0] = nvml.device_get_current_clocks_event_reasons(self._handle) 1c
632 output_reasons = [] 1c
633 for reason in _unpack_bitmask(reasons): 1c
634 try: 1c
635 output_reason = _CLOCKS_EVENT_REASONS_MAPPING[1 << reason] 1c
636 except KeyError:
637 raise ValueError(f"Unknown clock event reason bit: {1 << reason}")
638 output_reasons.append(output_reason) 1c
639 return output_reasons 1c
641 @property
642 def supported_clock_event_reasons(self) -> list[ClocksEventReasons]:
643 """
644 Retrieves supported :obj:`~ClocksEventReasons` that can be returned by
645 :meth:`get_current_clock_event_reasons`.
647 For all fully supported products.
649 This method is not supported in virtual machines running virtual GPU (vGPU).
650 """
651 cdef uint64_t[1] reasons
652 reasons[0] = nvml.device_get_supported_clocks_event_reasons(self._handle) 1c
653 output_reasons = [] 1c
654 for reason in _unpack_bitmask(reasons): 1c
655 try: 1c
656 output_reason = _CLOCKS_EVENT_REASONS_MAPPING[1 << reason] 1c
657 except KeyError:
658 raise ValueError(f"Unknown clock event reason bit: {1 << reason}")
659 output_reasons.append(output_reason) 1c
660 return output_reasons 1c
662 ##########################################################################
663 # COOLER
664 # See external class definitions in _cooler.pxi
666 @property
667 def cooler(self) -> CoolerInfo:
668 """
669 :obj:`~_device.CoolerInfo` object with cooler information for the device.
670 """
671 return CoolerInfo(nvml.device_get_cooler_info(self._handle))
673 ##########################################################################
674 # DEVICE ATTRIBUTES
675 # See external class definitions in _device_attributes.pxi
677 @property
678 def attributes(self) -> DeviceAttributes:
679 """
680 :obj:`~_device.DeviceAttributes` object with various device attributes.
682 For Ampere™ or newer fully supported devices. Only available on Linux
683 systems.
684 """
685 return DeviceAttributes(nvml.device_get_attributes_v2(self._handle)) 1w
687 #########################################################################
688 # DISPLAY
690 @property
691 def is_display_connected(self) -> bool:
692 """
693 The display mode for this device.
695 Indicates whether a physical display (e.g. monitor) is currently connected to
696 any of the device's connectors.
697 """
698 return nvml.device_get_display_mode(self._handle) == nvml.EnableState.FEATURE_ENABLED 1A
700 @property
701 def is_display_active(self) -> bool:
702 """
703 The display active status for this device.
705 Indicates whether a display is initialized on the device. For example,
706 whether X Server is attached to this device and has allocated memory for
707 the screen.
709 Display can be active even when no monitor is physically attached.
710 """
711 return nvml.device_get_display_active(self._handle) == nvml.EnableState.FEATURE_ENABLED 1A
713 ##########################################################################
714 # EVENTS
715 # See external class definitions in _event.pxi
717 def register_events(self, events: EventType | str | list[EventType | str]) -> DeviceEvents:
718 """
719 Starts recording events on this device.
721 For Fermi™ or newer fully supported devices. For Linux only.
723 ECC events are available only on ECC-enabled devices (see
724 :meth:`Device.get_total_ecc_errors`). Power capping events are
725 available only on Power Management enabled devices (see
726 :meth:`Device.get_power_management_mode`).
728 This call starts recording of events on specific device. All events
729 that occurred before this call are not recorded. Wait for events using
730 the :meth:`DeviceEvents.wait` method on the result.
732 Examples
733 --------
734 >>> device = Device(index=0)
735 >>> events = device.register_events([
736 ... EventType.XID_CRITICAL_ERROR,
737 ... ])
738 >>> while event := events.wait(timeout_ms=10000):
739 ... print(f"Event {event.event_type} occurred on device {event.device.uuid}")
741 Parameters
742 ----------
743 events: EventType, str, or list of EventType or str
744 The event type or list of event types to register for this device.
746 Returns
747 -------
748 :obj:`~_device.DeviceEvents`
749 An object representing the registered events. Call
750 :meth:`~_device.DeviceEvents.wait` on this object to wait for events.
752 Raises
753 ------
754 :class:`cuda.core.system.NotSupportedError`
755 None of the requested event types are registered.
756 """
757 return DeviceEvents(self._handle, events) 1i
759 def get_supported_event_types(self) -> list[EventType]:
760 """
761 Get the list of event types supported by this device.
763 For Fermi™ or newer fully supported devices. For Linux only (returns an
764 empty list on Windows).
766 Returns
767 -------
768 list[EventType]
769 The list of supported event types.
770 """
771 cdef uint64_t[1] bitmask
772 bitmask[0] = nvml.device_get_supported_event_types(self._handle) 1i
773 events = [] 1i
774 for ev in _unpack_bitmask(bitmask): 1i
775 try: 1i
776 ev_enum = _EVENT_TYPE_MAPPING[1 << ev] 1i
777 except KeyError:
778 raise ValueError(f"Unknown event type bit: {1 << ev}")
779 events.append(ev_enum) 1i
780 return events 1i
782 ##########################################################################
783 # FAN
784 # See external class definitions in _fan.pxi
786 def get_fan(self, fan: int = 0) -> FanInfo:
787 """
788 :obj:`~_device.FanInfo` object to get information and manage a specific fan on a device.
789 """
790 if fan < 0 or fan >= self.num_fans:
791 raise ValueError(f"Fan index {fan} is out of range [0, {self.num_fans})")
792 return FanInfo(self._handle, fan)
794 @property
795 def num_fans(self) -> int:
796 """
797 The number of fans on the device.
798 """
799 return nvml.device_get_num_fans(self._handle) 1JM
801 ##########################################################################
802 # FIELD VALUES
803 # See external class definitions in _field_values.pxi
805 def get_field_values(self, field_ids: list[int | tuple[int, int]]) -> FieldValues:
806 """
807 Get multiple field values from the device.
809 Each value specified can raise its own exception. That exception will
810 be raised when attempting to access the corresponding ``value`` from the
811 returned :obj:`~_device.FieldValues` container.
813 To confirm that there are no exceptions in the entire container, call
814 :meth:`~_device.FieldValues.validate`.
816 Parameters
817 ----------
818 field_ids: list[int | tuple[int, int]]
819 List of field IDs to query.
821 Each item may be either a single value from the :class:`FieldId`
822 enum, or a pair of (:class:`FieldId`, scope ID).
824 Returns
825 -------
826 :obj:`~_device.FieldValues`
827 Container of field values corresponding to the requested field IDs.
828 """
829 # Passing a field_ids array of length 0 raises an InvalidArgumentError,
830 # so avoid that.
831 if len(field_ids) == 0: 1lf30412
832 return FieldValues(nvml.FieldValue(0)) 1l
834 return FieldValues(nvml.device_get_field_values(self._handle, field_ids)) 1lf30412
836 def clear_field_values(self, field_ids: list[int | tuple[int, int]]) -> None:
837 """
838 Clear multiple field values from the device.
840 Parameters
841 ----------
842 field_ids: list[int | tuple[int, int]]
843 List of field IDs to clear.
845 Each item may be either a single value from the :class:`FieldId`
846 enum, or a pair of (:class:`FieldId`, scope ID).
847 """
848 # Passing a field_ids array of length 0 raises an InvalidArgumentError,
849 # so avoid that.
850 if len(field_ids) == 0: 1l
851 return
853 nvml.device_clear_field_values(self._handle, field_ids) 1l
855 ##########################################################################
856 # INFOROM
857 # See external class definitions in _inforom.pxi
859 @property
860 def inforom(self) -> InforomInfo:
861 """
862 :obj:`~_device.InforomInfo` object with InfoROM information.
864 For all products with an InfoROM.
865 """
866 return InforomInfo(self) 1B
868 ##########################################################################
869 # MEMORY
870 # See external class definitions in _memory.pxi
872 @property
873 def bar1_memory_info(self) -> BAR1MemoryInfo:
874 """
875 :obj:`~_device.BAR1MemoryInfo` object with BAR1 memory information.
877 BAR1 is used to map the FB (device memory) so that it can be directly
878 accessed by the CPU or by 3rd party devices (peer-to-peer on the PCIE
879 bus).
880 """
881 return BAR1MemoryInfo(nvml.device_get_bar1_memory_info(self._handle)) 1x
883 @property
884 def memory_info(self) -> MemoryInfo:
885 """
886 :obj:`~_device.MemoryInfo` object with memory information.
887 """
888 return MemoryInfo(nvml.device_get_memory_info_v2(self._handle)) 1y
890 ##########################################################################
891 # NVLINK
892 # See external class definitions in _nvlink.pxi
894 def get_nvlink(self, link: int) -> NvlinkInfo:
895 """
896 Get :obj:`~NvlinkInfo` about this device.
898 For devices with NVLink support.
900 .. version-changed:: 1.1.0
901 Any link number not supported by this specific device will raise a `ValueError`.
902 """
903 link_count = self.get_nvlink_count() 1f
904 if link < 0 or link >= link_count: 1f
905 raise ValueError(f"Link index {link} is out of range [0, {link_count})")
906 return NvlinkInfo(self, link) 1f
908 def get_nvlink_count(self) -> int:
909 """
910 Get the number of NVLink links on this device.
912 For devices with NVLink support.
914 .. version-added:: 1.1.0
915 """
916 return self.get_field_values([FieldId.DEV_NVLINK_LINK_COUNT])[0].value 1f30412
918 def get_nvlinks(self) -> Iterable[NvlinkInfo]:
919 """
920 Get :obj:`~NvlinkInfo` about all NVLink links on this device.
922 For devices with NVLink support.
924 .. version-added:: 1.1.0
925 """
926 for link in range(self.get_nvlink_count()): 1f012
927 yield self.get_nvlink(link) 1f
929 ##########################################################################
930 # PCI INFO
931 # See external class definitions in _pci_info.pxi
933 @property
934 def pci_info(self) -> PciInfo:
935 """
936 :obj:`~_device.PciInfo` object with the PCI attributes of this device.
938 Non-physical devices, such as MIG devices, may not have PCI attributes.
939 In that case, this property will raise a `RuntimeError`.
940 """
941 try: 1kqejm
942 pci_info = nvml.device_get_pci_info_ext(self._handle) 1kqejm
943 except nvml.InvalidArgumentError:
944 raise RuntimeError("This device does not have PCI attributes") from None
945 else:
946 return PciInfo(pci_info, self._handle) 1kqejm
948 ##########################################################################
949 # PERFORMANCE
950 # See external class definitions in _performance.pxi
952 @property
953 def performance_state(self) -> int | None:
954 """
955 The current performance state of the device.
957 For Fermi™ or newer fully supported devices.
959 Returns
960 -------
961 int | None
962 The current performance state of the device, as an integer between 0 and 15,
963 where 0 is maximum performance and higher numbers are lower performance.
964 Returns `None` if the performance state is unknown.
965 """
966 return _pstate_to_int(nvml.device_get_performance_state(self._handle)) 1gd
968 @property
969 def dynamic_pstates_info(self) -> GpuDynamicPstatesInfo:
970 """
971 :obj:`~_device.GpuDynamicPstatesInfo` object with performance monitor samples from the associated subdevice.
972 """
973 return GpuDynamicPstatesInfo(nvml.device_get_dynamic_pstates_info(self._handle)) 1d
975 @property
976 def supported_pstates(self) -> list[int]:
977 """
978 Get all supported Performance States (P-States) for the device.
980 The returned list contains a contiguous list of valid P-States supported by
981 the device.
983 Return
984 ------
985 list[int]
986 A list of supported performance state of the device, as an integer
987 between 0 and 15, where 0 is maximum performance and higher numbers
988 are lower performance.
989 """
990 # From nvml.h:
991 # The returned array would contain a contiguous list of valid P-States
992 # supported by the device. If the number of supported P-States is fewer
993 # than the size of the array supplied missing elements would contain \a
994 # NVML_PSTATE_UNKNOWN.
996 pstates = [] 1d
997 for pstate in nvml.device_get_supported_performance_states(self._handle): 1d
998 pstate_value = _pstate_to_int(pstate) 1d
999 if pstate_value is not None: 1d
1000 pstates.append(pstate_value) 1d
1001 return pstates 1d
1003 ##########################################################################
1004 # PROCESS
1005 # See external class definitions in _process.pxi
1007 @property
1008 def compute_running_processes(self) -> list[ProcessInfo]:
1009 """
1010 Get information about processes with a compute context on a device
1012 For Fermi™ or newer fully supported devices.
1014 This function returns information only about compute running processes
1015 (e.g. CUDA application which have active context). Any graphics
1016 applications (e.g. using OpenGL, DirectX) won't be listed by this
1017 function.
1019 Keep in mind that information returned by this call is dynamic and the
1020 number of elements might change in time.
1022 In MIG mode, if device handle is provided, the API returns aggregate
1023 information, only if the caller has appropriate privileges. Per-instance
1024 information can be queried by using specific MIG device handles.
1025 Querying per-instance information using MIG device handles is not
1026 supported if the device is in vGPU Host virtualization mode.
1027 """
1028 return [ProcessInfo(self, proc) for proc in nvml.device_get_compute_running_processes_v3(self._handle)] 1v
1030 ##########################################################################
1031 # REPAIR STATUS
1032 # See external class definitions in _repair_status.pxi
1034 @property
1035 def repair_status(self) -> RepairStatus:
1036 """
1037 :obj:`~_device.RepairStatus` object with TPC/Channel repair status.
1039 For Ampere™ or newer fully supported devices.
1040 """
1041 return RepairStatus(self._handle) 1F
1043 ##########################################################################
1044 # TEMPERATURE
1045 # See external class definitions in _temperature.pxi
1047 @property
1048 def temperature(self) -> Temperature:
1049 """
1050 :obj:`~_device.Temperature` object with temperature information for the device.
1051 """
1052 return Temperature(self._handle) 1TUG
1054 #######################################################################
1055 # TOPOLOGY
1057 def get_topology_nearest_gpus(self, level: GpuTopologyLevel | str) -> Iterable[Device]:
1058 """
1059 Retrieve the GPUs that are nearest to this device at a specific interconnectivity level.
1061 Supported on Linux only.
1063 Parameters
1064 ----------
1065 level: :class:`GpuTopologyLevel`
1066 The topology level.
1068 Returns
1069 -------
1070 Iterable of :class:`Device`
1071 The nearest devices at the given topology level.
1072 """
1073 cdef Device device
1074 try: 1ar
1075 level = _GPU_TOPOLOGY_LEVEL_MAPPING[level] 1ar
1076 except KeyError: 1a
1077 raise ValueError( 1a
1078 f"Invalid topology level: {level}. " 1a
1079 f"Must be one of {list(GpuTopologyLevel.__members__.values())}" 1a
1080 ) from None 1a
1081 for handle in nvml.device_get_topology_nearest_gpus(self._handle, level): 1r
1082 device = Device.__new__(Device)
1083 device._handle = handle
1084 yield device
1086 #######################################################################
1087 # UTILIZATION
1089 @property
1090 def utilization(self) -> Utilization:
1091 """
1092 Retrieves the current :obj:`~Utilization` rates for the device's major
1093 subsystems.
1095 For Fermi™ or newer fully supported devices.
1097 Note: During driver initialization when ECC is enabled one can see high
1098 GPU and Memory Utilization readings. This is caused by ECC Memory
1099 Scrubbing mechanism that is performed during driver initialization.
1101 Note: On MIG-enabled GPUs, querying device utilization rates is not
1102 currently supported.
1104 Returns
1105 -------
1106 Utilization
1107 An object containing the current utilization rates for the device.
1108 """
1109 return Utilization(nvml.device_get_utilization_rates(self._handle)) 1H
1112def get_topology_common_ancestor(Device device1 not None: Device, Device device2 not None: Device) -> GpuTopologyLevel:
1113 """
1114 Retrieve the common ancestor for two devices.
1116 For Linux only.
1118 Parameters
1119 ----------
1120 device1: :class:`Device`
1121 The first device.
1122 device2: :class:`Device`
1123 The second device.
1125 Returns
1126 -------
1127 :class:`GpuTopologyLevel`
1128 The common ancestor level of the two devices.
1129 """
1130 return _GPU_TOPOLOGY_LEVEL_INV_MAPPING[
1131 nvml.device_get_topology_common_ancestor(
1132 device1._handle,
1133 device2._handle,
1134 )
1135 ]
1138def get_p2p_status(Device device1 not None: Device, Device device2 not None: Device, index: GpuP2PCapsIndex | str) -> GpuP2PStatus:
1139 """
1140 Retrieve the P2P status between two devices.
1142 Parameters
1143 ----------
1144 device1: :class:`Device`
1145 The first device.
1146 device2: :class:`Device`
1147 The second device.
1148 index: :class:`GpuP2PCapsIndex` | str
1149 The P2P capability index being looked for between ``device1`` and ``device2``.
1151 Returns
1152 -------
1153 :class:`GpuP2PStatus`
1154 The P2P status between the two devices.
1155 """
1156 try: 1a
1157 index_enum = _GPU_P2P_CAPS_INDEX_MAPPING[index] 1a
1158 except KeyError: 1a
1159 raise ValueError( 1a
1160 f"Invalid P2P caps index: {index}. " 1a
1161 f"Must be one of {list(GpuP2PCapsIndex.__members__.values())}" 1a
1162 ) from None 1a
1163 return _GPU_P2P_STATUS_MAPPING.get(
1164 nvml.device_get_p2p_status(
1165 device1._handle,
1166 device2._handle,
1167 index_enum,
1168 ),
1169 GpuP2PStatus.UNKNOWN
1170 )
1173__all__ = [
1174 "Device",
1175 "get_p2p_status",
1176 "get_topology_common_ancestor",
1177 "NvlinkInfo",
1178]