Skip to content

ci: parallelize the server test suite (in-process concurrency, ~17min → faster locally + CI) - #1577

Merged
ko3n1g merged 2 commits into
mainfrom
wprazuch/ci-shard-test-suite
Jun 12, 2026
Merged

ci: parallelize the server test suite (in-process concurrency, ~17min → faster locally + CI)#1577
ko3n1g merged 2 commits into
mainfrom
wprazuch/ci-shard-test-suite

Conversation

@wprazuch

@wprazuch wprazuch commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Problem

ng_test_all runs all ~114 server modules strictly sequentially in one process (build venv →
pytest → delete venv per module), ~17 min. This is the long pole on every full-suite PR.

Approach (per review)

Run the suite concurrently within a single ng_test_all invocation rather than sharding
across CI matrix jobs — so local ng_test_all gets the same speedup, not just CI.

  • ng_test_all: new +max_concurrency (default 1 = sequential, fully backwards-compatible).
    Modules run in a ThreadPoolExecutor; each still runs in its own isolated subprocess + venv, so
    isolation is unchanged. Per-module output is captured and printed atomically so concurrent
    logs don't interleave. Extracted _run_module_tests (per-module worker) and
    _run_module_tests_all (orchestration) — both unit-tested.
  • run_command: optional capture= to pipe combined stdout/stderr in text mode. Strictly
    additive — the non-capture path is byte-identical (existing tests unchanged).
  • unit-tests.yml: single job (no matrix). Runs
    ng_test_all +max_concurrency=${TEST_CONCURRENCY|4} on runs-on: ${vars.TEST_RUNNER||ubuntu-latest}.
    The team can point TEST_RUNNER at a larger runner and bump TEST_CONCURRENCY via repo
    variables — no code change
    needed. Keeps the uv 0.11.19 pin.

Why concurrency helps even on a 2-core runner

Per-module time is dominated by venv build (network/disk I/O) + pytest startup, so running several
modules at once overlaps the waiting. A larger TEST_RUNNER amplifies it further.

Testing

  • _run_module_tests_all: sequential order preserved; concurrent runs every module exactly once;
    concurrency genuinely overlaps (in-flight > 1).
  • run_command capture branch: pipes stdout+STDOUT, text mode (asserted); non-capture path
    unchanged.
  • pytest tests/unit_tests/test_cli.py tests/unit_tests/test_cli_setup_command.py 54/54, ruff clean,
    workflow YAML parses. The full concurrent ng_test_all is validated on CI.

Notes

ng_test_all ran all ~114 server modules sequentially in one job (~17 min). Add
+num_shards/+shard_index to ng_test_all (round-robin over sorted module paths so
heavy modules spread evenly) and split the Unit tests workflow:

- detect: change classification (outputs run_full/run_servers)
- Test: core library unit tests (ng_dev_test) + the changed-servers path
- Server suite (shard N): full ng_test_all sharded across an 8-way matrix
- Server suite: aggregation gate over the shards (single required check)

Cuts full-suite wall-time from ~17 min to ~2-3 min. Also pins uv to 0.11.19
(0.11.20 resolver regression drops pinned deps).

Branch protection note: add 'Server suite' as a required check alongside 'Test'
to preserve server-suite gating (server tests moved out of the Test job).

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
@wprazuch
wprazuch requested a review from a team as a code owner June 11, 2026 10:25
@copy-pr-bot

copy-pr-bot Bot commented Jun 11, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@wprazuch wprazuch changed the title ci: shard the full server test suite across 8 parallel runners (~17min → ~2-3min) ci: shard the full server test suite across 8 parallel runners (~22min → ~2-3min) Jun 11, 2026
@ko3n1g

ko3n1g commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

/ok to test fcbad0e

@ko3n1g
ko3n1g enabled auto-merge (squash) June 12, 2026 11:20
@ko3n1g

ko3n1g commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

/ok to test 9c6db4c

@ko3n1g
ko3n1g merged commit b687f9d into main Jun 12, 2026
28 of 29 checks passed
@wprazuch wprazuch changed the title ci: shard the full server test suite across 8 parallel runners (~22min → ~2-3min) ci: parallelize the server test suite (in-process concurrency, ~17min → faster locally + CI) Jun 15, 2026
wprazuch added a commit that referenced this pull request Jun 22, 2026
…n → ~2-3min) (#1577)

The **Unit tests → `Test`** check runs `ng_test_all`, which iterates all
~114 server modules
**strictly sequentially** in a single runner (build venv → pytest →
delete venv per module),
taking **~22 min**. This is the long pole on every PR that touches core
files (which trigger the
full suite via the existing change-detection).

**`ng_test_all` sharding** (`nemo_gym/cli.py`): new `+num_shards` /
`+shard_index` options. Modules
are partitioned **round-robin over a sorted list** so heavy modules
(longmt_eval, the scientific
servers) spread evenly across shards. The
`fail_on_total_and_test_mismatch` check still runs
against the full (unsharded) module list. Extracted `_select_shard()`
with unit tests.

**Workflow restructure** (`.github/workflows/unit-tests.yml`):
- `detect` — change classification (unchanged logic), exposed as job
outputs.
- `Test` — core library unit tests (`ng_dev_test`) + the changed-servers
path. (Fast now — the
  full server loop moved out.)
- `Server suite (shard N)` — `ng_test_all +num_shards=8 +shard_index=N`
across an **8-way matrix**
  (`fail-fast: false`), only on a full run.
- `Server suite` — aggregation job that gates on all shards (single
required check).

**Result: full-suite wall-time ~22 min → ~2-3 min.** Same total compute,
parallelized.

Also pins uv to **0.11.19** (0.11.20 has a resolver regression that
drops pinned deps — see #1576;
this overlaps #1576 on `unit-tests.yml`, so merge #1576 first or fold
them).

Server tests moved out of the `Test` job into the sharded jobs. To
preserve gating, add
**`Server suite`** as a required status check alongside **`Test`**.
(`Server suite` uses
`if: always()` so it reports green when the full suite isn't needed for
a change, and red if any
shard fails — so it's safe to require unconditionally.)

- `_select_shard` unit tests: complete + disjoint partition, balanced
sizes, round-robin stride,
out-of-range guard. `pytest tests/unit_tests/test_cli.py` 14/14, ruff
clean, workflow YAML parses.
- The workflow itself can only be fully validated once it runs on CI.

Signed-off-by: Wojciech Prazuch <wprazuch@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants