Skip to content

[AG-GEMM] Add warp specialized ag-gemm that supports KDA and MLA up projections - #41

Merged
MaoZiming merged 16 commits into
uccl-project:mainfrom
ShawnWeiChew:ag-gemm-kda-mla-pub
Sep 10, 2026
Merged

[AG-GEMM] Add warp specialized ag-gemm that supports KDA and MLA up projections#41
MaoZiming merged 16 commits into
uccl-project:mainfrom
ShawnWeiChew:ag-gemm-kda-mla-pub

Conversation

@ShawnWeiChew

@ShawnWeiChew ShawnWeiChew commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

This PR implements AG-GEMM for KDA and MLA up projection specific shapes.

09/09 Findings
We initially had results where TK did much worse than it does now. I think it was because I was running the kernels in succession with TK last. After reverting back to the old commit and adding a timeout between different kernels, the TK timings remained within ~5% of previous measurements

Notes:

  • Compared to tuned configurations of Cutlass and TK's implementations of ag-gemm, we are within ±10% of their performance.
  • TK uses an SM-specialized TMA load and multicast store to perform all gather, while our implementation and cutlass' is a warp-specialized version performs an all-gather with ancudaAsyncMemcpy operation
    • Confident that asyncMemcpy always lands before the corresponding TMA store, because the time spent waiting on the memcpy completion flag is the same as the time spent on loading an already-set flag (0.2us)
  • Based on the above design choices, I think the general trends are that:
    • TK's SM specialized design performs better when the amount of communication work > computation work
    • Ours and cutlass' warp specialized design performs better when computation > communication. In our case, I also think it's because the bulk memcpy's are done in a per device manner, so it imposes some sort of restriction on the way we can traverse the A matrix.
  • I decided to make a separate file as opposed to using the original ag-gemm / ag-gemm-blackwell path because:
    • This kernel use a different all-gather mechanism
    • This kernel accommodates a 1-CTA MMA (and potentially other KDA / MLA specific fusions down the road)
  • My strategy for dealing with odd shapes (M=3072, 3584) was to pad them up to the tuned tile shape

KDA projection shapes (updated 09/09)
kda_allgather_gemm_tflops_all_shapes

MLA projection shapes (updated 09/09)
mla_allgather_gemm_tflops_all_shapes

logs

WIP

first implementation

chore: add notation on todos

feat: passes on nice shapes

benchmark against baseline

fix: use deprecated function

Perf is no good, not sure if it is the GEMM or the AG that is bad

M=2048 local_m=256 N=6284 padded_n=6400
  cuBLAS + NCCL        0.751 ms  (1.000x, 100.0%)
  ag_gemm_kda_mla      1.882 ms  ( 0.399x,   39.9% of baseline)
M=4096 local_m=512 N=6284 padded_n=6400
  cuBLAS + NCCL        1.380 ms  (1.000x, 100.0%)
  ag_gemm_kda_mla      3.891 ms  ( 0.355x,   35.5% of baseline)
M=8192 local_m=1024 N=6284 padded_n=6400
  cuBLAS + NCCL        2.546 ms  (1.000x, 100.0%)
  ag_gemm_kda_mla      7.991 ms  ( 0.319x,   31.9% of baseline)
M=16384 local_m=2048 N=6284 padded_n=6400
  cuBLAS + NCCL        5.057 ms  (1.000x, 100.0%)
  ag_gemm_kda_mla     18.892 ms  ( 0.268x,   26.8% of baseline)
M=32768 local_m=4096 N=6284 padded_n=6400
  cuBLAS + NCCL       10.487 ms  (1.000x, 100.0%)
  ag_gemm_kda_mla     44.726 ms  ( 0.234x,   23.4% of baseline)

oddly enough, this does even worse on a 4 device node

try memcpy

feat: minor optimizations

on a 4 device setup:

M=2048 local_m=512 N=12440 padded_n=12544
  cuBLAS + NCCL        0.280 ms  (1.000x, 100.0%)
  ag_gemm_kda_mla      0.236 ms  ( 1.190x,  119.0% of baseline)
M=4096 local_m=1024 N=12440 padded_n=12544
  cuBLAS + NCCL        0.507 ms  (1.000x, 100.0%)
  ag_gemm_kda_mla      0.420 ms  ( 1.208x,  120.8% of baseline)
M=8192 local_m=2048 N=12440 padded_n=12544
  cuBLAS + NCCL        0.972 ms  (1.000x, 100.0%)
  ag_gemm_kda_mla      0.823 ms  ( 1.181x,  118.1% of baseline)
M=16384 local_m=4096 N=12440 padded_n=12544
  cuBLAS + NCCL        1.906 ms  (1.000x, 100.0%)
  ag_gemm_kda_mla      1.680 ms  ( 1.135x,  113.5% of baseline)
M=32768 local_m=8192 N=12440 padded_n=12544
  cuBLAS + NCCL        3.780 ms  (1.000x, 100.0%)
  ag_gemm_kda_mla      3.516 ms  ( 1.075x,  107.5% of baseline)

feat: update benchmarking code to use padded because cublas does badly on non padded shapes

faet: add cutlass comparison

add cutlass bench

feat: add autotuned TK

feat: add TFLOPS calculation

feat: add MLA comparison

round up TK

feat: add deeper pipeline

chore: added SUPERGROUP_WIDTH as tuning parameter

feat: add autotuned config

chore: revert back pipeline

chore: reduce nanosleep poll

feat: add nasty shapes

give cutlass a wider autotune

feat: add 1 CTA instructions to kernel for tuning

update benching script

only tune odd shapes

feat: added tuned configurations for odd shapes
@ShawnWeiChew
ShawnWeiChew marked this pull request as ready for review September 8, 2026 02:33
@MaoZiming

Copy link
Copy Markdown
Member

@ShawnWeiChew Great work! " In our case, I also think it's because the bulk memcpy's are done in a per device manner, so it imposes some sort of restriction on the way we can traverse the A matrix."

Could you elaborate on this point?

Comment thread bench/ag_gemm_kda_mla_bench.py Outdated
Comment thread src/ag_gemm_warp_specialized.cu Outdated
@ShawnWeiChew

Copy link
Copy Markdown
Collaborator Author

@MaoZiming Because my implementation handles the copies serially, we have to work on device n's SP chunk before device n + 1's SP chunk. (I tried adjusting the number of copy streams that were running at once but that, at best, did not have a negative impact on performance)

For example, in a TP=8, global_m = 2048 case, we handle tile A in (256, K) chunk, rather than a (2048, K) chunk

Screenshot 2026-09-08 at 7 32 30 AM

Whereas in a regular GEMM, we could potentially make use of a traversal pattern like this:

Screenshot 2026-09-08 at 7 40 50 AM

I mentioned this because relative to a regular GEMM, the traversal pattern imposed by our implementation reduces the opportunity for reuse of the same chunk of B-tile in L2 cache, since we have to traverse the full B tile for each device's SP chunk.

@ShawnWeiChew ShawnWeiChew changed the title [AG-GEMM-KDA-MLA] Add ag-gemm that supports KDA and MLA up projections [Ag-Gemm-Warp-Specialized] Add warp specialized ag-gemm that supports KDA and MLA up projections Sep 9, 2026
@MaoZiming MaoZiming changed the title [Ag-Gemm-Warp-Specialized] Add warp specialized ag-gemm that supports KDA and MLA up projections [AG-GEMM] Add warp specialized ag-gemm that supports KDA and MLA up projections Sep 9, 2026
Comment thread include/operators/ag_gemm/ag_gemm_warp_specialized.cuh Outdated
Comment thread bench/ag_gemm_bench.py Outdated

@MaoZiming MaoZiming left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Others LGTM

fix: pdl and tmem alloc syncs
@MaoZiming
MaoZiming merged commit 18f4dff into uccl-project:main Sep 10, 2026
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