Skip to content

Commit 3fe877b

Browse files
cryvateJörg Kohlsdorf
and
Jörg Kohlsdorf
authored
LoadScope scheduler: Sort scopes by number of tests to assign biggest scopes first (#778)
Follow up to # 632. --------- Co-authored-by: Jörg Kohlsdorf <[email protected]>
1 parent f36ea25 commit 3fe877b

File tree

3 files changed

+25
-1
lines changed

3 files changed

+25
-1
lines changed

changelog/632.feature.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
``--dist=loadscope`` now sorts scopes by number of tests to assign largest scopes early -- in many cases this should improve overall test session running time, as there is less chance of a large scope being left to be processed near the end of the session, leaving other workers idle.

src/xdist/scheduler/loadscope.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -350,11 +350,18 @@ def schedule(self):
350350
return
351351

352352
# Determine chunks of work (scopes)
353+
unsorted_workqueue = OrderedDict()
353354
for nodeid in self.collection:
354355
scope = self._split_scope(nodeid)
355-
work_unit = self.workqueue.setdefault(scope, default=OrderedDict())
356+
work_unit = unsorted_workqueue.setdefault(scope, default=OrderedDict())
356357
work_unit[nodeid] = False
357358

359+
# Insert tests scopes into work queue ordered by number of tests.
360+
for scope, nodeids in sorted(
361+
unsorted_workqueue.items(), key=lambda item: -len(item[1])
362+
):
363+
self.workqueue[scope] = nodeids
364+
358365
# Avoid having more workers than work
359366
extra_nodes = len(self.nodes) - len(self.workqueue)
360367

testing/acceptance_test.py

+16
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,22 @@ def test(self, i):
12321232
"test_a.py::TestB", result.outlines
12331233
) in ({"gw0": 10}, {"gw1": 10})
12341234

1235+
def test_workqueue_ordered_by_size(self, pytester: pytest.Pytester) -> None:
1236+
test_file = """
1237+
import pytest
1238+
@pytest.mark.parametrize('i', range({}))
1239+
def test(i):
1240+
pass
1241+
"""
1242+
pytester.makepyfile(test_a=test_file.format(10), test_b=test_file.format(20))
1243+
result = pytester.runpytest("-n2", "--dist=loadscope", "-v")
1244+
assert get_workers_and_test_count_by_prefix(
1245+
"test_a.py::test", result.outlines
1246+
) == {"gw1": 10}
1247+
assert get_workers_and_test_count_by_prefix(
1248+
"test_b.py::test", result.outlines
1249+
) == {"gw0": 20}
1250+
12351251
def test_module_single_start(self, pytester: pytest.Pytester) -> None:
12361252
"""Fix test suite never finishing in case all workers start with a single test (#277)."""
12371253
test_file1 = """

0 commit comments

Comments
 (0)