Skip to content

Commit d95ad86

Browse files
rwgkisVoid
andauthored
Use the CUDA driver for cuda.core device enumeration (#2674)
* Use CUDA driver for CUDA device enumeration * Adapt CUDA device enumeration to current main Update the newer foreign-context test to use the CUDA-visible device count and regenerate the Device stub after applying the original public PR #2533 change. --------- Co-authored-by: isvoid <isVoid@users.noreply.github.com>
1 parent f1152a2 commit d95ad86

14 files changed

Lines changed: 50 additions & 40 deletions

cuda_core/cuda/core/_device.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,8 @@ class Device:
500500
tuple of Device
501501
A tuple containing instances of available devices.
502502
"""
503+
@classmethod
504+
def _get_all_devices_from_cuda_driver(cls): ...
503505
def to_system_device(self) -> cuda.core.system.Device:
504506
"""
505507
Get the corresponding :class:`cuda.core.system.Device` (which is used

cuda_core/cuda/core/_device.pyx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,9 +1033,12 @@ class Device:
10331033
tuple of Device
10341034
A tuple containing instances of available devices.
10351035
"""
1036-
from cuda.core import system
1037-
total = system.get_num_devices()
1038-
return tuple(cls(device_id) for device_id in range(total))
1036+
return cls._get_all_devices_from_cuda_driver()
1037+
1038+
@classmethod
1039+
def _get_all_devices_from_cuda_driver(cls):
1040+
Device_ensure_cuda_initialized()
1041+
return tuple(Device_ensure_tls_devices(cls))
10391042

10401043
def to_system_device(self) -> 'cuda.core.system.Device':
10411044
"""

cuda_core/docs/source/release/1.2.0-notes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,11 @@ Fixes and enhancements
172172
not worth a warning.
173173
(closes `#2640 <https://github.com/NVIDIA/cuda-python/issues/2640>`__)
174174

175+
- CUDA device enumeration now queries the CUDA driver rather than using the
176+
NVML system-device count. This prevents non-CUDA accelerators, such as an NPU,
177+
from being treated as CUDA devices by :meth:`Device.get_all_devices`, examples,
178+
and tests.
179+
175180
Deprecation Notices
176181
-------------------
177182

cuda_core/examples/show_device_properties.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
import sys
1717

18-
from cuda.core import Device, system
18+
from cuda.core import Device
1919

2020

2121
# Convert boolean to YES or NO string
@@ -219,11 +219,12 @@ def print_device_properties(properties):
219219

220220
# Print info about all CUDA devices in the system
221221
def show_device_properties():
222-
ndev = system.get_num_devices()
222+
devices = Device.get_all_devices()
223+
ndev = len(devices)
223224
print(f"Number of GPUs: {ndev}")
224225

225-
for device_id in range(ndev):
226-
device = Device(device_id)
226+
for device in devices:
227+
device_id = device.device_id
227228
print(f"DEVICE {device.name} (id={device_id})")
228229

229230
device.set_current()

cuda_core/examples/simple_multi_gpu_example.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import cupy as cp
1919

20-
from cuda.core import Device, LaunchConfig, Program, ProgramOptions, launch, system
20+
from cuda.core import Device, LaunchConfig, Program, ProgramOptions, launch
2121

2222
dtype = cp.float32
2323
size = 50000
@@ -35,7 +35,7 @@ def __cuda_stream__(self):
3535

3636

3737
def main():
38-
if system.get_num_devices() < 2:
38+
if len(Device.get_all_devices()) < 2:
3939
print("this example requires at least 2 GPUs", file=sys.stderr)
4040
sys.exit(1)
4141

cuda_core/tests/example_tests/test_basic_examples.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import pytest
1414
from cuda_python_test_helpers.pep723 import has_package_requirements_or_skip
1515

16-
from cuda.core import Device, ManagedMemoryResource, system
16+
from cuda.core import Device, ManagedMemoryResource
1717
from cuda.core._program import _can_load_generated_ptx
1818

1919

@@ -22,7 +22,7 @@ def has_compute_capability_9_or_higher() -> bool:
2222

2323

2424
def has_multiple_devices() -> bool:
25-
return system.get_num_devices() >= 2
25+
return len(Device.get_all_devices()) >= 2
2626

2727

2828
def has_display() -> bool:

cuda_core/tests/system/test_system_device.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import helpers
1616
import pytest
1717

18+
from cuda.core import Device as CudaDevice
1819
from cuda.core import system
1920
from cuda.core.system import typing
2021

@@ -128,7 +129,8 @@ def test_numa_node_id(subtests):
128129

129130

130131
def test_device_cuda_compute_capability():
131-
for device in system.Device.get_all_devices():
132+
for cuda_device in CudaDevice.get_all_devices():
133+
device = cuda_device.to_system_device()
132134
cuda_compute_capability = device.cuda_compute_capability
133135
assert isinstance(cuda_compute_capability, tuple)
134136
assert len(cuda_compute_capability) == 2
@@ -309,7 +311,8 @@ def test_device_brand():
309311

310312

311313
def test_device_pci_bus_id():
312-
for device in system.Device.get_all_devices():
314+
for cuda_device in CudaDevice.get_all_devices():
315+
device = cuda_device.to_system_device()
313316
pci_bus_id = device.pci_info.bus_id
314317
assert isinstance(pci_bus_id, str)
315318

@@ -852,7 +855,8 @@ def test_pstates(subtests):
852855

853856

854857
def test_compute_running_processes(subtests):
855-
for device in system.Device.get_all_devices():
858+
for cuda_device in CudaDevice.get_all_devices():
859+
device = cuda_device.to_system_device()
856860
with subtests.test(device_index=device.index):
857861
with unsupported_before(device, "FERMI"):
858862
processes = device.compute_running_processes

cuda_core/tests/system/test_system_system.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from cuda_python_test_helpers.arch_check import skip_if_nvml_unsupported
1010

1111
from cuda.bindings import driver
12+
from cuda.core import Device as CudaDevice
1213
from cuda.core import system
1314
from cuda.core._utils.cuda_utils import handle_return
1415

@@ -57,8 +58,9 @@ def test_nvml_version():
5758

5859
@skip_if_nvml_unsupported
5960
def test_get_process_name():
60-
for device in system.Device.get_all_devices():
61-
x = device.compute_running_processes
61+
for cuda_device in CudaDevice.get_all_devices():
62+
device = cuda_device.to_system_device()
63+
_ = device.compute_running_processes
6264

6365
try:
6466
process_name = system.get_process_name(os.getpid())

cuda_core/tests/test_green_context.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -291,12 +291,12 @@ def test_configure_scope_with_enum(self, wq_resource, scope):
291291
assert wq_resource.sharing_scope is scope
292292

293293
def test_device_id_matches_source_multi_gpu(self):
294-
from cuda.core import Device, system
294+
from cuda.core import Device
295295

296-
if system.get_num_devices() < 2:
296+
devices = Device.get_all_devices()
297+
if len(devices) < 2:
297298
pytest.skip("requires 2+ GPUs")
298-
dev0 = Device(0)
299-
dev1 = Device(1)
299+
dev0, dev1 = devices[:2]
300300
try:
301301
wq0 = dev0.resources.workqueue
302302
wq1 = dev1.resources.workqueue

cuda_core/tests/test_memory.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,6 @@
4545
VirtualMemoryResource,
4646
VirtualMemoryResourceOptions,
4747
)
48-
from cuda.core import (
49-
system as ccx_system,
50-
)
5148
from cuda.core._dlpack import DLDeviceType
5249
from cuda.core._memory._ipc import IPCBufferDescriptor
5350
from cuda.core._stream import default_stream
@@ -402,7 +399,7 @@ def test_buffer_external_host():
402399

403400
@pytest.mark.parametrize("change_device", [True, False])
404401
def test_buffer_external_device(change_device):
405-
n = ccx_system.get_num_devices()
402+
n = len(Device.get_all_devices())
406403
if n < 1:
407404
pytest.skip("No devices found")
408405
dev_id = n - 1
@@ -426,7 +423,7 @@ def test_buffer_external_device(change_device):
426423

427424
@pytest.mark.parametrize("change_device", [True, False])
428425
def test_buffer_external_pinned_alloc(change_device):
429-
n = ccx_system.get_num_devices()
426+
n = len(Device.get_all_devices())
430427
if n < 1:
431428
pytest.skip("No devices found")
432429
dev_id = n - 1
@@ -451,7 +448,7 @@ def test_buffer_external_pinned_alloc(change_device):
451448

452449
@pytest.mark.parametrize("change_device", [True, False])
453450
def test_buffer_external_pinned_registered(change_device):
454-
n = ccx_system.get_num_devices()
451+
n = len(Device.get_all_devices())
455452
if n < 1:
456453
pytest.skip("No devices found")
457454
dev_id = n - 1
@@ -484,7 +481,7 @@ def test_buffer_external_pinned_registered(change_device):
484481

485482
@pytest.mark.parametrize("change_device", [True, False])
486483
def test_buffer_external_managed(change_device):
487-
n = ccx_system.get_num_devices()
484+
n = len(Device.get_all_devices())
488485
if n < 1:
489486
pytest.skip("No devices found")
490487
dev_id = n - 1
@@ -760,7 +757,7 @@ def test_mr_deallocation_without_current_context(init_cuda, capsys, replace_stre
760757
@pytest.mark.parametrize("replace_stream", [False, True])
761758
def test_mr_deallocation_with_foreign_context(capsys, replace_stream):
762759
"""MR-backed Buffer teardown switches away from an unrelated current context."""
763-
if ccx_system.get_num_devices() < 2:
760+
if len(Device.get_all_devices()) < 2:
764761
pytest.skip("Test requires at least 2 GPUs")
765762

766763
alloc_dev = Device(0)

0 commit comments

Comments
 (0)