1*da0073e9SAndroid Build Coastguard Worker# Owner(s): ["module: multiprocessing"] 2*da0073e9SAndroid Build Coastguard Worker 3*da0073e9SAndroid Build Coastguard Workerimport os 4*da0073e9SAndroid Build Coastguard Workerimport pickle 5*da0073e9SAndroid Build Coastguard Workerimport random 6*da0073e9SAndroid Build Coastguard Workerimport signal 7*da0073e9SAndroid Build Coastguard Workerimport sys 8*da0073e9SAndroid Build Coastguard Workerimport time 9*da0073e9SAndroid Build Coastguard Workerimport unittest 10*da0073e9SAndroid Build Coastguard Worker 11*da0073e9SAndroid Build Coastguard Workerimport torch.multiprocessing as mp 12*da0073e9SAndroid Build Coastguard Worker 13*da0073e9SAndroid Build Coastguard Workerfrom torch.testing._internal.common_utils import ( 14*da0073e9SAndroid Build Coastguard Worker IS_WINDOWS, 15*da0073e9SAndroid Build Coastguard Worker NO_MULTIPROCESSING_SPAWN, 16*da0073e9SAndroid Build Coastguard Worker run_tests, 17*da0073e9SAndroid Build Coastguard Worker TestCase, 18*da0073e9SAndroid Build Coastguard Worker) 19*da0073e9SAndroid Build Coastguard Worker 20*da0073e9SAndroid Build Coastguard Workerdef _test_success_func(i): 21*da0073e9SAndroid Build Coastguard Worker pass 22*da0073e9SAndroid Build Coastguard Worker 23*da0073e9SAndroid Build Coastguard Worker 24*da0073e9SAndroid Build Coastguard Workerdef _test_success_single_arg_func(i, arg): 25*da0073e9SAndroid Build Coastguard Worker if arg: 26*da0073e9SAndroid Build Coastguard Worker arg.put(i) 27*da0073e9SAndroid Build Coastguard Worker 28*da0073e9SAndroid Build Coastguard Worker 29*da0073e9SAndroid Build Coastguard Workerdef _test_exception_single_func(i, arg): 30*da0073e9SAndroid Build Coastguard Worker if i == arg: 31*da0073e9SAndroid Build Coastguard Worker raise ValueError("legitimate exception from process %d" % i) 32*da0073e9SAndroid Build Coastguard Worker time.sleep(1.0) 33*da0073e9SAndroid Build Coastguard Worker 34*da0073e9SAndroid Build Coastguard Worker 35*da0073e9SAndroid Build Coastguard Workerdef _test_exception_all_func(i): 36*da0073e9SAndroid Build Coastguard Worker time.sleep(random.random() / 10) 37*da0073e9SAndroid Build Coastguard Worker raise ValueError("legitimate exception from process %d" % i) 38*da0073e9SAndroid Build Coastguard Worker 39*da0073e9SAndroid Build Coastguard Worker 40*da0073e9SAndroid Build Coastguard Workerdef _test_terminate_signal_func(i): 41*da0073e9SAndroid Build Coastguard Worker if i == 0: 42*da0073e9SAndroid Build Coastguard Worker os.kill(os.getpid(), signal.SIGABRT) 43*da0073e9SAndroid Build Coastguard Worker time.sleep(1.0) 44*da0073e9SAndroid Build Coastguard Worker 45*da0073e9SAndroid Build Coastguard Worker 46*da0073e9SAndroid Build Coastguard Workerdef _test_terminate_exit_func(i, arg): 47*da0073e9SAndroid Build Coastguard Worker if i == 0: 48*da0073e9SAndroid Build Coastguard Worker sys.exit(arg) 49*da0073e9SAndroid Build Coastguard Worker time.sleep(1.0) 50*da0073e9SAndroid Build Coastguard Worker 51*da0073e9SAndroid Build Coastguard Worker 52*da0073e9SAndroid Build Coastguard Workerdef _test_success_first_then_exception_func(i, arg): 53*da0073e9SAndroid Build Coastguard Worker if i == 0: 54*da0073e9SAndroid Build Coastguard Worker return 55*da0073e9SAndroid Build Coastguard Worker time.sleep(0.1) 56*da0073e9SAndroid Build Coastguard Worker raise ValueError("legitimate exception") 57*da0073e9SAndroid Build Coastguard Worker 58*da0073e9SAndroid Build Coastguard Worker 59*da0073e9SAndroid Build Coastguard Workerdef _test_nested_child_body(i, ready_queue, nested_child_sleep): 60*da0073e9SAndroid Build Coastguard Worker ready_queue.put(None) 61*da0073e9SAndroid Build Coastguard Worker time.sleep(nested_child_sleep) 62*da0073e9SAndroid Build Coastguard Worker 63*da0073e9SAndroid Build Coastguard Worker 64*da0073e9SAndroid Build Coastguard Workerdef _test_infinite_task(i): 65*da0073e9SAndroid Build Coastguard Worker while True: 66*da0073e9SAndroid Build Coastguard Worker time.sleep(1) 67*da0073e9SAndroid Build Coastguard Worker 68*da0073e9SAndroid Build Coastguard Worker 69*da0073e9SAndroid Build Coastguard Workerdef _test_process_exit(idx): 70*da0073e9SAndroid Build Coastguard Worker sys.exit(12) 71*da0073e9SAndroid Build Coastguard Worker 72*da0073e9SAndroid Build Coastguard Worker 73*da0073e9SAndroid Build Coastguard Workerdef _test_nested(i, pids_queue, nested_child_sleep, start_method): 74*da0073e9SAndroid Build Coastguard Worker context = mp.get_context(start_method) 75*da0073e9SAndroid Build Coastguard Worker nested_child_ready_queue = context.Queue() 76*da0073e9SAndroid Build Coastguard Worker nprocs = 2 77*da0073e9SAndroid Build Coastguard Worker mp_context = mp.start_processes( 78*da0073e9SAndroid Build Coastguard Worker fn=_test_nested_child_body, 79*da0073e9SAndroid Build Coastguard Worker args=(nested_child_ready_queue, nested_child_sleep), 80*da0073e9SAndroid Build Coastguard Worker nprocs=nprocs, 81*da0073e9SAndroid Build Coastguard Worker join=False, 82*da0073e9SAndroid Build Coastguard Worker daemon=False, 83*da0073e9SAndroid Build Coastguard Worker start_method=start_method, 84*da0073e9SAndroid Build Coastguard Worker ) 85*da0073e9SAndroid Build Coastguard Worker pids_queue.put(mp_context.pids()) 86*da0073e9SAndroid Build Coastguard Worker 87*da0073e9SAndroid Build Coastguard Worker # Wait for both children to have started, to ensure that they 88*da0073e9SAndroid Build Coastguard Worker # have called prctl(2) to register a parent death signal. 89*da0073e9SAndroid Build Coastguard Worker for _ in range(nprocs): 90*da0073e9SAndroid Build Coastguard Worker nested_child_ready_queue.get() 91*da0073e9SAndroid Build Coastguard Worker 92*da0073e9SAndroid Build Coastguard Worker # Kill self. This should take down the child processes as well. 93*da0073e9SAndroid Build Coastguard Worker os.kill(os.getpid(), signal.SIGTERM) 94*da0073e9SAndroid Build Coastguard Worker 95*da0073e9SAndroid Build Coastguard Workerclass _TestMultiProcessing: 96*da0073e9SAndroid Build Coastguard Worker start_method = None 97*da0073e9SAndroid Build Coastguard Worker 98*da0073e9SAndroid Build Coastguard Worker def test_success(self): 99*da0073e9SAndroid Build Coastguard Worker mp.start_processes(_test_success_func, nprocs=2, start_method=self.start_method) 100*da0073e9SAndroid Build Coastguard Worker 101*da0073e9SAndroid Build Coastguard Worker def test_success_non_blocking(self): 102*da0073e9SAndroid Build Coastguard Worker mp_context = mp.start_processes(_test_success_func, nprocs=2, join=False, start_method=self.start_method) 103*da0073e9SAndroid Build Coastguard Worker 104*da0073e9SAndroid Build Coastguard Worker # After all processes (nproc=2) have joined it must return True 105*da0073e9SAndroid Build Coastguard Worker mp_context.join(timeout=None) 106*da0073e9SAndroid Build Coastguard Worker mp_context.join(timeout=None) 107*da0073e9SAndroid Build Coastguard Worker self.assertTrue(mp_context.join(timeout=None)) 108*da0073e9SAndroid Build Coastguard Worker 109*da0073e9SAndroid Build Coastguard Worker def test_first_argument_index(self): 110*da0073e9SAndroid Build Coastguard Worker context = mp.get_context(self.start_method) 111*da0073e9SAndroid Build Coastguard Worker queue = context.SimpleQueue() 112*da0073e9SAndroid Build Coastguard Worker mp.start_processes(_test_success_single_arg_func, args=(queue,), nprocs=2, start_method=self.start_method) 113*da0073e9SAndroid Build Coastguard Worker self.assertEqual([0, 1], sorted([queue.get(), queue.get()])) 114*da0073e9SAndroid Build Coastguard Worker 115*da0073e9SAndroid Build Coastguard Worker def test_exception_single(self): 116*da0073e9SAndroid Build Coastguard Worker nprocs = 2 117*da0073e9SAndroid Build Coastguard Worker for i in range(nprocs): 118*da0073e9SAndroid Build Coastguard Worker with self.assertRaisesRegex( 119*da0073e9SAndroid Build Coastguard Worker Exception, 120*da0073e9SAndroid Build Coastguard Worker "\nValueError: legitimate exception from process %d$" % i, 121*da0073e9SAndroid Build Coastguard Worker ): 122*da0073e9SAndroid Build Coastguard Worker mp.start_processes(_test_exception_single_func, args=(i,), nprocs=nprocs, start_method=self.start_method) 123*da0073e9SAndroid Build Coastguard Worker 124*da0073e9SAndroid Build Coastguard Worker def test_exception_all(self): 125*da0073e9SAndroid Build Coastguard Worker with self.assertRaisesRegex( 126*da0073e9SAndroid Build Coastguard Worker Exception, 127*da0073e9SAndroid Build Coastguard Worker "\nValueError: legitimate exception from process (0|1)$", 128*da0073e9SAndroid Build Coastguard Worker ): 129*da0073e9SAndroid Build Coastguard Worker mp.start_processes(_test_exception_all_func, nprocs=2, start_method=self.start_method) 130*da0073e9SAndroid Build Coastguard Worker 131*da0073e9SAndroid Build Coastguard Worker def test_terminate_signal(self): 132*da0073e9SAndroid Build Coastguard Worker # SIGABRT is aliased with SIGIOT 133*da0073e9SAndroid Build Coastguard Worker message = "process 0 terminated with signal (SIGABRT|SIGIOT)" 134*da0073e9SAndroid Build Coastguard Worker 135*da0073e9SAndroid Build Coastguard Worker # Termination through with signal is expressed as a negative exit code 136*da0073e9SAndroid Build Coastguard Worker # in multiprocessing, so we know it was a signal that caused the exit. 137*da0073e9SAndroid Build Coastguard Worker # This doesn't appear to exist on Windows, where the exit code is always 138*da0073e9SAndroid Build Coastguard Worker # positive, and therefore results in a different exception message. 139*da0073e9SAndroid Build Coastguard Worker # Exit code 22 means "ERROR_BAD_COMMAND". 140*da0073e9SAndroid Build Coastguard Worker if IS_WINDOWS: 141*da0073e9SAndroid Build Coastguard Worker message = "process 0 terminated with exit code 22" 142*da0073e9SAndroid Build Coastguard Worker 143*da0073e9SAndroid Build Coastguard Worker with self.assertRaisesRegex(Exception, message): 144*da0073e9SAndroid Build Coastguard Worker mp.start_processes(_test_terminate_signal_func, nprocs=2, start_method=self.start_method) 145*da0073e9SAndroid Build Coastguard Worker 146*da0073e9SAndroid Build Coastguard Worker def test_terminate_exit(self): 147*da0073e9SAndroid Build Coastguard Worker exitcode = 123 148*da0073e9SAndroid Build Coastguard Worker with self.assertRaisesRegex( 149*da0073e9SAndroid Build Coastguard Worker Exception, 150*da0073e9SAndroid Build Coastguard Worker "process 0 terminated with exit code %d" % exitcode, 151*da0073e9SAndroid Build Coastguard Worker ): 152*da0073e9SAndroid Build Coastguard Worker mp.start_processes(_test_terminate_exit_func, args=(exitcode,), nprocs=2, start_method=self.start_method) 153*da0073e9SAndroid Build Coastguard Worker 154*da0073e9SAndroid Build Coastguard Worker def test_success_first_then_exception(self): 155*da0073e9SAndroid Build Coastguard Worker exitcode = 123 156*da0073e9SAndroid Build Coastguard Worker with self.assertRaisesRegex( 157*da0073e9SAndroid Build Coastguard Worker Exception, 158*da0073e9SAndroid Build Coastguard Worker "ValueError: legitimate exception", 159*da0073e9SAndroid Build Coastguard Worker ): 160*da0073e9SAndroid Build Coastguard Worker mp.start_processes(_test_success_first_then_exception_func, args=(exitcode,), nprocs=2, start_method=self.start_method) 161*da0073e9SAndroid Build Coastguard Worker 162*da0073e9SAndroid Build Coastguard Worker @unittest.skipIf( 163*da0073e9SAndroid Build Coastguard Worker sys.platform != "linux", 164*da0073e9SAndroid Build Coastguard Worker "Only runs on Linux; requires prctl(2)", 165*da0073e9SAndroid Build Coastguard Worker ) 166*da0073e9SAndroid Build Coastguard Worker def _test_nested(self): 167*da0073e9SAndroid Build Coastguard Worker context = mp.get_context(self.start_method) 168*da0073e9SAndroid Build Coastguard Worker pids_queue = context.Queue() 169*da0073e9SAndroid Build Coastguard Worker nested_child_sleep = 20.0 170*da0073e9SAndroid Build Coastguard Worker mp_context = mp.start_processes( 171*da0073e9SAndroid Build Coastguard Worker fn=_test_nested, 172*da0073e9SAndroid Build Coastguard Worker args=(pids_queue, nested_child_sleep, self.start_method), 173*da0073e9SAndroid Build Coastguard Worker nprocs=1, 174*da0073e9SAndroid Build Coastguard Worker join=False, 175*da0073e9SAndroid Build Coastguard Worker daemon=False, 176*da0073e9SAndroid Build Coastguard Worker start_method=self.start_method, 177*da0073e9SAndroid Build Coastguard Worker ) 178*da0073e9SAndroid Build Coastguard Worker 179*da0073e9SAndroid Build Coastguard Worker # Wait for nested children to terminate in time 180*da0073e9SAndroid Build Coastguard Worker pids = pids_queue.get() 181*da0073e9SAndroid Build Coastguard Worker start = time.time() 182*da0073e9SAndroid Build Coastguard Worker while len(pids) > 0: 183*da0073e9SAndroid Build Coastguard Worker for pid in pids: 184*da0073e9SAndroid Build Coastguard Worker try: 185*da0073e9SAndroid Build Coastguard Worker os.kill(pid, 0) 186*da0073e9SAndroid Build Coastguard Worker except ProcessLookupError: 187*da0073e9SAndroid Build Coastguard Worker pids.remove(pid) 188*da0073e9SAndroid Build Coastguard Worker break 189*da0073e9SAndroid Build Coastguard Worker 190*da0073e9SAndroid Build Coastguard Worker # This assert fails if any nested child process is still 191*da0073e9SAndroid Build Coastguard Worker # alive after (nested_child_sleep / 2) seconds. By 192*da0073e9SAndroid Build Coastguard Worker # extension, this test times out with an assertion error 193*da0073e9SAndroid Build Coastguard Worker # after (nested_child_sleep / 2) seconds. 194*da0073e9SAndroid Build Coastguard Worker self.assertLess(time.time() - start, nested_child_sleep / 2) 195*da0073e9SAndroid Build Coastguard Worker time.sleep(0.1) 196*da0073e9SAndroid Build Coastguard Worker 197*da0073e9SAndroid Build Coastguard Worker@unittest.skipIf( 198*da0073e9SAndroid Build Coastguard Worker NO_MULTIPROCESSING_SPAWN, 199*da0073e9SAndroid Build Coastguard Worker "Disabled for environments that don't support the spawn start method") 200*da0073e9SAndroid Build Coastguard Workerclass SpawnTest(TestCase, _TestMultiProcessing): 201*da0073e9SAndroid Build Coastguard Worker start_method = 'spawn' 202*da0073e9SAndroid Build Coastguard Worker 203*da0073e9SAndroid Build Coastguard Worker def test_exception_raises(self): 204*da0073e9SAndroid Build Coastguard Worker with self.assertRaises(mp.ProcessRaisedException): 205*da0073e9SAndroid Build Coastguard Worker mp.spawn(_test_success_first_then_exception_func, args=(), nprocs=1) 206*da0073e9SAndroid Build Coastguard Worker 207*da0073e9SAndroid Build Coastguard Worker def test_signal_raises(self): 208*da0073e9SAndroid Build Coastguard Worker context = mp.spawn(_test_infinite_task, args=(), nprocs=1, join=False) 209*da0073e9SAndroid Build Coastguard Worker for pid in context.pids(): 210*da0073e9SAndroid Build Coastguard Worker os.kill(pid, signal.SIGTERM) 211*da0073e9SAndroid Build Coastguard Worker with self.assertRaises(mp.ProcessExitedException): 212*da0073e9SAndroid Build Coastguard Worker context.join() 213*da0073e9SAndroid Build Coastguard Worker 214*da0073e9SAndroid Build Coastguard Worker def _test_process_exited(self): 215*da0073e9SAndroid Build Coastguard Worker with self.assertRaises(mp.ProcessExitedException) as e: 216*da0073e9SAndroid Build Coastguard Worker mp.spawn(_test_process_exit, args=(), nprocs=1) 217*da0073e9SAndroid Build Coastguard Worker self.assertEqual(12, e.exit_code) 218*da0073e9SAndroid Build Coastguard Worker 219*da0073e9SAndroid Build Coastguard Worker 220*da0073e9SAndroid Build Coastguard Worker@unittest.skipIf( 221*da0073e9SAndroid Build Coastguard Worker IS_WINDOWS, 222*da0073e9SAndroid Build Coastguard Worker "Fork is only available on Unix", 223*da0073e9SAndroid Build Coastguard Worker) 224*da0073e9SAndroid Build Coastguard Workerclass ForkTest(TestCase, _TestMultiProcessing): 225*da0073e9SAndroid Build Coastguard Worker start_method = 'fork' 226*da0073e9SAndroid Build Coastguard Worker 227*da0073e9SAndroid Build Coastguard Worker 228*da0073e9SAndroid Build Coastguard Worker@unittest.skipIf( 229*da0073e9SAndroid Build Coastguard Worker IS_WINDOWS, 230*da0073e9SAndroid Build Coastguard Worker "Fork is only available on Unix", 231*da0073e9SAndroid Build Coastguard Worker) 232*da0073e9SAndroid Build Coastguard Workerclass ParallelForkServerShouldWorkTest(TestCase, _TestMultiProcessing): 233*da0073e9SAndroid Build Coastguard Worker orig_paralell_env_val = None 234*da0073e9SAndroid Build Coastguard Worker 235*da0073e9SAndroid Build Coastguard Worker def setUp(self): 236*da0073e9SAndroid Build Coastguard Worker super().setUp() 237*da0073e9SAndroid Build Coastguard Worker self.orig_paralell_env_val = os.environ.get(mp.ENV_VAR_PARALLEL_START) 238*da0073e9SAndroid Build Coastguard Worker os.environ[mp.ENV_VAR_PARALLEL_START] = "1" 239*da0073e9SAndroid Build Coastguard Worker 240*da0073e9SAndroid Build Coastguard Worker def tearDown(self): 241*da0073e9SAndroid Build Coastguard Worker super().tearDown() 242*da0073e9SAndroid Build Coastguard Worker if self.orig_paralell_env_val is None: 243*da0073e9SAndroid Build Coastguard Worker del os.environ[mp.ENV_VAR_PARALLEL_START] 244*da0073e9SAndroid Build Coastguard Worker else: 245*da0073e9SAndroid Build Coastguard Worker os.environ[mp.ENV_VAR_PARALLEL_START] = self.orig_paralell_env_val 246*da0073e9SAndroid Build Coastguard Worker 247*da0073e9SAndroid Build Coastguard Worker 248*da0073e9SAndroid Build Coastguard Worker@unittest.skipIf( 249*da0073e9SAndroid Build Coastguard Worker IS_WINDOWS, 250*da0073e9SAndroid Build Coastguard Worker "Fork is only available on Unix", 251*da0073e9SAndroid Build Coastguard Worker) 252*da0073e9SAndroid Build Coastguard Workerclass ParallelForkServerPerfTest(TestCase): 253*da0073e9SAndroid Build Coastguard Worker 254*da0073e9SAndroid Build Coastguard Worker def test_forkserver_perf(self): 255*da0073e9SAndroid Build Coastguard Worker 256*da0073e9SAndroid Build Coastguard Worker start_method = 'forkserver' 257*da0073e9SAndroid Build Coastguard Worker expensive = Expensive() 258*da0073e9SAndroid Build Coastguard Worker nprocs = 4 259*da0073e9SAndroid Build Coastguard Worker orig_paralell_env_val = os.environ.get(mp.ENV_VAR_PARALLEL_START) 260*da0073e9SAndroid Build Coastguard Worker 261*da0073e9SAndroid Build Coastguard Worker # test the non parallel case 262*da0073e9SAndroid Build Coastguard Worker os.environ[mp.ENV_VAR_PARALLEL_START] = "0" 263*da0073e9SAndroid Build Coastguard Worker start = time.perf_counter() 264*da0073e9SAndroid Build Coastguard Worker mp.start_processes(expensive.my_call, nprocs=nprocs, start_method=start_method) 265*da0073e9SAndroid Build Coastguard Worker elapsed = time.perf_counter() - start 266*da0073e9SAndroid Build Coastguard Worker # the elapsed time should be at least {nprocs}x the sleep time 267*da0073e9SAndroid Build Coastguard Worker self.assertGreaterEqual(elapsed, Expensive.SLEEP_SECS * nprocs) 268*da0073e9SAndroid Build Coastguard Worker 269*da0073e9SAndroid Build Coastguard Worker # test the parallel case 270*da0073e9SAndroid Build Coastguard Worker os.environ[mp.ENV_VAR_PARALLEL_START] = "1" 271*da0073e9SAndroid Build Coastguard Worker start = time.perf_counter() 272*da0073e9SAndroid Build Coastguard Worker mp.start_processes(expensive.my_call, nprocs=nprocs, start_method=start_method) 273*da0073e9SAndroid Build Coastguard Worker elapsed = time.perf_counter() - start 274*da0073e9SAndroid Build Coastguard Worker # the elapsed time should be less than {nprocs}x the sleep time 275*da0073e9SAndroid Build Coastguard Worker self.assertLess(elapsed, Expensive.SLEEP_SECS * nprocs) 276*da0073e9SAndroid Build Coastguard Worker 277*da0073e9SAndroid Build Coastguard Worker if orig_paralell_env_val is None: 278*da0073e9SAndroid Build Coastguard Worker del os.environ[mp.ENV_VAR_PARALLEL_START] 279*da0073e9SAndroid Build Coastguard Worker else: 280*da0073e9SAndroid Build Coastguard Worker os.environ[mp.ENV_VAR_PARALLEL_START] = orig_paralell_env_val 281*da0073e9SAndroid Build Coastguard Worker 282*da0073e9SAndroid Build Coastguard Worker 283*da0073e9SAndroid Build Coastguard Workerclass Expensive: 284*da0073e9SAndroid Build Coastguard Worker SLEEP_SECS = 5 285*da0073e9SAndroid Build Coastguard Worker # Simulate startup overhead such as large imports 286*da0073e9SAndroid Build Coastguard Worker time.sleep(SLEEP_SECS) 287*da0073e9SAndroid Build Coastguard Worker 288*da0073e9SAndroid Build Coastguard Worker def __init__(self): 289*da0073e9SAndroid Build Coastguard Worker self.config: str = "*" * 1000000 290*da0073e9SAndroid Build Coastguard Worker 291*da0073e9SAndroid Build Coastguard Worker def my_call(self, *args): 292*da0073e9SAndroid Build Coastguard Worker pass 293*da0073e9SAndroid Build Coastguard Worker 294*da0073e9SAndroid Build Coastguard Worker 295*da0073e9SAndroid Build Coastguard Workerclass ErrorTest(TestCase): 296*da0073e9SAndroid Build Coastguard Worker def test_errors_pickleable(self): 297*da0073e9SAndroid Build Coastguard Worker for error in ( 298*da0073e9SAndroid Build Coastguard Worker mp.ProcessRaisedException("Oh no!", 1, 1), 299*da0073e9SAndroid Build Coastguard Worker mp.ProcessExitedException("Oh no!", 1, 1, 1), 300*da0073e9SAndroid Build Coastguard Worker ): 301*da0073e9SAndroid Build Coastguard Worker pickle.loads(pickle.dumps(error)) 302*da0073e9SAndroid Build Coastguard Worker 303*da0073e9SAndroid Build Coastguard Worker 304*da0073e9SAndroid Build Coastguard Workerif __name__ == '__main__': 305*da0073e9SAndroid Build Coastguard Worker run_tests() 306