NVIDIA / NVIDIA/cutlass

[BUG] Unexpected Slower Performance in C++ CuTe (77_blackwell_fmha) vs Python CuTe DSL (fmha.py) on Jetson Thor

Open
#3,056 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

? - Needs Triage inactive-30d inactive-90d question
Dominant language
C++
Stars
10.5k
Forks
2.1k
Avg merge
3d 11h
Merged PRs (30d)
7

Description

We observed significantly worse performance in the CUTLASS CuTe 77_blackwell_fmha example compared to the CuTe DSL examples/python/CuTeDSL/blackwell/fmha.py implementation on Jetson Thor.

Test Commands:
77_blackwell_fmha:

./77_blackwell_fmha --b=1 --h=16 --q=2225 --k=2225 --d=128 --mask=no --verbose --warmup_iterations=2 --iterations=10

fmha.py:

python3 fmha.py --iterations 10 --warmup_iterations 2 --skip_ref_check --mma_tiler_mn 128,128 --q_shape 1,2225,16,128 --k_shape 1,2225,16,128

Performance Results:
77_blackwell_fmha: 1,110,707 cycles
fmha.py: 922,724 cycles

Key Observations:

1. Local Memory Spilling:
ncu profiling reveals substantially higher Local Memory Spilling Requests in 77_blackwell_fmha compared to fmha.py.

2. Implementation Differences in softmax_step:
The softmax computation differs between implementations:

  • fmha.py uses 4 fragments:
frg_cnt = 4
frg_tile = cute.size(tTMEM_LOADrS) // frg_cnt
tTMEM_LOADrS_frg = cute.logical_divide(tTMEM_LOADrS, cute.make_layout(frg_tile))
tTMEM_STORErS_x4_e_frg = cute.logical_divide(
    tTMEM_STORErS_x4_e, cute.make_layout(frg_tile)
)
for j in range(frg_cnt):
    for k in cutlass.range(
        cute.size(tTMEM_LOADrS_frg, mode=[0]), vectorize=True
    ):
        tTMEM_LOADrS_frg[k, j] = (
            tTMEM_LOADrS_frg[k, j] * scale + minus_row_max_scale
        )
        tTMEM_LOADrS_frg[k, j] = cute.math.exp2(
            tTMEM_LOADrS_frg[k, j], fastmath=True
        )

    s_vec = tTMEM_LOADrS_frg[None, j].load()
    tTMEM_STORErS_x4_e_frg[None, j].store(s_vec.to(self.q_dtype))
  • 77_blackwell_fmha processes data without fragment:
CUTLASS_PRAGMA_UNROLL
for (int i = 0; i < size(tTMEM_LOADrS); i += 2) {
  float2 in = make_float2(
    tTMEM_LOADrS(i + 0),
    tTMEM_LOADrS(i + 1)
  );
  float2 out;
  cute::fma(out, scale_fp32x2, in, minus_row_max_scale_fp32x2);
  tTMEM_LOADrS(i + 0) = out.x;
  tTMEM_LOADrS(i + 1) = out.y;

  tTMEM_LOADrS(i+0) = ::exp2f(tTMEM_LOADrS(i+0));
  tTMEM_LOADrS(i+1) = ::exp2f(tTMEM_LOADrS(i+1));

  Array<ElementQK, kConversionsPerStep> in_conv;
  CUTLASS_PRAGMA_UNROLL
  for (int j = 0; j < kConversionsPerStep; j++) {
    in_conv[j] = tTMEM_LOADrS(i + j);
  }
  tTMEM_STORErS_x4_e[i / kConversionsPerStep] = convert(in_conv);


  if (i == size(tTMEM_LOADrS) - kReleasePipeCount) {
    order_s.arrive();
  }

  // this prevents register spills in fp16
  if constexpr (size<2>(tTMEM_STORErS_x4) == _2{}) {
    if (i == size(tTMEM_LOADrS) - 6) {
      copy(tiled_tmem_store, tTMEM_STORErS_x4(_, _, 0), tTMEM_STOREtS_x4(_, _, 0));
    }
  }
}

3. Failed Optimization Attempts:

  • Porting fmha.py's fragment strategy to 77_blackwell_fmha did not reduce spilling or improve performance.

  • Removing tiling from fmha.py increased spilling but still outperformed 77_blackwell_fmha (spilling remained lower than C++ version).

Despite similar algorithmic structures, why does 77_blackwell_fmha exhibit worse performance and higher spilling?

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing both commands on Jetson Thor and profiling them with ncu. Compare the 77_blackwell_fmha entry point with examples/python/CuTeDSL/blackwell/fmha.py, focusing on softmax_step, fragment handling, and local-memory spilling. Done means identifying the cause of the performance gap and documenting a validated remediation or focused next step.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python
Domain
performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.