Skip to content

CI perf: ci.yml test-release — single 29.5-min job is now the whole PR critical path (~12 min off PR push→ci-ok) #1181

Description

Measurement

Window: PR CI runs created 2026-10-08 19:00–20:40 UTC, after #1133 (00c658f) reached PR heads. Jobs API sample: 14 successful non-draft PR runs.

Where the time goes

step p50 min
Run tests (release) — cargo test --workspace --profile ci-release 29.1
Install Rust / Cache cargo / checkout ~0.2

Per the job's own comment, ~23 min of it is compiling and linking ~240 optimized test binaries (ci-release = release minus LTO); the test run itself is ~6 min.

Root cause

#1133 split test into two shards per OS with scripts/ci-test-shard.py (one shard links about half of the ~240 integration targets) but left test-release as one job, so it's now ~13 min longer than anything else on the PR path.

Proposed fix

In .github/workflows/ci.yml test-release (ci.yml:414): add strategy.matrix.shard: [1, 2] (or [1, 2, 3]) and select targets with the same scripts/ci-test-shard.py the test job uses, e.g. cargo test --workspace --profile ci-release $(python3 scripts/ci-test-shard.py --shard ${{ matrix.shard }} …). Each shard compiles the shared deps from the rust-cache, then links only its own targets. Job name becomes test-release (1) / test-release (2). ci-ok's needs names the job id, so it keeps working. Check that ci-ok's result evaluation treats a matrix job the same way it does for test.

Optionally also save a ci-release rust-cache key on main (save-if: main, key: ci-release) if the cache restored for this job is the dev-profile one. Check the "Cache cargo" restore key in a log first.

Expected saving

  • PR push → ci-ok: ~29 → ~17–18 min p50 (≈ −11 to −12 min), then bounded by test (windows-latest, 2) (~16.6 min) and coverage (~15.7 min). Across ~180 PR CI runs/day.
  • Push-to-main CI: 20–30 → ~15 min.
  • Cost: +1 Linux job per PR/push run, re-restoring the cache and re-compiling non-cached workspace crates (~3–5 min) ≈ +600–900 Linux job-min/day. macOS: 0.

Coverage and risk

The same tests run in release profile on every PR and push to main; only the partitioning changes. ci-test-shard.py already guarantees every target lands in exactly one shard for test. Required checks ci-ok / clippy are unchanged (test-release isn't required directly, and ci-ok already counts a skipped test-release as passing in merge_group).

Effort

S (copy the test job's shard plumbing).

ROI

~12 min × 180 PR runs/day of feedback latency (latency-weighted ≈ 2,000 pts) × confidence 0.8 / effort 1 ≈ 1600.

Activity

  1. mikolalysenko commented on Oct 8, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Open PR #1166 addresses this: it runs test-release as a three-shard matrix through scripts/ci-test-shard.py (48/96/95 integration targets, unit tests and doctests on shard 1), with ci-ok still waiting on the whole matrix. Its body reports the slowest release shard at 10m50s–13m22s across five hosted runs, down from ~26–30 min. Leaving this open until that PR lands.


    Generated by Claude Code

  2. mikolalysenko commented on Oct 9, 2026

    @mikolalysenko
    CollaboratorAuthor

    Profiler refresh, 2026-10-09 00:17 UTC

    test-release is still the last job before ci-ok on PR and push runs. It was the last job in 5 of 6 successful sampled PR runs and 5 of 6 push runs.


    Generated by Claude Code

  3. mikolalysenko commented on Oct 9, 2026

    @mikolalysenko
    CollaboratorAuthor

    Closing this as fixed by #1166 (merged 2026-10-09 08:40 UTC), which split test-release into three shards. Numbers from the runs since then:

    • PR run 37914251835: test-release (1/2/3) took 13.9 / 7.3 / 12.8 min. The longest job was test (windows-latest, 1) at 19.2 min, followed by coverage at 15.0 min.
    • Push run 37910917261: test-release took 14.2 / 10.8 / 11.7 min. The longest job was test (windows-latest, 2) at 18.8 min.

    test-release used to take 29–30 min and was the whole PR critical path. Its slowest shard now takes ~14 min, and the PR critical path is the Windows test legs (~19 min).


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions