ci: balance test shards by measured time per file - #905
Closed
pengfei-threemoonslab wants to merge 1 commit into
Closed
pengfei-threemoonslab wants to merge 1 commit into
pengfei-threemoonslab wants to merge 1 commit into
Conversation
The suite's three CI shards were balanced by collected item count. Item count is a poor proxy for time: a file of forty git-fixture tests costs more than a file of four hundred pure ones. - On `main`, shard 3 took 13 of its 15 minutes while shards 1 and 2 took 8. - Any new test file reshuffled most files. #904's one new file moved 298 of 363, which put shard 1 at 14 minutes and cancelled shard 3 at the cap. Shards are now balanced by measured seconds per file, in `tests/shard_seconds.json`. `scripts/measure_shard_seconds.py` writes that file from a `--junitxml` run. A file without a measurement costs its item count at the measured seconds per item. A stale measurement only unbalances, never drops a file. The union property, determinism and fail-loud rules are unchanged. On one full-suite measurement: - balancing by count gives main 25/30/45% of the work, matching CI's 6.8/6.8/11.6-minute shards; - balancing by time gives 33/33/33%, for main and for #904. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
CI's three test shards were balanced by test count, not time. This PR balances them by measured seconds per test file. It fixes the
suite (3)cancellation on #904 and restores main's margin.The problem
main,suite (3)takes 13 of its 15 minutes whilesuite (1)andsuite (2)take about 8.suite (1)at 14 minutes and cancelledsuite (3)at the cap at 98%, with no test failing (run).A file of forty git-fixture tests costs more than a file of four hundred pure ones, so item count is a poor proxy for time.
What changed
ci_sharding.shard_assignmenttakes optional seconds per file. A file without a measurement (new or renamed) costs its item count at the measured seconds per item. The rate is computed identically in every shard (fsumover sorted paths), so the partition stays deterministic.tests/shard_seconds.jsonholds one full-suite measurement: 363 files and 8,966 test-seconds. It was taken on Derive the application comparison scope from the change when --scope is omitted (#875) #904's branch, so it also covers that PR's new file. An entry for a file not in the collection is ignored.scripts/measure_shard_seconds.pyregenerates the file from a--junitxmlrun.conftest.pyloads the measurement. If it is missing or unreadable, balancing falls back to item counts.ci.yml's comment says to re-measure before adding a shard.What does not change:
suite (1)–suite (3));A stale measurement only unbalances; it never drops a file.
Evidence
Share of measured test time per shard:
The by-count rows reproduce CI's actual shape. Main's shards take 6.8/6.8/11.6 test-minutes (27/27/46%). #904's shard 2 is the small one, with 1 and 3 at the cap.
Tests
tests/test_shard_partition.py, all passing locally, including the real-collection union check:🤖 Generated with Claude Code