Skip to content

Commit 213baf4

Browse files
Add some basic test coverage for cuda.core.experimental (#153)
Add basic test coverage for cuda.core.experimental
1 parent e426810 commit 213baf4

File tree

12 files changed

+648
-1
lines changed

12 files changed

+648
-1
lines changed

cuda_core/cuda/core/experimental/_program.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ class Program:
1414
_supported_target_type = ("ptx", "cubin", "ltoir", )
1515

1616
def __init__(self, code, code_type):
17+
self._handle = None
1718
if code_type not in self._supported_code_type:
1819
raise NotImplementedError
19-
self._handle = None
2020

2121
if code_type.lower() == "c++":
2222
if not isinstance(code, str):

cuda_core/tests/conftest.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Copyright 2024 NVIDIA Corporation. All rights reserved.
2+
#
3+
# Please refer to the NVIDIA end user license agreement (EULA) associated
4+
# with this source code for terms and conditions that govern your use of
5+
# this software. Any use, reproduction, disclosure, or distribution of
6+
# this software and related documentation outside the terms of the EULA
7+
# is strictly prohibited.
8+
9+
from cuda.core.experimental._device import Device
10+
import pytest
11+
12+
@pytest.fixture(scope="module")
13+
def init_cuda():
14+
device = Device()
15+
device.set_current()
16+

cuda_core/tests/example_tests/__init__.py

Whitespace-only changes.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Copyright 2024 NVIDIA Corporation. All rights reserved.
2+
#
3+
# Please refer to the NVIDIA end user license agreement (EULA) associated
4+
# with this source code for terms and conditions that govern your use of
5+
# this software. Any use, reproduction, disclosure, or distribution of
6+
# this software and related documentation outside the terms of the EULA
7+
# is strictly prohibited.
8+
9+
# If we have subcategories of examples in the future, this file can be split along those lines
10+
11+
from .utils import run_example
12+
import os
13+
import glob
14+
import pytest
15+
16+
samples_path = os.path.join(
17+
os.path.dirname(__file__), '..', '..', 'examples')
18+
sample_files = glob.glob(samples_path+'**/*.py', recursive=True)
19+
@pytest.mark.parametrize(
20+
'example', sample_files
21+
)
22+
class TestExamples:
23+
def test_example(self, example):
24+
filename = os.path.basename(example)
25+
run_example(samples_path, example)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Copyright 2024 NVIDIA Corporation. All rights reserved.
2+
#
3+
# Please refer to the NVIDIA end user license agreement (EULA) associated
4+
# with this source code for terms and conditions that govern your use of
5+
# this software. Any use, reproduction, disclosure, or distribution of
6+
# this software and related documentation outside the terms of the EULA
7+
# is strictly prohibited.
8+
9+
from cuda import cuda
10+
import gc
11+
import os
12+
import sys
13+
import pytest
14+
import cupy as cp
15+
16+
class SampleTestError(Exception):
17+
pass
18+
19+
def parse_python_script(filepath):
20+
if not filepath.endswith('.py'):
21+
raise ValueError(f"{filepath} not supported")
22+
with open(filepath, "r", encoding='utf-8') as f:
23+
script = f.read()
24+
return script
25+
26+
27+
def run_example(samples_path, filename, env=None):
28+
fullpath = os.path.join(samples_path, filename)
29+
script = parse_python_script(fullpath)
30+
try:
31+
old_argv = sys.argv
32+
sys.argv = [fullpath]
33+
old_sys_path = sys.path.copy()
34+
sys.path.append(samples_path)
35+
exec(script, env if env else {})
36+
except ImportError as e:
37+
# for samples requiring any of optional dependencies
38+
for m in ('cupy',):
39+
if f"No module named '{m}'" in str(e):
40+
pytest.skip(f'{m} not installed, skipping related tests')
41+
break
42+
else:
43+
raise
44+
except Exception as e:
45+
msg = "\n"
46+
msg += f'Got error ({filename}):\n'
47+
msg += str(e)
48+
raise SampleTestError(msg) from e
49+
finally:
50+
sys.path = old_sys_path
51+
sys.argv = old_argv
52+
# further reduce the memory watermark
53+
gc.collect()
54+
cp.get_default_memory_pool().free_all_blocks()

cuda_core/tests/test_device.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Copyright 2024 NVIDIA Corporation. All rights reserved.
2+
#
3+
# Please refer to the NVIDIA end user license agreement (EULA) associated
4+
# with this source code for terms and conditions that govern your use of
5+
# this software. Any use, reproduction, disclosure, or distribution of
6+
# this software and related documentation outside the terms of the EULA
7+
# is strictly prohibited.
8+
9+
from cuda import cuda, cudart
10+
from cuda.core.experimental._device import Device
11+
from cuda.core.experimental._utils import handle_return, ComputeCapability, CUDAError, \
12+
precondition
13+
import pytest
14+
15+
def test_device_repr():
16+
device = Device(0)
17+
assert str(device).startswith('<Device 0')
18+
19+
def test_device_alloc(init_cuda):
20+
device = Device()
21+
buffer = device.allocate(1024)
22+
device.sync()
23+
assert buffer.handle != 0
24+
assert buffer.size == 1024
25+
assert buffer.device_id == 0
26+
27+
def test_device_set_current():
28+
device = Device()
29+
device.set_current()
30+
31+
def test_device_create_stream():
32+
device = Device()
33+
stream = device.create_stream()
34+
assert stream is not None
35+
assert stream.handle
36+
37+
def test_pci_bus_id():
38+
device = Device()
39+
bus_id = handle_return(cudart.cudaDeviceGetPCIBusId(13, device.device_id))
40+
assert device.pci_bus_id == bus_id[:12].decode()
41+
42+
def test_uuid():
43+
device = Device()
44+
driver_ver = handle_return(cuda.cuDriverGetVersion())
45+
if driver_ver >= 11040:
46+
uuid = handle_return(cuda.cuDeviceGetUuid_v2(device.device_id))
47+
else:
48+
uuid = handle_return(cuda.cuDeviceGetUuid(device.device_id))
49+
uuid = uuid.bytes.hex()
50+
expected_uuid = f"{uuid[:8]}-{uuid[8:12]}-{uuid[12:16]}-{uuid[16:20]}-{uuid[20:]}"
51+
assert device.uuid == expected_uuid
52+
53+
def test_name():
54+
device = Device()
55+
name = handle_return(cuda.cuDeviceGetName(128, device.device_id))
56+
name = name.split(b'\0')[0]
57+
assert device.name == name.decode()
58+
59+
def test_compute_capability():
60+
device = Device()
61+
major = handle_return(cudart.cudaDeviceGetAttribute(
62+
cudart.cudaDeviceAttr.cudaDevAttrComputeCapabilityMajor, device.device_id))
63+
minor = handle_return(cudart.cudaDeviceGetAttribute(
64+
cudart.cudaDeviceAttr.cudaDevAttrComputeCapabilityMinor, device.device_id))
65+
expected_cc = ComputeCapability(major, minor)
66+
assert device.compute_capability == expected_cc
67+

cuda_core/tests/test_event.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright 2024 NVIDIA Corporation. All rights reserved.
2+
#
3+
# Please refer to the NVIDIA end user license agreement (EULA) associated
4+
# with this source code for terms and conditions that govern your use of
5+
# this software. Any use, reproduction, disclosure, or distribution of
6+
# this software and related documentation outside the terms of the EULA
7+
# is strictly prohibited.
8+
9+
from cuda import cuda
10+
from cuda.core.experimental._event import EventOptions, Event
11+
from cuda.core.experimental._utils import handle_return
12+
from cuda.core.experimental._device import Device
13+
import pytest
14+
15+
def test_is_timing_disabled():
16+
options = EventOptions(enable_timing=False)
17+
event = Event._init(options)
18+
assert event.is_timing_disabled == True
19+
20+
def test_is_sync_busy_waited():
21+
options = EventOptions(busy_waited_sync=True)
22+
event = Event._init(options)
23+
assert event.is_sync_busy_waited == True
24+
25+
def test_sync():
26+
options = EventOptions()
27+
event = Event._init(options)
28+
event.sync()
29+
assert event.is_done == True
30+
31+
def test_is_done():
32+
options = EventOptions()
33+
event = Event._init(options)
34+
assert event.is_done == True
35+
36+
def test_handle():
37+
options = EventOptions()
38+
event = Event._init(options)
39+
assert isinstance(event.handle, int)

cuda_core/tests/test_launcher.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Copyright 2024 NVIDIA Corporation. All rights reserved.
2+
#
3+
# Please refer to the NVIDIA end user license agreement (EULA) associated
4+
# with this source code for terms and conditions that govern your use of
5+
# this software. Any use, reproduction, disclosure, or distribution of
6+
# this software and related documentation outside the terms of the EULA
7+
# is strictly prohibited.
8+
9+
from cuda import cuda
10+
from cuda.core.experimental._launcher import LaunchConfig
11+
from cuda.core.experimental._stream import Stream
12+
from cuda.core.experimental._device import Device
13+
from cuda.core.experimental._utils import handle_return
14+
import pytest
15+
16+
def test_launch_config_init():
17+
config = LaunchConfig(grid=(1, 1, 1), block=(1, 1, 1), stream=None, shmem_size=0)
18+
assert config.grid == (1, 1, 1)
19+
assert config.block == (1, 1, 1)
20+
assert config.stream is None
21+
assert config.shmem_size == 0
22+
23+
config = LaunchConfig(grid=(2, 2, 2), block=(2, 2, 2), stream=Device().create_stream(), shmem_size=1024)
24+
assert config.grid == (2, 2, 2)
25+
assert config.block == (2, 2, 2)
26+
assert isinstance(config.stream, Stream)
27+
assert config.shmem_size == 1024
28+
29+
def test_launch_config_cast_to_3_tuple():
30+
config = LaunchConfig(grid=1, block=1)
31+
assert config._cast_to_3_tuple(1) == (1, 1, 1)
32+
assert config._cast_to_3_tuple((1, 2)) == (1, 2, 1)
33+
assert config._cast_to_3_tuple((1, 2, 3)) == (1, 2, 3)
34+
35+
# Edge cases
36+
assert config._cast_to_3_tuple(999) == (999, 1, 1)
37+
assert config._cast_to_3_tuple((999, 888)) == (999, 888, 1)
38+
assert config._cast_to_3_tuple((999, 888, 777)) == (999, 888, 777)
39+
40+
def test_launch_config_invalid_values():
41+
with pytest.raises(ValueError):
42+
LaunchConfig(grid=0, block=1)
43+
44+
with pytest.raises(ValueError):
45+
LaunchConfig(grid=(0, 1), block=1)
46+
47+
with pytest.raises(ValueError):
48+
LaunchConfig(grid=(1, 1, 1), block=0)
49+
50+
with pytest.raises(ValueError):
51+
LaunchConfig(grid=(1, 1, 1), block=(0, 1))
52+
53+
def test_launch_config_stream():
54+
stream = Device().create_stream()
55+
config = LaunchConfig(grid=(1, 1, 1), block=(1, 1, 1), stream=stream, shmem_size=0)
56+
assert config.stream == stream
57+
58+
with pytest.raises(ValueError):
59+
LaunchConfig(grid=(1, 1, 1), block=(1, 1, 1), stream="invalid_stream", shmem_size=0)
60+
61+
def test_launch_config_shmem_size():
62+
config = LaunchConfig(grid=(1, 1, 1), block=(1, 1, 1), stream=None, shmem_size=2048)
63+
assert config.shmem_size == 2048
64+
65+
config = LaunchConfig(grid=(1, 1, 1), block=(1, 1, 1), stream=None)
66+
assert config.shmem_size == 0

0 commit comments

Comments
 (0)