Skip to content

vulkan: small M matrix optimizations for qwen - #28457

Merged
ggerganov merged 2 commits into
ggml-org:masterfrom
jeffbolznv:small_mat_qwen
Sep 10, 2026
Merged

ggerganov merged 2 commits into
ggml-org:masterfrom
jeffbolznv:small_mat_qwen

Conversation

@jeffbolznv

Copy link
Copy Markdown
Contributor

Overview

Optimize m=1 by swapping A and B matrices. codex rediscovered this then told me ggml-cuda already did this in #26171.

Optimize small m (e.g. m=32) by changing tile size selection heuristic and allowing split_k.

These changes target these buckets which appear in recent qwen models:

before:
MUL_MAT f32 m=1 n=512 k=2048: 440 x 60.885 us = 26789.7 us (34.4356 GFLOPS/s)
MUL_MAT f32 m=32 n=512 k=2048: 660 x 61.496 us = 40587.4 us (1091 GFLOPS/s)

after:
MUL_MAT f32 m=1 n=512 k=2048: 440 x 8.57 us = 3771.04 us (244.633 GFLOPS/s)
MUL_MAT f32 m=32 n=512 k=2048: 660 x 21.535 us = 14213.3 us (3115.46 GFLOPS/s)
before

Z:\github\jeffbolznv\llama.cpp\build\bin\RelWithDebInfo>llama-bench.exe -fa 1 -n 0 -p 512 -r 10 --prio 1 -m c:\models\Qwen_Qwen3-30B-A3B-Q2_K.gguf -m c:\models\Qwen3.6-35B-A3B-UD-Q3_K_M.gguf -m c:\models\Qwen3.8-27B-UD-Q4_K_M.gguf
ggml_vulkan: Found 1 Vulkan devices:
ggml_vulkan: 0 = NVIDIA GeForce RTX 5090 (NVIDIA) | uma: 0 | fp16: 1 | bf16: 1 | fp4: 1 | warp size: 32 | shared memory: 49152 | int dot: 1 | matrix cores: NV_coopmat2v
| model                          |       size |     params | backend    | ngl |  fa |            test |                  t/s |
| ------------------------------ | ---------: | ---------: | ---------- | --: | --: | --------------: | -------------------: |
| qwen3moe 30B.A3B Q2_K - Medium |  10.15 GiB |    30.53 B | Vulkan     |  -1 |   1 |           pp512 |    11950.14 ± 103.16 |
| qwen35moe 35B.A3B Q3_K - Medium |  15.45 GiB |    34.66 B | Vulkan     |  -1 |   1 |           pp512 |      8995.91 ± 92.09 |
| qwen35 27B Q4_K - Medium       |  15.32 GiB |    27.32 B | Vulkan     |  -1 |   1 |           pp512 |      2950.64 ± 11.72 |

build: 427291b5b (10816)

Z:\github\jeffbolznv\llama.cpp\build\bin\RelWithDebInfo>llama-bench.exe -fa 1 -n 0 -p 512 -r 10 --prio 1 -m c:\models\Qwen_Qwen3-30B-A3B-Q2_K.gguf -m c:\models\Qwen3.6-35B-A3B-UD-Q3_K_M.gguf -m c:\models\Qwen3.8-27B-UD-Q4_K_M.gguf
ggml_vulkan: Found 1 Vulkan devices:
ggml_vulkan: 0 = NVIDIA GeForce RTX 5090 (NVIDIA) | uma: 0 | fp16: 1 | bf16: 1 | fp4: 1 | warp size: 32 | shared memory: 49152 | int dot: 1 | matrix cores: KHR_coopmat
| model                          |       size |     params | backend    | ngl |  fa |            test |                  t/s |
| ------------------------------ | ---------: | ---------: | ---------- | --: | --: | --------------: | -------------------: |
| qwen3moe 30B.A3B Q2_K - Medium |  10.15 GiB |    30.53 B | Vulkan     |  -1 |   1 |           pp512 |      7914.64 ± 88.56 |
| qwen35moe 35B.A3B Q3_K - Medium |  15.45 GiB |    34.66 B | Vulkan     |  -1 |   1 |           pp512 |      5833.99 ± 62.46 |
| qwen35 27B Q4_K - Medium       |  15.32 GiB |    27.32 B | Vulkan     |  -1 |   1 |           pp512 |       2231.80 ± 5.48 |

build: 427291b5b (10816)

after

Z:\github\jeffbolznv\llama.cpp\build\bin\RelWithDebInfo>llama-bench.exe -fa 1 -n 0 -p 512 -r 10 --prio 1 -m c:\models\Qwen_Qwen3-30B-A3B-Q2_K.gguf -m c:\models\Qwen3.6-35B-A3B-UD-Q3_K_M.gguf -m c:\models\Qwen3.8-27B-UD-Q4_K_M.gguf
ggml_vulkan: Found 1 Vulkan devices:
ggml_vulkan: 0 = NVIDIA GeForce RTX 5090 (NVIDIA) | uma: 0 | fp16: 1 | bf16: 1 | fp4: 1 | warp size: 32 | shared memory: 49152 | int dot: 1 | matrix cores: NV_coopmat2v
| model                          |       size |     params | backend    | ngl |  fa |            test |                  t/s |
| ------------------------------ | ---------: | ---------: | ---------- | --: | --: | --------------: | -------------------: |
| qwen3moe 30B.A3B Q2_K - Medium |  10.15 GiB |    30.53 B | Vulkan     |  -1 |   1 |           pp512 |    11920.52 ± 267.66 |
| qwen35moe 35B.A3B Q3_K - Medium |  15.45 GiB |    34.66 B | Vulkan     |  -1 |   1 |           pp512 |     9648.96 ± 131.71 |
| qwen35 27B Q4_K - Medium       |  15.32 GiB |    27.32 B | Vulkan     |  -1 |   1 |           pp512 |      3437.53 ± 11.49 |

build: 22c8a29da (10818)

Z:\github\jeffbolznv\llama.cpp\build\bin\RelWithDebInfo>llama-bench.exe -fa 1 -n 0 -p 512 -r 10 --prio 1 -m c:\models\Qwen_Qwen3-30B-A3B-Q2_K.gguf -m c:\models\Qwen3.6-35B-A3B-UD-Q3_K_M.gguf -m c:\models\Qwen3.8-27B-UD-Q4_K_M.gguf
ggml_vulkan: Found 1 Vulkan devices:
ggml_vulkan: 0 = NVIDIA GeForce RTX 5090 (NVIDIA) | uma: 0 | fp16: 1 | bf16: 1 | fp4: 1 | warp size: 32 | shared memory: 49152 | int dot: 1 | matrix cores: KHR_coopmat
| model                          |       size |     params | backend    | ngl |  fa |            test |                  t/s |
| ------------------------------ | ---------: | ---------: | ---------- | --: | --: | --------------: | -------------------: |
| qwen3moe 30B.A3B Q2_K - Medium |  10.15 GiB |    30.53 B | Vulkan     |  -1 |   1 |           pp512 |      7902.34 ± 91.36 |
| qwen35moe 35B.A3B Q3_K - Medium |  15.45 GiB |    34.66 B | Vulkan     |  -1 |   1 |           pp512 |      7324.52 ± 98.68 |
| qwen35 27B Q4_K - Medium       |  15.32 GiB |    27.32 B | Vulkan     |  -1 |   1 |           pp512 |      2323.58 ± 10.16 |

build: 22c8a29da (10818)

Requirements

@jeffbolznv
jeffbolznv requested review from a team and ggerganov as code owners September 5, 2026 21:17
@github-actions github-actions Bot added testing Everything test related Vulkan Issues specific to the Vulkan backend ggml changes relating to the ggml tensor library for machine learning labels Sep 5, 2026
Allow split_k with small M.

Make small vs med tile selection (for coopmat2) depend on M, not just N.
@0cc4m

0cc4m commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

A bunch of ARGSORT tests failed completely on the T4 CM2 CI, please check.

@jeffbolznv

Copy link
Copy Markdown
Contributor Author

A bunch of ARGSORT tests failed completely on the T4 CM2 CI, please check.

This seems to be affecting multiple PRs. Maybe related to the driver update? I haven't been able to reproduce it locally so far.

@0cc4m

0cc4m commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Very likely the driver, yes. CM1 passed on 580 GB10, the 615 T4 failed.

@0cc4m 0cc4m added the merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge. label Sep 10, 2026
@ggerganov
ggerganov merged commit 6788edb into ggml-org:master Sep 10, 2026
26 of 30 checks passed
@BrewTestBot BrewTestBot mentioned this pull request Sep 14, 2026
1 task done
pl752 pushed a commit to pl752/llama.cpp that referenced this pull request Sep 15, 2026
* vulkan: optimize m=1 mul_mat by swapping A/B

* vulkan: Improve small M perf

Allow split_k with small M.

Make small vs med tile selection (for coopmat2) depend on M, not just N.
zsogitbe pushed a commit to zsogitbe/llama.cpp that referenced this pull request Sep 17, 2026
* vulkan: optimize m=1 mul_mat by swapping A/B

* vulkan: Improve small M perf

Allow split_k with small M.

Make small vs med tile selection (for coopmat2) depend on M, not just N.
gaetan-puleo pushed a commit to halo-box/strix-llama.cpp that referenced this pull request Oct 3, 2026
The m == 1 operand swap (ggml-org#28457) runs B^T*A as a mat-vec when dst has one
row. Extend it to dst->ne[0] <= mul_mat_vec_max_cols: the src0 rows become
the mat-vec columns (NUM_COLS = m), the mat-vec writes the result transposed
into the split_k scratch buffer, and a strided f32 copy of m*n floats puts it
in place. Without this, a [k, m] f32 weight with tiny m goes through mul_mm
and is padded to a full tile.

The motivating shape is the Flash-Next (qwen4exp) hyper-connection inject
projection, MUL_MAT f32 m=4 n=2048 k=10240, 95 calls per 2048-token ubatch.
Decode (n <= 8) and batched / broadcast cases keep their existing paths.

Tests: small-m cases (m = 2..5, 8, 9; n = 9..2048; the k = 10240 inject
shape at n = 1, 4, 8, 9, 512, 2048; f16 src0; a batched case that must not
take the route) added to test-backend-ops, plus two perf cases. Skipping the
transposing copy fails all 25 routed cases, so the tests see the route.

Tested on gfx1151 (RADV) only.

Assisted-by: Claude Opus 5.5
frostyautumnleaf pushed a commit to frostyautumnleaf/llama.cpp that referenced this pull request Oct 5, 2026
* vulkan: optimize m=1 mul_mat by swapping A/B

* vulkan: Improve small M perf

Allow split_k with small M.

Make small vs med tile selection (for coopmat2) depend on M, not just N.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ggml changes relating to the ggml tensor library for machine learning merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge. testing Everything test related Vulkan Issues specific to the Vulkan backend

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants