Files
paddlepaddle--paddle/test/legacy_test/test_cuda_unittest.py
T
2026-07-13 12:40:42 +08:00

606 lines
21 KiB
Python

# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# test_cuda_unittest.py
import ctypes
import platform
import types
import unittest
import warnings
from unittest import mock
import numpy as np
from op_test import get_device, is_custom_device
import paddle
from paddle.cuda import (
CudaError,
OutOfMemoryError,
Stream,
StreamContext,
_device_to_paddle,
check_error,
current_stream,
get_device_capability,
get_device_name,
get_device_properties,
is_available,
mem_get_info,
stream,
synchronize,
)
class TestDevice(unittest.TestCase):
def test_device(self):
tensor = paddle.tensor([1]).to(paddle.get_device())
tensor_device = tensor.device
with tensor_device:
new_tensor = paddle.tensor([1])
assert new_tensor.device == tensor_device
def test_static_device(self):
paddle.enable_static()
x = paddle.static.data(name="x", shape=[2, 3], dtype='float32')
assert x.device is None
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
_ = x.device
self.assertTrue(
any("device" in str(warning.message).lower() for warning in w),
msg=f"Expected a warning related to 'device', but got {[str(w.message) for w in w]}",
)
class TestCudaIpcCollect(unittest.TestCase):
def test_ipc_collect(self):
if (
paddle.device.is_compiled_with_cuda() or is_custom_device()
) and paddle.device.is_compiled_with_rocm():
reason = "Skip for ipc_collect function in dcu is not correct"
print(reason)
return
if platform.system().lower() == "windows":
print("Skip: ipc_collect function on Windows is not supported.")
return
device = paddle.device.get_device()
if device.startswith("gpu") or device.startswith("xpu"):
paddle.device.ipc_collect()
paddle.cuda.ipc_collect()
class TestCudaCompat(unittest.TestCase):
# ---------------------
# _device_to_paddle test
# ---------------------
def test_device_to_paddle_none(self):
self.assertEqual(_device_to_paddle(), paddle.device.get_device())
# ---------------------
# is_available test
# ---------------------
def test_is_available(self):
self.assertIsInstance(is_available(), bool)
self.assertIsInstance(paddle.device.is_available(), bool)
# ---------------------
# synchronize test
# ---------------------
def test_synchronize(self):
if paddle.is_compiled_with_cuda():
try:
synchronize(None)
synchronize(0)
synchronize('cuda:0')
synchronize('gpu:0')
except Exception as e:
self.fail(f"synchronize raised Exception {e}")
# ---------------------
# current_stream test
# ---------------------
def test_current_stream(self):
if paddle.is_compiled_with_cuda():
stream = current_stream(None)
self.assertIsNotNone(stream)
stream = current_stream(0)
self.assertIsNotNone(stream)
# ---------------------
# get_device_properties test
# ---------------------
def test_get_device_properties(self):
if paddle.is_compiled_with_cuda():
props = get_device_properties(0)
self.assertTrue(hasattr(props, 'name'))
self.assertTrue(hasattr(props, 'total_memory'))
with self.assertRaises(ValueError):
get_device_properties("cpu:2")
# ---------------------
# get_device_name / get_device_capability test
# ---------------------
def test_device_name_and_capability(self):
if paddle.is_compiled_with_cuda():
name = get_device_name(0)
self.assertIsInstance(name, str)
cap = get_device_capability(0)
self.assertIsInstance(cap, tuple)
self.assertEqual(len(cap), 2)
name = paddle.device.get_device_name(0)
self.assertIsInstance(name, str)
cap = paddle.device.get_device_capability(0)
self.assertIsInstance(cap, tuple)
self.assertEqual(len(cap), 2)
def test_stream_creation(self):
if paddle.is_compiled_with_cuda():
s = Stream()
s1 = Stream()
self.assertIsInstance(s, paddle.device.Stream)
self.assertIsInstance(s1, paddle.device.Stream)
def test_stream_context(self):
if paddle.is_compiled_with_cuda():
s = Stream(device=get_device(), priority=2)
with stream(s):
ctx = stream(s)
self.assertIsInstance(ctx, StreamContext)
current = current_stream()
self.assertEqual(current.stream_base, s.stream_base)
s = paddle.device.Stream()
data1 = paddle.ones(shape=[20])
data2 = paddle.ones(shape=[20])
data3 = data1 + data2
with paddle.device.StreamContext(s):
s.wait_stream(paddle.device.current_stream())
data4 = data1 + data3
ctx = stream(s)
self.assertIsInstance(ctx, paddle.device.StreamContext)
def test_nested_streams(self):
if paddle.is_compiled_with_cuda():
s1 = Stream()
s2 = Stream()
with stream(s1):
with stream(s2):
current = paddle.cuda.current_stream()
self.assertEqual(current.stream_base, s2.stream_base)
current = paddle.cuda.current_stream()
self.assertEqual(current.stream_base, s1.stream_base)
def test_manual_seed_all(self):
seed = 42
paddle.cuda.manual_seed_all(seed)
x = paddle.randn([3, 3])
y = paddle.randn([3, 3])
self.assertEqual(x.numpy().all(), y.numpy().all())
seed = 21
paddle.device.manual_seed_all(seed)
x = paddle.randn([3, 3])
y = paddle.randn([3, 3])
self.assertEqual(x.numpy().all(), y.numpy().all())
def test_get_default_device(self):
default_device = paddle.get_default_device()
self.assertIsInstance(default_device, str)
if paddle.is_compiled_with_cuda():
self.assertEqual(
paddle.get_default_device(), paddle.device('cuda:0')
)
def test_get_device(self):
x_cpu = paddle.to_tensor([1, 2, 3], place=paddle.CPUPlace())
self.assertEqual(paddle.get_device(x_cpu), -1)
if paddle.device.is_compiled_with_cuda():
x_gpu = paddle.to_tensor([1, 2, 3], place=paddle.CUDAPlace(0))
self.assertEqual(paddle.get_device(x_gpu), 0)
def test_version_hip(self):
version = paddle.version.hip
if not paddle.is_compiled_with_rocm():
self.assertEqual(version, None)
def test_set_default_device(self):
if paddle.is_compiled_with_cuda():
paddle.set_default_device("gpu:0")
self.assertEqual(
paddle.get_default_device(), paddle.device('cuda:0')
)
if paddle.is_compiled_with_xpu():
paddle.set_default_device("xpu")
self.assertEqual(
paddle.get_default_device(), paddle.device('xpu:0')
)
@unittest.skipIf(
(
not paddle.device.is_compiled_with_cuda()
or paddle.device.is_compiled_with_rocm()
),
reason="Skip if not in CUDA env",
)
def test_cudart_integrity(self):
cuda_rt_module = paddle.cuda.cudart()
self.assertIsNotNone(cuda_rt_module)
self.assertIsInstance(cuda_rt_module, types.ModuleType)
cuda_version = paddle.version.cuda()
if int(cuda_version.split(".")[0]) < 12:
self.assertTrue(hasattr(cuda_rt_module, "cudaOutputMode"))
self.assertTrue(hasattr(cuda_rt_module, "cudaProfilerInitialize"))
self.assertTrue(
hasattr(cuda_rt_module.cudaOutputMode, "KeyValuePair")
)
self.assertEqual(cuda_rt_module.cudaOutputMode.KeyValuePair, 0)
self.assertTrue(hasattr(cuda_rt_module.cudaOutputMode, "CSV"))
self.assertEqual(cuda_rt_module.cudaOutputMode.CSV, 1)
self.assertTrue(hasattr(cuda_rt_module, "cudaError"))
self.assertTrue(hasattr(cuda_rt_module.cudaError, "success"))
self.assertEqual(cuda_rt_module.cudaError.success, 0)
func_list = [
"cudaGetErrorString",
"cudaProfilerStart",
"cudaProfilerStop",
"cudaHostRegister",
"cudaHostUnregister",
"cudaStreamCreate",
"cudaStreamDestroy",
"cudaMemGetInfo",
]
for f in func_list:
self.assertTrue(hasattr(cuda_rt_module, f))
@unittest.skipIf(
(
not paddle.device.is_compiled_with_cuda()
or paddle.device.is_compiled_with_rocm()
),
reason="Skip if not in CUDA env",
)
def test_cudart_function(self):
cuda_rt_module = paddle.cuda.cudart()
# cudaGetErrorString
err_str = cuda_rt_module.cudaGetErrorString(
cuda_rt_module.cudaError.success
)
self.assertIsInstance(err_str, str)
# cudaMemGetInfo
free_mem, total_mem = cuda_rt_module.cudaMemGetInfo(0)
self.assertIsInstance(free_mem, int)
self.assertIsInstance(total_mem, int)
self.assertGreaterEqual(total_mem, free_mem)
self.assertGreater(free_mem, 0)
# cudaHostRegister / cudaHostUnregister
buf = np.zeros(1024, dtype=np.float32)
ptr = buf.ctypes.data
err = cuda_rt_module.cudaHostRegister(ptr, buf.nbytes, 0)
self.assertEqual(err, cuda_rt_module.cudaError.success)
err = cuda_rt_module.cudaHostUnregister(ptr)
self.assertEqual(err, cuda_rt_module.cudaError.success)
# cudaStreamCreate / cudaStreamDestroy
stream = ctypes.c_size_t(0)
err = cuda_rt_module.cudaStreamCreate(ctypes.addressof(stream))
assert err == cuda_rt_module.cudaError.success
err = cuda_rt_module.cudaStreamDestroy(stream.value)
assert err == cuda_rt_module.cudaError.success
err = cuda_rt_module.cudaProfilerStart()
self.assertEqual(err, cuda_rt_module.cudaError.success)
err = cuda_rt_module.cudaProfilerStop()
self.assertEqual(err, cuda_rt_module.cudaError.success)
@unittest.skipIf(
(
not paddle.device.is_compiled_with_cuda()
or paddle.device.is_compiled_with_rocm()
),
reason="Skip if not in CUDA env",
)
def test_mem_get_info(self):
a, b = mem_get_info(paddle.device.get_device())
self.assertGreaterEqual(a, 0)
self.assertGreaterEqual(b, 0)
a, b = mem_get_info('cuda:0')
self.assertGreaterEqual(a, 0)
self.assertGreaterEqual(b, 0)
a, b = mem_get_info()
self.assertGreaterEqual(a, 0)
self.assertGreaterEqual(b, 0)
a, b = mem_get_info(0)
self.assertGreaterEqual(a, 0)
self.assertGreaterEqual(b, 0)
with self.assertRaisesRegex(
ValueError, "Expected a cuda device, but got"
):
a, b = mem_get_info(paddle.CPUPlace())
@unittest.skipIf(
(
not paddle.device.is_compiled_with_cuda()
or paddle.device.is_compiled_with_rocm()
),
reason="Skip if not in CUDA env",
)
def test_check_error(self):
check_error(0)
with self.assertRaisesRegex(CudaError, "invalid argument"):
check_error(1)
with self.assertRaisesRegex(CudaError, "out of memory"):
check_error(2)
def test_out_of_memory_error(self):
# OutOfMemoryError is a RuntimeError, not a CudaError
self.assertTrue(issubclass(OutOfMemoryError, RuntimeError))
self.assertFalse(issubclass(OutOfMemoryError, CudaError))
self.assertTrue(issubclass(CudaError, RuntimeError))
# Direct construction
oom = OutOfMemoryError("test message")
self.assertIsInstance(oom, RuntimeError)
self.assertEqual(str(oom), "test message")
def can_use_cuda_graph():
return (
paddle.is_compiled_with_cuda() or is_custom_device()
) and not paddle.is_compiled_with_rocm()
class TestCurrentStreamCapturing(unittest.TestCase):
def test_cuda_fun(self):
self.assertFalse(paddle.cuda.is_current_stream_capturing())
self.assertFalse(paddle.device.is_current_stream_capturing())
class TestExternalStream(unittest.TestCase):
def test_get_stream_from_external(self):
# Only run test if CUDA is available
if not (paddle.cuda.is_available() and paddle.is_compiled_with_cuda()):
return
# Test case 1: Device specified by integer ID
device_id = 0
original_stream = paddle.cuda.Stream(device_id)
original_raw_ptr = original_stream.stream_base.raw_stream
external_stream = paddle.cuda.get_stream_from_external(
original_raw_ptr, device_id
)
self.assertEqual(
original_raw_ptr, external_stream.stream_base.raw_stream
)
# Test case 2: Device specified by CUDAPlace
device_place = paddle.CUDAPlace(0)
original_stream = paddle.device.Stream(device_place)
original_raw_ptr = original_stream.stream_base.raw_stream
external_stream = paddle.device.get_stream_from_external(
original_raw_ptr, device_place
)
self.assertEqual(
original_raw_ptr, external_stream.stream_base.raw_stream
)
# Test case 3: Device not specified (None)
device_none = None
original_stream = paddle.cuda.Stream(device_none)
original_raw_ptr = original_stream.stream_base.raw_stream
external_stream = paddle.cuda.get_stream_from_external(
original_raw_ptr, device_none
)
self.assertEqual(
original_raw_ptr, external_stream.stream_base.raw_stream
)
# Test case 4: Verify original stream remains valid after external stream deletion
del external_stream
with paddle.cuda.stream(stream=original_stream):
current_stream = paddle.cuda.current_stream(device_none)
self.assertEqual(
current_stream.stream_base.raw_stream, original_raw_ptr
)
with paddle.device.stream(stream=original_stream):
current_device_stream = paddle.cuda.current_stream(device_none)
self.assertEqual(
current_device_stream.stream_base.raw_stream, original_raw_ptr
)
class TestNvtx(unittest.TestCase):
def _test_nvtx_range_context_manager_and_decorator(self, nvtx):
events = []
def range_push(msg):
events.append(("push", msg))
def range_pop():
events.append(("pop", None))
with (
mock.patch.object(nvtx, "range_push", range_push),
mock.patch.object(nvtx, "range_pop", range_pop),
):
with nvtx.range("context-{name}", name="formatted"):
events.append(("body", "context"))
self.assertEqual(
events,
[
("push", "context-formatted"),
("body", "context"),
("pop", None),
],
)
events.clear()
@nvtx.range("decorator-{}", "formatted")
def decorated(value):
events.append(("body", value))
return value + 1
self.assertEqual(decorated(41), 42)
self.assertEqual(
events,
[
("push", "decorator-formatted"),
("body", 41),
("pop", None),
],
)
events.clear()
with nvtx.range("outer"):
events.append(("body", "outer"))
with nvtx.range("inner"):
events.append(("body", "inner"))
events.append(("body", "after-inner"))
self.assertEqual(
events,
[
("push", "outer"),
("body", "outer"),
("push", "inner"),
("body", "inner"),
("pop", None),
("body", "after-inner"),
("pop", None),
],
)
events.clear()
with (
self.assertRaisesRegex(RuntimeError, "boom"),
nvtx.range("exception"),
):
events.append(("body", "exception"))
raise RuntimeError("boom")
self.assertEqual(
events,
[
("push", "exception"),
("body", "exception"),
("pop", None),
],
)
def test_range_context_manager_and_decorator(self):
self._test_nvtx_range_context_manager_and_decorator(paddle.cuda.nvtx)
self._test_nvtx_range_context_manager_and_decorator(paddle.device.nvtx)
def test_range_push_pop(self):
if platform.system().lower() == "windows":
return
if not paddle.device.is_compiled_with_cuda():
return
if not paddle.device.get_device().startswith("gpu"):
return
if (
paddle.device.is_compiled_with_cuda() or is_custom_device()
) and paddle.device.is_compiled_with_rocm():
reason = "Skip for nvtx function in dcu is not correct"
print(reason)
return
try:
paddle.cuda.nvtx.range_push("test_push")
paddle.cuda.nvtx.range_pop()
paddle.device.nvtx.range_push("test_push")
paddle.device.nvtx.range_pop()
with paddle.cuda.nvtx.range("test_{}", "range"):
pass
with paddle.device.nvtx.range("test_{}", "range"):
pass
except Exception as e:
self.fail(f"nvtx test failed: {e}")
with self.assertRaises(TypeError):
paddle.cuda.nvtx.range_push(123)
with self.assertRaises(TypeError):
paddle.device.nvtx.range_push(123)
class TestDeviceDvice(unittest.TestCase):
def test_device_device(self):
current = paddle.device.get_device()
with paddle.device.device("cpu"):
self.assertEqual(paddle.device.get_device(), 'cpu')
self.assertEqual(paddle.device.get_device(), current)
paddle.disable_static()
current = paddle.device.get_device()
# Test: passing cpu tensor.place to device context manager
cpu_tensor = paddle.empty(1, dtype="float32", device='cpu')
with paddle.device.device(cpu_tensor.place):
self.assertEqual(paddle.device.get_device(), 'cpu')
self.assertEqual(paddle.device.get_device(), current)
if paddle.is_compiled_with_cuda() and paddle.cuda.is_available():
device_count = paddle.device.cuda.device_count()
# Test: passing gpu:0 tensor.place to cuda.device context manager
gpu_tensor_0 = paddle.empty(1, dtype="float32", device='cuda:0')
with paddle.cuda.device(gpu_tensor_0.place):
self.assertEqual(paddle.device.get_device(), 'gpu:0')
self.assertEqual(paddle.device.get_device(), current)
# Test: passing gpu tensor.place with non-zero device id
if device_count > 1:
gpu_tensor_1 = paddle.empty(1, dtype="float32", device='cuda:1')
with paddle.device.device(gpu_tensor_1.place):
self.assertEqual(paddle.device.get_device(), 'gpu:1')
self.assertEqual(paddle.device.get_device(), current)
class TestCudaDvice(unittest.TestCase):
def test_device_device(self):
current = paddle.device.get_device()
with paddle.cuda.device("cpu"):
self.assertEqual(paddle.device.get_device(), 'cpu')
self.assertEqual(paddle.device.get_device(), current)
if __name__ == '__main__':
unittest.main()