1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# triton_kernels/chunk_o.py
#
# GDN chunked output kernel (chunk_o), the SANCTIONED CUDA-only Triton AOT
# fast-path for the PROVEN codegen-bound kernel (see .agents/discipline.md
# "SANCTIONED EXCEPTION", .agents/mission.md, porting-inventory.md §9). Compiled
# to a cubin at BUILD time (cmake/TritonAOT.cmake, gated VLLM_CPP_TRITON=OFF by
# default) and embedded in libvllm; the RUNTIME is Triton/Python-free (cubin via
# the CUDA driver API). The portable hand-C++ CUDA kernel (GdnChunkOWmmaKernel in
# src/vt/cuda/cuda_gdn.cu) + the CPU reference are PRESERVED as the fallback and
# remain the default when VLLM_CPP_TRITON=OFF.
#
# Ported VERBATIM FROM (vLLM 0.24.0 oracle venv):
# vllm/model_executor/layers/fla/ops/chunk_o.py:47-160
# @triton.jit chunk_fwd_kernel_o
# (upstream flash-linear-attention; MIT). The kernel BODY is byte-for-byte the
# FLA source. The ONLY adaptations for AOT compilation are:
# (1) the @triton.heuristics / @triton.autotune decorators are removed — the
# flags (USE_G,IS_VARLEN) and dims (H,Hg,K,V,BT,BK,BV) are PINNED per-shape
# via the triton.tools.compile SIGNATURE (see CMakeLists.txt), and the
# winning (BK,BV,num_warps,num_stages) is selected there, exactly what the
# autotuner would pick for the gate shape;
# (2) one trailing runtime scalar `NT` (= total number of chunks across all
# sequences) is appended: the FLA launch grid is (cdiv(V,BV), NT, B*H) but
# NT is NOT a kernel argument, so the grid-y extent is carried in `NT` for
# the AOT launcher's baked grid expression. `B*H` == H because our varlen
# packing has B=1 (single packed [T,H,*] tensor + cu_seqlens), so grid-z is
# the constexpr H (baked per spec). `NT` is unused by the kernel body (dead
# arg → eliminated → the compute codegen is identical to FLA's).
# (3) the runtime `scale` arg is REMOVED and pinned to Dk^-0.5 (= K**-0.5, the
# GDN q-scale; K=128 pinned). Triton's AOT launcher mis-packs an fp32 scalar
# as an 8-byte double (the kernel reads 4 bytes → garbage), so a runtime
# float scalar is unusable here; the model always passes scale == Dk^-0.5
# (qwen3_5.cpp: scale = 1/sqrt(Dk)) and the dispatch (TryTritonChunkO) guards
# that args.scale matches before firing, so pinning it is exact.
#
# Pinned flags for the vllm.cpp GDN chunked-prefill call site: USE_G=1,
# IS_VARLEN=1. Buffer layout is a 1:1 drop-in (verified stride-for-stride against
# the FLA pointer arithmetic and our hand GdnChunkOWmmaKernel):
# q=[T,Hg,K] bf16, k=[T,Hg,K] bf16, v(=v_new)=[T,H,V] bf16,
# h(=hstate snapshot)=[NT,H,V,K] bf16, g(=gcum within-chunk cumsum)=[T,H] f32,
# o(=out)=[T,H,V] f32 or bf16, selected by the AOT signature. The bf16
# specialization mirrors FLA's empty_like(v) / output-buffer dtype and is
# evaluated before VT_GDN_OUT_BF16 can become a default. cu_seqlens=[N+1] i32,
# chunk_indices=[NT,2] i32 (per global chunk: (i_n, i_t_local)).
# fla/ops/op.py: exp (FLA_USE_FAST_OPS=0 default -> tl.exp).
=
# scale = Dk^-0.5 (GDN q-scale), pinned since Triton AOT can't take an fp32
# scalar arg reliably; K == Dk == 128 for the gate shape (see header note 3).
= ** -0.5
, , = , ,
, = // , %
=
, =
, =
= -
=
=
= * +
, = * , * +
# offset calculation
+= *
+= *
+= *
+= *
+= * *
=
=
=
=
=
# [BT, BK]
=
# [BK, BT]
=
# [BV, BK]
=
# [BT, BK] @ [BK, BV] -> [BT, BV]
+=
# [BT, BK] @ [BK, BT] -> [BT, BT]
+=
+= * +
=
=
= *
= *
= * +
= <
= &
=
=
=
=
# to fix mma -> mma layout conversion
# already solved by triton v3.2 or higher
= * + *