Skip to content

Commit 121d47a

Browse files
committed
Merge bitcoin/bitcoin#23799: test: Let test_runner.py start multiple jobs per timeslot
975097f Let test_runner.py start multiple jobs per timeslot (Pieter Wuille) Pull request description: test_runner.py currently only checks every 0.5s whether any job has finished, and if so, starts at most one new job. At higher parallellism it becomes increasingly likely that multiple jobs have finished at the same time. Fix this by always noticing *all* finished jobs every timeslot, and starting as many new ones. ACKs for top commit: laanwj: Code review and lightly tested ACK 975097f prayank23: ACK bitcoin/bitcoin@975097f Tree-SHA512: b70c51f05efcde9bc25475c192b86e86b4c399495b42dee20576af3e6b99e8298be8b9e82146abdabbaedb24a13ee158a7c8947518b16fc4f33a3b434935b550
2 parents af7fba3 + 975097f commit 121d47a

File tree

1 file changed

+34
-29
lines changed

1 file changed

+34
-29
lines changed

test/functional/test_runner.py

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -530,33 +530,35 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=
530530

531531
max_len_name = len(max(test_list, key=len))
532532
test_count = len(test_list)
533-
for i in range(test_count):
534-
test_result, testdir, stdout, stderr = job_queue.get_next()
535-
test_results.append(test_result)
536-
done_str = "{}/{} - {}{}{}".format(i + 1, test_count, BOLD[1], test_result.name, BOLD[0])
537-
if test_result.status == "Passed":
538-
logging.debug("%s passed, Duration: %s s" % (done_str, test_result.time))
539-
elif test_result.status == "Skipped":
540-
logging.debug("%s skipped" % (done_str))
541-
else:
542-
print("%s failed, Duration: %s s\n" % (done_str, test_result.time))
543-
print(BOLD[1] + 'stdout:\n' + BOLD[0] + stdout + '\n')
544-
print(BOLD[1] + 'stderr:\n' + BOLD[0] + stderr + '\n')
545-
if combined_logs_len and os.path.isdir(testdir):
546-
# Print the final `combinedlogslen` lines of the combined logs
547-
print('{}Combine the logs and print the last {} lines ...{}'.format(BOLD[1], combined_logs_len, BOLD[0]))
548-
print('\n============')
549-
print('{}Combined log for {}:{}'.format(BOLD[1], testdir, BOLD[0]))
550-
print('============\n')
551-
combined_logs_args = [sys.executable, os.path.join(tests_dir, 'combine_logs.py'), testdir]
552-
if BOLD[0]:
553-
combined_logs_args += ['--color']
554-
combined_logs, _ = subprocess.Popen(combined_logs_args, universal_newlines=True, stdout=subprocess.PIPE).communicate()
555-
print("\n".join(deque(combined_logs.splitlines(), combined_logs_len)))
556-
557-
if failfast:
558-
logging.debug("Early exiting after test failure")
559-
break
533+
i = 0
534+
while i < test_count:
535+
for test_result, testdir, stdout, stderr in job_queue.get_next():
536+
test_results.append(test_result)
537+
i += 1
538+
done_str = "{}/{} - {}{}{}".format(i, test_count, BOLD[1], test_result.name, BOLD[0])
539+
if test_result.status == "Passed":
540+
logging.debug("%s passed, Duration: %s s" % (done_str, test_result.time))
541+
elif test_result.status == "Skipped":
542+
logging.debug("%s skipped" % (done_str))
543+
else:
544+
print("%s failed, Duration: %s s\n" % (done_str, test_result.time))
545+
print(BOLD[1] + 'stdout:\n' + BOLD[0] + stdout + '\n')
546+
print(BOLD[1] + 'stderr:\n' + BOLD[0] + stderr + '\n')
547+
if combined_logs_len and os.path.isdir(testdir):
548+
# Print the final `combinedlogslen` lines of the combined logs
549+
print('{}Combine the logs and print the last {} lines ...{}'.format(BOLD[1], combined_logs_len, BOLD[0]))
550+
print('\n============')
551+
print('{}Combined log for {}:{}'.format(BOLD[1], testdir, BOLD[0]))
552+
print('============\n')
553+
combined_logs_args = [sys.executable, os.path.join(tests_dir, 'combine_logs.py'), testdir]
554+
if BOLD[0]:
555+
combined_logs_args += ['--color']
556+
combined_logs, _ = subprocess.Popen(combined_logs_args, universal_newlines=True, stdout=subprocess.PIPE).communicate()
557+
print("\n".join(deque(combined_logs.splitlines(), combined_logs_len)))
558+
559+
if failfast:
560+
logging.debug("Early exiting after test failure")
561+
break
560562

561563
print_results(test_results, max_len_name, (int(time.time() - start_time)))
562564

@@ -650,8 +652,9 @@ def get_next(self):
650652

651653
dot_count = 0
652654
while True:
653-
# Return first proc that finishes
655+
# Return all procs that have finished, if any. Otherwise sleep until there is one.
654656
time.sleep(.5)
657+
ret = []
655658
for job in self.jobs:
656659
(name, start_time, proc, testdir, log_out, log_err) = job
657660
if proc.poll() is not None:
@@ -670,7 +673,9 @@ def get_next(self):
670673
clearline = '\r' + (' ' * dot_count) + '\r'
671674
print(clearline, end='', flush=True)
672675
dot_count = 0
673-
return TestResult(name, status, int(time.time() - start_time)), testdir, stdout, stderr
676+
ret.append((TestResult(name, status, int(time.time() - start_time)), testdir, stdout, stderr))
677+
if ret:
678+
return ret
674679
if self.use_term_control:
675680
print('.', end='', flush=True)
676681
dot_count += 1

0 commit comments

Comments
 (0)