|
2 | 2 | # SPDX-License-Identifier: Apache-2.0 |
3 | 3 |
|
4 | 4 | import ctypes |
| 5 | +import os |
5 | 6 | import pickle |
| 7 | +import subprocess |
6 | 8 | import warnings |
| 9 | +from pathlib import Path |
7 | 10 |
|
| 11 | +import numpy as np |
8 | 12 | import pytest |
9 | 13 |
|
10 | 14 | import cuda.core |
11 | | -from cuda.core import Device, Kernel, ObjectCode, Program, ProgramOptions |
| 15 | +from cuda.core import Device, Kernel, Linker, LinkerOptions, ObjectCode, Program, ProgramOptions |
12 | 16 | from cuda.core._program import _can_load_generated_ptx |
13 | 17 | from cuda.core._utils.cuda_utils import CUDAError, driver, handle_return |
14 | 18 | from cuda.core._utils.version import binding_version, driver_version |
| 19 | +from cuda.pathfinder import find_nvidia_binary_utility |
15 | 20 |
|
16 | 21 | try: |
17 | 22 | import numba |
@@ -172,6 +177,32 @@ def get_saxpy_fatbin(init_cuda): |
172 | 177 | return bytes(fatbin), sym_map |
173 | 178 |
|
174 | 179 |
|
| 180 | +@pytest.fixture(scope="module") |
| 181 | +def get_saxpy_object(): |
| 182 | + """Read the pre-built saxpy.o. |
| 183 | +
|
| 184 | + In CI: produced by build stage into a test wheel file. |
| 185 | + In local dev: auto-built on demand if nvcc is available; if you edit |
| 186 | + saxpy.cu, remove the stale saxpy.o to force a rebuild. |
| 187 | + """ |
| 188 | + binaries_dir = Path(__file__).parent / "test_binaries" |
| 189 | + obj_path = binaries_dir / "saxpy.o" |
| 190 | + |
| 191 | + if not obj_path.is_file(): |
| 192 | + if find_nvidia_binary_utility("nvcc") is None: |
| 193 | + pytest.skip( |
| 194 | + f"saxpy.o not found at {obj_path} and nvcc is unavailable. " |
| 195 | + "In CI this is downloaded from the build stage." |
| 196 | + ) |
| 197 | + subprocess.run( # noqa: S603 |
| 198 | + ["bash", str(binaries_dir / "build_test_binaries.sh")], # noqa: S607 |
| 199 | + check=True, |
| 200 | + env=os.environ, |
| 201 | + ) |
| 202 | + |
| 203 | + return obj_path.read_bytes() |
| 204 | + |
| 205 | + |
175 | 206 | def test_get_kernel(init_cuda): |
176 | 207 | kernel = """extern "C" __global__ void ABC() { }""" |
177 | 208 |
|
@@ -330,6 +361,65 @@ def test_object_code_load_fatbin_from_file(get_saxpy_fatbin, tmp_path, convert_p |
330 | 361 | mod_obj.get_kernel("saxpy<double>") # force loading |
331 | 362 |
|
332 | 363 |
|
| 364 | +def test_object_code_load_object(get_saxpy_object): |
| 365 | + obj = get_saxpy_object |
| 366 | + assert isinstance(obj, bytes) |
| 367 | + mod_obj = ObjectCode.from_object(obj) |
| 368 | + assert mod_obj.code == obj |
| 369 | + assert mod_obj.code_type == "object" |
| 370 | + with pytest.raises(RuntimeError, match=r'Unsupported code type "object"'): |
| 371 | + mod_obj.get_kernel("saxpy<float>") |
| 372 | + |
| 373 | + |
| 374 | +def test_object_code_load_object_from_file(get_saxpy_object, tmp_path): |
| 375 | + obj_file = tmp_path / "test.o" |
| 376 | + obj_file.write_bytes(get_saxpy_object) |
| 377 | + arg = str(obj_file) |
| 378 | + mod_obj = ObjectCode.from_object(arg) |
| 379 | + assert mod_obj.code == arg |
| 380 | + assert mod_obj.code_type == "object" |
| 381 | + |
| 382 | + |
| 383 | +def test_object_code_load_object_with_linker(get_saxpy_object, init_cuda): |
| 384 | + arch = f"sm_{init_cuda.arch}" |
| 385 | + kernel_code = Program( |
| 386 | + r""" |
| 387 | + extern __device__ float saxpy_step(float a, float x, float y); |
| 388 | + extern "C" __global__ void linked_kernel(float a, float x, float y, float* out) { |
| 389 | + if (threadIdx.x == 0 && blockIdx.x == 0) *out = saxpy_step(a, x, y); |
| 390 | + } |
| 391 | + """, |
| 392 | + "c++", |
| 393 | + ProgramOptions(relocatable_device_code=True, arch=arch), |
| 394 | + ).compile("cubin") |
| 395 | + linked = Linker( |
| 396 | + kernel_code, |
| 397 | + ObjectCode.from_object(get_saxpy_object), |
| 398 | + options=LinkerOptions(arch=arch), |
| 399 | + ).link("cubin") |
| 400 | + kernel = linked.get_kernel("linked_kernel") |
| 401 | + |
| 402 | + stream = init_cuda.create_stream() |
| 403 | + host_buf = cuda.core.LegacyPinnedMemoryResource().allocate(4) |
| 404 | + result = np.from_dlpack(host_buf).view(np.float32) |
| 405 | + result[:] = 0.0 |
| 406 | + dev_buf = init_cuda.memory_resource.allocate(4, stream=init_cuda.default_stream) |
| 407 | + |
| 408 | + cuda.core.launch( |
| 409 | + stream, |
| 410 | + cuda.core.LaunchConfig(grid=1, block=1), |
| 411 | + kernel, |
| 412 | + np.float32(2.0), |
| 413 | + np.float32(3.0), |
| 414 | + np.float32(4.0), |
| 415 | + dev_buf, |
| 416 | + ) |
| 417 | + dev_buf.copy_to(host_buf, stream=stream) |
| 418 | + stream.sync() |
| 419 | + |
| 420 | + assert result[0] == 10.0 |
| 421 | + |
| 422 | + |
333 | 423 | def test_saxpy_arguments(get_saxpy_kernel_cubin, cuda12_4_prerequisite_check): |
334 | 424 | krn, _ = get_saxpy_kernel_cubin |
335 | 425 |
|
|
0 commit comments