Skip to content

Guard fused MoE auxiliary loss integer offsets - #3569

Open
arcusbuilds wants to merge 7 commits into
NVIDIA:mainfrom
arcusbuilds:fix/moe-aux-loss-int-overflow
Open

arcusbuilds wants to merge 7 commits into
NVIDIA:mainfrom
arcusbuilds:fix/moe-aux-loss-int-overflow

Conversation

@arcusbuilds

@arcusbuilds arcusbuilds commented Sep 24, 2026 •

Copy link
Copy Markdown

Description

The fused MoE auxiliary loss kernels use 32-bit flattened offsets. Reject shapes above INT_MAX in both forward launchers and the backward launcher before launching a kernel.

Fixes #3568

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Changes

  • Check num_rows * num_cols with 64-bit arithmetic in all three launchers.
  • Use 64-bit loop counters and grid-size math so shapes right at the limit don't overflow. Flattened offsets stay 32-bit.
  • Tests: an oversized shape is rejected on each path, and a shape of exactly INT_MAX elements gives the right result on each path.

Verification

  • pre-commit on both changed files: all hooks passed.
  • Built the real fused_moe_aux_loss.cu against stub headers and ran it on an RTX 2000 Ada (8 GB). At INT_MAX x 1, before the counter change both forward paths hit an illegal memory access and backward failed to launch. After it, all three return the right result. Kernel times in ncu at base clocks are within ±1.3% of the int32 version.
  • A full TE build was not available locally (fails on Windows in existing __uint128_t code), so the new PyTorch tests haven't run yet. CI covers that.

Checklist

  • I have read and followed the contributing guidelines.
  • The functionality is complete.
  • I have added a test for the fix.
  • New and existing unit tests pass locally with my changes (see Verification).

Signed-off-by: Srijan Keshri <212402043+arcusbuilds@users.noreply.github.com>
@github-actions github-actions Bot added the community-contribution PRs from external contributor outside the core maintainers, representing community-driven work. label Sep 24, 2026
@arcusbuilds
arcusbuilds marked this pull request as ready for review September 30, 2026 23:23
@greptile-apps

greptile-apps Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge.

Summary

The PR guards fused MoE auxiliary loss shapes and fixes arithmetic at the largest accepted shape.

  • Fused MoE loss calls reject inputs with more than INT_MAX elements.

The previous overflow finding is fixed. No new actionable issues were found.

Reviews (7) · Last reviewed commit: "Use 64-bit loop counters in fused MoE au..." · Reviewed by Greptile

@denera denera self-assigned this Oct 2, 2026
@denera
denera self-requested a review October 2, 2026 16:29

@denera denera left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!

It looks good to me overall. Just two nits:

  1. Unnecessary skip condition on CUDA GPU presence.
  2. fused_moe_aux_loss.cu needs #include <climits> for INT_MAX. This currently comes in transitively from another header, but as a matter of code style and header safety, we include it explicitly in other fused MoE/top-K files too. This one should adopt the same approach.

Comment thread tests/pytorch/test_fused_router.py Outdated
Co-authored-by: Alp Dener <adener@nvidia.com>
Signed-off-by: Srijan Keshri <212402043+arcusbuilds@users.noreply.github.com>
@ptrendx

ptrendx commented Oct 6, 2026

Copy link
Copy Markdown
Member

Actually, I have a different concern - if the problem is that the shapes could exceed the int32 maximum then we should actually make the kernel work with int64/size_t for the variables that could overflow.

Signed-off-by: Srijan Keshri <212402043+arcusbuilds@users.noreply.github.com>
@arcusbuilds

Copy link
Copy Markdown
Author

Extended the kernels to use int64_t indexing instead of rejecting shapes above INT_MAX.

@denera

denera commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Actually, I have a different concern - if the problem is that the shapes could exceed the int32 maximum then we should actually make the kernel work with int64/size_t for the variables that could overflow.

@ptrendx I took a closer look across the entire fused router stack of kernels and I would argue that #3568 is NOT actually a real bug.

The probs that feed into our aux loss kernel come from top-k and score kernels that are explicitly guarded to reject num_tokens * num_experts > INT_MAX. Consequently, there is no actual risk of the shapes overflowing unless our aux loss kernel is used together with external non-TE fused router components that do not guard the shapes like ours do.

The reported bug says:

I found this through source inspection and have not run the oversized kernel, since an overflowing offset may access memory outside the tensor.

So this bug was never actually observed in execution, and it couldn't have been in a pure-TE implementation anyway because our top-k and score kernels will never feed a shape into aux loss that would overflow.

If we want to make our fused router accept num_tokens * num_experts > INT_MAX and shift the boundary to maximum representable int64, that would require touching every fused router kernel, not just aux loss.

Otherwise, I think the right approach here is to simply add the same INT_MAX size guard into the aux loss kernel that we already have in other fused router kernels.


@arcusbuilds In local testing, I'm seeing a forward pass perf difference between the old int32 and the new int64 implementations. I believe this is because the compiler is unrolling the int64 loop but not unrolling the int32. Could you add #pragma unroll 4 to the forward inner loop so we don't have to leave this up to the compiler in the future regardless of whether we stick with int64 or go back to int32 per my comments above?

Signed-off-by: arcusbuilds <srijankeshri007@gmail.com>
@arcusbuilds

Copy link
Copy Markdown
Author

@denera Added #pragma unroll 4 to the inner row loop in both forward kernels.

@denera

denera commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator

@arcusbuilds After internal discussion about this, we're going to move forward with the original recommendation of rejecting num_tokens * num_experts > INT_MAX in the aux loss just like we do in all the other fused router kernels. Sorry for the back and forth about this! Would appreciate it if you could revert the int64 change and bring back the assert (we should keep #pragma unroll 4 in the inner row loop though regardless).

Effort to support int64 max sizes in the fused router should be deferred to a separate PR because it's going to have to touch ALL of the fused router kernels, not just aux loss.

Match the other fused router kernels, which reject
num_tokens * num_experts > INT_MAX. Keep #pragma unroll 4 on the
forward row loops.

Signed-off-by: arcusbuilds <srijankeshri007@gmail.com>
Comment thread transformer_engine/common/fused_router/fused_moe_aux_loss.cu
Shapes at the INT_MAX guard (e.g. INT_MAX x 1) overflowed the int loop
counters on their last increment and the backward grid-size math.
Flattened offsets stay 32-bit, which the guard bounds.

Signed-off-by: arcusbuilds <srijankeshri007@gmail.com>
@arcusbuilds

Copy link
Copy Markdown
Author

@denera Reverted the int64 change and brought back the INT_MAX assert in all three launchers, matching the other fused router kernels. #pragma unroll 4 is still there.

While testing the limit I found that a shape like INT_MAX x 1 passes the guard but still overflows: the int loop counters wrap on their last increment, and so does the backward grid-size math. So I made the loop counters and grid math 64-bit and kept the flattened offsets 32-bit, since the guard already bounds them. In ncu at base clocks on an RTX 2000 Ada this is within ±1.3% of the int32 version at 16384x128, 65536x256 and 262144x64. Making the offsets 64-bit as well cost 15-23% in backward, so I left them alone. I also added a test at exactly INT_MAX elements.

@denera denera left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! We'll merge after a clean pipeline (which is going to be slightly delayed because of some ongoing infra issues at the moment).

This branch has not been deployed

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

Labels

community-contribution PRs from external contributor outside the core maintainers, representing community-driven work.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Fused MoE auxiliary loss accepts shapes that overflow int offsets

3 participants