Skip to content

ssm_conv: channels-major input mode to drop the delta-net transpose#52

Merged
roberteg16 merged 2 commits into
gfx11from
rogarcia.qwen3.6-moe-optimization
Jul 16, 2026
Merged

ssm_conv: channels-major input mode to drop the delta-net transpose#52
roberteg16 merged 2 commits into
gfx11from
rogarcia.qwen3.6-moe-optimization

Conversation

@roberteg16

@roberteg16 roberteg16 commented Jul 15, 2026

Copy link
Copy Markdown

Summary

ggml_ssm_conv requires a time-major input [time, channels, seqs], while the delta-net projection produces channels-major [channels, time, seqs]. Feeding the op therefore required a physical transpose of the conv input on every layer, which is a significant kernel in prefill.

This PR adds an opt-in channels-major layout to ggml_ssm_conv (ggml_ssm_conv_channels_major): the input is [d_inner, d_conv-1+n_t, n_s] (channels contiguous) and the output layout is unchanged. build_conv_state keeps qkv_mixed channels-major, prepends the recurrent conv state along the time axis (concat dim 1), and calls the new entry point, so the transpose is no longer needed.

  • Implemented on CPU and CUDA (short- and long-token kernels; coalesced smem load).
  • Non-implementing backends fall back to CPU; existing (time-major) callers are bit-identical.
  • Shared by the qwen35, qwen35moe, and qwen3next graphs.

The two commits are: (1) force the conv-state concat input contiguous; (2) add the channels-major ssm_conv mode and switch build_conv_state to it.

Measured impact — roofline (Qwen3.6-35B-A3B, prefill pp4096, gfx1151)

-ub 4096 -b 4096 (M=4096)

op baseline this PR
CONCAT 1166 ms 34 ms
CONT (transpose) 10 ms 10 ms
SSM_CONV 47 ms 43 ms
total prefill 3825 ms 2717 ms

−1108 ms (−29 %).

-ub 4096 -b 2048 (M=2048; n_ubatch is clamped to n_batch, which defaults to 2048)

op baseline this PR
CONCAT 283 ms 35 ms
total prefill 2786 ms 2590 ms

−196 ms (−7.0 %).

Measured impact — throughput A/B (llama-bench, Qwen3.6-35B-A3B, gfx1151, t/s, CUDA graphs enabled)

test baseline this PR Δ
pp128 1061.2 ± 1.3 1052.4 ± 24.1 ~0
pp512 1558.8 ± 16.0 1641.8 ± 28.6 +5.3 %
pp1024 1584.9 ± 16.0 1652.9 ± 53.8 +4.3 %
pp512 @ d512 1536.2 ± 3.8 1615.8 ± 19.6 +5.2 %
pp1024 @ d1024 1527.9 ± 45.5 1632.0 ± 24.2 +6.8 %
tg128 @ d128 54.77 ± 0.42 54.95 ± 0.43 ~0
tg512 @ d512 54.17 ± 0.33 54.51 ± 0.20 ~0
tg1024 @ d1024 54.32 ± 0.21 54.82 ± 0.03 ~0

Baseline is the branch point 1847907d6.

Validation

Kernel numerics. test-backend-ops -o SSM_CONV runs the channels-major cases (short- and long-token paths, d_conv ∈ {3,4,9}, d_inner ∈ {1024,1536,2048}, single/multi-seq) against the CPU reference: 90/90 pass.

Output-preserving. Perplexity over a fixed ~500-token passage (-c 256, greedy) is bit-identical between baseline (1847907d6) and this PR on all three affected architectures:

arch model (Q4_K_M) baseline PPL this PR PPL
qwen35 Qwen3.5-0.8B 16.2847 16.2847
qwen35moe Qwen3.6-35B-A3B 3.4005 3.4005
qwen3next Qwen3-Coder-Next-REAP-40B-A3B 26.5075 26.5075

Qwen3.5-35B-A3B (qwen35moe) additionally runs at PPL 2.18.

Notes / out of scope

  • Non-CUDA backends only exercised via the CPU fallback path; not run on Metal/Vulkan/SYCL/etc.
  • ggml-backend-meta.cpp tensor-parallel split handles the channels-major layout (d_inner is sx axis 0 / c axis 1). Not exercised in a tensor-parallel run here.

@roberteg16
roberteg16 force-pushed the rogarcia.qwen3.6-moe-optimization branch 3 times, most recently from 5432325 to d0c4efc Compare July 15, 2026 12:16
@roberteg16
roberteg16 marked this pull request as ready for review July 15, 2026 15:24

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces an opt-in channels-major input layout for ggml_ssm_conv and updates the Qwen3.5/3.6 hybrid (DeltaNet + MoE) graphs to use it, eliminating a costly transpose in prefill and improving large-ubatch performance.

Changes:

  • Add GGML_SSM_CONV_LAYOUT_{TIME_MAJOR,CHANNELS_MAJOR}, a new entry point ggml_ssm_conv_channels_major(), and plumb layout through op params so CPU/CUDA can select the correct stride interpretation.
  • Update DeltaNet conv-state construction in the Qwen graphs to keep [channels, time, seq] and call ggml_ssm_conv_channels_major() directly (dropping the DeltaNet-side transpose).
  • Extend backend-op tests to exercise the new layout; gate non-CPU/CUDA backends to time-major until they implement channels-major.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/test-backend-ops.cpp Adds coverage for the channels-major SSM_CONV mode in backend op tests.
src/models/qwen3next.cpp Switches Qwen3Next to call ggml_ssm_conv_channels_major() for conv.
src/models/qwen35moe.cpp Switches Qwen3.6 MoE graph to the channels-major SSM_CONV entry point.
src/models/qwen35.cpp Switches Qwen3.5 graph to the channels-major SSM_CONV entry point.
src/models/delta-net-base.cpp Reworks conv-state concat to be channels-major and removes the DeltaNet transpose.
ggml/src/ggml.c Adds layout-aware SSM_CONV constructor + new channels-major API + layout getter.
ggml/src/ggml-webgpu/ggml-webgpu.cpp Disables channels-major offload on WebGPU (time-major only).
ggml/src/ggml-vulkan/ggml-vulkan.cpp Disables channels-major offload on Vulkan (time-major only).
ggml/src/ggml-sycl/ggml-sycl.cpp Disables channels-major offload on SYCL (time-major only).
ggml/src/ggml-opencl/ggml-opencl.cpp Disables channels-major offload on OpenCL (time-major only).
ggml/src/ggml-metal/ggml-metal-device.m Disables channels-major offload on Metal (time-major only).
ggml/src/ggml-hexagon/ggml-hexagon.cpp Disables channels-major offload on Hexagon (time-major only).
ggml/src/ggml-cuda/ssm-conv.cu Implements channels-major-aware CUDA kernels for SSM_CONV (short/long token paths).
ggml/src/ggml-cuda/ggml-cuda.cu Updates CUDA supports-op logic to interpret d_inner based on layout.
ggml/src/ggml-cpu/ops.cpp Makes the CPU SSM_CONV implementation layout-aware via computed channel/time strides.
ggml/src/ggml-cann/ggml-cann.cpp Disables channels-major offload on CANN (time-major only).
ggml/include/ggml.h Exposes the new layout enum, channels-major entry point, and layout getter in the public API.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ggml/src/ggml.c
@roberteg16
roberteg16 force-pushed the rogarcia.qwen3.6-moe-optimization branch from d0c4efc to 3a7b9ad Compare July 15, 2026 16:25
@roberteg16
roberteg16 requested a review from Copilot July 15, 2026 16:38

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.

Comment thread ggml/src/ggml-cann/ggml-cann.cpp
Materialize the transposed qkv_mixed before ggml_concat so the conv-state
prepend takes the coalesced concat_cont path instead of concat_non_cont,
which scaled super-linearly with chunk size (CONCAT ~1166ms -> ~34ms at
ub=4096, -899ms total prefill).
Delta-net fed ggml_ssm_conv a transposed (time-major) conv input, forcing a
physical transpose. Option A removed the quadratic concat but left a 221ms
CONT (transpose) kernel at ub=4096.

Add an opt-in channels-major layout to ggml_ssm_conv (op_params[0]=1):
input is [d_inner, d_conv-1+n_t, n_s] (channels contiguous); output layout
unchanged. Implemented on CPU and CUDA (both short and long-token kernels,
coalesced smem load); other backends' supports_op reject mode!=0 so the
scheduler falls back to CPU. build_conv_state now keeps qkv_mixed channels-
major, prepends the recurrent conv state along the time axis (concat dim 1),
and calls ggml_ssm_conv_channels_major (qwen35/qwen35moe/qwen3next).

Prefill pp4096 ub=4096: CONT 221->10ms, total 2925->2717ms (-1108ms vs the
pre-optimization baseline). Validated: test-backend-ops SSM_CONV channels-
major cases pass (CUDA vs CPU); Qwen3.6 perplexity 3.40 (healthy).
@roberteg16
roberteg16 force-pushed the rogarcia.qwen3.6-moe-optimization branch from 3a7b9ad to 20191d0 Compare July 15, 2026 18:36
@roberteg16
roberteg16 requested a review from Copilot July 16, 2026 07:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.

@mgehre-amd mgehre-amd left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Looks good

@roberteg16
roberteg16 merged commit f6ea7bc into gfx11 Jul 16, 2026
7 checks passed
@roberteg16
roberteg16 deleted the rogarcia.qwen3.6-moe-optimization branch July 16, 2026 07:34
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.

3 participants