Skip to content

Vulkan: MUL_MAT_ID is the dominant prefill bottleneck for large MoE models on gfx1151 #21948

Description

@0xSero

Vulkan: MUL_MAT_ID is the dominant prefill bottleneck for large MoE models on gfx1151

Summary

On a Strix Halo system (gfx1151, 120 GiB GTT), Vulkan MUL_MAT_ID accounts for 42–66% of total prefill time when running Qwen3.5-122B-A10B Q6_K at practical context lengths (≤32k). Even at 128k context, where FLASH_ATTN_EXT takes over, MUL_MAT_ID still contributes 20%.

Patched ROCm (with #21344 MMQ VGPR tuning) achieves 19–35% faster prefill than Vulkan on the same hardware and model. This gap appears to originate primarily from the MUL_MAT_ID path — the routed-expert matrix multiplication used by MoE architectures.

Hardware

Component Spec
CPU AMD Ryzen AI MAX+ 395 (Zen 5, 16C/32T)
GPU Radeon 8060S (gfx1151, RDNA 3.5, 40 CU)
RAM 128 GB LPDDR5X-8000 (~215 GB/s)
GTT 120 GiB
OS Fedora 43, kernel 6.17.1, mesa-vulkan-drivers 25.3.6

Model

  • Qwen3.5-122B-A10B REAP-20 Q6_K (75.73 GiB)
  • 205 total experts, 8 active per token
  • KV cache: q8_0/q8_0, flash attention enabled

Profiling method

Built llama.cpp b8779 with Vulkan backend. Used GGML_VK_PERF_LOGGER=1 environment variable to capture per-kernel timings during llama-bench runs with -pg (prefill+generate) at multiple context depths.

Results: kernel-level breakdown per layer step (batch=512)

At KV=512 (short context — total 1.70s/step)

Kernel Time (ms) % of step
MUL_MAT_ID q6_K m=1024 n=8 k=3072 n_expert=205 batch=512 772.6 45.4%
MUL_MAT_ID q6_K m=3072 n=8 k=1024 n_expert=205 batch=512 352.1 20.7%
MUL_MAT q6_K m=3072 n=512 k=8192 96.1 5.7%
FLASH_ATTN_EXT 9.4 0.6%
MUL_MAT_ID total 1124.7 66.2%

At KV=8192 (practical chat — total 1.84s/step)

Kernel Time (ms) % of step
MUL_MAT_ID (both shapes combined) 1059.3 57.6%
FLASH_ATTN_EXT 226.1 12.3%
MUL_MAT q6_K (various) 255.6 13.9%

At KV=32768 (long document — total 2.56s/step)

Kernel Time (ms) % of step
FLASH_ATTN_EXT 930.3 36.4%
MUL_MAT_ID (both shapes combined) 1072.6 41.9%
MUL_MAT q6_K (various) 280.8 11.0%

At KV=131072 (max context — total 5.35s/step)

Kernel Time (ms) % of step
FLASH_ATTN_EXT 3740.0 69.9%
MUL_MAT_ID (both shapes combined) 1052.9 19.7%
MUL_MAT q6_K (various) 281.6 5.3%

Key observation

MUL_MAT_ID time is essentially constant (~1050 ms) regardless of context length. It does not scale with KV cache size. The expert routing computation is the same cost whether processing 512 or 131072 tokens of context. It is purely a function of batch size and expert count.

End-to-end throughput: Vulkan vs patched ROCm

Test Vulkan (t/s) Patched ROCm (t/s) ROCm advantage
pp512 268.89 354.57 +32%
pp8192+tg128 249.65 302.44 +21%
pp32768+tg128 234.94 291.03 +24%
pp131072+tg128 145.03 171.66 +18%
tg128 23.52 21.00 −11% (Vulkan wins decode)

Relevant prior work

Analysis

The Vulkan MUL_MAT_ID kernel currently processes n=8 (active experts) × batch=512 tokens against 205 experts with a Q6_K weight matrix. The ~1050 ms constant cost suggests the kernel is not efficiently utilizing the GPU for this workload shape — it is a many-small-matmul pattern that could potentially benefit from the same remap/batch approach used in #13388.

The fact that patched ROCm is 18–32% faster on prefill while Vulkan wins decode by 11% further suggests this is not a memory bandwidth issue but a compute dispatch / kernel efficiency issue specific to the expert routing path.

Suggested direction

The Metal #13388 approach (map inputs → contiguous batched matmul → unmap results) seems like the most promising direction for Vulkan. The current per-expert dispatch pattern appears to leave significant GPU utilization on the table, especially on gfx1151 where the 40 CUs and 215 GB/s bandwidth should support higher throughput.

Alternatively, gfx1151-specific warptile tuning for the MUL_MAT_ID shader (similar in spirit to #21344's MMQ tuning) could help if the existing subgroup optimization from #15524 is hitting register pressure or occupancy limits on RDNA 3.5.

Build info

build: 75f3bc94e (8779)
Vulkan0: Radeon 8060S Graphics (RADV STRIX_HALO), uma: 1, fp16: 1, bf16: 0, warp size: 64, shared memory: 65536, int dot: 1, matrix cores: KHR_coopmat

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions