Skip to content

Commit 75e6984

Browse files
l0rincmaflcko
andcommitted
test/refactor: use test deque to avoid quadratic iteration
Extracted from bitcoin/bitcoin#33141 (comment). In Python, list `pop(0)` is linear, so consuming all items is quadratic. Switched to `collections.deque` with `popleft()` to express FIFO intent and avoid the O(n^2) path. Behavior is unchanged; for a few hundred items the perf impact is likely negligible. Ref: https://docs.python.org/3/tutorial/datastructures.html#using-lists-as-queues > While appends and pops from the end of list are fast, doing inserts or pops > from the beginning of a list is slow (because all of the other elements have > to be shifted by one). Co-authored-by: maflcko <[email protected]>
1 parent 176fac0 commit 75e6984

File tree

1 file changed

+6
-7
lines changed

1 file changed

+6
-7
lines changed

test/functional/test_runner.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -452,8 +452,8 @@ def main():
452452
print("Re-compile with the -DBUILD_DAEMON=ON build option")
453453
sys.exit(1)
454454

455-
# Build list of tests
456-
test_list = []
455+
# Build tests
456+
test_list = deque()
457457
if tests:
458458
# Individual tests have been specified. Run specified tests that exist
459459
# in the ALL_SCRIPTS list. Accept names with or without a .py extension.
@@ -472,7 +472,7 @@ def main():
472472
script = script + ".py" if ".py" not in script else script
473473
matching_scripts = [s for s in ALL_SCRIPTS if s.startswith(script)]
474474
if matching_scripts:
475-
test_list.extend(matching_scripts)
475+
test_list += matching_scripts
476476
else:
477477
print("{}WARNING!{} Test '{}' not found in full test list.".format(BOLD[1], BOLD[0], test))
478478
elif args.extended:
@@ -507,7 +507,7 @@ def remove_tests(exclude_list):
507507
remove_tests([test for test in test_list if test.split('.py')[0] == exclude_test.split('.py')[0]])
508508

509509
if args.filter:
510-
test_list = list(filter(re.compile(args.filter).search, test_list))
510+
test_list = deque(filter(re.compile(args.filter).search, test_list))
511511

512512
if not test_list:
513513
print("No valid test scripts specified. Check that your test is in one "
@@ -724,7 +724,7 @@ def done(self):
724724
def get_next(self):
725725
while len(self.jobs) < self.num_jobs and self.test_list:
726726
# Add tests
727-
test = self.test_list.pop(0)
727+
test = self.test_list.popleft()
728728
portseed = len(self.test_list)
729729
portseed_arg = ["--portseed={}".format(portseed)]
730730
log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16)
@@ -752,8 +752,7 @@ def proc_wait(task):
752752
]
753753
fut = self.executor.submit(proc_wait, task)
754754
self.jobs[fut] = test
755-
if not self.jobs:
756-
raise IndexError('pop from empty list')
755+
assert self.jobs # Must not be empty here
757756

758757
# Print remaining running jobs when all jobs have been started.
759758
if not self.test_list:

0 commit comments

Comments
 (0)