# 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()