Skip to content

Run fullsize bit-exact comparisons eager - #129

Open
ItzikVa wants to merge 1 commit into
mainfrom
bugfix/fullsize-vllm-bit-exact-eager
Open

Run fullsize bit-exact comparisons eager#129
ItzikVa wants to merge 1 commit into
mainfrom
bugfix/fullsize-vllm-bit-exact-eager

Conversation

@ItzikVa

@ItzikVa ItzikVa commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator
  • tests/vllm/_granite4_fullsize_tests.py builds the engine with enforce_eager=True, so the bit-exact comparison compares the two module trees rather than two independent inductor compilations. Without
    it, IrOpPriorityConfig(rms_norm=['vllm_c','native']) vs ['native'] gives a different rms_norm kernel on each side and the "bit-exact" case is not a statement about our code.
    • The bit-exact and tolerant branches collapse into one assert_close(...) call with atol=rtol=0.0 when bit-exact. torch.testing.assert_close's msg= replaces the whole diagnostic; the repo's
      assert_close keeps counts and worst-diff numbers.
    • assert_close now treats matching non-finite entries as equal (ok = abs_ok | rel_ok | (actual == expected)). Logprob tensors are padded with -inf, and -inf - -inf is nan, which fails every comparison
      including diff <= 0.0.
    • On a pass it prints the finite-entry count and max |delta|, so a shrinking margin is visible before it becomes a red.

tests/vllm/_granite4_fullsize_tests.py::test_logits_match[4.0-micro] fails on
the vllm20 CI leg and passes on vllm19, and has done so on unrelated PRs -- 117
(2f919be) is a docs-and-comments-only commit, which cannot move a logit. So the
assertion is measuring something other than the code under test.

What it measures is compilation. The test asserts atol=rtol=0 between two
separately launched vLLM engines: upstream GraniteMoeHybrid and GraniteSwitch
with num_adapters=0. Those are different graphs, so torch.compile and inductor
are free to fuse and tile them differently, and at production dimensions that
is enough to round one bf16 logit's last bit apart. vLLM logs its own per-engine
kernel choice: the failing engine reported IrOpPriorityConfig(rms_norm=
['native']) where its sibling reported ['vllm_c', 'native'] -- a different
RMSNorm kernel in 80 places.

The attribution rests on what does pass. 4.0-1b and 4.0-350m have the same 40
dense layers and are bit-exact on both legs; the same comparison on the HF
backend is bit-exact for all three; and real granite-4.0-micro weights are
bit-exact through vLLM in test_skinning_equivalence.py. A weight-transfer or
skinning bug would not spare all of those.

So run these eager. Bit-exactness is a property of the module tree, and eager is
where the module tree is what executes -- enforce_eager takes the compiler, the
CUDA-graph capture and vLLM's on-disk compile cache out of the comparison and
leaves the gate at atol=rtol=0 rather than loosening it. There was already
precedent for the flag in _granite4_mini_tests.py's _UPSTREAM_EAGER_CONFIGS. The
compiled path keeps the coverage it already had, from the two tests that are
deliberately tolerant of a flipped last bit: test_skinning_equivalence.py on
real weights and test_generation_equivalence.py on distributions.

Two supporting changes, because the failure was also unreadable:

  * The bit-exact branch now calls this repo's assert_close instead of
    torch.testing.assert_close. A msg= string handed to the latter *replaces*
    its whole diagnostic, which is why four CI runs recorded "logprobs should be
    bit-exact" and not one number -- there was no way to tell a last-bit drift
    from a real regression without re-running 4 GPU-hours. assert_close reports
    the count, the worst diff and its magnitude.

  * assert_close now treats matching non-finite entries as equal. Logprob
    tensors are padded with -inf for positions vLLM did not return, and
    -inf - -inf is nan, which fails every comparison including diff <= 0.0. That
    trap was latent while only the tolerance branch used the helper; the
    bit-exact branch would have hit it as a bogus worst=nan.

The margin is printed on a pass too, so a gate that has quietly started riding
at one ULP is visible before it trips.

Verified on CPU: 35 tests in tests/hf/test_granite4_mini.py and
test_granitemoe_mini.py (the existing assert_close callers) still pass, the three
TestGranite4FullSizeWeightTransfer cases pass, and the five assert_close
semantics above were checked directly. The GPU legs are the real gate.

Signed-off-by: itzikvaisman <yizhak.vaisman@ibm.com>
@ItzikVa

ItzikVa commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator Author

/gpu-test-multi

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

✅ GPU tests passed — vllm19-multi

3789 passed, 65 skipped, 23 warnings in 11751.97s (3:15:51)

Commit: e8a9b1649ed2ce7f66dd51f9cbf7e5eda700716b
Full run & artifact log

Last 40 log lines

tests/composer/test_compose_e2e.py:83
  /tmp/granite-switch/tests/composer/test_compose_e2e.py:83: PytestUnknownMarkWarning: Unknown pytest.mark.xdist_group - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    @pytest.mark.xdist_group("compose_e2e")

tests/composer/test_multi_audio_compose_e2e.py:143
  /tmp/granite-switch/tests/composer/test_multi_audio_compose_e2e.py:143: PytestUnknownMarkWarning: Unknown pytest.mark.xdist_group - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    @pytest.mark.xdist_group("multi_audio_compose_e2e")

tests/composer/test_multi_audio_compose_e2e.py:149
  /tmp/granite-switch/tests/composer/test_multi_audio_compose_e2e.py:149: PytestUnknownMarkWarning: Unknown pytest.mark.xdist_group - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    @pytest.mark.xdist_group("multi_audio_compose_e2e")

tests/composer/test_multi_audio_compose_e2e.py:155
  /tmp/granite-switch/tests/composer/test_multi_audio_compose_e2e.py:155: PytestUnknownMarkWarning: Unknown pytest.mark.xdist_group - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    @pytest.mark.xdist_group("multi_audio_compose_e2e")

tests/composer/test_upstream_files.py:218
  /tmp/granite-switch/tests/composer/test_upstream_files.py:218: PytestUnknownMarkWarning: Unknown pytest.mark.xdist_group - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    @pytest.mark.xdist_group("upstream_build_e2e")

tests/integration/test_hf_to_vllm_weights.py::TestSingleSwitchForwardEquivalence::test_forward_logit_equivalence
  /tmp/granite-switch/.venv/lib/python3.12/site-packages/flashinfer/gemm/kernels/grouped_gemm_masked_blackwell.py:2059: DeprecationWarning: tcgen05.OperandMajorMode is deprecated, use cute.nvgpu.OperandMajorMode instead
    a_major_mode: tcgen05.OperandMajorMode,

tests/integration/test_hf_to_vllm_weights.py::TestSingleSwitchForwardEquivalence::test_forward_logit_equivalence
  /tmp/granite-switch/.venv/lib/python3.12/site-packages/flashinfer/gemm/kernels/grouped_gemm_masked_blackwell.py:2061: DeprecationWarning: tcgen05.OperandMajorMode is deprecated, use cute.nvgpu.OperandMajorMode instead
    b_major_mode: tcgen05.OperandMajorMode,

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
========= 3789 passed, 65 skipped, 23 warnings in 11751.97s (3:15:51) ==========
sys:1: DeprecationWarning: builtin type swigvarlink has no __module__ attribute
[rank0]:[W909 11:37:26.790303954 ProcessGroupNCCL.cpp:1553] Warning: WARNING: destroy_process_group() was not called before program exit, which can leak resources. For more info, please see https://pytorch.org/docs/stable/distributed.html#shutdown (function operator())
===== ALL GPU TESTS PASSED =====
[11:37:46] <job> Succeeded
[11:37:49] verified: found success sentinel in pod log
[11:37:49] cleanup: deleting <job> (exit=0)
<job> "<job>" deleted

Verdict: PASSED

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

✅ GPU tests passed — vllm20-multi

3789 passed, 65 skipped, 25 warnings in 12899.15s (3:34:59)

Commit: e8a9b1649ed2ce7f66dd51f9cbf7e5eda700716b
Full run & artifact log

Last 40 log lines
    @pytest.mark.xdist_group("multi_audio_compose_e2e")

tests/composer/test_multi_audio_compose_e2e.py:149
  /tmp/granite-switch/tests/composer/test_multi_audio_compose_e2e.py:149: PytestUnknownMarkWarning: Unknown pytest.mark.xdist_group - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    @pytest.mark.xdist_group("multi_audio_compose_e2e")

tests/composer/test_multi_audio_compose_e2e.py:155
  /tmp/granite-switch/tests/composer/test_multi_audio_compose_e2e.py:155: PytestUnknownMarkWarning: Unknown pytest.mark.xdist_group - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    @pytest.mark.xdist_group("multi_audio_compose_e2e")

tests/composer/test_upstream_files.py:218
  /tmp/granite-switch/tests/composer/test_upstream_files.py:218: PytestUnknownMarkWarning: Unknown pytest.mark.xdist_group - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    @pytest.mark.xdist_group("upstream_build_e2e")

tests/integration/test_hf_to_vllm_weights.py::TestSingleSwitchForwardEquivalence::test_forward_logit_equivalence
  /tmp/granite-switch/.venv/lib/python3.12/site-packages/flashinfer/gemm/kernels/grouped_gemm_masked_blackwell.py:2059: DeprecationWarning: tcgen05.OperandMajorMode is deprecated, use cute.nvgpu.OperandMajorMode instead
    a_major_mode: tcgen05.OperandMajorMode,

tests/integration/test_hf_to_vllm_weights.py::TestSingleSwitchForwardEquivalence::test_forward_logit_equivalence
  /tmp/granite-switch/.venv/lib/python3.12/site-packages/flashinfer/gemm/kernels/grouped_gemm_masked_blackwell.py:2061: DeprecationWarning: tcgen05.OperandMajorMode is deprecated, use cute.nvgpu.OperandMajorMode instead
    b_major_mode: tcgen05.OperandMajorMode,

tests/integration/test_hf_to_vllm_weights.py::TestSingleSwitchForwardEquivalence::test_forward_logit_equivalence
tests/integration/test_hf_to_vllm_weights.py::TestSingleSwitchForwardEquivalence::test_forward_logit_equivalence
  /tmp/granite-switch/.venv/lib/python3.12/site-packages/flashinfer/gdn_kernels/blackwell/gated_delta_net_chunked.py:99: DeprecationWarning: tcgen05.OperandMajorMode is deprecated, use cute.nvgpu.OperandMajorMode instead
    from cutlass.cute.nvgpu.tcgen05 import OperandMajorMode

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
========= 3789 passed, 65 skipped, 25 warnings in 12899.15s (3:34:59) ==========
sys:1: DeprecationWarning: builtin type swigvarlink has no __module__ attribute
[rank0]:[W909 11:56:20.534068159 ProcessGroupNCCL.cpp:1575] Warning: WARNING: destroy_process_group() was not called before program exit, which can leak resources. For more info, please see https://pytorch.org/docs/stable/distributed.html#shutdown (function operator())
sys:1: DeprecationWarning: builtin type swigvarlink has no __module__ attribute
[rank0]:[W909 11:56:20.534068159 ProcessGroupNCCL.cpp:1575] Warning: WARNING: destroy_process_group() was not called before program exit, which can leak resources. For more info, please see https://pytorch.org/docs/stable/distributed.html#shutdown (function operator())
===== ALL GPU TESTS PASSED =====
[11:56:43] <job> Succeeded
[11:56:48] verified: found success sentinel in pod log
[11:56:48] cleanup: deleting <job> (exit=0)
<job> "<job>" deleted

Verdict: PASSED

@ItzikVa
ItzikVa marked this pull request as ready for review September 9, 2026 12:09
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