Coverage for cuda/core/system/_device.pyx: 56.72%
268 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-16 01:23 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-16 01:23 +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: 1fc
45 return None 1c
46 assert ( 1fc
47 int(pstate) >= 0 and int(pstate) <= 15 1fc
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) 1fc
52cdef int _pstate_to_enum(int pstate):
53 if pstate < 0 or pstate > 15: 1f
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 nvml.BrandType.BRAND_NVIDIA_DLA: "NVIDIA DLA",
109 nvml.BrandType.BRAND_NVIDIA_VGAMEDEV: "NVIDIA vGameDev",
110 nvml.BrandType.BRAND_NVIDIA_NPU: "NVIDIA NPU",
111}
114_GPU_P2P_CAPS_INDEX_MAPPING = {
115 GpuP2PCapsIndex.READ: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_READ,
116 GpuP2PCapsIndex.WRITE: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_WRITE,
117 GpuP2PCapsIndex.NVLINK: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_NVLINK,
118 GpuP2PCapsIndex.ATOMICS: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_ATOMICS,
119 GpuP2PCapsIndex.PCI: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_PCI,
120 GpuP2PCapsIndex.PROP: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_PROP,
121 GpuP2PCapsIndex.UNKNOWN: nvml.GpuP2PCapsIndex.P2P_CAPS_INDEX_UNKNOWN,
122}
125_GPU_P2P_STATUS_MAPPING = {
126 nvml.GpuP2PStatus.P2P_STATUS_OK: GpuP2PStatus.OK,
127 nvml.GpuP2PStatus.P2P_STATUS_CHIPSET_NOT_SUPPORTED: GpuP2PStatus.CHIPSET_NOT_SUPPORTED,
128 nvml.GpuP2PStatus.P2P_STATUS_GPU_NOT_SUPPORTED: GpuP2PStatus.GPU_NOT_SUPPORTED,
129 nvml.GpuP2PStatus.P2P_STATUS_IOH_TOPOLOGY_NOT_SUPPORTED: GpuP2PStatus.IOH_TOPOLOGY_NOT_SUPPORTED,
130 nvml.GpuP2PStatus.P2P_STATUS_DISABLED_BY_REGKEY: GpuP2PStatus.DISABLED_BY_REGKEY,
131 nvml.GpuP2PStatus.P2P_STATUS_NOT_SUPPORTED: GpuP2PStatus.NOT_SUPPORTED,
132 nvml.GpuP2PStatus.P2P_STATUS_UNKNOWN: GpuP2PStatus.UNKNOWN,
133}
136_GPU_TOPOLOGY_LEVEL_MAPPING = {
137 GpuTopologyLevel.INTERNAL: nvml.GpuTopologyLevel.TOPOLOGY_INTERNAL,
138 GpuTopologyLevel.SINGLE: nvml.GpuTopologyLevel.TOPOLOGY_SINGLE,
139 GpuTopologyLevel.MULTIPLE: nvml.GpuTopologyLevel.TOPOLOGY_MULTIPLE,
140 GpuTopologyLevel.HOSTBRIDGE: nvml.GpuTopologyLevel.TOPOLOGY_HOSTBRIDGE,
141 GpuTopologyLevel.NODE: nvml.GpuTopologyLevel.TOPOLOGY_NODE,
142 GpuTopologyLevel.SYSTEM: nvml.GpuTopologyLevel.TOPOLOGY_SYSTEM,
143}
146_GPU_TOPOLOGY_LEVEL_INV_MAPPING = {v: k for k, v in _GPU_TOPOLOGY_LEVEL_MAPPING.items()}
149cdef class Device:
150 """
151 Representation of a device.
153 :class:`cuda.core.system.Device` provides access to various pieces of metadata
154 about devices and their topology, as provided by the NVIDIA Management
155 Library (NVML). To use CUDA with a device, use :class:`cuda.core.Device`.
157 Creating a device instance causes NVML to initialize the target GPU.
158 NVML may initialize additional GPUs if the target GPU is an SLI slave.
160 Parameters
161 ----------
162 index: int, optional
163 Integer representing the CUDA device index to get a handle to. Valid
164 values are between ``0`` and ``cuda.core.system.get_num_devices() - 1``.
166 The order in which devices are enumerated has no guarantees of
167 consistency between reboots. For that reason, it is recommended that
168 devices are looked up by their PCI ids or UUID.
170 uuid: bytes or str, optional
171 UUID of a CUDA device to get a handle to.
173 pci_bus_id: bytes or str, optional
174 PCI bus ID of a CUDA device to get a handle to.
176 Raises
177 ------
178 ValueError
179 If anything other than a single `index`, `uuid` or `pci_bus_id` are specified.
180 """
182 # This is made public for testing purposes only
183 cdef public intptr_t _handle
185 def __init__(
186 self,
187 *,
188 index: int | None = None,
189 uuid: bytes | str | None = None,
190 pci_bus_id: bytes | str | None = None,
191 ) -> None:
192 args = [index, uuid, pci_bus_id] 1sbtudfvJpawxKVhQyLkqzoAMlBNrOCDEgnciFTUGeHPjRSm
193 cdef int arg_count = sum(arg is not None for arg in args) 1sbtudfvJpawxKVhQyLkqzoAMlBNrOCDEgnciFTUGeHPjRSm
195 if arg_count > 1: 1sbtudfvJpawxKVhQyLkqzoAMlBNrOCDEgnciFTUGeHPjRSm
196 raise ValueError("Handle requires only one of `index`, `uuid`, or `pci_bus_id`.") 1V
197 if arg_count == 0: 1sbtudfvJpawxKVhQyLkqzoAMlBNrOCDEgnciFTUGeHPjRSm
198 raise ValueError("Handle requires either a device `index`, `uuid`, or `pci_bus_id`.") 1V
200 initialize() 1sbtudfvJpawxKhQyLkqzoAMlBNrOCDEgnciFTUGeHPjRSm
202 if index is not None: 1sbtudfvJpawxKhQyLkqzoAMlBNrOCDEgnciFTUGeHPjRSm
203 self._handle = nvml.device_get_handle_by_index_v2(index) 1sbtudfpawxKhyLzoAlBNrOCDEgnciFTUGeHP
204 elif uuid is not None: 1vJQkqMjRSm
205 if isinstance(uuid, bytes): 1vJQkqMjRSm
206 uuid = uuid.decode("ascii")
207 self._handle = nvml.device_get_handle_by_uuid(uuid) 1vJQkqMjRSm
208 elif pci_bus_id is not None: 1kj
209 if isinstance(pci_bus_id, bytes): 1kj
210 pci_bus_id = pci_bus_id.decode("ascii")
211 self._handle = nvml.device_get_handle_by_pci_bus_id_v2(pci_bus_id) 1kj
213 #########################################################################
214 # BASIC PROPERTIES
216 @property
217 def index(self) -> int:
218 """
219 The NVML index of this device.
221 Valid indices are derived from the count returned by
222 :meth:`Device.get_device_count`. For example, if ``get_device_count()``
223 returns 2, the valid indices are 0 and 1, corresponding to GPU 0 and GPU
224 1.
226 The order in which NVML enumerates devices has no guarantees of
227 consistency between reboots. For that reason, it is recommended that
228 devices be looked up by their PCI ids or GPU UUID.
230 Note: The NVML index may not correlate with other APIs, such as the CUDA
231 device index.
232 """
233 return nvml.device_get_index(self._handle) 1sbtudfvJwxhykqzMlIBOCDEgncFGeHj
235 @property
236 def uuid(self) -> str:
237 """
238 Retrieves the globally unique immutable UUID associated with this
239 device, as a 5 part hexadecimal string, that augments the immutable,
240 board serial identifier.
242 Returns the UUID exactly as reported by NVML. It usually includes a
243 ``GPU-``, ``MIG-``, or ``DLA-`` prefix, but some platforms report an
244 unprefixed UUID. To interact with CUDA, use the `uuid_without_prefix`
245 property.
246 """
247 return nvml.device_get_uuid(self._handle) 1oePWXYZm
249 @property
250 def uuid_without_prefix(self) -> str:
251 """
252 Retrieves the globally unique immutable UUID associated with this
253 device, as a 5 part hexadecimal string, that augments the immutable,
254 board serial identifier.
256 Removes a ``GPU-``, ``MIG-``, or ``DLA-`` prefix when present, to match
257 the UUIDs used in CUDA. An already unprefixed UUID is returned
258 unchanged. For the UUID exactly as reported by NVML, use the `uuid`
259 property.
260 """
261 uuid = self.uuid 1oeWXYZm
262 if uuid.startswith(("GPU-", "MIG-", "DLA-")): 1oeWXYZm
263 return uuid[4:] 1oeWXYm
264 return uuid 1Z
266 @property
267 def pci_bus_id(self) -> str:
268 """
269 Retrieves the PCI bus ID of this device.
270 """
271 return self.pci_info.bus_id 1j
273 @property
274 def numa_node_id(self) -> int:
275 """
276 The NUMA node of the given GPU device.
278 This only applies to platforms where the GPUs are NUMA nodes.
279 """
280 return nvml.device_get_numa_node_id(self._handle) 1E
282 @property
283 def arch(self) -> DeviceArch:
284 """
285 :obj:`~DeviceArch` device architecture.
287 For example, a Tesla V100 will report ``DeviceArchitecture.name ==
288 "VOLTA"``, and RTX A6000 will report ``DeviceArchitecture.name ==
289 "AMPERE"``.
290 """
291 arch = nvml.device_get_architecture(self._handle) 1p
292 try: 1p
293 return DeviceArch(arch) 1p
294 except ValueError:
295 return DeviceArch.UNKNOWN
297 @property
298 def name(self) -> str:
299 """
300 Name of the device, e.g.: `"Tesla V100-SXM2-32GB"`
301 """
302 return nvml.device_get_name(self._handle) 1L
304 @property
305 def brand(self) -> str:
306 """
307 The brand of the device.
309 Returns "Unknown" if the brand is unknown.
310 """
311 return _BRAND_TYPE_MAPPING.get(nvml.device_get_brand(self._handle), "Unknown") 1K
313 @property
314 def serial(self) -> str:
315 """
316 Retrieves the globally unique board serial number associated with this
317 device's board.
319 For all products with an InfoROM.
320 """
321 return nvml.device_get_serial(self._handle) 1z
323 @property
324 def module_id(self) -> int:
325 """
326 Get a unique identifier for the device module on the baseboard.
328 This API retrieves a unique identifier for each GPU module that exists
329 on a given baseboard. For non-baseboard products, this ID would always
330 be 0.
331 """
332 return nvml.device_get_module_id(self._handle) 1D
334 @property
335 def minor_number(self) -> int:
336 """
337 The minor number of this device.
339 For Linux only.
341 The minor number is used by the Linux device driver to identify the
342 device node in ``/dev/nvidiaX``.
343 """
344 return nvml.device_get_minor_number(self._handle) 1N
346 @property
347 def is_c2c_enabled(self) -> bool:
348 """
349 Whether the C2C (Chip-to-Chip) mode is enabled for this device.
350 """
351 return bool(nvml.device_get_c2c_mode_info_v(self._handle).is_c2c_enabled) 1u
353 @property
354 def is_persistence_mode_enabled(self) -> bool:
355 """
356 Whether persistence mode is enabled for this device.
358 For Linux only.
359 """
360 return nvml.device_get_persistence_mode(self._handle) == nvml.EnableState.FEATURE_ENABLED 1n
362 @is_persistence_mode_enabled.setter
363 def is_persistence_mode_enabled(self, enabled: bool) -> None:
364 nvml.device_set_persistence_mode( 1n
365 self._handle, 1n
366 nvml.EnableState.FEATURE_ENABLED if enabled else nvml.EnableState.FEATURE_DISABLED 1n
367 )
369 @property
370 def cuda_compute_capability(self) -> tuple[int, int]:
371 """
372 CUDA compute capability of the device, e.g.: `(7, 0)` for a Tesla V100.
374 Returns a tuple `(major, minor)`.
375 """
376 return nvml.device_get_cuda_compute_capability(self._handle) 1Q
378 def to_cuda_device(self) -> "cuda.core.Device":
379 """
380 Get the corresponding :class:`cuda.core.Device` (which is used for CUDA
381 access) for this :class:`cuda.core.system.Device` (which is used for
382 NVIDIA Management Library (NVML) access).
384 The devices are mapped to one another by their UUID.
386 Returns
387 -------
388 cuda.core.Device
389 The corresponding CUDA device.
391 Raises
392 ------
393 RuntimeError
394 No corresponding CUDA device is found for this NVML device.
396 For example, on a MIG system, the physical GPU will not have an
397 available CUDA device, since it can not be used directly, even
398 though it can be enumerated from NVML.
399 """
400 from cuda.core import Device as CudaDevice 1e
402 # CUDA does not have an API to get a device by its UUID, so we just
403 # search all the devices for one with a matching UUID.
405 for cuda_device in CudaDevice.get_all_devices(): 1e
406 if cuda_device.uuid == self.uuid_without_prefix: 1e
407 return cuda_device 1e
409 raise RuntimeError("No corresponding CUDA device found for this NVML device.")
411 @classmethod
412 def get_device_count(cls) -> int:
413 """
414 Get the number of available devices.
416 Returns
417 -------
418 int
419 The number of available devices.
420 """
421 initialize() 1567
423 return nvml.device_get_count_v2() 1567
425 @classmethod
426 def get_all_devices(cls) -> Iterable[Device]:
427 """
428 Query the available device instances.
430 Returns
431 -------
432 Iterator over :obj:`~Device`
433 An iterator over available devices.
434 """
435 initialize() 1sbtudfpwxKhyLzoAlBNrOCDEgnciFGeHP
437 for device_id in range(nvml.device_get_count_v2()): 1sbtudfpwxKhyLzoAlBNrOCDEgnciFGeHP
438 yield cls(index=device_id) 1sbtudfpwxKhyLzoAlBNrOCDEgnciFGeHP
440 #########################################################################
441 # ADDRESSING MODE
443 @property
444 def addressing_mode(self) -> AddressingMode | None:
445 """
446 Get the :obj:`~AddressingMode` of the device.
447 """
448 return _ADDRESSING_MODE_MAPPING.get(nvml.device_get_addressing_mode(self._handle).value, None) 1s
450 #########################################################################
451 # MIG (MULTI-INSTANCE GPU) DEVICES
453 @property
454 def mig(self) -> MigInfo:
455 """
456 Get :obj:`~MigInfo` accessor for MIG (Multi-Instance GPU) information.
458 For Ampere™ or newer fully supported devices.
459 """
460 return MigInfo(self) 1vC
462 #########################################################################
463 # AFFINITY
465 @classmethod
466 def get_all_devices_with_cpu_affinity(cls, cpu_index: int) -> Iterable[Device]:
467 """
468 Retrieve the set of GPUs that have a CPU affinity with the given CPU number.
470 Supported on Linux only.
472 Parameters
473 ----------
474 cpu_index: int
475 The CPU index.
477 Returns
478 -------
479 Iterator of :obj:`~Device`
480 An iterator over available devices.
481 """
482 cdef Device device
483 for handle in nvml.system_get_topology_gpu_set(cpu_index): 1I
484 device = Device.__new__(Device) 1I
485 device._handle = handle 1I
486 yield device 1I
488 def get_memory_affinity(self, scope: AffinityScope | str=AffinityScope.NODE) -> list[int]:
489 """
490 Retrieves a list of indices of NUMA nodes or CPU sockets with the ideal
491 memory affinity for the device.
493 For Kepler™ or newer fully supported devices.
495 Supported on Linux only.
497 If requested scope is not applicable to the target topology, the API
498 will fall back to reporting the memory affinity for the immediate non-I/O
499 ancestor of the device.
501 Parameters
502 ----------
503 scope: AffinityScope | str, optional
504 The scope of the affinity query. Must be one of the values of
505 :class:`AffinityScope`. Default is :attr:`AffinityScope.NODE`.
507 Returns
508 -------
509 list[int]
510 A list of indices of NUMA nodes or CPU sockets with the ideal memory
511 affinity for the device.
512 """
513 try: 1ba
514 scope = _AFFINITY_SCOPE_MAPPING[scope] 1ba
515 except KeyError: 1a
516 raise ValueError( 1a
517 f"Invalid affinity scope: {scope}. " 1a
518 f"Must be one of {list(AffinityScope.__members__.values())}" 1a
519 ) from None 1a
520 return _unpack_bitmask( 1b
521 nvml.device_get_memory_affinity( 1b
522 self._handle, 1b
523 <unsigned int>ceil(cpu_count() / 64), 1b
524 scope, 1b
525 )
526 )
528 def get_cpu_affinity(self, scope: AffinityScope | str=AffinityScope.NODE) -> list[int]:
529 """
530 Retrieves a list of indices of NUMA nodes or CPU sockets with the ideal
531 CPU affinity for the device.
533 For Kepler™ or newer fully supported devices.
535 Supported on Linux only.
537 If requested scope is not applicable to the target topology, the API
538 will fall back to reporting the memory affinity for the immediate non-I/O
539 ancestor of the device.
541 Parameters
542 ----------
543 scope: AffinityScope | str, optional
544 The scope of the affinity query. Must be one of the values of
545 :class:`AffinityScope`. Default is :attr:`AffinityScope.NODE`.
547 Returns
548 -------
549 list[int]
550 A list of indices of NUMA nodes or CPU sockets with the ideal memory
551 affinity for the device.
552 """
553 try: 1bahI
554 scope = _AFFINITY_SCOPE_MAPPING[scope] 1bahI
555 except KeyError: 1a
556 raise ValueError( 1a
557 f"Invalid affinity scope: {scope}. " 1a
558 f"Must be one of {list(AffinityScope.__members__.values())}" 1a
559 ) from None 1a
560 return _unpack_bitmask( 1bhI
561 nvml.device_get_cpu_affinity_within_scope( 1bhI
562 self._handle, 1bhI
563 <unsigned int>ceil(cpu_count() / 64), 1bhI
564 scope, 1bhI
565 )
566 )
568 def set_cpu_affinity(self) -> None:
569 """
570 Sets the ideal affinity for the calling thread and device.
572 For Kepler™ or newer fully supported devices.
574 Supported on Linux only.
575 """
576 nvml.device_set_cpu_affinity(self._handle)
578 def clear_cpu_affinity(self) -> None:
579 """
580 Clear all affinity bindings for the calling thread.
582 For Kepler™ or newer fully supported devices.
584 Supported on Linux only.
585 """
586 nvml.device_clear_cpu_affinity(self._handle)
588 #########################################################################
589 # CLOCK
590 # See external class definitions in _clock.pxi
592 def get_clock(self, clock_type: ClockType | str) -> ClockInfo:
593 """
594 :obj:`~_device.ClockInfo` object to get information about and manage a specific clock on a device.
595 """
596 return ClockInfo(self._handle, clock_type) 1f
598 @property
599 def is_auto_boosted_clocks_enabled(self) -> tuple[bool, bool]:
600 """
601 Retrieve the current state of auto boosted clocks on a device.
603 For Kepler™ or newer fully supported devices.
605 Auto Boosted clocks are enabled by default on some hardware, allowing
606 the GPU to run at higher clock rates to maximize performance as thermal
607 limits allow.
609 On Pascal™ and newer hardware, Auto Boosted clocks are controlled
610 through application clocks. Use :meth:`set_application_clocks` and
611 :meth:`reset_application_clocks` to control Auto Boost behavior.
613 Returns
614 -------
615 bool
616 The current state of Auto Boosted clocks
617 bool
618 The default Auto Boosted clocks behavior
620 """
621 current, default = nvml.device_get_auto_boosted_clocks_enabled(self._handle) 1t
622 return current == nvml.EnableState.FEATURE_ENABLED, default == nvml.EnableState.FEATURE_ENABLED
624 @property
625 def current_clock_event_reasons(self) -> list[ClocksEventReasons]:
626 """
627 Retrieves the current :obj:`~ClocksEventReasons`.
629 For all fully supported products.
630 """
631 cdef uint64_t[1] reasons
632 reasons[0] = nvml.device_get_current_clocks_event_reasons(self._handle) 1d
633 output_reasons = [] 1d
634 for reason in _unpack_bitmask(reasons): 1d
635 try:
636 output_reason = _CLOCKS_EVENT_REASONS_MAPPING[1 << reason]
637 except KeyError:
638 raise ValueError(f"Unknown clock event reason bit: {1 << reason}")
639 output_reasons.append(output_reason)
640 return output_reasons 1d
642 @property
643 def supported_clock_event_reasons(self) -> list[ClocksEventReasons]:
644 """
645 Retrieves supported :obj:`~ClocksEventReasons` that can be returned by
646 :meth:`get_current_clock_event_reasons`.
648 For all fully supported products.
650 This method is not supported in virtual machines running virtual GPU (vGPU).
651 """
652 cdef uint64_t[1] reasons
653 reasons[0] = nvml.device_get_supported_clocks_event_reasons(self._handle) 1d
654 output_reasons = [] 1d
655 for reason in _unpack_bitmask(reasons): 1d
656 try: 1d
657 output_reason = _CLOCKS_EVENT_REASONS_MAPPING[1 << reason] 1d
658 except KeyError:
659 raise ValueError(f"Unknown clock event reason bit: {1 << reason}")
660 output_reasons.append(output_reason) 1d
661 return output_reasons 1d
663 ##########################################################################
664 # COOLER
665 # See external class definitions in _cooler.pxi
667 @property
668 def cooler(self) -> CoolerInfo:
669 """
670 :obj:`~_device.CoolerInfo` object with cooler information for the device.
671 """
672 return CoolerInfo(nvml.device_get_cooler_info(self._handle))
674 ##########################################################################
675 # DEVICE ATTRIBUTES
676 # See external class definitions in _device_attributes.pxi
678 @property
679 def attributes(self) -> DeviceAttributes:
680 """
681 :obj:`~_device.DeviceAttributes` object with various device attributes.
683 For Ampere™ or newer fully supported devices. Only available on Linux
684 systems.
685 """
686 return DeviceAttributes(nvml.device_get_attributes_v2(self._handle)) 1w
688 #########################################################################
689 # DISPLAY
691 @property
692 def is_display_connected(self) -> bool:
693 """
694 The display mode for this device.
696 Indicates whether a physical display (e.g. monitor) is currently connected to
697 any of the device's connectors.
698 """
699 return nvml.device_get_display_mode(self._handle) == nvml.EnableState.FEATURE_ENABLED 1A
701 @property
702 def is_display_active(self) -> bool:
703 """
704 The display active status for this device.
706 Indicates whether a display is initialized on the device. For example,
707 whether X Server is attached to this device and has allocated memory for
708 the screen.
710 Display can be active even when no monitor is physically attached.
711 """
712 return nvml.device_get_display_active(self._handle) == nvml.EnableState.FEATURE_ENABLED 1A
714 ##########################################################################
715 # EVENTS
716 # See external class definitions in _event.pxi
718 def register_events(self, events: EventType | str | list[EventType | str]) -> DeviceEvents:
719 """
720 Starts recording events on this device.
722 For Fermi™ or newer fully supported devices. For Linux only.
724 ECC events are available only on ECC-enabled devices (see
725 :meth:`Device.get_total_ecc_errors`). Power capping events are
726 available only on Power Management enabled devices (see
727 :meth:`Device.get_power_management_mode`).
729 This call starts recording of events on specific device. All events
730 that occurred before this call are not recorded. Wait for events using
731 the :meth:`DeviceEvents.wait` method on the result.
733 Examples
734 --------
735 >>> device = Device(index=0)
736 >>> events = device.register_events([
737 ... EventType.XID_CRITICAL_ERROR,
738 ... ])
739 >>> while event := events.wait(timeout_ms=10000):
740 ... print(f"Event {event.event_type} occurred on device {event.device.uuid}")
742 Parameters
743 ----------
744 events: EventType, str, or list of EventType or str
745 The event type or list of event types to register for this device.
747 Returns
748 -------
749 :obj:`~_device.DeviceEvents`
750 An object representing the registered events. Call
751 :meth:`~_device.DeviceEvents.wait` on this object to wait for events.
753 Raises
754 ------
755 :class:`cuda.core.system.NotSupportedError`
756 None of the requested event types are registered.
757 """
758 return DeviceEvents(self._handle, events) 1i
760 def get_supported_event_types(self) -> list[EventType]:
761 """
762 Get the list of event types supported by this device.
764 For Fermi™ or newer fully supported devices. For Linux only (returns an
765 empty list on Windows).
767 Returns
768 -------
769 list[EventType]
770 The list of supported event types.
771 """
772 cdef uint64_t[1] bitmask
773 bitmask[0] = nvml.device_get_supported_event_types(self._handle) 1i
774 events = [] 1i
775 for ev in _unpack_bitmask(bitmask): 1i
776 try: 1i
777 ev_enum = _EVENT_TYPE_MAPPING[1 << ev] 1i
778 except KeyError:
779 raise ValueError(f"Unknown event type bit: {1 << ev}")
780 events.append(ev_enum) 1i
781 return events 1i
783 ##########################################################################
784 # FAN
785 # See external class definitions in _fan.pxi
787 def get_fan(self, fan: int = 0) -> FanInfo:
788 """
789 :obj:`~_device.FanInfo` object to get information and manage a specific fan on a device.
790 """
791 if fan < 0 or fan >= self.num_fans:
792 raise ValueError(f"Fan index {fan} is out of range [0, {self.num_fans})")
793 return FanInfo(self._handle, fan)
795 @property
796 def num_fans(self) -> int:
797 """
798 The number of fans on the device.
799 """
800 return nvml.device_get_num_fans(self._handle) 1JM
802 ##########################################################################
803 # FIELD VALUES
804 # See external class definitions in _field_values.pxi
806 def get_field_values(self, field_ids: list[int | tuple[int, int]]) -> FieldValues:
807 """
808 Get multiple field values from the device.
810 Each value specified can raise its own exception. That exception will
811 be raised when attempting to access the corresponding ``value`` from the
812 returned :obj:`~_device.FieldValues` container.
814 To confirm that there are no exceptions in the entire container, call
815 :meth:`~_device.FieldValues.validate`.
817 Parameters
818 ----------
819 field_ids: list[int | tuple[int, int]]
820 List of field IDs to query.
822 Each item may be either a single value from the :class:`FieldId`
823 enum, or a pair of (:class:`FieldId`, scope ID).
825 Returns
826 -------
827 :obj:`~_device.FieldValues`
828 Container of field values corresponding to the requested field IDs.
829 """
830 # Passing a field_ids array of length 0 raises an InvalidArgumentError,
831 # so avoid that.
832 if len(field_ids) == 0: 1lg30412
833 return FieldValues(nvml.FieldValue(0)) 1l
835 return FieldValues(nvml.device_get_field_values(self._handle, field_ids)) 1lg30412
837 def clear_field_values(self, field_ids: list[int | tuple[int, int]]) -> None:
838 """
839 Clear multiple field values from the device.
841 Parameters
842 ----------
843 field_ids: list[int | tuple[int, int]]
844 List of field IDs to clear.
846 Each item may be either a single value from the :class:`FieldId`
847 enum, or a pair of (:class:`FieldId`, scope ID).
848 """
849 # Passing a field_ids array of length 0 raises an InvalidArgumentError,
850 # so avoid that.
851 if len(field_ids) == 0: 1l
852 return
854 nvml.device_clear_field_values(self._handle, field_ids) 1l
856 ##########################################################################
857 # INFOROM
858 # See external class definitions in _inforom.pxi
860 @property
861 def inforom(self) -> InforomInfo:
862 """
863 :obj:`~_device.InforomInfo` object with InfoROM information.
865 For all products with an InfoROM.
866 """
867 return InforomInfo(self) 1B
869 ##########################################################################
870 # MEMORY
871 # See external class definitions in _memory.pxi
873 @property
874 def bar1_memory_info(self) -> BAR1MemoryInfo:
875 """
876 :obj:`~_device.BAR1MemoryInfo` object with BAR1 memory information.
878 BAR1 is used to map the FB (device memory) so that it can be directly
879 accessed by the CPU or by 3rd party devices (peer-to-peer on the PCIE
880 bus).
881 """
882 return BAR1MemoryInfo(nvml.device_get_bar1_memory_info(self._handle)) 1x
884 @property
885 def memory_info(self) -> MemoryInfo:
886 """
887 :obj:`~_device.MemoryInfo` object with memory information.
888 """
889 return MemoryInfo(nvml.device_get_memory_info_v2(self._handle)) 1y
891 ##########################################################################
892 # NVLINK
893 # See external class definitions in _nvlink.pxi
895 def get_nvlink(self, link: int) -> NvlinkInfo:
896 """
897 Get :obj:`~NvlinkInfo` about this device.
899 For devices with NVLink support.
901 .. version-changed:: 1.1.0
902 Any link number not supported by this specific device will raise a `ValueError`.
903 """
904 link_count = self.get_nvlink_count() 1g
905 if link < 0 or link >= link_count: 1g
906 raise ValueError(f"Link index {link} is out of range [0, {link_count})")
907 return NvlinkInfo(self, link) 1g
909 def get_nvlink_count(self) -> int:
910 """
911 Get the number of NVLink links on this device.
913 For devices with NVLink support.
915 .. version-added:: 1.1.0
916 """
917 return self.get_field_values([FieldId.DEV_NVLINK_LINK_COUNT])[0].value 1g30412
919 def get_nvlinks(self) -> Iterable[NvlinkInfo]:
920 """
921 Get :obj:`~NvlinkInfo` about all NVLink links on this device.
923 For devices with NVLink support.
925 .. version-added:: 1.1.0
926 """
927 for link in range(self.get_nvlink_count()): 1g012
928 yield self.get_nvlink(link) 1g
930 ##########################################################################
931 # PCI INFO
932 # See external class definitions in _pci_info.pxi
934 @property
935 def pci_info(self) -> PciInfo:
936 """
937 :obj:`~_device.PciInfo` object with the PCI attributes of this device.
939 Non-physical devices, such as MIG devices, may not have PCI attributes.
940 In that case, this property will raise a `RuntimeError`.
941 """
942 try: 1kqejm
943 pci_info = nvml.device_get_pci_info_ext(self._handle) 1kqejm
944 except nvml.InvalidArgumentError:
945 raise RuntimeError("This device does not have PCI attributes") from None
946 else:
947 return PciInfo(pci_info, self._handle) 1kqejm
949 ##########################################################################
950 # PERFORMANCE
951 # See external class definitions in _performance.pxi
953 @property
954 def performance_state(self) -> int | None:
955 """
956 The current performance state of the device.
958 For Fermi™ or newer fully supported devices.
960 Returns
961 -------
962 int | None
963 The current performance state of the device, as an integer between 0 and 15,
964 where 0 is maximum performance and higher numbers are lower performance.
965 Returns `None` if the performance state is unknown.
966 """
967 return _pstate_to_int(nvml.device_get_performance_state(self._handle)) 1fc
969 @property
970 def dynamic_pstates_info(self) -> GpuDynamicPstatesInfo:
971 """
972 :obj:`~_device.GpuDynamicPstatesInfo` object with performance monitor samples from the associated subdevice.
973 """
974 return GpuDynamicPstatesInfo(nvml.device_get_dynamic_pstates_info(self._handle)) 1c
976 @property
977 def supported_pstates(self) -> list[int]:
978 """
979 Get all supported Performance States (P-States) for the device.
981 The returned list contains a contiguous list of valid P-States supported by
982 the device.
984 Return
985 ------
986 list[int]
987 A list of supported performance state of the device, as an integer
988 between 0 and 15, where 0 is maximum performance and higher numbers
989 are lower performance.
990 """
991 # From nvml.h:
992 # The returned array would contain a contiguous list of valid P-States
993 # supported by the device. If the number of supported P-States is fewer
994 # than the size of the array supplied missing elements would contain \a
995 # NVML_PSTATE_UNKNOWN.
997 pstates = [] 1c
998 for pstate in nvml.device_get_supported_performance_states(self._handle): 1c
999 pstate_value = _pstate_to_int(pstate) 1c
1000 if pstate_value is not None: 1c
1001 pstates.append(pstate_value) 1c
1002 return pstates 1c
1004 ##########################################################################
1005 # PROCESS
1006 # See external class definitions in _process.pxi
1008 @property
1009 def compute_running_processes(self) -> list[ProcessInfo]:
1010 """
1011 Get information about processes with a compute context on a device
1013 For Fermi™ or newer fully supported devices.
1015 This function returns information only about compute running processes
1016 (e.g. CUDA application which have active context). Any graphics
1017 applications (e.g. using OpenGL, DirectX) won't be listed by this
1018 function.
1020 Keep in mind that information returned by this call is dynamic and the
1021 number of elements might change in time.
1023 In MIG mode, if device handle is provided, the API returns aggregate
1024 information, only if the caller has appropriate privileges. Per-instance
1025 information can be queried by using specific MIG device handles.
1026 Querying per-instance information using MIG device handles is not
1027 supported if the device is in vGPU Host virtualization mode.
1028 """
1029 return [ProcessInfo(self, proc) for proc in nvml.device_get_compute_running_processes_v3(self._handle)] 1v
1031 ##########################################################################
1032 # REPAIR STATUS
1033 # See external class definitions in _repair_status.pxi
1035 @property
1036 def repair_status(self) -> RepairStatus:
1037 """
1038 :obj:`~_device.RepairStatus` object with TPC/Channel repair status.
1040 For Ampere™ or newer fully supported devices.
1041 """
1042 return RepairStatus(self._handle) 1F
1044 ##########################################################################
1045 # TEMPERATURE
1046 # See external class definitions in _temperature.pxi
1048 @property
1049 def temperature(self) -> Temperature:
1050 """
1051 :obj:`~_device.Temperature` object with temperature information for the device.
1052 """
1053 return Temperature(self._handle) 1TUG
1055 #######################################################################
1056 # TOPOLOGY
1058 def get_topology_nearest_gpus(self, level: GpuTopologyLevel | str) -> Iterable[Device]:
1059 """
1060 Retrieve the GPUs that are nearest to this device at a specific interconnectivity level.
1062 Supported on Linux only.
1064 Parameters
1065 ----------
1066 level: :class:`GpuTopologyLevel`
1067 The topology level.
1069 Returns
1070 -------
1071 Iterable of :class:`Device`
1072 The nearest devices at the given topology level.
1073 """
1074 cdef Device device
1075 try: 1ar
1076 level = _GPU_TOPOLOGY_LEVEL_MAPPING[level] 1ar
1077 except KeyError: 1a
1078 raise ValueError( 1a
1079 f"Invalid topology level: {level}. " 1a
1080 f"Must be one of {list(GpuTopologyLevel.__members__.values())}" 1a
1081 ) from None 1a
1082 for handle in nvml.device_get_topology_nearest_gpus(self._handle, level): 1r
1083 device = Device.__new__(Device)
1084 device._handle = handle
1085 yield device
1087 #######################################################################
1088 # UTILIZATION
1090 @property
1091 def utilization(self) -> Utilization:
1092 """
1093 Retrieves the current :obj:`~Utilization` rates for the device's major
1094 subsystems.
1096 For Fermi™ or newer fully supported devices.
1098 Note: During driver initialization when ECC is enabled one can see high
1099 GPU and Memory Utilization readings. This is caused by ECC Memory
1100 Scrubbing mechanism that is performed during driver initialization.
1102 Note: On MIG-enabled GPUs, querying device utilization rates is not
1103 currently supported.
1105 Returns
1106 -------
1107 Utilization
1108 An object containing the current utilization rates for the device.
1109 """
1110 return Utilization(nvml.device_get_utilization_rates(self._handle)) 1H
1113def get_topology_common_ancestor(Device device1 not None: Device, Device device2 not None: Device) -> GpuTopologyLevel:
1114 """
1115 Retrieve the common ancestor for two devices.
1117 For Linux only.
1119 Parameters
1120 ----------
1121 device1: :class:`Device`
1122 The first device.
1123 device2: :class:`Device`
1124 The second device.
1126 Returns
1127 -------
1128 :class:`GpuTopologyLevel`
1129 The common ancestor level of the two devices.
1130 """
1131 return _GPU_TOPOLOGY_LEVEL_INV_MAPPING[
1132 nvml.device_get_topology_common_ancestor(
1133 device1._handle,
1134 device2._handle,
1135 )
1136 ]
1139def get_p2p_status(Device device1 not None: Device, Device device2 not None: Device, index: GpuP2PCapsIndex | str) -> GpuP2PStatus:
1140 """
1141 Retrieve the P2P status between two devices.
1143 Parameters
1144 ----------
1145 device1: :class:`Device`
1146 The first device.
1147 device2: :class:`Device`
1148 The second device.
1149 index: :class:`GpuP2PCapsIndex` | str
1150 The P2P capability index being looked for between ``device1`` and ``device2``.
1152 Returns
1153 -------
1154 :class:`GpuP2PStatus`
1155 The P2P status between the two devices.
1156 """
1157 try: 1a
1158 index_enum = _GPU_P2P_CAPS_INDEX_MAPPING[index] 1a
1159 except KeyError: 1a
1160 raise ValueError( 1a
1161 f"Invalid P2P caps index: {index}. " 1a
1162 f"Must be one of {list(GpuP2PCapsIndex.__members__.values())}" 1a
1163 ) from None 1a
1164 return _GPU_P2P_STATUS_MAPPING.get(
1165 nvml.device_get_p2p_status(
1166 device1._handle,
1167 device2._handle,
1168 index_enum,
1169 ),
1170 GpuP2PStatus.UNKNOWN
1171 )
1174__all__ = [
1175 "Device",
1176 "get_p2p_status",
1177 "get_topology_common_ancestor",
1178 "NvlinkInfo",
1179]