Repository navigation
[OMNIML-6180] [7/11] Trim the llm_eval, llm_qat, EAGLE and megatron_bridge example tests - #2851
shengliangxu wants to merge 6 commits into
Conversation
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2851 +/- ##
==========================================
- Coverage 70.16% 70.10% -0.07%
==========================================
Files 659 659
Lines 74081 74081
==========================================
- Hits 51978 51931 -47
- Misses 22103 22150 +47
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
/ok to test 2519292 |
2519292 to
f8fa147
Compare
2d82a59 to
7383ca1
Compare
|
/ok to test f8fa147 |
7383ca1 to
5f3497e
Compare
f8fa147 to
0a781bd
Compare
5529023 to
5366b9c
Compare
…#2845) ### What does this PR do? Type of change: CI (unit-test runtime) The unit `linux` job gates every GPU and example workflow (their pr-gate jobs wait for it), and its tests are CPU-bound but run serially. This runs them under pytest-xdist on the runner's four vCPUs. The `linux` job and the multi-version matrix get `PYTEST_ADDOPTS=-n 4 --dist loadfile` and `OMP_NUM_THREADS=1`: one worker per vCPU (`-n auto` counts physical cores), whole files per worker, and one thread per worker, because with torch's default threads the runner is oversubscribed and slower than serial (1,481 s and 41 failures in my local runs). What else changes so the suite passes under xdist: - `noxfile.py`: the second pytest process that runs the `manual` tests clears `PYTEST_ADDOPTS`, so it stays serial. Those tests leak global state into each other, and a worker would run them in some order. - `tests/_test_utils/torch/quantization/onnx_export.py`: `TEST_MODELS` was a set of classes, whose iteration order differs between processes, so workers collected different test ids. It is a tuple now. - `test_hf_dflash2.py::test_overfits_a_single_batch` takes about 30 s on one thread on main (53 s before #2836 halved its loop to 30 steps; that version hit the 60 s default call timeout in the nightly on main on 2026-10-20). Its tiny model is built in bf16, and a CPU without native bf16 support emulates bf16 matmuls (about 0.9 s per step, 0.1 s in float32). The model is float32 now, which takes the test to about 4 s on one thread, so it needs no timeout override; the loop and both assertions are unchanged. - `test_full_algorithms_vision.py::test_search_constraints` assigned `ConstraintsFunc._get_true_latency` and never restored it. Serial runs never noticed, because `test_evaluate_constraints.py` sorts first. Under xdist a worker can get the files in the other order, and the Python 3.10 and 3.14 legs failed two tests after it. It uses `monkeypatch` now. - `tests/conftest.py`: the unit per-test cap is 120 s on every platform. `test_dist.py::test_data_parallel` takes 8-15 s serial and 25-35 s with four workers sharing four vCPUs, and went over 60 s on the slowest runner. A hung test is still reported, after 2 min instead of 1. Why: on current main the `linux` job has a median of 12.9 min (27 runs of other PRs since #2823 merged), and a pull request's GPU run waits a median 14.5 min for it (125 runs of 33 PRs). ### Time improvement (measured in CI) Unit `linux` job: serial on current main (27 runs of other PRs since #2823 merged) against the runs of this series with `-n 4`. | | before (serial) | with this PR | |---|---|---| | pytest | 630 s median (355-709 s) | 479 s in this PR's own run; 294 s median over the 11 runs of the series (166-479 s) | | whole job | 12.9 min median (8.8-14.8) | 10.9 min in this PR's own run; 7.0 min median over the 11 runs (5.0-10.9) | | unit workflow: `linux`, then the multi-version and Windows legs | 24.1 min median (12 runs) | 17.2 min median (the 7 runs that ran every leg) | - The runs of #2846 and above also carry the sysmon core of #2846 (about 22% off the unit suite on its own, measured locally), so the 294 s median is xdist plus sysmon; this PR's own run is the xdist-only number. It was the slowest of the 11 (166-479 s for nearly the same tests: runner variance), so it understates the gain. Locally on 4 CPUs with coverage as in CI, the base took 825 s serial and 332-344 s with this configuration (3 runs). - The GPU, Example and Regression workflows hold their jobs until the unit `linux` check is done (`pr-gate / wait-checks`, at least 5 min). That wait is a median 14.5 min (IQR 12.9-15.8) on 125 GPU runs of 33 PRs since #2823; in this PR's own GPU run it was 9.7 min (its `linux` job took 10.9 min). With a 7 min `linux` job instead of 12.9 min, a GPU run requested right after a push starts about 6 min earlier. That figure is derived from the job times: the later runs of the series were requested after their unit check had finished (the wait sat at its 5.2 min floor in 7 of the 9 GPU runs), so they cannot show it. Method: every PR of the series has its own CI run, so "before" is the run of the PR(s) below that lack the change and "after" the runs that carry it. Times come from the job logs (`--durations`, or the gap between consecutive result lines). Where runner speed matters, the tests that no PR of the series touches scale each run, and the raw and the scaled medians are both shown. One test varies by 15-30% from run to run on its own, so smaller differences are not evidence. ### Usage Nothing user-facing. Locally: `OMP_NUM_THREADS=1 pytest tests/unit -n 4 --dist loadfile`. ### Testing - Full `tests/unit` on 4 CPUs with coverage as in CI, on the base before #2823: serial 825 s, this configuration 332-344 s in three repeated runs (4,724 passed, 0 failed). - This PR's own CI run: the `linux` job took 10.9 min (479 s of pytest) against the 12.9 min serial median; see the time section above for the later runs of the series. - `tests/unit` without `puzzletron` (it needs `hydra`, absent from my local environment) in reversed and in shuffled file order shows no other order dependence; `test_search_constraints` followed by `test_evaluate_constraints.py` in one process failed before the fix and passes after it. - `test_hf_dflash2.py` (33 tests) on one CPU thread: 13.5 s, of which `test_overfits_a_single_batch` takes about 4 s (30 s with the bf16 model on main; the next slowest test takes about 1.3 s). - Pre-commit (all hooks) passes. ### Before your PR is "*Ready for review*" Make sure you read and follow [Contributor guidelines](https://github.com/NVIDIA/Model-Optimizer/blob/main/CONTRIBUTING.md) and your commits are signed (`git commit -s -S`). Make sure you read and follow the [Security Best Practices](https://github.com/NVIDIA/Model-Optimizer/blob/main/SECURITY.md#security-coding-practices-for-contributors) (e.g. avoiding hardcoded `trust_remote_code=True`, `torch.load(..., weights_only=False)`, `pickle`, etc.). - Is this change backward compatible?: N/A (CI and tests) - If you copied code from any other sources or added a new PIP dependency, did you follow guidance in `CONTRIBUTING.md`: no new dependency (`pytest-xdist` is already in the `dev-test` extra on main) - Did you write any new necessary tests?: N/A (two existing tests fixed or sped up so they pass under xdist) - Did you update [Changelog](https://github.com/NVIDIA/Model-Optimizer/blob/main/CHANGELOG.rst)?: N/A (CI and tests) - Did you get Claude approval on this PR?: N/A (optional, not run) ### Additional Information Slice 1 of 11 of the GPU-CI speed-up work, split out of the reference draft #2730 (not for merge; it holds the whole series with its measurements). Merge in order; each PR stands on its own and passes CI without the later ones. 1. #2845 [OMNIML-6178] [1/11] Run the unit tests in parallel with pytest-xdist **(this PR)** 2. #2846 [OMNIML-6178] [2/11] Use the sysmon coverage core in CI 3. #2847 [OMNIML-6179] [3/11] Run manual-marked tests on nightly and on-demand GPU runs 4. #2848 [OMNIML-6181] [4/11] Give gpu_megatron's slow cold starts more time 5. #2849 [OMNIML-6179] [5/11] Make the ONNX tests cheaper: CPU-only ones to the unit lane, small models 6. #2850 [OMNIML-6179] [6/11] Use local tokenizers and calibration text in GPU tests, shrink puzzletron data 7. #2851 [OMNIML-6180] [7/11] Trim the llm_eval, llm_qat, EAGLE and megatron_bridge example tests 8. #2852 [OMNIML-6180] [8/11] Trim the DFlash regression test 9. #2853 [OMNIML-6180] [9/11] Trim the torch_onnx example lane 10. #2854 [OMNIML-6181] [10/11] Make the distributed worker pool fail fast when a worker dies 11. #2855 [OMNIML-6181] [11/11] Share one Megatron worker pool across the gpu_megatron modules <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Improved consistency and performance of automated test runs across platforms and Python configurations through controlled parallel execution. * Preserved predictable model-check ordering and isolated temporary test changes. * Increased unit-test time limits to better support process-spawning and slower runs. * Improved test reliability by explicitly controlling numeric precision and ensuring serial execution for manual CPU tests. * No end-user functionality or product behavior changed. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
9c4d11c to
9bcfae8
Compare
9bcfae8 to
349db95
Compare
bd0525c to
126279b
Compare
### What does this PR do? Type of change: CI (test runtime) Sets `COVERAGE_CORE=sysmon` on the unit `linux` job, `gpu_tests.yml` and `regression_tests.yml`. Python 3.12 defaults to coverage's C tracer, which slows every line of Python run under it, and every lane starts coverage in each spawned worker and subprocess through `COVERAGE_PROCESS_START`, so import-heavy start-ups pay for it (the 76 s Megatron pool start, the 22 s hf_ptq processes of the unified-export tests, the puzzletron spawns, the vLLM engine core). sysmon records the same lines through `sys.monitoring`. The example runner is left to #2727, which makes the same change there. On a Python older than 3.12 coverage warns and keeps its default core, so a lane that turned out to run an older Python would be slower, not broken (the gpu and gpu_megatron logs show 3.12). ### Time improvement (measured in CI) pytest time of each lane in the run of #2845 (the base of this PR) and in this PR's run, one run each: | lane | #2845 | this PR | change | |---|---|---|---| | gpu | 2,093 s | 1,289 s | -38% | | gpu_megatron | 2,240 s | 1,212 s | -46% | | gpu_vllm v0.20.0 | 204 s | 170 s | -17% | | gpu_vllm v0.30.0 | 426 s | 328 s | -23% | | regression | 366 s | 268 s | -27% | | unit `linux` (xdist) | 479 s | 305 s | -36% | Workflow wall time: GPU tests 59.2 -> 39.6 min, Regression 21.3 -> 15.2 min. - **How much of that is this PR.** Two single runs of the same code differ by 15-30% on their own: the eight example lanes that run over 100 s, which this PR does not touch, moved by -4% to -31% (llm_sparsity +38%) between the same two runs. The deterministic part is the Megatron worker-pool start, the setup of the first test of each gpu_megatron module: 75-77 s in each of 14 modules before (all setups of 12 s or more add up to 1,365 s) and 22-27 s after (575 s), which is 790 s of the lane's 1,028 s. Locally the unit suite takes 825 s with the C tracer, 640 s with sysmon and 572 s without coverage (4 CPUs, serial). - **A `coverage.xml`-only report change was dropped from this PR.** The runs above are of its earlier head, which also had it. It showed no CI effect: the pytest summary line came 1-4 s after the last test in the #2845 runs, which still wrote the html report, and 0-3 s in this PR's runs (median 1.1 s over the 82 lane runs of the series), so the table is the sysmon core's. It would only have saved developers' local runs (about 25 s per pytest session). Method: every PR of the series has its own CI run, so "before" is the run of the PR(s) below that lack the change and "after" the runs that carry it. Times come from the job logs (`--durations`, or the gap between consecutive result lines). Where runner speed matters, the tests that no PR of the series touches scale each run, and the raw and the scaled medians are both shown. One test varies by 15-30% from run to run on its own, so smaller differences are not evidence. ### Usage Nothing user-facing. ### Testing Measured on this tree (tests/unit on 4 CPUs serial: 572 s without coverage, 825 s with the C tracer, 640 s with sysmon; `import modelopt.torch.quantization.extensions`: 17.1 s native, 23.6 s with the C tracer, 18.3 s with sysmon, with the same 362 files and 13,821 executed lines in the spawned child's data file; one TinyLlama fp8 plus TRT-LLM deploy test: 64.8 s without coverage, 103.3 s with the C tracer, 70.5 s with sysmon, identical covered lines). Pre-commit and actionlint pass. The CI runs of the series are the check on real runners (time section above). ### Before your PR is "*Ready for review*" Make sure you read and follow [Contributor guidelines](https://github.com/NVIDIA/Model-Optimizer/blob/main/CONTRIBUTING.md) and your commits are signed (`git commit -s -S`). Make sure you read and follow the [Security Best Practices](https://github.com/NVIDIA/Model-Optimizer/blob/main/SECURITY.md#security-coding-practices-for-contributors) (e.g. avoiding hardcoded `trust_remote_code=True`, `torch.load(..., weights_only=False)`, `pickle`, etc.). - Is this change backward compatible?: N/A (CI and tests) - If you copied code from any other sources or added a new PIP dependency, did you follow guidance in `CONTRIBUTING.md`: no new dependency - Did you write any new necessary tests?: N/A (CI configuration) - Did you update [Changelog](https://github.com/NVIDIA/Model-Optimizer/blob/main/CHANGELOG.rst)?: N/A (CI and tests) - Did you get Claude approval on this PR?: N/A (optional, not run) ### Additional Information Slice 2 of 11 of the GPU-CI speed-up work, split out of the reference draft #2730 (not for merge; it holds the whole series with its measurements). Slices 5, 8 and 10 (#2849, #2852, #2854) target main and merge independently; the other open slices form a stack and merge bottom-up. Each PR stands on its own and passes CI without the later ones. 1. #2845 [OMNIML-6178] [1/11] Run the unit tests in parallel with pytest-xdist (merged) 2. #2846 [OMNIML-6178] [2/11] Use the sysmon coverage core in CI **(this PR)** 3. #2847 [OMNIML-6179] [3/11] Run manual-marked tests on nightly and on-demand GPU runs 4. #2848 [OMNIML-6181] [4/11] Give gpu_megatron's slow cold starts more time 5. #2849 [OMNIML-6179] [5/11] Make the ONNX tests cheaper: CPU-only ones to the unit lane, small models (targets main) 6. #2850 [OMNIML-6179] [6/11] Use local tokenizers and calibration text in GPU tests, shrink puzzletron data 7. #2851 [OMNIML-6180] [7/11] Trim the llm_eval, llm_qat, EAGLE and megatron_bridge example tests 8. #2852 [OMNIML-6180] [8/11] Trim the DFlash regression test (targets main) 9. #2853 [OMNIML-6180] [9/11] Trim the torch_onnx example lane 10. #2854 [OMNIML-6181] [10/11] Make the distributed worker pool fail fast when a worker dies (targets main) 11. #2855 [OMNIML-6181] [11/11] Share one Megatron worker pool across the gpu_megatron modules <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Updated coverage collection for GPU, regression, and Linux unit-test runs to use Python’s monitoring-based coverage core on supported Python 3.12+ environments. * This configuration reduces overhead during coverage-enabled test execution, particularly for import-heavy worker processes. * No changes to application functionality or public interfaces are included. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
349db95 to
d09436a
Compare
### What does this PR do? Type of change: CI (test runtime, tests only) **The DFlash regression trains 500 steps and resumes for 20.** `test_dflash_training` trained 3 epochs (1,500 steps) and `test_dflash_resume` then a fourth epoch (500 more). On the 1-GPU PR runner the recorded durations solve to about 33 s of start-up plus 55-73 ms per step, so the two tests spend roughly 115-140 s and 60-70 s. The loss assertion only needs a final loss below 3.0, and the L40 baseline is already 1.78 at step 500. The resume still goes through the whole restore-and-train path, and it now reads `trainer_state.json` and checks that `global_step` is 520 and that a log entry follows step 500 (it had no assertion besides the exit status). The step count is fixed with `max_steps` rather than `num_train_epochs`, because the regression job runs on 2 GPUs off pull requests, where `accelerate launch` starts one process per visible GPU and an epoch is 250 steps. Measured: 81 s per PR regression job. Risk: the 1.78 baseline comes from a 1,500-step run, and with `max_steps=500` the linear schedule decays to zero at step 500, so the final loss can differ from it; the bound leaves 1.2 of margin. ### Time improvement (measured in CI) | lane | | before | after | change | |---|---|---|---|---| | regression | `test_dflash_training` | 118 s | 62 s | -56 s | | regression | `test_dflash_resume` | 56 s | 31 s | -25 s | | regression | **lane pytest** | 268 s | 170 s | **-98 s (-37%)** | DFlash: before = #2846, #2848 and #2850 (#2849 ran on a slower runner), after = #2852, #2854 and #2855 (median; the lane took 168 and 170 s on the normal-speed runners and 243 s on the slow one). On its own, on main (2026-10-21): this PR's regression job against #2854's, which has the same base and lacks this change. The unchanged DFlash tests took the same time within about 3% (equally fast runners). `test_dflash_training` takes 144 s before and 83 s after, `test_dflash_resume` 73 s and 47 s, and the lane's pytest time goes from 374 s to 291 s (-83 s). The lane passes (5 passed), so the loss stays below 3.0 after 500 steps and the resume ends at `global_step` 520. A vLLM change that sized the KV pool of the Qwen3-MoE and DeepSeek engines down was dropped from this PR. The runs above are of its earlier head, which had it: the engines it touched booted 5-6 s per vLLM version faster than the ones it left alone, in line with the 1-3 s per boot expected and below the boot-to-boot noise (the unchanged Llama engine took 84-99 s on v0.30.0), so it saved nothing measurable. Method: every PR of the series has its own CI run, so "before" is the run of the PR(s) below that lack the change and "after" the runs that carry it. Times come from the job logs (`--durations`, or the gap between consecutive result lines). Where runner speed matters, the tests that no PR of the series touches scale each run, and the raw and the scaled medians are both shown. One test varies by 15-30% from run to run on its own, so smaller differences are not evidence. ### Usage Nothing user-facing. ### Testing I read the transformers 4.57.1 sources (`max_steps` overrides `num_train_epochs`; with the steps save strategy a checkpoint is saved at step 500 and again at the end) and the accelerate 1.10.0 launcher defaults. Not run on a GPU here: this PR's regression job is the check, in particular that the final DFlash loss stays below 3.0 after 500 steps and that the resume ends at `global_step` 520. Pre-commit passes. ### Before your PR is "*Ready for review*" Make sure you read and follow [Contributor guidelines](https://github.com/NVIDIA/Model-Optimizer/blob/main/CONTRIBUTING.md) and your commits are signed (`git commit -s -S`). Make sure you read and follow the [Security Best Practices](https://github.com/NVIDIA/Model-Optimizer/blob/main/SECURITY.md#security-coding-practices-for-contributors) (e.g. avoiding hardcoded `trust_remote_code=True`, `torch.load(..., weights_only=False)`, `pickle`, etc.). - Is this change backward compatible?: N/A (CI and tests) - If you copied code from any other sources or added a new PIP dependency, did you follow guidance in `CONTRIBUTING.md`: no new dependency - Did you write any new necessary tests?: N/A (existing tests made cheaper; the DFlash resume test now also asserts on its result) - Did you update [Changelog](https://github.com/NVIDIA/Model-Optimizer/blob/main/CHANGELOG.rst)?: N/A (CI and tests) - Did you get Claude approval on this PR?: N/A (optional, not run) ### Additional Information Slice 8 of 11 of the GPU-CI speed-up work, split out of the reference draft #2730 (not for merge; it holds the whole series with its measurements). Slices 5, 8 and 10 (#2849, #2852, #2854) target main and merge independently; the other open slices form a stack and merge bottom-up. Each PR stands on its own and passes CI without the later ones. The times above are from the series' CI runs before 2026-10-21, when all slices formed one linear stack; a PR number in a method note names that PR's run from then. 1. #2845 [OMNIML-6178] [1/11] Run the unit tests in parallel with pytest-xdist (merged) 2. #2846 [OMNIML-6178] [2/11] Use the sysmon coverage core in CI 3. #2847 [OMNIML-6179] [3/11] Run manual-marked tests on nightly and on-demand GPU runs 4. #2848 [OMNIML-6181] [4/11] Give gpu_megatron's slow cold starts more time 5. #2849 [OMNIML-6179] [5/11] Make the ONNX tests cheaper: CPU-only ones to the unit lane, small models (targets main) 6. #2850 [OMNIML-6179] [6/11] Use local tokenizers and calibration text in GPU tests, shrink puzzletron data 7. #2851 [OMNIML-6180] [7/11] Trim the llm_eval, llm_qat, EAGLE and megatron_bridge example tests 8. #2852 [OMNIML-6180] [8/11] Trim the DFlash regression test (targets main) **(this PR)** 9. #2853 [OMNIML-6180] [9/11] Trim the torch_onnx example lane 10. #2854 [OMNIML-6181] [10/11] Make the distributed worker pool fail fast when a worker dies (targets main) 11. #2855 [OMNIML-6181] [11/11] Share one Megatron worker pool across the gpu_megatron modules <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Updated regression coverage to use fixed training limits of 500 steps, with resumed runs extending to step 520. * Improved checkpoint and resume validation to confirm the final training step and expected post-resume progress logs. * Updated loss expectations to reflect the result at the 500-step training milestone. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
… a worker dies (#2854) ### What does this PR do? Type of change: CI (test reliability); changes `tests/_test_utils` only A worker that exits without reporting (an illegal memory access aborts the process, or an OOM kill) was only noticed when the result timeout ran out: 600 s for a job, 120 s for the start. Until then the parent waits on a queue nobody writes to, and the other workers wait in the job, typically in a collective, for their dead peer. A start that fails, for example on a bad backend, also waited out the whole ready timeout and left the workers it had spawned behind. `DistributedWorkerPool` now checks the workers' liveness once a second while it waits. A dead worker is noticed within a second and fails the run, or the start, naming its rank and exit code (about 4 s after the death, which includes the 3 s the pool already waits for the other workers' stack dumps). If another rank had already reported an exception, its traceback is kept in that error. The pool is marked `broken` and the other workers are killed with their stacks printed, the way a hung job or a failed rank already ends in main (`get_live_pool` then hands out a new pool). A start that fails kills the workers it had spawned. `ready_timeout` is a constructor argument (120 s by default, as before), so a test can reach the start timeout without waiting for it. This builds on the hang handling of #2832 (`broken`, `get_live_pool`, the stack dump) and does not change it. ### Time improvement (measured locally, not in CI) No lane time changes in a passing run, and no worker died in this series' CI runs, so CI cannot show it. What changes is how long a dead worker costs. CPU, gloo, two ranks, the pool test's own job (rank 0 exits with code 13, rank 1 keeps waiting), seconds from `pool.run(...)` (or the constructor) to the exception, on main and on this PR: | scenario | before | after | |---|---|---| | a rank dies mid-job, its peer is stuck in a wait, `job_timeout` 30 s (as in the test) | 33.1 s, `queue.Empty` | 4.0 s, `Worker process(es) died (rank, exit code): [(0, 13)]` | | the same with the default `job_timeout` of 600 s | 603.1 s, `queue.Empty` | 4.0 s | | the same, the peer waits in `dist.barrier()` | 33.3 s (the 30 s `failure_grace`) | 4.3 s | | the start fails (`backend="not-a-backend"`), default `ready_timeout` of 120 s | 120.1 s, `queue.Empty` | 5.0 s | | rank 0 dies at the start, rank 1 hangs in the rendezvous | 120.0 s, one live worker left behind | 5.0 s, no worker left | The after time is the 1 s liveness poll plus the 3 s the pool waits for the other workers' stack dumps before it kills them. At the production timeouts (120 s for the start, 600 s for a job) a dead worker therefore costs 4-5 s instead of 2-10 minutes of a CI job: the test fails at once and the next one gets a fresh pool from `get_live_pool`, instead of waiting for a queue nobody writes to. Cost: the four new cases add about 27 s to the `gpu` lane: the pool test module takes 43 s in this PR's run and 17 s in #2849's run, which has the same base (main) and lacks them (both from the job logs). Method: a small script (not part of this PR) builds the pool the way the repo's test does and times each scenario with `time.monotonic()` around the call, once per commit, on a CPU host. ### Usage ```python pool = DistributedWorkerPool(world_size=2, backend="nccl", ready_timeout=300) # new argument, default 120 ``` ### Testing `tests/gpu/torch/utils/test_distributed_worker_pool.py` runs the pool with gloo on CPU (it extends main's three tests; the new cases take 24 s together): - a rank that exits with code 13 while its peer waits fails the run in about 5 s and kills the peer. The test sets `job_timeout = 30`, so a regression fails there with `queue.Empty` instead of at the test's own cap. With the liveness check disabled it fails exactly that way. - the same test with a second job: rank 0 raises an exception and rank 1 exits with code 13 two seconds later, after rank 0 has reported. The error carries the exit code and rank 0's traceback. Without the change it carries only the exit code, and the case fails. - a start that fails raises and leaves no worker, both when every worker dies (a bad backend) and when the wait times out while they are still starting (`ready_timeout=0.01`). With `_abort()` removed from the failed-start path, the second case fails ("workers left behind"); the first passes either way, since all its workers die on their own, so it covers the liveness wiring only. Main's three tests (as reworked by #2836) still pass, and the three new cases fail against main's unmodified pool. Pre-commit passes. This PR is rebased onto #2836, which also edited the pool (reporting a failed rank before its teardown, retiring a pool after any failed job); the changes are in different places. The default start timeout stays 120 s here; #2848 raises it to 300 s, so whichever of the two merges second resolves that one line. ### Before your PR is "*Ready for review*" Make sure you read and follow [Contributor guidelines](https://github.com/NVIDIA/Model-Optimizer/blob/main/CONTRIBUTING.md) and your commits are signed (`git commit -s -S`). Make sure you read and follow the [Security Best Practices](https://github.com/NVIDIA/Model-Optimizer/blob/main/SECURITY.md#security-coding-practices-for-contributors) (e.g. avoiding hardcoded `trust_remote_code=True`, `torch.load(..., weights_only=False)`, `pickle`, etc.). - Is this change backward compatible?: N/A (CI and tests) - If you copied code from any other sources or added a new PIP dependency, did you follow guidance in `CONTRIBUTING.md`: no new dependency - Did you write any new necessary tests?: ✅ 2 test functions (4 cases) in `tests/gpu/torch/utils/test_distributed_worker_pool.py`, run on CPU with gloo; each fails without its fix - Did you update [Changelog](https://github.com/NVIDIA/Model-Optimizer/blob/main/CHANGELOG.rst)?: N/A (CI and tests) - Did you get Claude approval on this PR?: N/A (optional, not run) ### Additional Information Slice 10 of 11 of the GPU-CI speed-up work, split out of the reference draft #2730 (not for merge; it holds the whole series with its measurements). Slices 5, 8 and 10 (#2849, #2852, #2854) target main and merge independently; the other open slices form a stack and merge bottom-up. Each PR stands on its own and passes CI without the later ones. The times above are from the series' CI runs before 2026-10-21, when all slices formed one linear stack; a PR number in a method note names that PR's run from then. 1. #2845 [OMNIML-6178] [1/11] Run the unit tests in parallel with pytest-xdist (merged) 2. #2846 [OMNIML-6178] [2/11] Use the sysmon coverage core in CI 3. #2847 [OMNIML-6179] [3/11] Run manual-marked tests on nightly and on-demand GPU runs 4. #2848 [OMNIML-6181] [4/11] Give gpu_megatron's slow cold starts more time 5. #2849 [OMNIML-6179] [5/11] Make the ONNX tests cheaper: CPU-only ones to the unit lane, small models (targets main) 6. #2850 [OMNIML-6179] [6/11] Use local tokenizers and calibration text in GPU tests, shrink puzzletron data 7. #2851 [OMNIML-6180] [7/11] Trim the llm_eval, llm_qat, EAGLE and megatron_bridge example tests 8. #2852 [OMNIML-6180] [8/11] Trim the DFlash regression test (targets main) 9. #2853 [OMNIML-6180] [9/11] Trim the torch_onnx example lane 10. #2854 [OMNIML-6181] [10/11] Make the distributed worker pool fail fast when a worker dies (targets main) **(this PR)** 11. #2855 [OMNIML-6181] [11/11] Share one Megatron worker pool across the gpu_megatron modules <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Distributed worker pools now detect workers that exit during startup or job execution and report failures instead of waiting for the full job timeout. * Worker startup supports a configurable readiness timeout with prompt timeout handling. * Failed or timed-out initialization now cleans up spawned worker processes, preventing orphaned processes and leaving the pool in a consistent state. * Job result retrieval now responds promptly when a worker fails. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
…e unit lane, small models (#2849) ### What does this PR do? Type of change: CI (test runtime, tests only) Four changes to the ONNX tests of the `gpu` job: - **Three CPU-only files move to the unit lane** (`tests/gpu/onnx/quantization/` to `tests/unit/onnx/quantization/`, content unchanged): `test_dla_qdq_rules.py`, `test_dla_scalar_constants.py` and `test_quantization_initializer_names.py` (added with #2678, 68 cases). They quantize with `calibration_eps=["cpu"]` and run the result on the CPUExecutionProvider, so they need no GPU, but they cost 26.8 s per `gpu` job (1.5 + 5.3 + 20.0 s in the CI logs); the unit job runs them in a few seconds on its xdist workers. - **`test_concat_elim` calibrates a 32-channel 16x16 model on the CPU** instead of the (1, 128, 240, 64) three-conv model on `[cpu, cuda:0, trt]`: the two tests took about 22 s each on the base (15 s together in the series' CI runs with the sysmon core of #2846), and their assertions only look at where the pass places Q/DQ nodes. The convs stay above the 16-channel limit of `graph_selection.py`, and both modes produce the same 8 Q and 8 DQ nodes as with the default size. `build_conv_concat_model` takes optional `channels`, `height` and `width` (defaults: the old values; with a seeded RNG the default model serializes to the same bytes). - **The autotune benchmark tests build a 1x32x32x32 model** instead of the 64x32x224x224 one (103 M random floats and about 1.2 GB copied per iteration; the five tests took 31 s, and none looks at the latency beyond "a positive float"). The two trtexec tests also pass `--duration=0`, because trtexec measures for at least 3 s whatever the iteration count. `_create_simple_conv_onnx_model` takes optional `batch_size` and `spatial_size` with the old defaults, so the unit autotuner tests that share it build the same model (their 161 tests pass). - **The autotune workflow test passes `--duration=0` to trtexec**: `test_export_quantized_model[True]` took 44 s, mostly inside trtexec's 3 s minimum measurement per scheme. It still runs the 100 requested iterations per measurement; the model and `timing_runs` keep their size, because the test asserts the best scheme carries Q/DQ nodes. ### Time improvement (measured in CI) gpu lane, time per file from the per-test timestamps; before = the runs of #2846-#2848, after = this PR's run and the 4 runs above it (median): | | before | after | change | |---|---|---|---| | three CPU-only files (68 cases), moved to the unit lane | 7.4 s | 0 | -7.4 s | | `test_concat_elim.py` | 15.2 s | 1.2 s | -14.0 s | | `autotune/test_benchmark.py` (36 cases) | 37.1 s | 21.0 s | -16.0 s | | `autotune/test_workflow.py` | 44.4 s | 28.5 s | -15.9 s | | **sum** | 104 s | 51 s | **-53 s per gpu job** (-59 s after speed scaling) | The whole `tests/gpu/onnx` directory takes 110-120 s before and 58 s in the three later runs on normal-speed runners (81 s and 74 s in #2849 and #2850, which ran on 1.3x slower runners). The 68 moved cases cost the unit job 7-13 s of CPU, spread over four xdist workers (below the unit job's run-to-run spread). My first estimate of the gpu saving (97-107 s) came from base runs without sysmon, where these files were slower. On its own, on main as of 07:06 UTC on 2026-10-21 (before #2846 added the sysmon core): the `gpu` lane's `tests/gpu/onnx` directory takes 145 s in #2854's run, which has the same base and lacks this change, and 66 s in this PR's run (-79 s). The runners were equally fast (median ratio 0.99 over the 17 untouched files above 20 s). `test_concat_elim.py` goes from 35 s to 2.7 s, `autotune/test_benchmark.py` from 39 s to 24 s and `autotune/test_workflow.py` from 46 s to 28 s, and the three moved files cost 14 s there. Times are the gaps between consecutive result lines in the job logs. Method: every PR of the series has its own CI run, so "before" is the run of the PR(s) below that lack the change and "after" the runs that carry it. Times come from the job logs (`--durations`, or the gap between consecutive result lines). Where runner speed matters, the tests that no PR of the series touches scale each run, and the raw and the scaled medians are both shown. One test varies by 15-30% from run to run on its own, so smaller differences are not evidence. ### Usage Nothing user-facing. ### Testing - The three moved files: 68 passed in 7.1 s at the old location and in 13.3 s from the new one (this includes the unit conftest's session setup) on Python 3.12 with onnx 1.21.0 and onnxruntime 1.24.4, and 68 passed in 15.3 s on Python 3.10.19 with onnxruntime 1.22.0, the oldest runtime `pyproject` allows. The whole `tests/unit/onnx` directory passes (756 passed, 12 xfailed). - `test_concat_elim`: the two tests pass in 1.3 s on CPU; quantizing the default and the small model in both modes gives Q=8, DQ=8. - The shared helper changes: the unit autotune tests (161) pass. - Not run: the TensorRT tests, because there is no TensorRT here; this PR's `gpu` job is the check. Pre-commit passes. ### Before your PR is "*Ready for review*" Make sure you read and follow [Contributor guidelines](https://github.com/NVIDIA/Model-Optimizer/blob/main/CONTRIBUTING.md) and your commits are signed (`git commit -s -S`). Make sure you read and follow the [Security Best Practices](https://github.com/NVIDIA/Model-Optimizer/blob/main/SECURITY.md#security-coding-practices-for-contributors) (e.g. avoiding hardcoded `trust_remote_code=True`, `torch.load(..., weights_only=False)`, `pickle`, etc.). - Is this change backward compatible?: N/A (CI and tests) - If you copied code from any other sources or added a new PIP dependency, did you follow guidance in `CONTRIBUTING.md`: no new dependency - Did you write any new necessary tests?: N/A (existing tests moved or made smaller; the 68 moved cases are unchanged) - Did you update [Changelog](https://github.com/NVIDIA/Model-Optimizer/blob/main/CHANGELOG.rst)?: N/A (CI and tests) - Did you get Claude approval on this PR?: N/A (optional, not run) ### Additional Information Slice 5 of 11 of the GPU-CI speed-up work, split out of the reference draft #2730 (not for merge; it holds the whole series with its measurements). Slices 1, 2, 8 and 10 (#2845, #2846, #2852, #2854) have merged. Slice 5 (#2849) targets main and merges independently; the other open slices form a stack and merge bottom-up. Each PR stands on its own and passes CI without the later ones. The times above are from the series' CI runs before 2026-10-21, when all slices formed one linear stack; a PR number in a method note names that PR's run from then. 1. #2845 [OMNIML-6178] [1/11] Run the unit tests in parallel with pytest-xdist (merged) 2. #2846 [OMNIML-6178] [2/11] Use the sysmon coverage core in CI (merged) 3. #2847 [OMNIML-6179] [3/11] Run manual-marked tests on nightly and on-demand GPU runs 4. #2848 [OMNIML-6181] [4/11] Give gpu_megatron's slow cold starts more time 5. #2849 [OMNIML-6179] [5/11] Make the ONNX tests cheaper: CPU-only ones to the unit lane, small models (targets main) **(this PR)** 6. #2850 [OMNIML-6179] [6/11] Use local tokenizers and calibration text in GPU tests, shrink puzzletron data 7. #2851 [OMNIML-6180] [7/11] Trim the llm_eval, llm_qat, EAGLE and megatron_bridge example tests 8. #2852 [OMNIML-6180] [8/11] Trim the DFlash regression test (merged) 9. #2853 [OMNIML-6180] [9/11] Trim the torch_onnx example lane 10. #2854 [OMNIML-6181] [10/11] Make the distributed worker pool fail fast when a worker dies (merged) 11. #2855 [OMNIML-6181] [11/11] Share one Megatron worker pool across the gpu_megatron modules <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **Tests** * Added configurable dimensions to ONNX test models and smaller inputs for selected scenarios. * Streamlined GPU benchmark timing while retaining configured measurement runs. * Updated INT8 and FP8 concat-elimination coverage to use CPU calibration and smaller model shapes. * Reorganized DLA and quantization checks as unit tests instead of GPU tests. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
test_lm_eval_hf ran `--tasks mmlu --limit 0.1`: the 57-subtask group, about 5.6k loglikelihood requests, on a tiny Qwen3 whose max_position_embeddings is 32, so every context is truncated to 32 tokens. Its runtime is dominated by loading one HF dataset config per subtask and does not depend on the host (over 331 CI runs: min 198.9 s, median 212.5 s, mean 221.0 s). Run `mmlu_abstract_algebra` (100 test documents, 5-shot) instead. It goes through the same lm_eval_hf.py code path and the same accuracy gate (which requires exactly one task and reads results[task]['acc,none']); only the number of datasets and documents changes. The gate's lower bound of 0.1 is unchanged. The label distribution of that split is 22/26/31/21, so even a model that always predicts one letter scores at least 0.21. Testing: ran the test's command on CPU (CUDA hidden) with the tiny Qwen3 the test builds. Old configuration: 223.4 s wall, mmlu/acc 0.2343, gate PASS. New configuration: 22.4 to 24.0 s wall, mmlu_abstract_algebra/acc 0.27, gate PASS. Also ran ruff check, ruff format --check and pytest --collect-only on the file. A GPU CI run is still needed to confirm the accuracy with CUDA bf16 numerics. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
test_qwen3_qat_nvfp4 (fsdp2, deepspeed, ddp) and test_qwen3_qad_nvfp4 (fsdp2, deepspeed) each ran quantize.py on the same tiny Qwen3 with the same recipe, and every quantize.py and train.py call built its own tokenized dataset cache (the cache key contains max_length, 8192 in quantize.py and 128 in train.py, so even the two steps of one test could not share it). With test_qwen3_qlora_nvfp4 that is 6 quantize.py runs and 12 cold dataset builds per module. These tests take 104 to 121 s each on CI (qlora 169 s). Run quantize.py once in a module-scoped fixture and let the five tests read the checkpoint, guarded by assert_unmodified_tree like the shared tiny-model fixtures. qat_nvfp4.yaml and qad_nvfp4.yaml give quantize.py identical arguments (distill and teacher_model are not quantize arguments), so one checkpoint serves both. test_qwen3_qlora_nvfp4 keeps its own PTQ because it passes --compress True. All quantize.py and train.py calls now share one dataset cache directory, so the 8192 and 128 variants are each built once; calibration keeps its 8192 tokens. test_dataset_utils_pretokenize keeps its own cache directory so it still checks that the CLI writes one. Fixture time is outside pytest-timeout (timeout_func_only = true), as for the other shared fixtures in tests/examples. Testing: node IDs are unchanged. With run_example_command faked, quantize.py runs 6 -> 2 times and cold dataset builds go 12 -> 2 (plus the pretokenize test's own); a train.py that writes into the shared checkpoint is reported by the fixture teardown. Real quantize.py and train.py (QAT, then QAD from the checkpoint made with the QAT config) ran on CPU with the int4 and fp8 recipes, since NVFP4 dynamic-block quantization needs CUDA: train.py left the checkpoint unmodified and the QAD run reused the dataset cache the QAT run built. The saving, about 3 minutes of the 21.7 minute lane, is an estimate from the CI timings; a GPU CI run is needed to measure it. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
test_llama_eagle3[1-False] is the one compiled EAGLE3 training run on the 1-GPU PR lane: hf_eagle.py compiles _eagle_forward with mode="max-autotune". It takes 175.5 s per job against 40.6 s for [1-True], the same flow without compile (call time 158.5 s vs 34.7 s on PRs, 147.8 s vs 34.4 s nightly), so about 135 s is torch.compile. That includes benchmarking Triton GEMM templates for a draft model that is one tiny decoder layer. Launch it with TORCHINDUCTOR_MAX_AUTOTUNE_GEMM_BACKENDS=ATEN, the mechanism test_diffusers.py already uses for its compile tests. The mode stays max-autotune, so cudagraphs, coordinate-descent tuning, Dynamo tracing and Inductor lowering still run; only the Triton GEMM template search is dropped. There is no conv variable here because the draft has no convolutions. [2-False] (2 GPUs, nightly) keeps the full autotune. Testing: with run_example_command faked, only [1-False] gets the variable (on top of the full os.environ) and the other parametrizations pass no env. On torch 2.14 torch._inductor.config.max_autotune_gemm_backends reads the variable and the max-autotune mode options do not override it. CPU cannot reproduce the Triton autotune, so the saving is not measured; a GPU CI run is needed to see how much of the 135 s it removes. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
test_offline_eagle3_training[tinyllama] trains one step (num_train_epochs=0.1) of offline EAGLE3 on the tiny llama with its real base model. It takes 34.9 s per job, almost all launcher start-up. test_eagle_offline_ptq.py's test_offline_eagle_training (35.2 s) already runs that mode on the same model (use_fake_base_for_offline defaults to false) with hidden states dumped by compute_hidden_states_hf.py, and the FakeBaseModel case keeps the synthetic dump path. The only thing the dropped case covered that stage 2 did not is the offline collator truncating dumps: its 128-token dumps were cut to training_seq_len=64, while stage 2's dumps are 28 tokens against 64, so they were only padded. Set stage 2 to training_seq_len=16 so the collator truncates there. The collator is also unit tested on CPU (test_collator_truncates, test_collator_pads). Stage 3 (hf_ptq.py --specdec_offline_dataset) takes its collator length from --calib_seq and does not read the tokenizer saved with the checkpoint, which now records model_max_length 16. Testing: ran stage 1 (compute_hidden_states_hf.py, two 28-token dumps) and stage 2 (main.py, offline EAGLE3 on the tiny llama) on CPU with training_seq_len=64 and 16 (use_cpu, bf16 and tf32 off are the only changes from the test): both train and write the checkpoint, and the collator pads 28 -> 64 and truncates 28 -> 16. With run_example_command faked, the launch commands of the remaining parametrizations are unchanged and the only removed test ID is test_offline_eagle3_training[tinyllama]; nothing else reads its eagle-tinyllama-offline output. The ~30 s saving per job is not measured. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
The megatron_bridge conftest resets Megatron's global state before and after every test: destroy_model_parallel, destroy_rerun_state_machine, then gc.collect() and torch.cuda.empty_cache(). With torch, Megatron and modelopt imported the collection walks a large heap and costs about 1.3 s per test in the recorded durations. 77 tests in this directory are pure Python (the mlflow wiring tests and the checkpoint-path tests), never run an example step and leave nothing to reset, so the lane pays about 100 s per job for nothing. The megatron_bridge job runs at 68-75 minutes against its 75-minute nightly limit. Reset the Megatron state only for tests that request `num_gpus`, which is how every test that runs an example step reaches a GPU in this directory. The environment restore stays for every test: it is cheap, and the NVTE_* leak it guards against does not depend on a GPU. Tests that run steps keep both resets, and run_example_in_process and run_torchrun_in_process already reset at the start of each step. A future test that runs a step without taking `num_gpus` would lose the reset around it, though its steps would still reset at their start. Testing: ruff check and ruff format with the pinned ruff 0.15.20, and py_compile. Ran a throwaway pytest module (not part of this change) on CPU against the patched conftest with the real fixture, counting calls to reset_megatron_global_state: plain tests trigger none, tests that request `num_gpus` directly or through another fixture trigger one before and one after, and the environment is restored in both cases. The same module fails against the old conftest. Not run: the megatron_bridge suite itself, because megatron.bridge and the GPUs are not available on this machine. The next GPU CI run should show the setup and teardown time of the mlflow tests drop to near zero. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
Review feedback on this PR: `cp_size == 1` does not mean one GPU. launch_train.sh starts one accelerate process per visible GPU, so on the 2-GPU nightly runner `[1-False]` runs with two processes and still got TORCHINDUCTOR_MAX_AUTOTUNE_GEMM_BACKENDS=ATEN, although the comment says the nightly keeps the full autotune. Key the shortcut on the GPU count instead. Testing: pre-commit passes. Calling test_llama_eagle3 on a CPU host with run_example_command captured: only cp_size=1, mix_hidden_states=False and num_gpus=1 gets the ATEN variable; that case with 2 GPUs, and every other case, keep the full autotune; cp_size=2 on one GPU is still skipped. Not run: the example job itself, which needs GPUs. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
d09436a to
5b4b6ea
Compare
cjluo-nv
left a comment
There was a problem hiding this comment.
Bot review (gpt-6.1-sol) — DM the bot to share feedback.
LGTM: the test reductions are justified and preserve the relevant smoke paths; modifying and removing existing tests requires human sign-off.
Needs action:
- Confirm human sign-off on the narrowed MMLU smoke and duplicate EAGLE removal; offline real-model training and collator truncation remain covered.
No action needed:
- Shared QAT/QAD PTQ setup uses the existing immutability guard; QLoRA retains separate compressed PTQ.
- Current Megatron example runners request
num_gpus; pure-Python tests retain environment restoration. - Tests were inspected, not executed locally.
### What does this PR do?
Type of change: CI (test runtime); the only non-test file is
`examples/torch_onnx/torch_quant_to_onnx.py`
Three cuts to the torch_onnx example lane:
- **No DataLoader workers in the calibration loaders.**
`load_calibration_data` builds its DataLoaders over lists of tensors
that are already on the GPU, so the four workers load nothing, and since
the script forced the `spawn` start method (CUDA cannot be used in
forked workers), every loader pass spawned four processes that
re-imported torch, timm and modelopt and received the dataset over CUDA
IPC: about 14 s per pass and about 300 s per torch_onnx CI job. Both
loaders use `num_workers=0`, and the module-level
`mp.set_start_method("spawn", force=True)` is dropped, which also stops
importing the script from changing the start method of the importing
process (two tests import it inside the pytest process). Nothing else in
the script uses multiprocessing. The `--evaluate` path keeps the
CPU-only DataLoader workers of `examples/onnx_ptq/evaluation.py`, now
under the default start method, exactly as in the `onnx_ptq` example
that calls the same function.
- **swinv2 int8, mxfp8 and auto are skipped on pull requests.**
`swinv2_tiny` runs all five formats on top of `swin_tiny`, which already
covers every format through the same exporter and TensorRT path; swinv2
only adds its cosine attention and post-norm blocks. On PRs
(`GITHUB_REF` under `refs/heads/pull-request/`) fp8 and nvfp4 still run
and exercise those blocks; scheduled and local runs keep every
combination, and test ids are unchanged. `swinv2_tiny[auto]` alone
averages 121 s over 304 CI runs; the three skipped cases cost about 110
s of every PR run.
- **`build_trt_engine` runs trtexec for one iteration.** It let trtexec
run its default benchmark after the build (200 ms warm-up, then at least
3 s and 10 iterations) and discarded the output. `--warmUp=0
--duration=0 --iterations=1` still executes the engine once and removes
about 3 s per engine, roughly 40 s per lane run. `--trt_build` users see
no difference besides it returning sooner.
### Time improvement (measured in CI)
torch_onnx lane; before = #2846, #2848 and #2850 (875-880 s; #2849 ran
on a slower runner: 1,060 s), after = #2853, #2854 and #2855 (452-463
s).
| | before | after | change |
|---|---|---|---|
| **lane pytest** | 877 s | 458 s | **-419 s (-48%)** |
| of which: the three swinv2 cases skipped on PRs | 143 s | 0 | -143 s |
| of which: the cases that still run (no DataLoader workers, trtexec
runs once) | | | -277 s |
| whole job | 18.6 min | 12.2 min | -6.4 min |
This lane repeats to within 1% (875-880 s before, 452-463 s after), so
it is the cleanest measurement of the series. For example `swin_tiny`
with auto quantization goes from 66 s to 24 s and `vit_tiny` with auto
from 60 s to 17 s.
Method: every PR of the series has its own CI run, so "before" is the
run of the PR(s) below that lack the change and "after" the runs that
carry it. Times come from the job logs (`--durations`, or the gap
between consecutive result lines). Where runner speed matters, the tests
that no PR of the series touches scale each run, and the raw and the
scaled medians are both shown. One test varies by 15-30% from run to run
on its own, so smaller differences are not evidence.
### Usage
No API change. The skip is keyed on `GITHUB_REF`, so a local run keeps
every combination.
### Testing
`py_compile`, ruff 0.15.20 and `pytest --collect-only` on CPU (24 tests,
ids unchanged). With the example command stubbed,
`GITHUB_REF=refs/heads/pull-request/123` skips exactly swinv2 int8,
mxfp8 and auto, and any other ref skips none; the two in-process mapping
tests that import the script pass on CPU, and `build_trt_engine` passes
the three flags to a fake trtexec. Not run: the lane itself (it needs a
GPU, TensorRT and model downloads) and the flags against a real trtexec,
so this PR's torch_onnx job is the check. Pre-commit passes. #2685
(open) also edits this example; the changes touch different lines.
### Before your PR is "*Ready for review*"
Make sure you read and follow [Contributor
guidelines](https://github.com/NVIDIA/Model-Optimizer/blob/main/CONTRIBUTING.md)
and your commits are signed (`git commit -s -S`).
Make sure you read and follow the [Security Best
Practices](https://github.com/NVIDIA/Model-Optimizer/blob/main/SECURITY.md#security-coding-practices-for-contributors)
(e.g. avoiding hardcoded `trust_remote_code=True`, `torch.load(...,
weights_only=False)`, `pickle`, etc.).
- Is this change backward compatible?: N/A (CI and tests)
- If you copied code from any other sources or added a new PIP
dependency, did you follow guidance in `CONTRIBUTING.md`: no new
dependency
- Did you write any new necessary tests?: N/A (existing tests; the
PR-only skip keeps test ids)
- Did you update
[Changelog](https://github.com/NVIDIA/Model-Optimizer/blob/main/CHANGELOG.rst)?:
N/A (CI and tests)
- Did you get Claude approval on this PR?: N/A (optional, not run)
### Additional Information
Slice 9 of 11 of the GPU-CI speed-up work, split out of the reference
draft #2730 (not for merge; it holds the whole series with its
measurements). Slices 1, 2, 5, 8 and 10 (#2845, #2846, #2849, #2852,
#2854) have merged. The remaining slices (#2847, #2848, #2850, #2851,
#2853, #2855) are independent PRs on main: each applies to main on its
own, and merging all six onto main in different orders gives the same
tree. The times above are from the series' CI runs before 2026-10-21,
when all slices formed one linear stack; a PR number in a method note
names that PR's run from then.
1. #2845 [OMNIML-6178] [1/11] Run the unit tests in parallel with
pytest-xdist (merged)
2. #2846 [OMNIML-6178] [2/11] Use the sysmon coverage core in CI
(merged)
3. #2847 [OMNIML-6179] [3/11] Run manual-marked tests on nightly and
on-demand GPU runs
4. #2848 [OMNIML-6181] [4/11] Give gpu_megatron's slow cold starts more
time
5. #2849 [OMNIML-6179] [5/11] Make the ONNX tests cheaper: CPU-only ones
to the unit lane, small models (merged)
6. #2850 [OMNIML-6179] [6/11] Use local tokenizers and calibration text
in GPU tests, shrink puzzletron data
7. #2851 [OMNIML-6180] [7/11] Trim the llm_eval, llm_qat, EAGLE and
megatron_bridge example tests
8. #2852 [OMNIML-6180] [8/11] Trim the DFlash regression test (merged)
9. #2853 [OMNIML-6180] [9/11] Trim the torch_onnx example lane **(this
PR)**
10. #2854 [OMNIML-6181] [10/11] Make the distributed worker pool fail
fast when a worker dies (merged)
11. #2855 [OMNIML-6181] [11/11] Share one Megatron worker pool across
the gpu_megatron modules
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Updates**
* Quantization examples now use zero-worker calibration loading with
device-resident samples.
* TensorRT example builds perform a single inference iteration without
warmup or timing.
* **Tests**
* Pull-request validation skips selected SwinV2 Tiny formats, while
scheduled validation continues to cover them.
* Pull-request detection uses the repository’s CI reference environment.
* **Impact**
* These changes affect example workflows and validation coverage only;
no application user-facing functionality is changed.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
|
The flagged line is not new: |
What does this PR do?
Type of change: CI (test runtime, tests only)
Five cuts to the example lanes, each with its reasoning:
test_lm_eval_hfevaluates one MMLU subtask. It ran--tasks mmlu --limit 0.1: the 57-subtask group, about 5.6k loglikelihood requests, on a tiny Qwen3 whosemax_position_embeddingsis 32, so its runtime is dominated by loading one HF dataset config per subtask (over 331 CI runs: min 198.9 s, median 212.5 s). It runsmmlu_abstract_algebra(100 test documents, 5-shot) through the samelm_eval_hf.pypath and the same accuracy gate (exactly one task, lower bound 0.1 unchanged; the label distribution of that split is 22/26/31/21, so even a model that always predicts one letter scores at least 0.21).test_qwen3_qat_nvfp4(3 backends),test_qwen3_qad_nvfp4(2) andtest_qwen3_qlora_nvfp4ran 6quantize.pyand 12 cold tokenized-dataset builds per module (104-121 s each, qlora 169 s). A module-scoped fixture runsquantize.pyonce (guarded byassert_unmodified_tree, like the other shared tiny-model fixtures) and all quantize and train calls share one dataset cache; the qlora test keeps its own PTQ because it passes--compress True.TORCHINDUCTOR_MAX_AUTOTUNE_GEMM_BACKENDS=ATEN, the mechanismtest_diffusers.pyalready uses).test_llama_eagle3[1-False]takes 175.5 s against 40.6 s for[1-True](the same flow without compile), about 135 s of ittorch.compilebenchmarking Triton GEMM templates for a draft model that is one tiny decoder layer. The mode staysmax-autotune, and the shortcut applies only when the run has one GPU:[2-False]and any run on more GPUs (the nightly) keep the full autotune.test_offline_eagle3_training[tinyllama], 34.9 s per job, almost all launcher start-up).test_offline_eagle_trainingalready runs that mode on the same model with hidden states fromcompute_hidden_states_hf.py, and the FakeBaseModel case keeps the synthetic path. The one thing the dropped case covered that stage 2 did not, the collator truncating dumps, moves there (training_seq_len=16, so 28-token dumps are truncated), and the collator is also unit tested on CPU.megatron_bridgetests that use no GPU skip the Megatron state reset. The conftest resets Megatron's global state around every test (destroy_model_parallel,gc.collect(),empty_cache), about 1.3 s per test; 77 tests in the directory are pure Python (the mlflow wiring and checkpoint-path tests) and leave nothing to reset (the 82 tests that took under 3 s each add up to 118 s in the series' runs before this PR and to 0.3 s after it). The reset now runs only for tests that requestnum_gpus; the environment restore stays for every test. The job runs at 68-75 minutes against its 75-minute nightly limit.Time improvement (measured in CI)
Example lanes, pytest time of the changed tests and of the lane; before = #2846 (plus #2848 where its runner was as fast), after = #2851, #2854 and #2855 (median). #2849 and #2850 ran on runners 1.3-1.5x slower for every test and are left out of the before column.
test_lm_eval_hftest_llama_eagle3[1-False]test_offline_eagle3_training[tinyllama]mmlu_limit=1change fortest_qwen3_eval_fp8was dropped from this PR. The runs above are of its earlier head, which had it: the test took 175-246 s in all 7 runs, before and after (187 s against 176 s on comparable runners), so the CI history it was based on (mean 723.7 s, 2026-09-25 to 10-09) is not reproduced by the current lane and the change saved nothing measurable. The llm_eval lane figure above istest_lm_eval_hf's.Method: every PR of the series has its own CI run, so "before" is the run of the PR(s) below that lack the change and "after" the runs that carry it. Times come from the job logs (
--durations, or the gap between consecutive result lines). Where runner speed matters, the tests that no PR of the series touches scale each run, and the raw and the scaled medians are both shown. One test varies by 15-30% from run to run on its own, so smaller differences are not evidence.Usage
Nothing user-facing.
Testing
mmlu/acc0.2343; new 22.4-24.0 s,mmlu_abstract_algebra/acc0.27, gate passes.run_example_commandfaked,quantize.pyruns 6 -> 2 times and cold dataset builds go 12 -> 2; realquantize.pyandtrain.py(QAT, then QAD from the checkpoint) ran on CPU with the int4 and fp8 recipes (NVFP4 needs CUDA) and left the checkpoint unmodified.training_seq_len64 and 16 (the collator pads 28 -> 64 and truncates 28 -> 16); withrun_example_commandfaked, only[1-False]on one GPU gets the autotune variable (that case on 2 GPUs and every other case keep the full autotune) and the only removed test id istest_offline_eagle3_training[tinyllama].num_gpustrigger one before and one after; it fails against the old conftest.trust_remote_code=Trueintest_offline_eagle3_trainingis not new: it is the line on main (the Kimi and MiniMax repos it loads need remote code), and this PR only renames its variable after dropping the tinyllama case.Before your PR is "Ready for review"
Make sure you read and follow Contributor guidelines and your commits are signed (
git commit -s -S).Make sure you read and follow the Security Best Practices (e.g. avoiding hardcoded
trust_remote_code=True,torch.load(..., weights_only=False),pickle, etc.).CONTRIBUTING.md: no new dependencyAdditional Information
Slice 7 of 11 of the GPU-CI speed-up work, split out of the reference draft #2730 (not for merge; it holds the whole series with its measurements). Slices 1, 2, 5, 8, 9 and 10 (#2845, #2846, #2849, #2852, #2853, #2854) have merged. The remaining slices (#2847, #2848, #2850, #2851, #2855) are independent PRs on main: each applies to main on its own, and merging all of them onto main in different orders gives the same tree. The times above are from the series' CI runs before 2026-10-21, when all slices formed one linear stack; a PR number in a method note names that PR's run from then.
Summary by CodeRabbit