|
19 | 19 | import subprocess |
20 | 20 | import sys |
21 | 21 | import unittest |
| 22 | +from multiprocessing.pool import ThreadPool |
22 | 23 | from collections import OrderedDict |
23 | | -from concurrent.futures import ThreadPoolExecutor |
24 | 24 | from pathlib import Path |
25 | | -import queue |
26 | 25 | import io |
27 | | -import threading |
28 | | -from functools import partial |
29 | 26 |
|
30 | 27 | from scripts.test import binaryenjs |
31 | 28 | from scripts.test import lld |
@@ -253,54 +250,32 @@ def run_one_spec_test(wast: Path, stdout=None, stderr=None): |
253 | 250 | check_expected(actual, os.path.join(shared.get_test_dir('spec'), 'expected-output', test_name + '.log'), stdout=stdout) |
254 | 251 |
|
255 | 252 |
|
256 | | -def run_spec_test_with_wrapped_stdout(output_queue, wast: Path): |
| 253 | +def run_spec_test_with_wrapped_stdout(wast: Path): |
257 | 254 | out = io.StringIO() |
258 | 255 | try: |
259 | | - ret = run_one_spec_test(wast, stdout=out, stderr=out) |
| 256 | + run_one_spec_test(wast, stdout=out, stderr=out) |
260 | 257 | except Exception as e: |
| 258 | + # Serialize exceptions into the output string buffer |
| 259 | + # so they can be reported on the main thread. |
261 | 260 | print(e, file=out) |
262 | 261 | raise |
263 | | - finally: |
264 | | - # If a test fails, it's important to keep its output |
265 | | - output_queue.put(out.getvalue()) |
266 | | - return ret |
| 262 | + return out.getvalue() |
267 | 263 |
|
268 | 264 |
|
269 | 265 | def run_spec_tests(): |
270 | 266 | print('\n[ checking wasm-shell spec testcases... ]\n') |
271 | 267 |
|
272 | | - output_queue = queue.Queue() |
273 | | - |
274 | | - stop_printer = object() |
275 | | - |
276 | | - def printer(): |
277 | | - while True: |
278 | | - string = output_queue.get() |
279 | | - if string is stop_printer: |
280 | | - break |
281 | | - |
282 | | - print(string, end="") |
283 | | - |
284 | | - printing_thread = threading.Thread(target=printer) |
285 | | - printing_thread.start() |
286 | | - |
287 | 268 | worker_count = os.cpu_count() |
288 | 269 | print("Running with", worker_count, "workers") |
289 | | - executor = ThreadPoolExecutor(max_workers=worker_count) |
290 | | - try: |
291 | | - results = executor.map(partial(run_spec_test_with_wrapped_stdout, output_queue), map(Path, shared.options.spec_tests)) |
292 | | - for _ in results: |
293 | | - # Iterating joins the threads. No return value here. |
294 | | - pass |
295 | | - except KeyboardInterrupt: |
296 | | - # Hard exit to avoid threads continuing to run after Ctrl-C. |
297 | | - # There's no concern of deadlocking during shutdown here. |
298 | | - os._exit(1) |
299 | | - finally: |
300 | | - executor.shutdown(cancel_futures=True) |
301 | | - |
302 | | - output_queue.put(stop_printer) |
303 | | - printing_thread.join() |
| 270 | + test_paths = [Path(x) for x in shared.options.spec_tests] |
| 271 | + with ThreadPool(processes=worker_count) as pool: |
| 272 | + try: |
| 273 | + for result in pool.imap_unordered(run_spec_test_with_wrapped_stdout, test_paths): |
| 274 | + print(result, end="") |
| 275 | + except KeyboardInterrupt: |
| 276 | + # Hard exit to avoid threads continuing to run after Ctrl-C. |
| 277 | + # There's no concern of deadlocking during shutdown here. |
| 278 | + os._exit(1) |
304 | 279 |
|
305 | 280 |
|
306 | 281 | def run_validator_tests(): |
|
0 commit comments