test_init.py 4.39 KB
Newer Older
dugupeiwen's avatar
dugupeiwen committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import multiprocessing as mp
import os

from numba import cuda
from numba.cuda.cudadrv.driver import CudaAPIError, driver
from numba.cuda.cudadrv.error import CudaSupportError
from numba.cuda.testing import skip_on_cudasim, unittest, CUDATestCase


# A mock of cuInit that always raises a CudaAPIError
def cuInit_raising(arg):
    raise CudaAPIError(999, 'CUDA_ERROR_UNKNOWN')


# Test code to run in a child that patches driver.cuInit to a variant that
# always raises. We can't use mock.patch.object here because driver.cuInit is
# not assigned until we attempt to initialize - mock.patch.object cannot locate
# the non-existent original method, and so fails. Instead we patch
# driver.cuInit with our raising version prior to any attempt to initialize.
def cuInit_raising_test(result_queue):
    driver.cuInit = cuInit_raising

    success = False
    msg = None

    try:
        # A CUDA operation that forces initialization of the device
        cuda.device_array(1)
    except CudaSupportError as e:
        success = True
        msg = e.msg

    result_queue.put((success, msg))


# Similar to cuInit_raising_test above, but for testing that the string
# returned by cuda_error() is as expected.
def initialization_error_test(result_queue):
    driver.cuInit = cuInit_raising

    success = False
    msg = None

    try:
        # A CUDA operation that forces initialization of the device
        cuda.device_array(1)
    except CudaSupportError:
        success = True

    msg = cuda.cuda_error()
    result_queue.put((success, msg))


# For testing the path where Driver.__init__() catches a CudaSupportError
def cuda_disabled_test(result_queue):
    success = False
    msg = None

    try:
        # A CUDA operation that forces initialization of the device
        cuda.device_array(1)
    except CudaSupportError as e:
        success = True
        msg = e.msg

    result_queue.put((success, msg))


# Similar to cuda_disabled_test, but checks cuda.cuda_error() instead of the
# exception raised on initialization
def cuda_disabled_error_test(result_queue):
    success = False
    msg = None

    try:
        # A CUDA operation that forces initialization of the device
        cuda.device_array(1)
    except CudaSupportError:
        success = True

    msg = cuda.cuda_error()
    result_queue.put((success, msg))


@skip_on_cudasim('CUDA Simulator does not initialize driver')
class TestInit(CUDATestCase):
    def _test_init_failure(self, target, expected):
        # Run the initialization failure test in a separate subprocess
        ctx = mp.get_context('spawn')
        result_queue = ctx.Queue()
        proc = ctx.Process(target=target, args=(result_queue,))
        proc.start()
        proc.join(30) # should complete within 30s
        success, msg = result_queue.get()

        # Ensure the child process raised an exception during initialization
        # before checking the message
        if not success:
            self.fail('CudaSupportError not raised')

        self.assertIn(expected, msg)

    def test_init_failure_raising(self):
        expected = 'Error at driver init: CUDA_ERROR_UNKNOWN (999)'
        self._test_init_failure(cuInit_raising_test, expected)

    def test_init_failure_error(self):
        expected = 'CUDA_ERROR_UNKNOWN (999)'
        self._test_init_failure(initialization_error_test, expected)

    def _test_cuda_disabled(self, target):
        # Uses _test_init_failure to launch the test in a separate subprocess
        # with CUDA disabled.
        cuda_disabled = os.environ.get('NUMBA_DISABLE_CUDA')
        os.environ['NUMBA_DISABLE_CUDA'] = "1"
        try:
            expected = 'CUDA is disabled due to setting NUMBA_DISABLE_CUDA=1'
            self._test_init_failure(cuda_disabled_test, expected)
        finally:
            if cuda_disabled is not None:
                os.environ['NUMBA_DISABLE_CUDA'] = cuda_disabled
            else:
                os.environ.pop('NUMBA_DISABLE_CUDA')

    def test_cuda_disabled_raising(self):
        self._test_cuda_disabled(cuda_disabled_test)

    def test_cuda_disabled_error(self):
        self._test_cuda_disabled(cuda_disabled_error_test)

    def test_init_success(self):
        # Here we assume that initialization is successful (because many bad
        # things will happen with the test suite if it is not) and check that
        # there is no error recorded.
        self.assertIsNone(cuda.cuda_error())


if __name__ == '__main__':
    unittest.main()