chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
file(
|
||||
GLOB TEST_OPS
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
"test_*.py")
|
||||
string(REPLACE ".py" "" TEST_OPS "${TEST_OPS}")
|
||||
|
||||
foreach(TEST_OP ${TEST_OPS})
|
||||
py_test_modules(${TEST_OP} MODULES ${TEST_OP})
|
||||
endforeach()
|
||||
@@ -0,0 +1,35 @@
|
||||
# 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.
|
||||
|
||||
|
||||
def try_import_torch():
|
||||
try:
|
||||
import torch
|
||||
|
||||
return torch
|
||||
except ModuleNotFoundError:
|
||||
return None
|
||||
|
||||
|
||||
def use_torch_specific_fn():
|
||||
torch = try_import_torch()
|
||||
|
||||
if torch is None:
|
||||
return
|
||||
# torch._dynamo.allow_in_graph is a torch specific function, it shouldn't be accessed via proxy
|
||||
torch._dynamo.allow_in_graph(lambda x: x)
|
||||
|
||||
|
||||
# Use torch specific function at execute module stage
|
||||
use_torch_specific_fn()
|
||||
@@ -0,0 +1,22 @@
|
||||
# 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.
|
||||
|
||||
|
||||
def use_torch_compat_api():
|
||||
import torch
|
||||
|
||||
torch.randn([2, 3])
|
||||
|
||||
|
||||
use_torch_compat_api()
|
||||
@@ -0,0 +1,22 @@
|
||||
# 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.
|
||||
|
||||
from torch_module_side_effects import _ensure_init_once
|
||||
|
||||
from . import (
|
||||
_dynamo as _dynamo,
|
||||
nn as nn,
|
||||
)
|
||||
|
||||
_ensure_init_once()
|
||||
@@ -0,0 +1,17 @@
|
||||
# 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.
|
||||
|
||||
|
||||
def allow_in_graph(fn):
|
||||
return fn
|
||||
@@ -0,0 +1,15 @@
|
||||
# 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.
|
||||
|
||||
from . import functional as functional
|
||||
@@ -0,0 +1,17 @@
|
||||
# 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.
|
||||
|
||||
|
||||
def relu(x):
|
||||
return max(x, 0)
|
||||
@@ -0,0 +1,43 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
PyTorch module side effects simulation.
|
||||
|
||||
The PyTorch module can only be initialized once. If imported multiple times,
|
||||
it raises a RuntimeError to simulate side effects during imports.
|
||||
|
||||
For example:
|
||||
|
||||
>>> import sys
|
||||
>>> import torch # Works fine the first time
|
||||
>>> del sys.modules['torch']
|
||||
>>> import torch # Raises an error due to re-initialization
|
||||
|
||||
We simulate this behavior to test how Paddle's torch proxy handles such side effects.
|
||||
Since the torch module will be cleared when removed from sys.modules, we need to create
|
||||
a new module to record the initialization state.
|
||||
"""
|
||||
|
||||
initialized = False
|
||||
|
||||
|
||||
def _ensure_init_once():
|
||||
global initialized
|
||||
if not initialized:
|
||||
initialized = True
|
||||
return
|
||||
raise RuntimeError(
|
||||
"torch core module is already initialized, this can happen due to side effects of imports."
|
||||
)
|
||||
@@ -0,0 +1,34 @@
|
||||
# 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.
|
||||
|
||||
import unittest
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
class TestCAPI(unittest.TestCase):
|
||||
def test_glibcxx_use_cxx11_abi(self):
|
||||
val = paddle._C._GLIBCXX_USE_CXX11_ABI
|
||||
self.assertIsInstance(
|
||||
val, bool, "_GLIBCXX_USE_CXX11_ABI should return a bool"
|
||||
)
|
||||
|
||||
def test_get_custom_class_python_wrapper_not_found(self):
|
||||
with self.assertRaises(Exception) as cm:
|
||||
paddle._C._get_custom_class_python_wrapper("fake_ns", "FakeClass")
|
||||
self.assertIn("not found", str(cm.exception).lower())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,32 @@
|
||||
# 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.
|
||||
|
||||
import unittest
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
class TestForbidKeywordsDecorator(unittest.TestCase):
|
||||
def test(self):
|
||||
with self.assertRaises(TypeError) as cm:
|
||||
self.assertWarnsRegex(
|
||||
UserWarning,
|
||||
"may behave differently from its PyTorch counterpart",
|
||||
paddle.sort,
|
||||
)
|
||||
paddle.sort(input=paddle.to_tensor([2, 1, 3]), axis=0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,361 @@
|
||||
# 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.
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
import paddle.base as core
|
||||
from paddle.utils.cpp_extension import (
|
||||
CUDA_HOME,
|
||||
_get_cuda_arch_flags,
|
||||
_get_num_workers,
|
||||
_get_pybind11_abi_build_flags,
|
||||
extension_utils,
|
||||
)
|
||||
|
||||
|
||||
class TestGetCudaArchFlags(unittest.TestCase):
|
||||
def setUp(self):
|
||||
if not core.is_compiled_with_cuda() or core.is_compiled_with_rocm():
|
||||
self.skipTest('should compile with cuda (not rocm).')
|
||||
self._old_env = dict(os.environ)
|
||||
|
||||
def tearDown(self):
|
||||
os.environ.clear()
|
||||
os.environ.update(self._old_env)
|
||||
|
||||
def test_with_user_cflags(self):
|
||||
flags = _get_cuda_arch_flags(cflags=["-arch=sm_90"])
|
||||
self.assertEqual(flags, [])
|
||||
|
||||
def test_with_env_hopper(self):
|
||||
os.environ["PADDLE_CUDA_ARCH_LIST"] = "Hopper"
|
||||
flags = _get_cuda_arch_flags()
|
||||
# Hopper -> 9.0+PTX -> sm_90 + compute_90
|
||||
self.assertIn("-gencode=arch=compute_90,code=sm_90", flags)
|
||||
self.assertIn("-gencode=arch=compute_90,code=compute_90", flags)
|
||||
|
||||
def test_with_env_hopper_and_flags(self):
|
||||
os.environ["PADDLE_CUDA_ARCH_LIST"] = "Hopper"
|
||||
flags = _get_cuda_arch_flags("Hopper")
|
||||
# Hopper -> 9.0+PTX -> sm_90 + compute_90
|
||||
self.assertIn("-gencode=arch=compute_90,code=sm_90", flags)
|
||||
self.assertIn("-gencode=arch=compute_90,code=compute_90", flags)
|
||||
|
||||
def test_with_env_multiple(self):
|
||||
os.environ["PADDLE_CUDA_ARCH_LIST"] = "8.6;9.0+PTX"
|
||||
flags = _get_cuda_arch_flags()
|
||||
self.assertIn("-gencode=arch=compute_86,code=sm_86", flags)
|
||||
self.assertIn("-gencode=arch=compute_90,code=sm_90", flags)
|
||||
self.assertIn("-gencode=arch=compute_90,code=compute_90", flags)
|
||||
|
||||
os.environ["PADDLE_CUDA_ARCH_LIST"] = "8.6,9.0+PTX"
|
||||
flags = _get_cuda_arch_flags()
|
||||
self.assertIn("-gencode=arch=compute_86,code=sm_86", flags)
|
||||
self.assertIn("-gencode=arch=compute_90,code=sm_90", flags)
|
||||
self.assertIn("-gencode=arch=compute_90,code=compute_90", flags)
|
||||
|
||||
os.environ["PADDLE_CUDA_ARCH_LIST"] = "8.6 9.0+PTX"
|
||||
flags = _get_cuda_arch_flags()
|
||||
self.assertIn("-gencode=arch=compute_86,code=sm_86", flags)
|
||||
self.assertIn("-gencode=arch=compute_90,code=sm_90", flags)
|
||||
self.assertIn("-gencode=arch=compute_90,code=compute_90", flags)
|
||||
|
||||
def test_auto_detect(self):
|
||||
if "PADDLE_CUDA_ARCH_LIST" in os.environ:
|
||||
del os.environ["PADDLE_CUDA_ARCH_LIST"]
|
||||
flags = _get_cuda_arch_flags()
|
||||
self.assertTrue(len(flags) > 0)
|
||||
|
||||
def test_get_cuda_arch_flags_with_invalid_arch(self):
|
||||
os.environ["PADDLE_CUDA_ARCH_LIST"] = "invalid_arch"
|
||||
with self.assertRaises(ValueError) as context:
|
||||
_get_cuda_arch_flags()
|
||||
self.assertIn(
|
||||
"Unknown CUDA arch (invalid_arch) or GPU not supported",
|
||||
str(context.exception),
|
||||
)
|
||||
|
||||
def test_skip_paddle_extension_name_flag(self):
|
||||
flags = _get_cuda_arch_flags(cflags=["-DPADDLE_EXTENSION_NAME=my_ext"])
|
||||
self.assertNotEqual(flags, [])
|
||||
|
||||
def test_rocm_returns_empty_flags(self):
|
||||
with mock.patch.object(
|
||||
extension_utils.core, "is_compiled_with_rocm", return_value=True
|
||||
):
|
||||
self.assertEqual(_get_cuda_arch_flags(), [])
|
||||
|
||||
|
||||
class TestGetRocmArchFlags(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self._old_env = dict(os.environ)
|
||||
|
||||
def tearDown(self):
|
||||
os.environ.clear()
|
||||
os.environ.update(self._old_env)
|
||||
|
||||
def test_default_arch_list(self):
|
||||
if "PADDLE_ROCM_ARCH_LIST" in os.environ:
|
||||
del os.environ["PADDLE_ROCM_ARCH_LIST"]
|
||||
os.environ["ROCM_PATH"] = "/tmp/paddle-missing-rocm-for-test"
|
||||
os.environ["ROCM_HOME"] = "/tmp/paddle-missing-rocm-for-test"
|
||||
flags = extension_utils.get_rocm_arch_flags([])
|
||||
self.assertIn("-fno-gpu-rdc", flags)
|
||||
self.assertIn("--offload-arch=gfx906", flags)
|
||||
self.assertIn("--offload-arch=gfx936", flags)
|
||||
self.assertNotIn("--offload-arch=gfx950", flags)
|
||||
|
||||
def test_rocm70_default_arch_list(self):
|
||||
if "PADDLE_ROCM_ARCH_LIST" in os.environ:
|
||||
del os.environ["PADDLE_ROCM_ARCH_LIST"]
|
||||
with tempfile.TemporaryDirectory() as rocm_home:
|
||||
hip_include = os.path.join(rocm_home, "include", "hip")
|
||||
os.makedirs(hip_include)
|
||||
with open(
|
||||
os.path.join(hip_include, "hip_version.h"),
|
||||
"w",
|
||||
encoding="utf-8",
|
||||
) as f:
|
||||
f.write(
|
||||
"#define HIP_VERSION_MAJOR 7\n"
|
||||
"#define HIP_VERSION_MINOR 0\n"
|
||||
"#define HIP_VERSION_PATCH 0\n"
|
||||
)
|
||||
os.environ["ROCM_PATH"] = rocm_home
|
||||
os.environ["ROCM_HOME"] = rocm_home
|
||||
flags = extension_utils.get_rocm_arch_flags([])
|
||||
self.assertIn("--offload-arch=gfx90a", flags)
|
||||
self.assertIn("--offload-arch=gfx950", flags)
|
||||
|
||||
def test_env_arch_list_override(self):
|
||||
os.environ["PADDLE_ROCM_ARCH_LIST"] = "gfx950;gfx942 gfx942,gfx908"
|
||||
flags = extension_utils.get_rocm_arch_flags([])
|
||||
arch_flags = [
|
||||
flag for flag in flags if flag.startswith("--offload-arch=")
|
||||
]
|
||||
self.assertEqual(
|
||||
sorted(arch_flags),
|
||||
[
|
||||
"--offload-arch=gfx908",
|
||||
"--offload-arch=gfx942",
|
||||
"--offload-arch=gfx950",
|
||||
],
|
||||
)
|
||||
|
||||
def test_user_arch_flags_keep_no_gpu_rdc(self):
|
||||
flags = extension_utils.get_rocm_arch_flags(["--offload-arch=gfx950"])
|
||||
self.assertEqual(flags, ["-fno-gpu-rdc"])
|
||||
|
||||
def test_user_split_arch_flags_keep_no_gpu_rdc(self):
|
||||
flags = extension_utils.get_rocm_arch_flags(
|
||||
["--offload-arch", "gfx950"]
|
||||
)
|
||||
self.assertEqual(flags, ["-fno-gpu-rdc"])
|
||||
|
||||
def test_user_arch_flags_without_duplicate_no_gpu_rdc(self):
|
||||
flags = extension_utils.get_rocm_arch_flags(
|
||||
["-fno-gpu-rdc", "--offload-arch=gfx950"]
|
||||
)
|
||||
self.assertEqual(flags, [])
|
||||
|
||||
def test_rocm_version_header_empty_home(self):
|
||||
self.assertIsNone(extension_utils._get_rocm_version_from_header(""))
|
||||
|
||||
def test_rocm_version_header_oserror(self):
|
||||
with tempfile.TemporaryDirectory() as rocm_home:
|
||||
hip_include = os.path.join(rocm_home, "include", "hip")
|
||||
os.makedirs(hip_include)
|
||||
hip_version_file = os.path.join(hip_include, "hip_version.h")
|
||||
with open(hip_version_file, "w", encoding="utf-8") as f:
|
||||
f.write("")
|
||||
with mock.patch(
|
||||
"paddle.utils.cpp_extension.extension_utils.open",
|
||||
side_effect=OSError("forced"),
|
||||
create=True,
|
||||
):
|
||||
self.assertIsNone(
|
||||
extension_utils._get_rocm_version_from_header(rocm_home)
|
||||
)
|
||||
|
||||
def test_default_arch_list_falls_back_to_opt_rocm(self):
|
||||
for var in ("ROCM_HOME", "ROCM_PATH"):
|
||||
os.environ.pop(var, None)
|
||||
with mock.patch.object(
|
||||
extension_utils,
|
||||
"_get_rocm_version_from_header",
|
||||
return_value=None,
|
||||
) as mocked:
|
||||
result = extension_utils._get_default_rocm_arch_list()
|
||||
mocked.assert_called_once_with("/opt/rocm")
|
||||
self.assertEqual(result, extension_utils._ROCM_LEGACY_AMDGPU_TARGETS)
|
||||
|
||||
def test_get_rocm_arch_flags_accepts_none_cflags(self):
|
||||
if "PADDLE_ROCM_ARCH_LIST" in os.environ:
|
||||
del os.environ["PADDLE_ROCM_ARCH_LIST"]
|
||||
os.environ["ROCM_PATH"] = "/tmp/paddle-missing-rocm-for-test"
|
||||
os.environ["ROCM_HOME"] = "/tmp/paddle-missing-rocm-for-test"
|
||||
flags = extension_utils.get_rocm_arch_flags(None)
|
||||
self.assertIn("-fno-gpu-rdc", flags)
|
||||
self.assertIn("--offload-arch=gfx906", flags)
|
||||
|
||||
|
||||
class TestCppExtensionUtils(unittest.TestCase):
|
||||
def test_cuda_home(self):
|
||||
if core.is_compiled_with_cuda():
|
||||
value = CUDA_HOME
|
||||
self.assertTrue(value is None or isinstance(value, str))
|
||||
|
||||
def test_get_pybind11_abi_build_flags(self):
|
||||
flags = _get_pybind11_abi_build_flags()
|
||||
self.assertIsInstance(flags, list)
|
||||
for f in flags:
|
||||
self.assertIsInstance(f, str)
|
||||
|
||||
def test_get_num_workers_with_env_verbose_false(self):
|
||||
os.environ["MAX_JOBS"] = "8"
|
||||
num = _get_num_workers(verbose=False)
|
||||
self.assertEqual(num, 8)
|
||||
|
||||
def test_get_num_workers_with_env_verbose_true(self):
|
||||
os.environ["MAX_JOBS"] = "8"
|
||||
num = _get_num_workers(verbose=True)
|
||||
self.assertEqual(num, 8)
|
||||
|
||||
def test_get_num_workers_without_env_verbose_true(self):
|
||||
if "MAX_JOBS" in os.environ:
|
||||
del os.environ["MAX_JOBS"]
|
||||
num = _get_num_workers(verbose=True)
|
||||
self.assertEqual(num, None)
|
||||
|
||||
def test_normalize_extension_kwargs_add_phi_lib_on_windows(self):
|
||||
with (
|
||||
mock.patch.object(extension_utils, 'IS_WINDOWS', True),
|
||||
mock.patch.object(
|
||||
extension_utils,
|
||||
'create_sym_link_if_not_exist',
|
||||
return_value='libpaddle.lib',
|
||||
),
|
||||
mock.patch.object(
|
||||
extension_utils, 'find_paddle_libraries', return_value=[]
|
||||
),
|
||||
mock.patch.object(
|
||||
extension_utils,
|
||||
'find_paddle_custom_device_includes',
|
||||
return_value=[],
|
||||
),
|
||||
mock.patch.object(
|
||||
extension_utils, 'find_paddle_includes', return_value=[]
|
||||
),
|
||||
mock.patch.object(
|
||||
extension_utils, 'find_python_includes', return_value=[]
|
||||
),
|
||||
):
|
||||
kwargs = extension_utils.normalize_extension_kwargs(
|
||||
{'extra_link_args': ['/DEBUG']}, use_cuda=False
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
kwargs['extra_link_args'],
|
||||
[
|
||||
'/DEBUG',
|
||||
*extension_utils.MSVC_LINK_FLAGS,
|
||||
'libpaddle.lib',
|
||||
'phi.lib',
|
||||
],
|
||||
)
|
||||
|
||||
def test_normalize_extension_kwargs_keep_user_phi_lib_on_windows(self):
|
||||
with (
|
||||
mock.patch.object(extension_utils, 'IS_WINDOWS', True),
|
||||
mock.patch.object(
|
||||
extension_utils,
|
||||
'create_sym_link_if_not_exist',
|
||||
return_value='libpaddle.lib',
|
||||
),
|
||||
mock.patch.object(
|
||||
extension_utils, 'find_paddle_libraries', return_value=[]
|
||||
),
|
||||
mock.patch.object(
|
||||
extension_utils,
|
||||
'find_paddle_custom_device_includes',
|
||||
return_value=[],
|
||||
),
|
||||
mock.patch.object(
|
||||
extension_utils, 'find_paddle_includes', return_value=[]
|
||||
),
|
||||
mock.patch.object(
|
||||
extension_utils, 'find_python_includes', return_value=[]
|
||||
),
|
||||
):
|
||||
kwargs = extension_utils.normalize_extension_kwargs(
|
||||
{
|
||||
'extra_link_args': [
|
||||
'/DEBUG',
|
||||
'phi.lib',
|
||||
'libpaddle.lib',
|
||||
]
|
||||
},
|
||||
use_cuda=False,
|
||||
)
|
||||
|
||||
self.assertEqual(kwargs['extra_link_args'].count('phi.lib'), 1)
|
||||
self.assertEqual(kwargs['extra_link_args'].count('libpaddle.lib'), 1)
|
||||
|
||||
def test_normalize_extension_kwargs_add_cuda_libs_on_windows(self):
|
||||
with (
|
||||
mock.patch.object(extension_utils, 'IS_WINDOWS', True),
|
||||
mock.patch.object(
|
||||
extension_utils,
|
||||
'create_sym_link_if_not_exist',
|
||||
return_value='libpaddle.lib',
|
||||
),
|
||||
mock.patch.object(
|
||||
extension_utils, 'find_paddle_libraries', return_value=[]
|
||||
),
|
||||
mock.patch.object(
|
||||
extension_utils,
|
||||
'find_paddle_custom_device_includes',
|
||||
return_value=[],
|
||||
),
|
||||
mock.patch.object(
|
||||
extension_utils, 'find_paddle_includes', return_value=[]
|
||||
),
|
||||
mock.patch.object(
|
||||
extension_utils, 'find_python_includes', return_value=[]
|
||||
),
|
||||
):
|
||||
kwargs = extension_utils.normalize_extension_kwargs(
|
||||
{
|
||||
'extra_link_args': [
|
||||
'/DEBUG',
|
||||
'phi.lib',
|
||||
'cudadevrt.lib',
|
||||
]
|
||||
},
|
||||
use_cuda=True,
|
||||
)
|
||||
|
||||
self.assertEqual(kwargs['extra_link_args'].count('phi.lib'), 1)
|
||||
self.assertEqual(kwargs['extra_link_args'].count('libpaddle.lib'), 1)
|
||||
self.assertEqual(kwargs['extra_link_args'].count('cudadevrt.lib'), 1)
|
||||
self.assertEqual(
|
||||
kwargs['extra_link_args'].count('cudart_static.lib'), 1
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,817 @@
|
||||
# Copyright (c) 2023 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.
|
||||
|
||||
import unittest
|
||||
|
||||
import paddle
|
||||
from paddle.base import core
|
||||
|
||||
|
||||
def is_custom_device():
|
||||
custom_dev_types = paddle.device.get_all_custom_device_type()
|
||||
if custom_dev_types and paddle.device.is_compiled_with_custom_device(
|
||||
custom_dev_types[0]
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def only_has_cpu():
|
||||
return (
|
||||
not core.is_compiled_with_cuda()
|
||||
and not core.is_compiled_with_xpu()
|
||||
and not is_custom_device()
|
||||
)
|
||||
|
||||
|
||||
class TestErrorCPU(unittest.TestCase):
|
||||
def test_max_memory_allocated_raises_on_cpu(self):
|
||||
if only_has_cpu():
|
||||
with self.assertRaisesRegex(
|
||||
ValueError, "not supported in CPU PaddlePaddle"
|
||||
):
|
||||
paddle.cuda.max_memory_allocated()
|
||||
with self.assertRaisesRegex(
|
||||
ValueError, "not supported in CPU PaddlePaddle"
|
||||
):
|
||||
paddle.device.max_memory_allocated()
|
||||
with self.assertRaisesRegex(
|
||||
ValueError, "not supported in CPU PaddlePaddle"
|
||||
):
|
||||
paddle.cuda.max_memory_reserved()
|
||||
with self.assertRaisesRegex(
|
||||
ValueError, "not supported in CPU PaddlePaddle"
|
||||
):
|
||||
paddle.device.max_memory_reserved()
|
||||
with self.assertRaisesRegex(
|
||||
ValueError, "not supported in CPU PaddlePaddle"
|
||||
):
|
||||
paddle.cuda.reset_max_memory_allocated()
|
||||
with self.assertRaisesRegex(
|
||||
ValueError, "not supported in CPU PaddlePaddle"
|
||||
):
|
||||
paddle.device.reset_max_memory_allocated()
|
||||
with self.assertRaisesRegex(
|
||||
ValueError, "not supported in CPU PaddlePaddle"
|
||||
):
|
||||
paddle.cuda.reset_max_memory_reserved()
|
||||
with self.assertRaisesRegex(
|
||||
ValueError, "not supported in CPU PaddlePaddle"
|
||||
):
|
||||
paddle.device.reset_max_memory_reserved()
|
||||
|
||||
|
||||
class TestDeviceAPIs(unittest.TestCase):
|
||||
"""Test paddle.device APIs across different hardware types."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test environment."""
|
||||
self.cuda_available = core.is_compiled_with_cuda()
|
||||
self.xpu_available = core.is_compiled_with_xpu()
|
||||
self.custom_device_available = is_custom_device()
|
||||
|
||||
# Get available custom device types
|
||||
if self.custom_device_available:
|
||||
self.custom_device_types = core.get_all_custom_device_type()
|
||||
self.default_custom_device = self.custom_device_types[0]
|
||||
else:
|
||||
self.custom_device_types = []
|
||||
self.default_custom_device = None
|
||||
|
||||
def test_device_count_cuda(self):
|
||||
"""Test device_count with CUDA."""
|
||||
if not core.is_compiled_with_cuda():
|
||||
self.skipTest("CUDA not available")
|
||||
count = paddle.device.device_count()
|
||||
self.assertIsInstance(count, int)
|
||||
self.assertGreaterEqual(count, 0)
|
||||
|
||||
def test_device_count_xpu(self):
|
||||
"""Test device_count with XPU."""
|
||||
if not core.is_compiled_with_xpu():
|
||||
self.skipTest("XPU not available")
|
||||
count = paddle.device.device_count()
|
||||
self.assertIsInstance(count, int)
|
||||
self.assertGreaterEqual(count, 0)
|
||||
|
||||
def test_device_count_customdevice(self):
|
||||
"""Test device_count with custom device."""
|
||||
if not is_custom_device():
|
||||
self.skipTest("Custom device not available")
|
||||
count = paddle.device.device_count()
|
||||
self.assertIsInstance(count, int)
|
||||
self.assertGreaterEqual(count, 0)
|
||||
|
||||
# Test with specific device type
|
||||
count_custom = paddle.device.device_count(self.default_custom_device)
|
||||
self.assertIsInstance(count_custom, int)
|
||||
self.assertGreaterEqual(count_custom, 0)
|
||||
|
||||
def test_get_device_properties_cuda(self):
|
||||
"""Test get_device_properties with CUDA."""
|
||||
if not core.is_compiled_with_cuda():
|
||||
self.skipTest("CUDA not available")
|
||||
# Test with default device
|
||||
props = paddle.device.get_device_properties()
|
||||
self.assertIsNotNone(props)
|
||||
|
||||
# Test with string input
|
||||
props_str = paddle.device.get_device_properties('gpu:0')
|
||||
self.assertIsNotNone(props_str)
|
||||
|
||||
props_str = paddle.device.get_device_properties('cuda:0')
|
||||
self.assertIsNotNone(props_str)
|
||||
|
||||
# Test with integer input
|
||||
props_int = paddle.device.get_device_properties(0)
|
||||
self.assertIsNotNone(props_int)
|
||||
|
||||
# Test with CUDAPlace input
|
||||
props_int = paddle.device.get_device_properties(paddle.CUDAPlace(0))
|
||||
self.assertIsNotNone(props_int)
|
||||
|
||||
def test_get_device_properties_customdevice(self):
|
||||
"""Test get_device_properties with custom device."""
|
||||
if not is_custom_device():
|
||||
self.skipTest("Custom device not available")
|
||||
# Test with default device
|
||||
props = paddle.device.get_device_properties()
|
||||
self.assertIsNotNone(props)
|
||||
|
||||
# Test with string input (device only)
|
||||
props_device = paddle.device.get_device_properties(
|
||||
self.default_custom_device
|
||||
)
|
||||
self.assertIsNotNone(props_device)
|
||||
|
||||
# Test with string input (device:id)
|
||||
props_str = paddle.device.get_device_properties(
|
||||
f'{self.default_custom_device}:0'
|
||||
)
|
||||
self.assertIsNotNone(props_str)
|
||||
|
||||
# Test with integer input
|
||||
props_int = paddle.device.get_device_properties(0)
|
||||
self.assertIsNotNone(props_int)
|
||||
|
||||
# Test with CustomPlace input
|
||||
props_custom = paddle.device.get_device_properties(
|
||||
paddle.CustomPlace(self.default_custom_device, 0)
|
||||
)
|
||||
self.assertIsNotNone(props_custom)
|
||||
|
||||
def test_empty_cache_cuda(self):
|
||||
"""Test empty_cache with CUDA."""
|
||||
if not core.is_compiled_with_cuda():
|
||||
self.skipTest("CUDA not available")
|
||||
# Should not raise any exception
|
||||
paddle.device.empty_cache()
|
||||
|
||||
def test_empty_cache_customdevice(self):
|
||||
"""Test empty_cache with custom device."""
|
||||
if not is_custom_device():
|
||||
self.skipTest("Custom device not available")
|
||||
# Should not raise any exception
|
||||
paddle.device.empty_cache()
|
||||
|
||||
def test_memory_apis_cuda(self):
|
||||
"""Test memory management APIs with CUDA with actual tensor allocation."""
|
||||
if not core.is_compiled_with_cuda():
|
||||
self.skipTest("CUDA not available")
|
||||
# Set device to GPU
|
||||
paddle.device.set_device('gpu')
|
||||
|
||||
# Test max_memory_allocated with different input types
|
||||
mem1 = paddle.device.max_memory_allocated()
|
||||
self.assertIsInstance(mem1, int)
|
||||
self.assertGreaterEqual(mem1, 0)
|
||||
|
||||
mem2 = paddle.device.max_memory_allocated('gpu:0')
|
||||
self.assertIsInstance(mem2, int)
|
||||
self.assertGreaterEqual(mem2, 0)
|
||||
|
||||
mem3 = paddle.device.max_memory_allocated(0)
|
||||
self.assertIsInstance(mem3, int)
|
||||
self.assertGreaterEqual(mem3, 0)
|
||||
|
||||
mem7 = paddle.device.max_memory_allocated(paddle.CUDAPlace(0))
|
||||
self.assertIsInstance(mem7, int)
|
||||
self.assertGreaterEqual(mem7, 0)
|
||||
|
||||
# Test max_memory_allocated with different input types
|
||||
mem1 = paddle.cuda.max_memory_allocated()
|
||||
self.assertIsInstance(mem1, int)
|
||||
self.assertGreaterEqual(mem1, 0)
|
||||
|
||||
mem2 = paddle.cuda.max_memory_allocated('gpu:0')
|
||||
self.assertIsInstance(mem2, int)
|
||||
self.assertGreaterEqual(mem2, 0)
|
||||
|
||||
mem3 = paddle.cuda.max_memory_allocated(0)
|
||||
self.assertIsInstance(mem3, int)
|
||||
self.assertGreaterEqual(mem3, 0)
|
||||
|
||||
mem7 = paddle.cuda.max_memory_allocated(paddle.CUDAPlace(0))
|
||||
self.assertIsInstance(mem7, int)
|
||||
self.assertGreaterEqual(mem7, 0)
|
||||
|
||||
# Test max_memory_reserved with different input types
|
||||
mem4 = paddle.device.max_memory_reserved()
|
||||
self.assertIsInstance(mem4, int)
|
||||
self.assertGreaterEqual(mem4, 0)
|
||||
|
||||
mem8 = paddle.device.max_memory_reserved('gpu:0')
|
||||
self.assertIsInstance(mem8, int)
|
||||
self.assertGreaterEqual(mem8, 0)
|
||||
|
||||
mem4 = paddle.cuda.max_memory_reserved()
|
||||
self.assertIsInstance(mem4, int)
|
||||
self.assertGreaterEqual(mem4, 0)
|
||||
|
||||
mem8 = paddle.cuda.max_memory_reserved('gpu:0')
|
||||
self.assertIsInstance(mem8, int)
|
||||
self.assertGreaterEqual(mem8, 0)
|
||||
|
||||
mem9 = paddle.device.max_memory_reserved(0)
|
||||
self.assertIsInstance(mem9, int)
|
||||
self.assertGreaterEqual(mem9, 0)
|
||||
|
||||
mem10 = paddle.device.max_memory_reserved(paddle.CUDAPlace(0))
|
||||
self.assertIsInstance(mem10, int)
|
||||
self.assertGreaterEqual(mem10, 0)
|
||||
|
||||
# Test memory_allocated with different input types
|
||||
mem5 = paddle.device.memory_allocated()
|
||||
self.assertIsInstance(mem5, int)
|
||||
self.assertGreaterEqual(mem5, 0)
|
||||
|
||||
mem11 = paddle.device.memory_allocated('gpu:0')
|
||||
self.assertIsInstance(mem11, int)
|
||||
self.assertGreaterEqual(mem11, 0)
|
||||
|
||||
mem12 = paddle.device.memory_allocated(0)
|
||||
self.assertIsInstance(mem12, int)
|
||||
self.assertGreaterEqual(mem12, 0)
|
||||
|
||||
mem13 = paddle.device.memory_allocated(paddle.CUDAPlace(0))
|
||||
self.assertIsInstance(mem13, int)
|
||||
self.assertGreaterEqual(mem13, 0)
|
||||
|
||||
# Test memory_reserved with different input types
|
||||
mem6 = paddle.device.memory_reserved()
|
||||
self.assertIsInstance(mem6, int)
|
||||
self.assertGreaterEqual(mem6, 0)
|
||||
|
||||
mem14 = paddle.device.memory_reserved('gpu:0')
|
||||
self.assertIsInstance(mem14, int)
|
||||
self.assertGreaterEqual(mem14, 0)
|
||||
|
||||
mem15 = paddle.device.memory_reserved(0)
|
||||
self.assertIsInstance(mem15, int)
|
||||
self.assertGreaterEqual(mem15, 0)
|
||||
|
||||
mem16 = paddle.device.memory_reserved(paddle.CUDAPlace(0))
|
||||
self.assertIsInstance(mem16, int)
|
||||
self.assertGreaterEqual(mem16, 0)
|
||||
|
||||
# Now test actual memory allocation and tracking
|
||||
initial_allocated = paddle.device.memory_allocated()
|
||||
initial_max_allocated = paddle.device.max_memory_allocated()
|
||||
initial_reserved = paddle.device.memory_reserved()
|
||||
initial_max_reserved = paddle.device.max_memory_reserved()
|
||||
|
||||
# Allocate first tensor (10MB)
|
||||
tensor1 = paddle.randn([256, 256, 256], dtype='float32') # ~67MB
|
||||
|
||||
# Check memory after first allocation
|
||||
allocated_after_first = paddle.device.memory_allocated()
|
||||
max_allocated_after_first = paddle.device.max_memory_allocated()
|
||||
reserved_after_first = paddle.device.memory_reserved()
|
||||
max_reserved_after_first = paddle.device.max_memory_reserved()
|
||||
|
||||
self.assertGreater(allocated_after_first, initial_allocated)
|
||||
self.assertGreater(max_allocated_after_first, initial_max_allocated)
|
||||
self.assertGreaterEqual(reserved_after_first, initial_reserved)
|
||||
self.assertGreaterEqual(max_reserved_after_first, initial_max_reserved)
|
||||
|
||||
# Allocate second tensor (5MB)
|
||||
tensor2 = paddle.randn([128, 128, 128], dtype='float32') # ~8MB
|
||||
|
||||
# Check memory after second allocation
|
||||
allocated_after_second = paddle.device.memory_allocated()
|
||||
max_allocated_after_second = paddle.device.max_memory_allocated()
|
||||
reserved_after_second = paddle.device.memory_reserved()
|
||||
max_reserved_after_second = paddle.device.max_memory_reserved()
|
||||
|
||||
# Memory should have increased further
|
||||
self.assertGreater(allocated_after_second, allocated_after_first)
|
||||
self.assertGreater(
|
||||
max_allocated_after_second, max_allocated_after_first
|
||||
)
|
||||
self.assertGreaterEqual(reserved_after_second, reserved_after_first)
|
||||
self.assertGreaterEqual(
|
||||
max_reserved_after_second, max_reserved_after_first
|
||||
)
|
||||
|
||||
# Release first tensor
|
||||
del tensor1
|
||||
|
||||
# Check memory after releasing first tensor
|
||||
allocated_after_release = paddle.device.memory_allocated()
|
||||
max_allocated_after_release = paddle.device.max_memory_allocated()
|
||||
reserved_after_release = paddle.device.memory_reserved()
|
||||
max_reserved_after_release = paddle.device.max_memory_reserved()
|
||||
|
||||
# Current allocated should decrease, but max should stay the same
|
||||
self.assertLess(allocated_after_release, allocated_after_second)
|
||||
self.assertEqual(
|
||||
max_allocated_after_release, max_allocated_after_second
|
||||
)
|
||||
self.assertLessEqual(reserved_after_release, reserved_after_second)
|
||||
self.assertEqual(max_reserved_after_release, max_reserved_after_second)
|
||||
|
||||
# Test reset functions
|
||||
paddle.device.reset_max_memory_allocated()
|
||||
paddle.device.reset_max_memory_reserved()
|
||||
paddle.device.synchronize()
|
||||
|
||||
# Check memory after reset
|
||||
allocated_after_reset = paddle.device.memory_allocated()
|
||||
max_allocated_after_reset = paddle.device.max_memory_allocated()
|
||||
reserved_after_reset = paddle.device.memory_reserved()
|
||||
max_reserved_after_reset = paddle.device.max_memory_reserved()
|
||||
|
||||
# Current allocated should remain the same, but max should be reset to current level
|
||||
self.assertEqual(allocated_after_reset, allocated_after_release)
|
||||
self.assertLessEqual(
|
||||
max_allocated_after_reset, max_allocated_after_release
|
||||
)
|
||||
self.assertEqual(reserved_after_reset, reserved_after_release)
|
||||
self.assertLessEqual(
|
||||
max_reserved_after_reset, max_reserved_after_release
|
||||
)
|
||||
|
||||
# Clean up
|
||||
del tensor2
|
||||
paddle.device.empty_cache()
|
||||
|
||||
def test_memory_apis_customdevice(self):
|
||||
"""Test memory management APIs with custom device with actual tensor allocation."""
|
||||
if not is_custom_device():
|
||||
self.skipTest("Custom device not available")
|
||||
# Set device to custom device
|
||||
paddle.device.set_device(self.default_custom_device)
|
||||
|
||||
# Test max_memory_allocated with different input types
|
||||
mem1 = paddle.device.max_memory_allocated()
|
||||
self.assertIsInstance(mem1, int)
|
||||
self.assertGreaterEqual(mem1, 0)
|
||||
|
||||
mem2 = paddle.device.max_memory_allocated(self.default_custom_device)
|
||||
self.assertIsInstance(mem2, int)
|
||||
self.assertGreaterEqual(mem2, 0)
|
||||
|
||||
mem3 = paddle.device.max_memory_allocated(
|
||||
f'{self.default_custom_device}:0'
|
||||
)
|
||||
self.assertIsInstance(mem3, int)
|
||||
self.assertGreaterEqual(mem3, 0)
|
||||
|
||||
mem4 = paddle.device.max_memory_allocated(0)
|
||||
self.assertIsInstance(mem4, int)
|
||||
self.assertGreaterEqual(mem4, 0)
|
||||
|
||||
# Test with CustomPlace
|
||||
custom_place = core.CustomPlace(self.default_custom_device, 0)
|
||||
mem5 = paddle.device.max_memory_allocated(custom_place)
|
||||
self.assertIsInstance(mem5, int)
|
||||
self.assertGreaterEqual(mem5, 0)
|
||||
|
||||
# Test max_memory_reserved with different input types
|
||||
mem6 = paddle.device.max_memory_reserved()
|
||||
self.assertIsInstance(mem6, int)
|
||||
self.assertGreaterEqual(mem6, 0)
|
||||
|
||||
mem7 = paddle.device.max_memory_reserved(self.default_custom_device)
|
||||
self.assertIsInstance(mem7, int)
|
||||
self.assertGreaterEqual(mem7, 0)
|
||||
|
||||
mem8 = paddle.device.max_memory_reserved(
|
||||
f'{self.default_custom_device}:0'
|
||||
)
|
||||
self.assertIsInstance(mem8, int)
|
||||
self.assertGreaterEqual(mem8, 0)
|
||||
|
||||
mem9 = paddle.device.max_memory_reserved(0)
|
||||
self.assertIsInstance(mem9, int)
|
||||
self.assertGreaterEqual(mem9, 0)
|
||||
|
||||
# Test with CustomPlace
|
||||
custom_place = core.CustomPlace(self.default_custom_device, 0)
|
||||
mem10 = paddle.device.max_memory_reserved(custom_place)
|
||||
self.assertIsInstance(mem10, int)
|
||||
self.assertGreaterEqual(mem10, 0)
|
||||
|
||||
# Test memory_allocated with different input types
|
||||
mem11 = paddle.device.memory_allocated()
|
||||
self.assertIsInstance(mem11, int)
|
||||
self.assertGreaterEqual(mem11, 0)
|
||||
|
||||
mem12 = paddle.device.memory_allocated(self.default_custom_device)
|
||||
self.assertIsInstance(mem12, int)
|
||||
self.assertGreaterEqual(mem12, 0)
|
||||
|
||||
mem13 = paddle.device.memory_allocated(
|
||||
f'{self.default_custom_device}:0'
|
||||
)
|
||||
self.assertIsInstance(mem13, int)
|
||||
self.assertGreaterEqual(mem13, 0)
|
||||
|
||||
mem14 = paddle.device.memory_allocated(0)
|
||||
self.assertIsInstance(mem14, int)
|
||||
self.assertGreaterEqual(mem14, 0)
|
||||
|
||||
# Test with CustomPlace
|
||||
custom_place = core.CustomPlace(self.default_custom_device, 0)
|
||||
mem15 = paddle.device.memory_allocated(custom_place)
|
||||
self.assertIsInstance(mem15, int)
|
||||
self.assertGreaterEqual(mem15, 0)
|
||||
|
||||
# Test memory_reserved with different input types
|
||||
mem16 = paddle.device.memory_reserved()
|
||||
self.assertIsInstance(mem16, int)
|
||||
self.assertGreaterEqual(mem16, 0)
|
||||
|
||||
mem17 = paddle.device.memory_reserved(self.default_custom_device)
|
||||
self.assertIsInstance(mem17, int)
|
||||
self.assertGreaterEqual(mem17, 0)
|
||||
|
||||
mem18 = paddle.device.memory_reserved(f'{self.default_custom_device}:0')
|
||||
self.assertIsInstance(mem18, int)
|
||||
self.assertGreaterEqual(mem18, 0)
|
||||
|
||||
mem19 = paddle.device.memory_reserved(0)
|
||||
self.assertIsInstance(mem19, int)
|
||||
self.assertGreaterEqual(mem19, 0)
|
||||
|
||||
# Test with CustomPlace
|
||||
custom_place = core.CustomPlace(self.default_custom_device, 0)
|
||||
mem20 = paddle.device.memory_reserved(custom_place)
|
||||
self.assertIsInstance(mem20, int)
|
||||
self.assertGreaterEqual(mem20, 0)
|
||||
|
||||
# Now test actual memory allocation and tracking
|
||||
initial_allocated = paddle.device.memory_allocated()
|
||||
initial_max_allocated = paddle.device.max_memory_allocated()
|
||||
initial_reserved = paddle.device.memory_reserved()
|
||||
initial_max_reserved = paddle.device.max_memory_reserved()
|
||||
|
||||
# Allocate first tensor
|
||||
tensor1 = paddle.randn([128, 128, 128], dtype='float32') # ~8MB
|
||||
|
||||
# Check memory after first allocation
|
||||
allocated_after_first = paddle.device.memory_allocated()
|
||||
max_allocated_after_first = paddle.device.max_memory_allocated()
|
||||
reserved_after_first = paddle.device.memory_reserved()
|
||||
max_reserved_after_first = paddle.device.max_memory_reserved()
|
||||
|
||||
# Memory should have increased
|
||||
self.assertGreater(allocated_after_first, initial_allocated)
|
||||
self.assertGreater(max_allocated_after_first, initial_max_allocated)
|
||||
self.assertGreaterEqual(reserved_after_first, initial_reserved)
|
||||
self.assertGreaterEqual(max_reserved_after_first, initial_max_reserved)
|
||||
|
||||
# Allocate second tensor
|
||||
tensor2 = paddle.randn([64, 64, 64], dtype='float32') # ~2MB
|
||||
|
||||
# Check memory after second allocation
|
||||
allocated_after_second = paddle.device.memory_allocated()
|
||||
max_allocated_after_second = paddle.device.max_memory_allocated()
|
||||
reserved_after_second = paddle.device.memory_reserved()
|
||||
max_reserved_after_second = paddle.device.max_memory_reserved()
|
||||
|
||||
# Memory should have increased further
|
||||
self.assertGreater(allocated_after_second, allocated_after_first)
|
||||
self.assertGreater(
|
||||
max_allocated_after_second, max_allocated_after_first
|
||||
)
|
||||
self.assertGreaterEqual(reserved_after_second, reserved_after_first)
|
||||
self.assertGreaterEqual(
|
||||
max_reserved_after_second, max_reserved_after_first
|
||||
)
|
||||
|
||||
# Release first tensor
|
||||
del tensor1
|
||||
|
||||
# Check memory after releasing first tensor
|
||||
allocated_after_release = paddle.device.memory_allocated()
|
||||
max_allocated_after_release = paddle.device.max_memory_allocated()
|
||||
reserved_after_release = paddle.device.memory_reserved()
|
||||
max_reserved_after_release = paddle.device.max_memory_reserved()
|
||||
|
||||
# Current allocated should decrease, but max should stay the same
|
||||
self.assertLess(allocated_after_release, allocated_after_second)
|
||||
self.assertEqual(
|
||||
max_allocated_after_release, max_allocated_after_second
|
||||
)
|
||||
self.assertLessEqual(reserved_after_release, reserved_after_second)
|
||||
self.assertEqual(max_reserved_after_release, max_reserved_after_second)
|
||||
|
||||
# Test reset functions
|
||||
paddle.device.reset_max_memory_allocated()
|
||||
paddle.device.reset_max_memory_reserved()
|
||||
|
||||
# Check memory after reset
|
||||
allocated_after_reset = paddle.device.memory_allocated()
|
||||
max_allocated_after_reset = paddle.device.max_memory_allocated()
|
||||
reserved_after_reset = paddle.device.memory_reserved()
|
||||
max_reserved_after_reset = paddle.device.max_memory_reserved()
|
||||
|
||||
# Current allocated should remain the same, but max should be reset to current level
|
||||
self.assertEqual(allocated_after_reset, allocated_after_release)
|
||||
self.assertLessEqual(
|
||||
max_allocated_after_reset, max_allocated_after_release
|
||||
)
|
||||
self.assertEqual(reserved_after_reset, reserved_after_release)
|
||||
self.assertLessEqual(
|
||||
max_reserved_after_reset, max_reserved_after_release
|
||||
)
|
||||
|
||||
# Clean up
|
||||
del tensor2
|
||||
paddle.device.empty_cache()
|
||||
|
||||
def test_reset_memory_apis_cuda(self):
|
||||
"""Test reset memory APIs with CUDA with actual tensor allocation."""
|
||||
if not core.is_compiled_with_cuda():
|
||||
self.skipTest("CUDA not available")
|
||||
# Set device to GPU
|
||||
paddle.device.set_device('gpu')
|
||||
|
||||
# Get initial memory values
|
||||
initial_max_allocated = paddle.device.max_memory_allocated()
|
||||
initial_max_reserved = paddle.device.max_memory_reserved()
|
||||
|
||||
# Allocate tensor to increase memory usage
|
||||
tensor = paddle.randn([256, 256, 256], dtype='float32') # ~67MB
|
||||
|
||||
# Check that max memory has increased
|
||||
max_allocated_after_alloc = paddle.device.max_memory_allocated()
|
||||
max_reserved_after_alloc = paddle.device.max_memory_reserved()
|
||||
self.assertGreater(max_allocated_after_alloc, initial_max_allocated)
|
||||
self.assertGreaterEqual(max_reserved_after_alloc, initial_max_reserved)
|
||||
|
||||
# Test reset functions with different input types
|
||||
paddle.device.reset_max_memory_allocated()
|
||||
paddle.device.reset_max_memory_allocated('gpu:0')
|
||||
paddle.device.reset_max_memory_allocated(0)
|
||||
paddle.device.reset_max_memory_allocated(paddle.CUDAPlace(0))
|
||||
|
||||
# Test reset functions with different input types
|
||||
paddle.device.reset_peak_memory_stats()
|
||||
paddle.device.reset_peak_memory_stats('gpu:0')
|
||||
paddle.device.reset_peak_memory_stats('cuda:0')
|
||||
paddle.device.reset_peak_memory_stats(0)
|
||||
paddle.device.reset_peak_memory_stats(paddle.CUDAPlace(0))
|
||||
|
||||
# Test reset functions with different input types
|
||||
paddle.cuda.reset_peak_memory_stats()
|
||||
paddle.cuda.reset_peak_memory_stats('gpu:0')
|
||||
paddle.cuda.reset_peak_memory_stats(0)
|
||||
paddle.cuda.reset_peak_memory_stats(paddle.CUDAPlace(0))
|
||||
|
||||
paddle.device.reset_max_memory_reserved()
|
||||
paddle.device.reset_max_memory_reserved('gpu:0')
|
||||
paddle.device.reset_max_memory_reserved('cuda:0')
|
||||
paddle.device.reset_max_memory_reserved(0)
|
||||
paddle.device.reset_max_memory_reserved(paddle.CUDAPlace(0))
|
||||
|
||||
# Test reset functions with different input types
|
||||
paddle.cuda.reset_max_memory_allocated()
|
||||
paddle.cuda.reset_max_memory_allocated('gpu:0')
|
||||
paddle.cuda.reset_max_memory_allocated('cuda:0')
|
||||
paddle.cuda.reset_max_memory_allocated(0)
|
||||
paddle.cuda.reset_max_memory_allocated(paddle.CUDAPlace(0))
|
||||
|
||||
paddle.cuda.reset_max_memory_reserved()
|
||||
paddle.cuda.reset_max_memory_reserved('gpu:0')
|
||||
paddle.cuda.reset_max_memory_reserved('cuda:0')
|
||||
paddle.cuda.reset_max_memory_reserved(0)
|
||||
paddle.cuda.reset_max_memory_reserved(paddle.CUDAPlace(0))
|
||||
|
||||
# Check that max memory has been reset
|
||||
max_allocated_after_reset = paddle.device.max_memory_allocated()
|
||||
max_reserved_after_reset = paddle.device.max_memory_reserved()
|
||||
|
||||
# Max memory should be reset to current level (which should be lower than after allocation)
|
||||
self.assertLessEqual(
|
||||
max_allocated_after_reset, max_allocated_after_alloc
|
||||
)
|
||||
self.assertLessEqual(max_reserved_after_reset, max_reserved_after_alloc)
|
||||
|
||||
# Clean up
|
||||
del tensor
|
||||
paddle.device.empty_cache()
|
||||
|
||||
def test_reset_memory_apis_customdevice(self):
|
||||
"""Test reset memory APIs with custom device with actual tensor allocation."""
|
||||
if not is_custom_device():
|
||||
self.skipTest("Custom device not available")
|
||||
# Set device to custom device
|
||||
paddle.device.set_device(self.default_custom_device)
|
||||
|
||||
# Get initial memory values
|
||||
initial_max_allocated = paddle.device.max_memory_allocated()
|
||||
initial_max_reserved = paddle.device.max_memory_reserved()
|
||||
|
||||
# Allocate tensor to increase memory usage
|
||||
tensor = paddle.randn([128, 128, 128], dtype='float32') # ~8MB
|
||||
|
||||
# Check that max memory has increased
|
||||
max_allocated_after_alloc = paddle.device.max_memory_allocated()
|
||||
max_reserved_after_alloc = paddle.device.max_memory_reserved()
|
||||
self.assertGreater(max_allocated_after_alloc, initial_max_allocated)
|
||||
self.assertGreaterEqual(max_reserved_after_alloc, initial_max_reserved)
|
||||
|
||||
# Test reset functions with different input types
|
||||
paddle.device.reset_max_memory_allocated()
|
||||
paddle.device.reset_max_memory_allocated(self.default_custom_device)
|
||||
paddle.device.reset_max_memory_allocated(
|
||||
f'{self.default_custom_device}:0'
|
||||
)
|
||||
paddle.device.reset_max_memory_allocated(0)
|
||||
|
||||
custom_place = core.CustomPlace(self.default_custom_device, 0)
|
||||
paddle.device.reset_max_memory_allocated(custom_place)
|
||||
|
||||
paddle.device.reset_max_memory_reserved()
|
||||
paddle.device.reset_max_memory_reserved(self.default_custom_device)
|
||||
paddle.device.reset_max_memory_reserved(
|
||||
f'{self.default_custom_device}:0'
|
||||
)
|
||||
paddle.device.reset_max_memory_reserved(0)
|
||||
|
||||
custom_place = core.CustomPlace(self.default_custom_device, 0)
|
||||
paddle.device.reset_max_memory_reserved(custom_place)
|
||||
|
||||
# Check that max memory has been reset
|
||||
max_allocated_after_reset = paddle.device.max_memory_allocated()
|
||||
max_reserved_after_reset = paddle.device.max_memory_reserved()
|
||||
|
||||
# Max memory should be reset to current level (which should be lower than after allocation)
|
||||
self.assertLessEqual(
|
||||
max_allocated_after_reset, max_allocated_after_alloc
|
||||
)
|
||||
self.assertLessEqual(max_reserved_after_reset, max_reserved_after_alloc)
|
||||
|
||||
# Clean up
|
||||
del tensor
|
||||
paddle.device.empty_cache()
|
||||
|
||||
def test_stream_apis_cuda(self):
|
||||
"""Test stream APIs with CUDA."""
|
||||
if not core.is_compiled_with_cuda():
|
||||
self.skipTest("CUDA not available")
|
||||
# Test current_stream with different input types
|
||||
stream1 = paddle.device.current_stream()
|
||||
self.assertIsNotNone(stream1)
|
||||
|
||||
stream2 = paddle.device.current_stream(paddle.CUDAPlace(0))
|
||||
self.assertIsNotNone(stream2)
|
||||
|
||||
# stream3 = paddle.device.current_stream(0)
|
||||
# self.assertIsNotNone(stream3)
|
||||
|
||||
# Test synchronize
|
||||
paddle.device.synchronize()
|
||||
paddle.device.synchronize(paddle.CUDAPlace(0))
|
||||
# paddle.device.synchronize(0)
|
||||
|
||||
def test_stream_apis_customdevice(self):
|
||||
"""Test stream APIs with custom device."""
|
||||
if not is_custom_device():
|
||||
self.skipTest("Custom device not available")
|
||||
# Test current_stream with different input types
|
||||
stream1 = paddle.device.current_stream()
|
||||
self.assertIsNotNone(stream1)
|
||||
|
||||
stream2 = paddle.device.current_stream(self.default_custom_device)
|
||||
self.assertIsNotNone(stream2)
|
||||
|
||||
stream3 = paddle.device.current_stream(
|
||||
f'{self.default_custom_device}:0'
|
||||
)
|
||||
self.assertIsNotNone(stream3)
|
||||
|
||||
# stream4 = paddle.device.current_stream(0)
|
||||
# self.assertIsNotNone(stream4)
|
||||
|
||||
# Test synchronize
|
||||
paddle.device.synchronize()
|
||||
paddle.device.synchronize(self.default_custom_device)
|
||||
paddle.device.synchronize(f'{self.default_custom_device}:0')
|
||||
# paddle.device.synchronize(0)
|
||||
|
||||
def test_stream_apis_xpu(self):
|
||||
"""Test stream APIs with XPU."""
|
||||
if not core.is_compiled_with_xpu():
|
||||
self.skipTest("XPU not available")
|
||||
# Test current_stream with different input types
|
||||
stream1 = paddle.device.current_stream()
|
||||
self.assertIsNotNone(stream1)
|
||||
|
||||
stream2 = paddle.device.current_stream(core.XPUPlace(0))
|
||||
self.assertIsNotNone(stream2)
|
||||
|
||||
# stream3 = paddle.device.current_stream(0)
|
||||
# self.assertIsNotNone(stream3)
|
||||
|
||||
# Test synchronize
|
||||
paddle.device.synchronize()
|
||||
paddle.device.synchronize('xpu:0')
|
||||
# paddle.device.synchronize(0)
|
||||
|
||||
def test_error_handling(self):
|
||||
"""Test error handling for invalid inputs."""
|
||||
if not (
|
||||
core.is_compiled_with_xpu()
|
||||
or core.is_compiled_with_cuda()
|
||||
or is_custom_device()
|
||||
):
|
||||
self.skipTest("CUDA, XPU and Custom device not available")
|
||||
# Test invalid device ID format
|
||||
with self.assertRaises(ValueError):
|
||||
paddle.device.max_memory_allocated('gpu:invalid')
|
||||
|
||||
# Test invalid input type
|
||||
with self.assertRaises(ValueError):
|
||||
paddle.device.max_memory_allocated([1, 2, 3])
|
||||
|
||||
def test_get_default_device_cuda(self):
|
||||
"""Test get_default_device with CUDA."""
|
||||
if not core.is_compiled_with_cuda():
|
||||
self.skipTest("CUDA not available")
|
||||
paddle.device.set_device('gpu')
|
||||
dev = paddle.get_default_device()
|
||||
self.assertIsInstance(dev, paddle.device.Device)
|
||||
self.assertEqual(dev.type, 'cuda')
|
||||
|
||||
def test_get_default_device_customdevice(self):
|
||||
"""Test get_default_device with custom device."""
|
||||
if not is_custom_device():
|
||||
self.skipTest("Custom device not available")
|
||||
paddle.device.set_device(self.default_custom_device)
|
||||
dev = paddle.get_default_device()
|
||||
self.assertIsInstance(dev, paddle.device.Device)
|
||||
self.assertEqual(dev.type, self.default_custom_device)
|
||||
|
||||
def test_tensor_device_cuda(self):
|
||||
"""Test Tensor.device property with CUDA."""
|
||||
if not core.is_compiled_with_cuda():
|
||||
self.skipTest("CUDA not available")
|
||||
paddle.device.set_device('gpu')
|
||||
t = paddle.randn([2, 2])
|
||||
dev = t.device
|
||||
self.assertIsInstance(dev, paddle.device.Device)
|
||||
self.assertEqual(dev.type, 'cuda')
|
||||
self.assertIsNotNone(dev.index)
|
||||
del t
|
||||
|
||||
def test_tensor_device_customdevice(self):
|
||||
"""Test Tensor.device property with custom device."""
|
||||
if not is_custom_device():
|
||||
self.skipTest("Custom device not available")
|
||||
paddle.device.set_device(self.default_custom_device)
|
||||
t = paddle.randn([2, 2])
|
||||
dev = t.device
|
||||
self.assertIsInstance(dev, paddle.device.Device)
|
||||
self.assertEqual(dev.type, self.default_custom_device)
|
||||
self.assertIsNotNone(dev.index)
|
||||
del t
|
||||
|
||||
def test_device_class_customdevice(self):
|
||||
"""Test Device class with custom device type string and Place conversion."""
|
||||
if not is_custom_device():
|
||||
self.skipTest("Custom device not available")
|
||||
# String construction
|
||||
dev = paddle.device.Device(f'{self.default_custom_device}:0')
|
||||
self.assertEqual(dev.type, self.default_custom_device)
|
||||
self.assertEqual(dev.index, 0)
|
||||
# _to_place round-trip
|
||||
place = dev._to_place()
|
||||
self.assertTrue(place.is_custom_place())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,400 @@
|
||||
# Copyright (c) 2023 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.
|
||||
|
||||
import unittest
|
||||
|
||||
import paddle
|
||||
from paddle.base import core
|
||||
|
||||
|
||||
def is_custom_device():
|
||||
custom_dev_types = paddle.device.get_all_custom_device_type()
|
||||
if custom_dev_types and paddle.device.is_compiled_with_custom_device(
|
||||
custom_dev_types[0]
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class TestEventStreamAPIs(unittest.TestCase):
|
||||
"""Test paddle.device Event and Stream APIs across different hardware types."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test environment."""
|
||||
if not (
|
||||
core.is_compiled_with_cuda()
|
||||
or core.is_compiled_with_xpu()
|
||||
or is_custom_device()
|
||||
):
|
||||
self.skipTest("CUDA, XPU or Custom Device not available")
|
||||
|
||||
self.cuda_available = core.is_compiled_with_cuda()
|
||||
self.xpu_available = core.is_compiled_with_xpu()
|
||||
self.custom_device_available = is_custom_device()
|
||||
|
||||
# Get available custom device types
|
||||
if self.custom_device_available:
|
||||
self.custom_device_types = core.get_all_custom_device_type()
|
||||
self.default_custom_device = self.custom_device_types[0]
|
||||
else:
|
||||
self.custom_device_types = []
|
||||
self.default_custom_device = None
|
||||
|
||||
self._original_device = paddle.device.get_device()
|
||||
self._original_stream = paddle.device.current_stream()
|
||||
|
||||
def tearDown(self):
|
||||
"""Clean up after timing functionality test."""
|
||||
paddle.device.synchronize()
|
||||
paddle.device.set_device(self._original_device)
|
||||
try:
|
||||
paddle.device.set_stream(self._original_stream)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def test_event_stream_apis_cuda(self):
|
||||
"""Test Event and Stream APIs with CUDA."""
|
||||
if not core.is_compiled_with_cuda():
|
||||
self.skipTest("CUDA not available")
|
||||
self._test_event_stream_apis_impl('gpu:0')
|
||||
|
||||
def test_event_stream_apis_customdevice(self):
|
||||
"""Test Event and Stream APIs with custom device."""
|
||||
if not is_custom_device():
|
||||
self.skipTest("Custom device not available")
|
||||
self._test_event_stream_apis_impl(f'{self.default_custom_device}:0')
|
||||
|
||||
def test_event_stream_apis_xpu(self):
|
||||
"""Test Event and Stream APIs with XPU."""
|
||||
if not core.is_compiled_with_xpu():
|
||||
self.skipTest("XPU not available")
|
||||
self._test_event_stream_apis_impl('xpu:0')
|
||||
|
||||
def _test_event_stream_apis_impl(self, device_str):
|
||||
"""Test Event and Stream APIs implementation."""
|
||||
# Set device
|
||||
paddle.device.set_device(device_str)
|
||||
|
||||
# Test Event creation with different parameters
|
||||
event1 = paddle.device.Event()
|
||||
self.assertIsInstance(event1, paddle.device.Event)
|
||||
|
||||
event2 = paddle.device.Event(enable_timing=True)
|
||||
self.assertIsInstance(event2, paddle.device.Event)
|
||||
|
||||
event3 = paddle.device.Event(enable_timing=True, blocking=True)
|
||||
self.assertIsInstance(event3, paddle.device.Event)
|
||||
|
||||
# Test Stream creation with different parameters
|
||||
stream1 = paddle.device.Stream()
|
||||
self.assertIsInstance(stream1, paddle.device.Stream)
|
||||
|
||||
stream2 = paddle.device.Stream(device=device_str)
|
||||
self.assertIsInstance(stream2, paddle.device.Stream)
|
||||
|
||||
stream3 = paddle.device.Stream(device=device_str, priority=1)
|
||||
self.assertIsInstance(stream3, paddle.device.Stream)
|
||||
|
||||
# Test current_stream
|
||||
current_stream = paddle.device.current_stream()
|
||||
self.assertIsInstance(current_stream, paddle.device.Stream)
|
||||
|
||||
# Test set_stream
|
||||
prev_stream = paddle.device.set_stream(stream1)
|
||||
self.assertIsInstance(prev_stream, paddle.device.Stream)
|
||||
|
||||
prev_stream = paddle.cuda.set_stream(stream1)
|
||||
self.assertIsInstance(prev_stream, paddle.cuda.Stream)
|
||||
|
||||
# Test Event.record() with default stream
|
||||
event1.record()
|
||||
# Query result may be True immediately for some devices
|
||||
try:
|
||||
self.assertFalse(event1.query())
|
||||
except AssertionError:
|
||||
pass # Some devices may complete immediately
|
||||
|
||||
# Test Event.record() with specific stream
|
||||
self.assertTrue(event2.query())
|
||||
|
||||
# Test Event.synchronize()
|
||||
event1.synchronize() # Wait for event to complete
|
||||
self.assertTrue(event1.query()) # Should be completed now
|
||||
|
||||
# Test Stream.query()
|
||||
if not core.is_compiled_with_xpu():
|
||||
self.assertTrue(
|
||||
stream1.query()
|
||||
) # Should be completed (no work submitted)
|
||||
|
||||
# Test Stream.synchronize()
|
||||
stream1.synchronize() # Should not raise exception
|
||||
|
||||
# Test Stream.wait_event()
|
||||
stream2.wait_event(event1)
|
||||
|
||||
# Test Stream.wait_stream()
|
||||
stream2.wait_stream(stream1)
|
||||
|
||||
# Test Stream.record_event()
|
||||
event4 = stream1.record_event()
|
||||
self.assertIsInstance(event4, paddle.device.Event)
|
||||
|
||||
# Test record_event with existing event
|
||||
stream1.record_event(event3)
|
||||
|
||||
# Test Event.elapsed_time()
|
||||
if hasattr(event1, 'event_base') and hasattr(event2, 'event_base'):
|
||||
# Create events with timing enabled
|
||||
start_event = paddle.device.Event(enable_timing=True)
|
||||
end_event = paddle.device.Event(enable_timing=True)
|
||||
|
||||
# Record start event
|
||||
start_event.record()
|
||||
|
||||
# Submit some work to the stream
|
||||
with paddle.device.stream_guard(stream1):
|
||||
# Create a tensor to ensure some work is done
|
||||
tensor = paddle.randn([100, 100], dtype='float32')
|
||||
result = tensor * 2
|
||||
|
||||
# Record end event
|
||||
end_event.record()
|
||||
|
||||
# Synchronize to ensure events are recorded
|
||||
end_event.synchronize()
|
||||
|
||||
# Measure elapsed time
|
||||
if not core.is_compiled_with_xpu():
|
||||
elapsed_time = start_event.elapsed_time(end_event)
|
||||
self.assertIsInstance(elapsed_time, (int, float))
|
||||
self.assertGreaterEqual(elapsed_time, 0)
|
||||
|
||||
# Test stream_guard context manager
|
||||
with paddle.device.stream_guard(stream1):
|
||||
# Inside the context, current stream should be stream1
|
||||
guarded_stream = paddle.device.current_stream()
|
||||
self.assertEqual(guarded_stream.device, stream1.device)
|
||||
|
||||
# Test operations within stream guard
|
||||
tensor1 = paddle.ones([10, 10])
|
||||
tensor2 = paddle.ones([10, 10])
|
||||
result = tensor1 + tensor2
|
||||
|
||||
# After exiting context, stream should be restored
|
||||
restored_stream = paddle.device.current_stream()
|
||||
self.assertEqual(restored_stream.device, prev_stream.device)
|
||||
|
||||
# Test Stream properties and methods
|
||||
self.assertTrue(hasattr(stream1, 'stream_base'))
|
||||
self.assertTrue(hasattr(stream1, 'device'))
|
||||
if not core.is_compiled_with_xpu():
|
||||
self.assertTrue(callable(stream1.query))
|
||||
self.assertTrue(callable(stream1.synchronize))
|
||||
self.assertTrue(callable(stream1.wait_event))
|
||||
self.assertTrue(callable(stream1.wait_stream))
|
||||
self.assertTrue(callable(stream1.record_event))
|
||||
|
||||
# Test Event properties and methods
|
||||
self.assertTrue(hasattr(event1, 'event_base'))
|
||||
self.assertTrue(hasattr(event1, 'device'))
|
||||
self.assertTrue(callable(event1.record))
|
||||
self.assertTrue(callable(event1.query))
|
||||
if not core.is_compiled_with_xpu():
|
||||
self.assertTrue(callable(event1.elapsed_time))
|
||||
self.assertTrue(callable(event1.synchronize))
|
||||
|
||||
# Test Stream equality and hash
|
||||
stream_copy = paddle.device.Stream(device=device_str)
|
||||
self.assertNotEqual(stream1, stream_copy) # Different stream objects
|
||||
self.assertEqual(
|
||||
hash(stream1), hash(stream1)
|
||||
) # Same hash for same object
|
||||
|
||||
# Test Stream representation
|
||||
stream_repr = repr(stream1)
|
||||
self.assertIn('paddle.device.Stream', stream_repr)
|
||||
self.assertIn(str(stream1.device), stream_repr)
|
||||
|
||||
# Test Event representation
|
||||
event_repr = repr(event1)
|
||||
self.assertIsNotNone(event_repr)
|
||||
|
||||
# Clean up
|
||||
paddle.device.synchronize()
|
||||
|
||||
def test_event_stream_error_handling(self):
|
||||
"""Test Event and Stream error handling."""
|
||||
# Test with invalid device types
|
||||
with self.assertRaises(TypeError):
|
||||
paddle.device.Event(device='invalid_device:0')
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
paddle.device.Stream(device='invalid_device:0')
|
||||
|
||||
# Test Event.elapsed_time with incompatible events
|
||||
if core.is_compiled_with_cuda() or is_custom_device():
|
||||
device_str = (
|
||||
'gpu:0'
|
||||
if core.is_compiled_with_cuda()
|
||||
else f'{self.default_custom_device}:0'
|
||||
)
|
||||
paddle.device.set_device(device_str)
|
||||
|
||||
event1 = paddle.device.Event()
|
||||
event2 = paddle.device.Event()
|
||||
|
||||
# Should not raise exception even if events are not recorded
|
||||
try:
|
||||
elapsed = event1.elapsed_time(event2)
|
||||
self.assertIsInstance(elapsed, (int, float))
|
||||
except Exception:
|
||||
# Some implementations might raise exception, which is also acceptable
|
||||
pass
|
||||
|
||||
|
||||
class TestEventStreamTimingFunctionality(unittest.TestCase):
|
||||
"""Test Event timing functionality with actual work in isolated environment."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test environment for timing functionality."""
|
||||
if not (
|
||||
core.is_compiled_with_cuda()
|
||||
or core.is_compiled_with_xpu()
|
||||
or is_custom_device()
|
||||
):
|
||||
self.skipTest("CUDA, XPU or Custom Device not available")
|
||||
|
||||
self.cuda_available = core.is_compiled_with_cuda()
|
||||
self.custom_device_available = is_custom_device()
|
||||
|
||||
# Get available custom device types
|
||||
if self.custom_device_available:
|
||||
self.custom_device_types = core.get_all_custom_device_type()
|
||||
self.default_custom_device = self.custom_device_types[0]
|
||||
else:
|
||||
self.custom_device_types = []
|
||||
self.default_custom_device = None
|
||||
|
||||
self._original_device = paddle.device.get_device()
|
||||
self._original_stream = paddle.device.current_stream()
|
||||
|
||||
def tearDown(self):
|
||||
"""Clean up after timing functionality test."""
|
||||
paddle.device.synchronize()
|
||||
paddle.device.set_device(self._original_device)
|
||||
try:
|
||||
paddle.device.set_stream(self._original_stream)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def test_event_stream_timing_functionality(self):
|
||||
"""Test Event timing functionality with actual work."""
|
||||
if not (self.cuda_available or self.custom_device_available):
|
||||
self.skipTest(
|
||||
"Timing functionality test requires CUDA or custom device"
|
||||
)
|
||||
|
||||
device_str = (
|
||||
'gpu:0'
|
||||
if self.cuda_available
|
||||
else f'{self.default_custom_device}:0'
|
||||
)
|
||||
paddle.device.set_device(device_str)
|
||||
|
||||
# Create events with timing enabled
|
||||
start_event = paddle.device.Event(enable_timing=True)
|
||||
end_event = paddle.device.Event(enable_timing=True)
|
||||
|
||||
# Create a stream for work execution
|
||||
stream = paddle.device.Stream(device=device_str)
|
||||
|
||||
# Record start event
|
||||
start_event.record(stream)
|
||||
|
||||
# Perform some work on the stream
|
||||
with paddle.device.stream_guard(stream):
|
||||
# Create and perform operations on tensors
|
||||
x = paddle.randn([1000, 1000], dtype='float32')
|
||||
y = paddle.randn([1000, 1000], dtype='float32')
|
||||
# Matrix multiplication - computationally intensive
|
||||
z = paddle.matmul(x, y)
|
||||
# Ensure the operation is executed
|
||||
z_mean = z.mean()
|
||||
|
||||
# Record end event
|
||||
end_event.record(stream)
|
||||
|
||||
# Wait for the end event to complete
|
||||
end_event.synchronize()
|
||||
if not core.is_compiled_with_xpu():
|
||||
# Calculate elapsed time
|
||||
elapsed_time = start_event.elapsed_time(end_event)
|
||||
|
||||
# Verify the timing result
|
||||
self.assertIsInstance(elapsed_time, (int, float))
|
||||
self.assertGreater(elapsed_time, 0) # Should take some time
|
||||
|
||||
|
||||
class TestEventAPIs(unittest.TestCase):
|
||||
"""Unified test for paddle.Event, paddle.device.Event, and paddle.cuda.Event."""
|
||||
|
||||
def setUp(self):
|
||||
if not paddle.device.is_compiled_with_cuda():
|
||||
self.skipTest("This test requires CUDA.")
|
||||
self.device = "gpu:0"
|
||||
paddle.device.set_device(self.device)
|
||||
|
||||
self.event_classes = [
|
||||
("paddle.Event", paddle.Event),
|
||||
("paddle.cuda.Event", paddle.cuda.Event),
|
||||
]
|
||||
|
||||
def test_event_timing_consistency(self):
|
||||
"""Check timing consistency across different Event APIs."""
|
||||
for name, EventCls in self.event_classes:
|
||||
with self.subTest(api=name):
|
||||
start = EventCls(enable_timing=True)
|
||||
end = EventCls(enable_timing=True)
|
||||
|
||||
start.record()
|
||||
|
||||
x = paddle.randn([2048, 2048], dtype="float32")
|
||||
y = paddle.randn([2048, 2048], dtype="float32")
|
||||
z = paddle.matmul(x, y)
|
||||
_ = z.mean()
|
||||
|
||||
end.record()
|
||||
end.synchronize()
|
||||
|
||||
elapsed = start.elapsed_time(end)
|
||||
self.assertIsInstance(elapsed, (int, float))
|
||||
self.assertGreater(
|
||||
elapsed,
|
||||
0.0,
|
||||
f"{name} should measure positive elapsed time.",
|
||||
)
|
||||
|
||||
def test_event_methods_available(self):
|
||||
"""Ensure all Event variants expose expected methods."""
|
||||
for name, EventCls in self.event_classes:
|
||||
with self.subTest(api=name):
|
||||
e = EventCls(enable_timing=True)
|
||||
self.assertTrue(hasattr(e, "record"))
|
||||
self.assertTrue(hasattr(e, "synchronize"))
|
||||
self.assertTrue(hasattr(e, "elapsed_time"))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,79 @@
|
||||
# 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.
|
||||
|
||||
import unittest
|
||||
|
||||
import paddle
|
||||
from paddle import get_device_module
|
||||
|
||||
|
||||
class TestGetDeviceModule(unittest.TestCase):
|
||||
def test_str_devices(self):
|
||||
self.assertIs(get_device_module("gpu:0"), paddle.cuda)
|
||||
self.assertIs(get_device_module("cuda:0"), paddle.cuda)
|
||||
|
||||
self.assertIs(get_device_module("xpu:0"), paddle.device.xpu)
|
||||
|
||||
custom_devices = [
|
||||
"metax_gpu",
|
||||
"biren_gpu",
|
||||
"custom_cpu",
|
||||
"gcu",
|
||||
"iluvatar_gpu",
|
||||
"intel_gpu",
|
||||
"intel_hpu",
|
||||
"mlu",
|
||||
"mps",
|
||||
"npu",
|
||||
"sdaa",
|
||||
]
|
||||
for dev in custom_devices:
|
||||
self.assertIs(get_device_module(dev), paddle.device.custom_device)
|
||||
|
||||
self.assertIs(get_device_module('cpu'), paddle.device.cpu)
|
||||
|
||||
with self.assertRaises(RuntimeError):
|
||||
get_device_module("unknown_device")
|
||||
|
||||
def test_place_devices(self):
|
||||
if paddle.cuda.is_available() and paddle.device.is_compiled_with_cuda():
|
||||
self.assertIs(get_device_module(paddle.CUDAPlace(0)), paddle.cuda)
|
||||
|
||||
def test_none_device(self):
|
||||
current_device_module = get_device_module(None)
|
||||
current_device_type = paddle.device.get_device().split(":")[0].lower()
|
||||
if current_device_type in ("cuda", "gpu"):
|
||||
self.assertIs(current_device_module, paddle.cuda)
|
||||
elif current_device_type == "xpu":
|
||||
self.assertIs(current_device_module, paddle.device.xpu)
|
||||
elif current_device_type in [
|
||||
"metax_gpu",
|
||||
"biren_gpu",
|
||||
"custom_cpu",
|
||||
"gcu",
|
||||
"iluvatar_gpu",
|
||||
"intel_gpu",
|
||||
"intel_hpu",
|
||||
"mlu",
|
||||
"mps",
|
||||
"npu",
|
||||
"sdaa",
|
||||
]:
|
||||
self.assertIs(current_device_module, paddle.device.custom_device)
|
||||
elif current_device_type == "cpu":
|
||||
self.assertIs(current_device_module, paddle.device.cpu)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,60 @@
|
||||
# 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.
|
||||
|
||||
import unittest
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
@paddle.library.custom_op(
|
||||
"test_namespace::add_one",
|
||||
mutates_args=(),
|
||||
)
|
||||
def add_one(x):
|
||||
return x + 1
|
||||
|
||||
|
||||
@add_one.register_fake
|
||||
def add_one_fake_fn(x):
|
||||
return x
|
||||
|
||||
|
||||
@paddle.library.custom_op(
|
||||
"test_namespace::add_two",
|
||||
mutates_args=(),
|
||||
)
|
||||
def add_two(x):
|
||||
return x + 2
|
||||
|
||||
|
||||
class TestCallCustomOp(unittest.TestCase):
|
||||
def test_call_custom_op(self):
|
||||
self.assertEqual(paddle.ops.test_namespace.add_one(1), 2)
|
||||
|
||||
|
||||
class TestRegisterFake(unittest.TestCase):
|
||||
def test_register_fake_without_call(self):
|
||||
paddle.library.register_fake(
|
||||
"test_namespace::add_two",
|
||||
lambda x: x + 2,
|
||||
)
|
||||
|
||||
def test_register_fake_with_call(self):
|
||||
paddle.library.register_fake("test_namespace::add_three")(
|
||||
lambda x: x + 3,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,496 @@
|
||||
# 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.
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
from unittest import TestCase
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def should_skip_tests():
|
||||
"""
|
||||
Check if tests should be skipped based on device availability.
|
||||
Skip if neither CUDA, XPU, nor any custom device is available.
|
||||
"""
|
||||
# Check CUDA availability
|
||||
cuda_available = paddle.is_compiled_with_cuda()
|
||||
|
||||
# Check XPU availability
|
||||
xpu_available = paddle.is_compiled_with_xpu()
|
||||
|
||||
# Check custom device availability
|
||||
custom_available = False
|
||||
try:
|
||||
custom_devices = paddle.device.get_all_custom_device_type()
|
||||
if custom_devices:
|
||||
for device_type in custom_devices:
|
||||
if paddle.device.is_compiled_with_custom_device(device_type):
|
||||
custom_available = True
|
||||
break
|
||||
except Exception:
|
||||
custom_available = False
|
||||
|
||||
# Skip tests if no supported devices are available
|
||||
return not (cuda_available or xpu_available or custom_available)
|
||||
|
||||
|
||||
# Check if we should skip all tests
|
||||
if should_skip_tests():
|
||||
print(
|
||||
"Skipping paddle.cuda API tests: No CUDA, XPU, or custom devices available"
|
||||
)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
class TestCurrentDevice(TestCase):
|
||||
def test_current_device_return_type(self):
|
||||
"""Test that current_device returns an integer."""
|
||||
device_id = paddle.cuda.current_device()
|
||||
self.assertIsInstance(
|
||||
device_id, int, "current_device should return an integer"
|
||||
)
|
||||
|
||||
def test_current_device_non_negative(self):
|
||||
"""Test that current_device returns a non-negative integer."""
|
||||
device_id = paddle.cuda.current_device()
|
||||
self.assertGreaterEqual(
|
||||
device_id, 0, "current_device should return a non-negative integer"
|
||||
)
|
||||
|
||||
def test_current_device_with_device_set(self):
|
||||
"""Test current_device after setting device."""
|
||||
if paddle.device.cuda.device_count() > 0:
|
||||
# Test with CUDA device
|
||||
original_device = paddle.device.get_device()
|
||||
|
||||
# Set to device 0 if available
|
||||
paddle.device.set_device('gpu:0')
|
||||
device_id = paddle.cuda.current_device()
|
||||
self.assertEqual(
|
||||
device_id, 0, "current_device should return 0 when gpu:0 is set"
|
||||
)
|
||||
|
||||
# Restore original device
|
||||
paddle.device.set_device(original_device)
|
||||
|
||||
|
||||
class TestDeviceCount(TestCase):
|
||||
def test_device_count_return_type(self):
|
||||
"""Test that device_count returns an integer."""
|
||||
count = paddle.cuda.device_count()
|
||||
self.assertIsInstance(
|
||||
count, int, "device_count should return an integer"
|
||||
)
|
||||
|
||||
def test_device_count_non_negative(self):
|
||||
"""Test that device_count returns a non-negative integer."""
|
||||
count = paddle.cuda.device_count()
|
||||
self.assertGreaterEqual(
|
||||
count, 0, "device_count should return a non-negative integer"
|
||||
)
|
||||
|
||||
|
||||
class TestEmptyCache(TestCase):
|
||||
def test_empty_cache_return_type(self):
|
||||
"""Test that empty_cache returns None."""
|
||||
result = paddle.cuda.empty_cache()
|
||||
self.assertIsNone(result, "empty_cache should return None")
|
||||
|
||||
def test_empty_cache_no_exception(self):
|
||||
"""Test that empty_cache does not raise any exceptions."""
|
||||
try:
|
||||
paddle.cuda.empty_cache()
|
||||
except Exception as e:
|
||||
self.fail(f"empty_cache raised an exception: {e}")
|
||||
|
||||
def test_empty_cache_with_memory_allocation(self):
|
||||
"""Test that empty_cache works after memory allocation."""
|
||||
if paddle.cuda.device_count() > 0:
|
||||
# Get initial memory state
|
||||
initial_memory = paddle.cuda.memory_allocated()
|
||||
|
||||
# Allocate some memory
|
||||
tensor = paddle.randn([1000, 1000])
|
||||
allocated_memory = paddle.cuda.memory_allocated()
|
||||
|
||||
# Verify that memory was actually allocated
|
||||
self.assertGreater(
|
||||
allocated_memory,
|
||||
initial_memory,
|
||||
"Memory should increase after tensor allocation",
|
||||
)
|
||||
|
||||
# Delete tensor and empty cache
|
||||
del tensor
|
||||
paddle.cuda.empty_cache()
|
||||
|
||||
# Check memory after empty_cache
|
||||
final_memory = paddle.cuda.memory_allocated()
|
||||
|
||||
# Memory should be reduced after empty_cache
|
||||
# Note: We allow some tolerance as memory management may not free everything immediately
|
||||
self.assertLessEqual(
|
||||
final_memory,
|
||||
allocated_memory,
|
||||
"Memory should be reduced after empty_cache",
|
||||
)
|
||||
|
||||
|
||||
class TestIsInitialized(TestCase):
|
||||
def test_is_initialized_return_type(self):
|
||||
"""Test that is_initialized returns a boolean."""
|
||||
result = paddle.cuda.is_initialized()
|
||||
self.assertIsInstance(
|
||||
result, bool, "is_initialized should return a boolean"
|
||||
)
|
||||
|
||||
def test_is_initialized_no_exception(self):
|
||||
"""Test that is_initialized does not raise any exceptions."""
|
||||
try:
|
||||
paddle.cuda.is_initialized()
|
||||
except Exception as e:
|
||||
self.fail(f"is_initialized raised an exception: {e}")
|
||||
|
||||
def test_is_initialized_with_device_availability(self):
|
||||
"""Test that is_initialized returns True when devices are available."""
|
||||
# This test checks if is_initialized correctly detects device compilation
|
||||
# The result should be consistent with device availability checks
|
||||
initialized = paddle.cuda.is_initialized()
|
||||
|
||||
# If any device is available, is_initialized should return True
|
||||
cuda_available = paddle.is_compiled_with_cuda()
|
||||
xpu_available = paddle.is_compiled_with_xpu()
|
||||
|
||||
# Check custom devices
|
||||
custom_available = False
|
||||
try:
|
||||
custom_devices = paddle.device.get_all_custom_device_type()
|
||||
if custom_devices:
|
||||
for device_type in custom_devices:
|
||||
if paddle.device.is_compiled_with_custom_device(
|
||||
device_type
|
||||
):
|
||||
custom_available = True
|
||||
break
|
||||
except Exception:
|
||||
custom_available = False
|
||||
|
||||
# is_initialized should return True if any device type is compiled
|
||||
expected = cuda_available or xpu_available or custom_available
|
||||
self.assertEqual(
|
||||
initialized,
|
||||
expected,
|
||||
f"is_initialized should return {expected} when cuda={cuda_available}, xpu={xpu_available}, custom={custom_available}",
|
||||
)
|
||||
|
||||
|
||||
class TestMemoryAllocated(TestCase):
|
||||
def test_memory_allocated_return_type(self):
|
||||
"""Test that memory_allocated returns an integer."""
|
||||
result = paddle.cuda.memory_allocated()
|
||||
self.assertIsInstance(
|
||||
result, int, "memory_allocated should return an integer"
|
||||
)
|
||||
|
||||
def test_memory_allocated_non_negative(self):
|
||||
"""Test that memory_allocated returns a non-negative integer."""
|
||||
result = paddle.cuda.memory_allocated()
|
||||
self.assertGreaterEqual(
|
||||
result, 0, "memory_allocated should return a non-negative integer"
|
||||
)
|
||||
|
||||
def test_memory_allocated_consistency(self):
|
||||
"""Test that memory_allocated returns consistent results when called multiple times."""
|
||||
result1 = paddle.cuda.memory_allocated()
|
||||
result2 = paddle.cuda.memory_allocated()
|
||||
# Memory should be the same or increase (but not decrease without explicit free)
|
||||
self.assertGreaterEqual(
|
||||
result2, result1 - 1024, "memory_allocated should be consistent"
|
||||
)
|
||||
|
||||
def test_memory_allocated_with_device_param(self):
|
||||
"""Test that memory_allocated works with device parameter."""
|
||||
if paddle.cuda.device_count() > 0:
|
||||
# Test with device index
|
||||
result_index = paddle.cuda.memory_allocated(0)
|
||||
self.assertIsInstance(
|
||||
result_index,
|
||||
int,
|
||||
"memory_allocated should return an integer with device index",
|
||||
)
|
||||
self.assertGreaterEqual(
|
||||
result_index,
|
||||
0,
|
||||
"memory_allocated should return non-negative with device index",
|
||||
)
|
||||
|
||||
def test_memory_allocated_no_exception(self):
|
||||
"""Test that memory_allocated does not raise any exceptions."""
|
||||
try:
|
||||
paddle.cuda.memory_allocated()
|
||||
except Exception as e:
|
||||
self.fail(f"memory_allocated raised an exception: {e}")
|
||||
|
||||
|
||||
class TestMemoryReserved(TestCase):
|
||||
def test_memory_reserved_return_type(self):
|
||||
"""Test that memory_reserved returns an integer."""
|
||||
result = paddle.cuda.memory_reserved()
|
||||
self.assertIsInstance(
|
||||
result, int, "memory_reserved should return an integer"
|
||||
)
|
||||
|
||||
def test_memory_reserved_non_negative(self):
|
||||
"""Test that memory_reserved returns a non-negative integer."""
|
||||
result = paddle.cuda.memory_reserved()
|
||||
self.assertGreaterEqual(
|
||||
result, 0, "memory_reserved should return a non-negative integer"
|
||||
)
|
||||
|
||||
def test_memory_reserved_consistency(self):
|
||||
"""Test that memory_reserved returns consistent results when called multiple times."""
|
||||
result1 = paddle.cuda.memory_reserved()
|
||||
result2 = paddle.cuda.memory_reserved()
|
||||
# Reserved memory should be the same or increase (but not decrease without explicit free)
|
||||
self.assertGreaterEqual(
|
||||
result2, result1 - 1024, "memory_reserved should be consistent"
|
||||
)
|
||||
|
||||
def test_memory_reserved_with_device_param(self):
|
||||
"""Test that memory_reserved works with device parameter."""
|
||||
if paddle.cuda.device_count() > 0:
|
||||
# Test with device index
|
||||
result_index = paddle.cuda.memory_reserved(0)
|
||||
self.assertIsInstance(
|
||||
result_index,
|
||||
int,
|
||||
"memory_reserved should return an integer with device index",
|
||||
)
|
||||
self.assertGreaterEqual(
|
||||
result_index,
|
||||
0,
|
||||
"memory_reserved should return non-negative with device index",
|
||||
)
|
||||
|
||||
def test_memory_reserved_no_exception(self):
|
||||
"""Test that memory_reserved does not raise any exceptions."""
|
||||
try:
|
||||
paddle.cuda.memory_reserved()
|
||||
except Exception as e:
|
||||
self.fail(f"memory_reserved raised an exception: {e}")
|
||||
|
||||
def test_memory_reserved_vs_allocated(self):
|
||||
"""Test that memory_reserved is greater than or equal to memory_allocated."""
|
||||
if paddle.cuda.is_initialized():
|
||||
reserved = paddle.cuda.memory_reserved()
|
||||
allocated = paddle.cuda.memory_allocated()
|
||||
self.assertGreaterEqual(
|
||||
reserved,
|
||||
allocated,
|
||||
"memory_reserved should be >= memory_allocated",
|
||||
)
|
||||
|
||||
|
||||
class TestSetDevice(TestCase):
|
||||
def test_set_device_return_type(self):
|
||||
"""Test that set_device returns None."""
|
||||
if paddle.is_compiled_with_cuda() and paddle.cuda.device_count() > 0:
|
||||
result = paddle.cuda.set_device(0)
|
||||
self.assertIsNone(result, "set_device should return None")
|
||||
|
||||
def test_set_device_no_exception(self):
|
||||
"""Test that set_device does not raise any exceptions."""
|
||||
if paddle.is_compiled_with_cuda() and paddle.cuda.device_count() > 0:
|
||||
try:
|
||||
paddle.cuda.set_device(0)
|
||||
except Exception as e:
|
||||
self.fail(f"set_device raised an exception: {e}")
|
||||
|
||||
def test_set_device_with_int_param(self):
|
||||
"""Test that set_device works with integer parameter."""
|
||||
if paddle.is_compiled_with_cuda() and paddle.cuda.device_count() > 0:
|
||||
try:
|
||||
# Test with device index 0
|
||||
paddle.cuda.set_device(0)
|
||||
# Verify device was set correctly
|
||||
current_device = paddle.cuda.current_device()
|
||||
self.assertEqual(
|
||||
current_device, 0, "set_device should set device to 0"
|
||||
)
|
||||
except Exception as e:
|
||||
self.fail(
|
||||
f"set_device with int parameter raised an exception: {e}"
|
||||
)
|
||||
|
||||
def test_set_device_int_after_cpu_place(self):
|
||||
"""Test int parameter after switching the expected place to CPU."""
|
||||
if not (
|
||||
paddle.is_compiled_with_cuda() and paddle.cuda.device_count() > 0
|
||||
):
|
||||
return
|
||||
original_device = paddle.device.get_device()
|
||||
try:
|
||||
paddle.device.set_device('cpu')
|
||||
paddle.cuda.set_device(0)
|
||||
self.assertEqual(
|
||||
paddle.cuda.current_device(),
|
||||
0,
|
||||
'cuda.set_device(0) should select GPU 0 even when the '
|
||||
'current place is CPU',
|
||||
)
|
||||
except Exception as e:
|
||||
self.fail(
|
||||
f'cuda.set_device(int) after a CPU place raised an '
|
||||
f'exception: {e}'
|
||||
)
|
||||
finally:
|
||||
paddle.device.set_device(original_device)
|
||||
|
||||
def test_set_device_with_str_param(self):
|
||||
"""Test that set_device works with string parameter."""
|
||||
if paddle.is_compiled_with_cuda() and paddle.cuda.device_count() > 0:
|
||||
try:
|
||||
# Test with device string
|
||||
paddle.cuda.set_device('gpu:0')
|
||||
# Verify device was set correctly
|
||||
current_device = paddle.cuda.current_device()
|
||||
self.assertEqual(
|
||||
current_device,
|
||||
0,
|
||||
"set_device should set device to 0 with 'gpu:0'",
|
||||
)
|
||||
paddle.cuda.set_device('cuda:0')
|
||||
current_device = paddle.cuda.current_device()
|
||||
self.assertEqual(
|
||||
current_device,
|
||||
0,
|
||||
"set_device should set device to 0 with 'cuda:0'",
|
||||
)
|
||||
# bare 'gpu' / 'cuda' select the default GPU without raising
|
||||
paddle.cuda.set_device('gpu')
|
||||
paddle.cuda.set_device('cuda')
|
||||
except Exception as e:
|
||||
self.fail(
|
||||
f"set_device with string parameter raised an exception: {e}"
|
||||
)
|
||||
|
||||
def test_set_device_with_cuda_place_param(self):
|
||||
"""Test that set_device works with CUDAPlace parameter."""
|
||||
if paddle.is_compiled_with_cuda() and paddle.cuda.device_count() > 0:
|
||||
try:
|
||||
# Test with CUDAPlace
|
||||
place = paddle.CUDAPlace(0)
|
||||
paddle.cuda.set_device(place)
|
||||
# Verify device was set correctly
|
||||
current_device = paddle.cuda.current_device()
|
||||
self.assertEqual(
|
||||
current_device,
|
||||
0,
|
||||
"set_device should set device to 0 with CUDAPlace",
|
||||
)
|
||||
except Exception as e:
|
||||
self.fail(
|
||||
f"set_device with CUDAPlace parameter raised an exception: {e}"
|
||||
)
|
||||
|
||||
def test_set_device_with_xpu_place_param(self):
|
||||
"""paddle.cuda.set_device rejects an XPUPlace; use paddle.device.set_device."""
|
||||
if paddle.is_compiled_with_xpu():
|
||||
with self.assertRaises(ValueError):
|
||||
paddle.cuda.set_device(paddle.XPUPlace(0))
|
||||
|
||||
def test_set_device_with_xpu_str_param(self):
|
||||
"""paddle.cuda.set_device rejects an 'xpu:*' string; use paddle.device.set_device."""
|
||||
with self.assertRaises(ValueError):
|
||||
paddle.cuda.set_device('xpu:0')
|
||||
|
||||
def test_set_device_with_custom_place_param(self):
|
||||
"""paddle.cuda.set_device rejects a CustomPlace; use paddle.device.set_device."""
|
||||
custom_devices = paddle.device.get_all_custom_device_type()
|
||||
if custom_devices:
|
||||
with self.assertRaises(ValueError):
|
||||
paddle.cuda.set_device(paddle.CustomPlace(custom_devices[0], 0))
|
||||
|
||||
def test_set_device_with_custom_str_param(self):
|
||||
"""paddle.cuda.set_device rejects a custom-device string; use paddle.device.set_device."""
|
||||
with self.assertRaises(ValueError):
|
||||
paddle.cuda.set_device('npu:0')
|
||||
|
||||
def test_set_device_invalid_param(self):
|
||||
"""Test that set_device raises ValueError for invalid parameter types."""
|
||||
with self.assertRaises(ValueError) as context:
|
||||
paddle.cuda.set_device(3.14) # Invalid float parameter
|
||||
self.assertIn("Unsupported device type", str(context.exception))
|
||||
|
||||
with self.assertRaises(ValueError) as context:
|
||||
paddle.cuda.set_device([0]) # Invalid list parameter
|
||||
self.assertIn("Unsupported device type", str(context.exception))
|
||||
|
||||
|
||||
class TestBf16Supported(unittest.TestCase):
|
||||
def test_is_bf16_supported(self):
|
||||
self.assertIsInstance(paddle.cuda.is_bf16_supported(), bool)
|
||||
self.assertIsInstance(paddle.device.is_bf16_supported(), bool)
|
||||
self.assertIsInstance(paddle.device.is_bf16_supported(True), bool)
|
||||
self.assertIsInstance(paddle.cuda.is_bf16_supported(False), bool)
|
||||
if should_skip_tests():
|
||||
self.assertFalse(paddle.cuda.is_bf16_supported())
|
||||
self.assertFalse(paddle.device.is_bf16_supported())
|
||||
|
||||
|
||||
class TestManualSeed(unittest.TestCase):
|
||||
def test_device_manual_seed(self):
|
||||
paddle.device.manual_seed(102)
|
||||
x1 = paddle.randn([2, 3])
|
||||
|
||||
paddle.device.manual_seed(999)
|
||||
x2 = paddle.randn([2, 3])
|
||||
|
||||
paddle.device.manual_seed(102)
|
||||
x3 = paddle.randn([2, 3])
|
||||
|
||||
self.assertTrue(
|
||||
paddle.equal_all(x1, x3),
|
||||
"Random outputs should be identical with the same seed",
|
||||
)
|
||||
|
||||
self.assertFalse(
|
||||
paddle.equal_all(x1, x2),
|
||||
"Random outputs should differ with different seeds",
|
||||
)
|
||||
|
||||
def test_cuda_manual_seed(self):
|
||||
paddle.cuda.manual_seed(102)
|
||||
x1 = paddle.randn([2, 3], dtype='float32')
|
||||
|
||||
paddle.cuda.manual_seed(999)
|
||||
x2 = paddle.randn([2, 3], dtype='float32')
|
||||
|
||||
paddle.cuda.manual_seed(102)
|
||||
x3 = paddle.randn([2, 3], dtype='float32')
|
||||
|
||||
self.assertTrue(
|
||||
paddle.equal_all(x1, x3),
|
||||
"Random outputs should be identical with the same seed",
|
||||
)
|
||||
|
||||
self.assertFalse(
|
||||
paddle.equal_all(x1, x2),
|
||||
"Random outputs should differ with different seeds",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,88 @@
|
||||
# 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.
|
||||
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
class TestRngState(unittest.TestCase):
|
||||
def test_get_and_set_rng_state_cuda(self):
|
||||
original_state = paddle.cuda.get_rng_state()
|
||||
try:
|
||||
r = paddle.cuda.get_rng_state()
|
||||
self.assertIsInstance(r, paddle.core.GeneratorState)
|
||||
|
||||
s = paddle.randn([10, 10])
|
||||
paddle.cuda.set_rng_state(r)
|
||||
s1 = paddle.randn([10, 10])
|
||||
np.testing.assert_allclose(s.numpy(), s1.numpy(), rtol=0, atol=0)
|
||||
finally:
|
||||
paddle.cuda.set_rng_state(original_state)
|
||||
|
||||
def test_get_and_set_rng_state_cpu(self):
|
||||
original_state = paddle.cuda.get_rng_state('cpu')
|
||||
cur_dev = paddle.device.get_device()
|
||||
|
||||
paddle.set_device('cpu')
|
||||
r = paddle.cuda.get_rng_state('cpu')
|
||||
self.assertIsInstance(r, paddle.core.GeneratorState)
|
||||
|
||||
s = paddle.randn([10, 10])
|
||||
paddle.cuda.set_rng_state(r, device='cpu')
|
||||
s1 = paddle.randn([10, 10])
|
||||
np.testing.assert_allclose(s.numpy(), s1.numpy(), rtol=0, atol=0)
|
||||
|
||||
paddle.cuda.set_rng_state(original_state, device='cpu')
|
||||
paddle.set_device(cur_dev)
|
||||
|
||||
def test_invalid_device_raises(self):
|
||||
with self.assertRaises(ValueError):
|
||||
paddle.set_rng_state(paddle.get_rng_state(), device="unknown:0")
|
||||
|
||||
original_state = paddle.get_rng_state()
|
||||
|
||||
try:
|
||||
r = paddle.get_rng_state()
|
||||
if len(r) > 0:
|
||||
self.assertIsInstance(r[0], paddle.core.GeneratorState)
|
||||
|
||||
s = paddle.randn([10, 10])
|
||||
|
||||
paddle.set_rng_state(r)
|
||||
|
||||
s1 = paddle.randn([10, 10])
|
||||
|
||||
np.testing.assert_allclose(s.numpy(), s1.numpy(), rtol=0, atol=0)
|
||||
|
||||
finally:
|
||||
paddle.set_rng_state(original_state)
|
||||
|
||||
def test_api_compatibility(self):
|
||||
paddle_get_obj = paddle.device.cpu.get_rng_state
|
||||
alias_get_obj = paddle.random.get_rng_state
|
||||
self.assertTrue(paddle_get_obj is alias_get_obj)
|
||||
paddle_set_obj = paddle.device.cpu.set_rng_state
|
||||
alias_set_obj = paddle.random.set_rng_state
|
||||
self.assertTrue(paddle_set_obj is alias_set_obj)
|
||||
|
||||
def test_alias(self):
|
||||
state = paddle.random.get_rng_state()
|
||||
paddle.random.set_rng_state(state)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,209 @@
|
||||
# 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.
|
||||
|
||||
import pathlib
|
||||
import sys
|
||||
import unittest
|
||||
from typing import Optional
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import numpy as np
|
||||
|
||||
import paddle
|
||||
from paddle.compat.proxy import create_fake_class, create_fake_function
|
||||
|
||||
sys.path.append(str(pathlib.Path(__file__).parent / "fake_modules"))
|
||||
|
||||
|
||||
def use_torch_inside_inner_function():
|
||||
import torch
|
||||
|
||||
return torch.sin(torch.tensor([0.0, 1.0, 2.0])).numpy()
|
||||
|
||||
|
||||
class TestTorchProxy(unittest.TestCase):
|
||||
def test_enable_compat(self):
|
||||
with self.assertRaises(ModuleNotFoundError):
|
||||
import torch
|
||||
|
||||
paddle.enable_compat()
|
||||
import torch
|
||||
|
||||
self.assertIs(torch.sin, paddle.sin)
|
||||
|
||||
import torch.nn
|
||||
|
||||
self.assertIs(torch.nn.Conv2d, paddle.nn.Conv2d)
|
||||
|
||||
import torch.nn.functional
|
||||
|
||||
self.assertIs(torch.nn.functional.sigmoid, paddle.nn.functional.sigmoid)
|
||||
|
||||
with self.assertRaises(ModuleNotFoundError):
|
||||
import torch.nonexistent_module
|
||||
|
||||
paddle.disable_compat()
|
||||
with self.assertRaises(ModuleNotFoundError):
|
||||
import torch
|
||||
with self.assertRaises(ModuleNotFoundError):
|
||||
import torch.nn
|
||||
with self.assertRaises(ModuleNotFoundError):
|
||||
import torch.nn.functional
|
||||
|
||||
def test_use_compat_guard(self):
|
||||
with self.assertRaises(ModuleNotFoundError):
|
||||
import torch
|
||||
with paddle.use_compat_guard():
|
||||
import torch
|
||||
|
||||
self.assertIs(torch.sin, paddle.sin)
|
||||
with self.assertRaises(ModuleNotFoundError):
|
||||
import torch
|
||||
|
||||
with paddle.use_compat_guard():
|
||||
import torch
|
||||
|
||||
self.assertIs(torch.cos, paddle.cos)
|
||||
with paddle.use_compat_guard(enable=False):
|
||||
with self.assertRaises(ModuleNotFoundError):
|
||||
import torch
|
||||
with paddle.use_compat_guard(enable=True):
|
||||
import torch
|
||||
|
||||
with self.assertRaises(ModuleNotFoundError):
|
||||
import torch
|
||||
|
||||
@paddle.use_compat_guard()
|
||||
def test_use_torch_inside_inner_function(self):
|
||||
result = use_torch_inside_inner_function()
|
||||
|
||||
np.testing.assert_allclose(
|
||||
result, np.sin([0.0, 1.0, 2.0]), atol=1e-6, rtol=1e-6
|
||||
)
|
||||
|
||||
|
||||
class TestTorchProxyBlockedModule(unittest.TestCase):
|
||||
def test_blocked_module(self):
|
||||
with paddle.use_compat_guard():
|
||||
with self.assertRaises(ModuleNotFoundError):
|
||||
import torch._dynamo.allow_in_graph # noqa: F401
|
||||
|
||||
with self.assertRaises(AttributeError):
|
||||
import torch_proxy_blocked_module
|
||||
|
||||
paddle.compat.extend_torch_proxy_blocked_modules(
|
||||
{"torch_proxy_blocked_module"}
|
||||
)
|
||||
import torch_proxy_blocked_module
|
||||
|
||||
# Use torch specific function out of execute module stage
|
||||
torch_proxy_blocked_module.use_torch_specific_fn()
|
||||
|
||||
|
||||
class TestTorchProxyLocalEnabledModule(unittest.TestCase):
|
||||
def test_local_enabled_module(self):
|
||||
with self.assertRaises(ModuleNotFoundError):
|
||||
import torch_proxy_local_enabled_module
|
||||
|
||||
paddle.enable_compat(scope="torch_proxy_local_enabled_module")
|
||||
with self.assertRaises(ModuleNotFoundError):
|
||||
import torch # noqa: F401
|
||||
|
||||
import torch_proxy_local_enabled_module
|
||||
|
||||
torch_proxy_local_enabled_module.use_torch_compat_api()
|
||||
paddle.compat.proxy.TORCH_PROXY_FINDER._globally_enabled = False
|
||||
paddle.compat.proxy.TORCH_PROXY_FINDER._local_enabled_scope = set()
|
||||
paddle.disable_compat()
|
||||
|
||||
|
||||
class TestTorchProxyUseMockedModule(unittest.TestCase):
|
||||
def test_use_mocked_module(self):
|
||||
# Define mocked torch before use torch proxy
|
||||
mocked_torch = MagicMock()
|
||||
sys.modules["torch"] = mocked_torch
|
||||
with paddle.use_compat_guard(scope=set()):
|
||||
import torch
|
||||
|
||||
# torch proxy should not affect mocked torch,
|
||||
# because the `import torch` not under the enabled scope
|
||||
self.assertIs(torch, mocked_torch)
|
||||
|
||||
self.assertIs(torch, mocked_torch)
|
||||
|
||||
|
||||
class TestOverrideTorchModule(unittest.TestCase):
|
||||
@paddle.use_compat_guard()
|
||||
def test_relu(self):
|
||||
import torch
|
||||
|
||||
self.assertIs(torch.relu, paddle.nn.functional.relu)
|
||||
|
||||
@paddle.use_compat_guard()
|
||||
def test_torch_version_class(self):
|
||||
import torch
|
||||
|
||||
self.assertIs(torch.TorchVersion, paddle.PaddleVersion)
|
||||
self.assertIsInstance(torch.__version__, paddle.PaddleVersion)
|
||||
|
||||
@paddle.use_compat_guard()
|
||||
def test_access_compat_functions_by_getattr(self):
|
||||
import torch
|
||||
|
||||
self.assertIs(torch.nn.Unfold, paddle.compat.nn.Unfold)
|
||||
self.assertIs(torch.nn.Linear, paddle.compat.nn.Linear)
|
||||
|
||||
@paddle.use_compat_guard()
|
||||
def test_access_compat_functions_by_import(self):
|
||||
from torch.nn.functional import linear, softmax
|
||||
|
||||
self.assertIs(softmax, paddle.compat.nn.functional.softmax)
|
||||
self.assertIs(linear, paddle.compat.nn.functional.linear)
|
||||
|
||||
|
||||
class TestFakeInterface(unittest.TestCase):
|
||||
def test_fake_interface(self):
|
||||
FakeGenerator = create_fake_class(
|
||||
"torch.Generator",
|
||||
{"manual_seed": create_fake_function("manual_seed")},
|
||||
)
|
||||
|
||||
fake_gen = FakeGenerator()
|
||||
self.assertTrue(hasattr(fake_gen, "manual_seed"))
|
||||
|
||||
|
||||
class TestDeviceAsTypeHints(unittest.TestCase):
|
||||
@paddle.use_compat_guard()
|
||||
def test_device_as_type_hints(self):
|
||||
import torch
|
||||
|
||||
# TODO: Remove Optional[...] coverage once Python 3.10 support is dropped.
|
||||
def fn(x: Optional[torch.device]): # noqa: UP045
|
||||
return x
|
||||
|
||||
self.assertTrue(callable(torch.device))
|
||||
self.assertEqual(
|
||||
fn.__annotations__["x"],
|
||||
Optional[torch.device], # noqa: UP045
|
||||
)
|
||||
cpu_device = torch.device("cpu")
|
||||
self.assertEqual(str(cpu_device), "cpu")
|
||||
self.assertEqual(
|
||||
torch.device.is_compiled_with_xpu(),
|
||||
paddle.device.is_compiled_with_xpu(),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,98 @@
|
||||
# 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.
|
||||
|
||||
import pathlib
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import paddle
|
||||
from paddle.compat.proxy import (
|
||||
ProxyModule,
|
||||
)
|
||||
|
||||
sys.path.append(str(pathlib.Path(__file__).parent / "fake_modules"))
|
||||
sys.path.append(str(pathlib.Path(__file__).parent / "fake_torch_modules"))
|
||||
|
||||
|
||||
class TestTorchProxyMixRealTorch(unittest.TestCase):
|
||||
def check_is_not_proxy(self):
|
||||
import torch
|
||||
from torch.nn.functional import relu
|
||||
|
||||
self.assertNotIsInstance(torch, ProxyModule)
|
||||
self.assertIsNot(paddle.nn.functional.relu, relu)
|
||||
|
||||
def check_is_proxy(self):
|
||||
import torch
|
||||
from torch.nn.functional import relu
|
||||
|
||||
self.assertIsInstance(torch, ProxyModule)
|
||||
self.assertIs(paddle.nn.functional.relu, relu)
|
||||
|
||||
def test_nested_torch_proxy(self):
|
||||
self.check_is_not_proxy()
|
||||
with paddle.use_compat_guard(enable=True):
|
||||
self.check_is_proxy()
|
||||
|
||||
with paddle.use_compat_guard(enable=False):
|
||||
self.check_is_not_proxy()
|
||||
|
||||
with paddle.use_compat_guard(enable=True):
|
||||
self.check_is_proxy()
|
||||
with paddle.use_compat_guard(enable=True):
|
||||
self.check_is_proxy()
|
||||
with paddle.use_compat_guard(enable=False):
|
||||
self.check_is_not_proxy()
|
||||
|
||||
self.check_is_not_proxy()
|
||||
|
||||
self.check_is_proxy()
|
||||
|
||||
self.check_is_not_proxy()
|
||||
|
||||
def test_local_enabled_module_import(self):
|
||||
self.check_is_not_proxy()
|
||||
with paddle.use_compat_guard(
|
||||
enable=True, scope={"torch_proxy_local_enabled_module"}
|
||||
):
|
||||
self.check_is_not_proxy()
|
||||
self.check_is_not_proxy()
|
||||
|
||||
def test_blocked_module_import(self):
|
||||
self.check_is_not_proxy()
|
||||
paddle.compat.extend_torch_proxy_blocked_modules(
|
||||
{"torch_proxy_blocked_module"}
|
||||
)
|
||||
with paddle.use_compat_guard(enable=True):
|
||||
import torch_proxy_blocked_module # noqa: F401
|
||||
|
||||
self.check_is_proxy()
|
||||
self.check_is_not_proxy()
|
||||
|
||||
def test_blocked_module_inside_local_enabled_proxy_import(self):
|
||||
self.check_is_not_proxy()
|
||||
paddle.compat.extend_torch_proxy_blocked_modules(
|
||||
{"torch_proxy_blocked_module"}
|
||||
)
|
||||
with paddle.use_compat_guard(
|
||||
enable=True, scope={"torch_proxy_local_enabled_module"}
|
||||
):
|
||||
import torch_proxy_blocked_module # noqa: F401
|
||||
|
||||
self.check_is_not_proxy()
|
||||
self.check_is_not_proxy()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,55 @@
|
||||
# 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.
|
||||
|
||||
import inspect
|
||||
import unittest
|
||||
|
||||
from paddle.version import cuda
|
||||
|
||||
|
||||
class TestCudaVariable(unittest.TestCase):
|
||||
def test_has_signature(self):
|
||||
self.assertTrue(hasattr(cuda, '__signature__'))
|
||||
self.assertIsInstance(cuda.__signature__, inspect.Signature)
|
||||
self.assertEqual(len(cuda.__signature__.parameters), 0)
|
||||
|
||||
def test_has_doc(self):
|
||||
self.assertTrue(hasattr(cuda, '__doc__'))
|
||||
self.assertIsInstance(cuda.__doc__, str)
|
||||
self.assertTrue(len(cuda.__doc__.strip()) > 0)
|
||||
|
||||
def test_inspect_recognizes(self):
|
||||
self.assertTrue(inspect.getdoc(cuda))
|
||||
self.assertIsInstance(inspect.signature(cuda), inspect.Signature)
|
||||
|
||||
def test_cuda_functionality(self):
|
||||
self.assertIsInstance(cuda, str)
|
||||
self.assertTrue(len(cuda) > 0)
|
||||
self.assertEqual(str(cuda), cuda)
|
||||
self.assertTrue(callable(cuda))
|
||||
self.assertTrue(
|
||||
hasattr(cuda, 'startswith'),
|
||||
"Return value of cuda does not have 'startswith' attribute",
|
||||
)
|
||||
result = cuda()
|
||||
self.assertIsInstance(result, str)
|
||||
self.assertEqual(result, cuda)
|
||||
self.assertTrue(
|
||||
hasattr(result, 'startswith'),
|
||||
"Return value of cuda() does not have 'startswith' attribute",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user