|
4 | 4 | from itertools import product |
5 | 5 | from numba import vectorize |
6 | 6 | from numba import cuda, int32, float32, float64 |
| 7 | +from numba.cuda.cudadrv.driver import CudaAPIError, driver |
7 | 8 | from numba.cuda.testing import skip_on_cudasim |
8 | 9 | from numba.cuda.testing import CUDATestCase |
9 | 10 | import unittest |
@@ -227,6 +228,56 @@ def bar(x): |
227 | 228 |
|
228 | 229 | self.assertEqual(bar.__name__, 'bar') |
229 | 230 |
|
| 231 | + def test_no_transfer_for_device_data(self): |
| 232 | + # Initialize test data on the device prior to banning host <-> device |
| 233 | + # transfer |
| 234 | + |
| 235 | + noise = np.random.randn(1, 3, 64, 64).astype(np.float32) |
| 236 | + noise = cuda.to_device(noise) |
| 237 | + |
| 238 | + # A mock of a CUDA function that always raises a CudaAPIError |
| 239 | + |
| 240 | + def raising_transfer(*args, **kwargs): |
| 241 | + raise CudaAPIError(999, 'Transfer not allowed') |
| 242 | + |
| 243 | + # Use the mock for transfers between the host and device |
| 244 | + |
| 245 | + old_HtoD = getattr(driver, 'cuMemcpyHtoD', None) |
| 246 | + old_DtoH = getattr(driver, 'cuMemcpyDtoH', None) |
| 247 | + |
| 248 | + setattr(driver, 'cuMemcpyHtoD', raising_transfer) |
| 249 | + setattr(driver, 'cuMemcpyDtoH', raising_transfer) |
| 250 | + |
| 251 | + # Ensure that the mock functions are working as expected |
| 252 | + |
| 253 | + with self.assertRaisesRegex(CudaAPIError, "Transfer not allowed"): |
| 254 | + noise.copy_to_host() |
| 255 | + |
| 256 | + with self.assertRaisesRegex(CudaAPIError, "Transfer not allowed"): |
| 257 | + cuda.to_device([1]) |
| 258 | + |
| 259 | + try: |
| 260 | + # Check that defining and calling a ufunc with data on the device |
| 261 | + # induces no transfers |
| 262 | + |
| 263 | + @vectorize(['float32(float32)'], target='cuda') |
| 264 | + def func(noise): |
| 265 | + return noise + 1.0 |
| 266 | + |
| 267 | + func(noise) |
| 268 | + finally: |
| 269 | + # Replace our mocks with the original implementations. If there was |
| 270 | + # no original implementation, simply remove ours. |
| 271 | + |
| 272 | + if old_HtoD is not None: |
| 273 | + setattr(driver, 'cuMemcpyHtoD', old_HtoD) |
| 274 | + else: |
| 275 | + del driver.cuMemcpyHtoD |
| 276 | + if old_DtoH is not None: |
| 277 | + setattr(driver, 'cuMemcpyDtoH', old_DtoH) |
| 278 | + else: |
| 279 | + del driver.cuMemcpyDtoH |
| 280 | + |
230 | 281 |
|
231 | 282 | if __name__ == '__main__': |
232 | 283 | unittest.main() |
0 commit comments