Skip to content

Align causal GQA threadgroup memory length to 16 bytes - #44

Open
jordanswilson wants to merge 1 commit into
antirez:mainfrom
jordanswilson:gqa-threadgroup-alignment
Open

Align causal GQA threadgroup memory length to 16 bytes#44
jordanswilson wants to merge 1 commit into
antirez:mainfrom
jordanswilson:gqa-threadgroup-alignment

Conversation

@jordanswilson

Copy link
Copy Markdown

setThreadgroupMemoryLength requires the length to be a multiple of 16 bytes, but h3_gpu_gqa_causal_bf16 sizes the causal score buffer as sequence * sizeof(float) — out of spec whenever the prompt's token count is not a multiple of 4.

The driver tolerates this silently, so ordinary runs work. But with the Metal API validation layer active (MTL_DEBUG_LAYER=1 — which any child process inherits from an Xcode-launched app with default scheme diagnostics), the first text encoder dispatch aborts:

-[MTLDebugComputeCommandEncoder setThreadgroupMemoryLength:atIndex:]:799:
failed assertion `length(140) must be a multiple of 16 bytes.'

(140 bytes = a 35-token prompt.)

Fix

Round the threadgroup memory length up to the next 16-byte multiple. The kernel never reads the padding, and the rounding happens before the maxThreadgroupMemoryLength capacity check so that check stays accurate. Behavior for already-aligned sequence lengths is unchanged.

Verification

The bundled h3_text_tests can't catch this — its fixture sequence length of 32 is already a multiple of 4. I verified with a minimal fixture-free repro calling h3_gpu_gqa_causal_bf16 at sequence 35 (synthetic bf16 tensors, same head geometry as the Qwen text encoder):

  • pre-fix, MTL_DEBUG_LAYER=1: aborts with the exact assertion above (SIGABRT)
  • post-fix, MTL_DEBUG_LAYER=1: passes, all outputs finite
  • post-fix, no validation: passes — no change for normal runs

Happy to add the repro as a test if you'd like it.

🤖 Generated with Claude Code

setThreadgroupMemoryLength requires a multiple of 16 bytes, but the
causal GQA score buffer was sized as sequence * sizeof(float), which
violates that whenever the token count is not a multiple of 4. The
driver tolerates it silently, so plain runs work, but under the Metal
API validation layer (MTL_DEBUG_LAYER=1, e.g. any process spawned from
an Xcode-launched app with default scheme diagnostics) the first text
encoder dispatch aborts:

  -[MTLDebugComputeCommandEncoder setThreadgroupMemoryLength:atIndex:]:
  failed assertion `length(140) must be a multiple of 16 bytes.'

(140 bytes = a 35-token prompt.) Round the length up to 16; the kernel
never reads the padding. The rounding happens before the
maxThreadgroupMemoryLength check so the check stays accurate.

The bundled text encoder test cannot catch this because its fixture
sequence length of 32 is already a multiple of 4. Verified with a
sequence-35 repro: pre-fix it aborts under MTL_DEBUG_LAYER=1 with the
assertion above, post-fix it passes with and without validation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant