← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
ssm_kernels.c File Reference

FP32 SSM causal depthwise convolution kernels for qwen3next/Qwen3.5. More...

#include "bf16_utils.h"
#include "ckernel_engine.h"
#include "ck_threadpool.h"
#include <math.h>
#include <stddef.h>
#include <string.h>

Go to the source code of this file.

Functions

static void ck_ssm_conv1d_llama_channel_range (int begin, int end, void *opaque)
 
static void ck_ssm_conv1d_llama_fma_channel_range (int begin, int end, void *opaque)
 
void ssm_conv1d_backward (const float *d_out, const float *conv_x, const float *kernel, float *d_conv_x, float *d_kernel, int kernel_size, int num_channels, int num_tokens, int num_seqs)
 
void ssm_conv1d_backward_ref (const float *d_out, const float *conv_x, const float *kernel, float *d_conv_x, float *d_kernel, int kernel_size, int num_channels, int num_tokens, int num_seqs)
 
void ssm_conv1d_forward (const float *conv_x, const float *kernel, float *out, int kernel_size, int num_channels, int num_tokens, int num_seqs)
 
void ssm_conv1d_forward_llama_fma (const float *conv_x, const float *kernel, float *out, int kernel_size, int num_channels, int num_tokens, int num_seqs)
 
void ssm_conv1d_forward_llama_production (const float *conv_x, const float *kernel, float *out, int kernel_size, int num_channels, int num_tokens, int num_seqs)
 
void ssm_conv1d_forward_llama_production_serial (const float *conv_x, const float *kernel, float *out, int kernel_size, int num_channels, int num_tokens, int num_seqs)
 
void ssm_conv1d_forward_pytorch_bf16_storage (const float *conv_x, const float *kernel, float *out, int kernel_size, int num_channels, int num_tokens, int num_seqs)
 
void ssm_conv1d_forward_ref (const float *conv_x, const float *kernel, float *out, int kernel_size, int num_channels, int num_tokens, int num_seqs)
 

Detailed Description

FP32 SSM causal depthwise convolution kernels for qwen3next/Qwen3.5.

CK-ENGINE KERNEL RULES:

  1. NO malloc/free - memory via bump allocator, pointers passed in
  2. NO OpenMP - parallelization at orchestrator/codegen layer
  3. API must define: inputs, outputs, workspace, and memory layouts
  4. Pure computation - deterministic, no side effects

After changes: make test-ssm-conv && make test-kernels

This file implements the GGML_OP_SSM_CONV semantics used by qwen3next before the recurrent DeltaNet update: out[seq, token, ch] = dot(conv_x[seq, ch, token:token+kernel], kernel[ch, :])

Memory layouts: conv_x : [num_seqs, num_channels, kernel_size - 1 + num_tokens] kernel : [num_channels, kernel_size] out : [num_seqs, num_tokens, num_channels] d_out : same as out d_conv_x : same as conv_x d_kernel : same as kernel

Definition in file ssm_kernels.c.

Function Documentation

◆ ck_ssm_conv1d_llama_channel_range()

static void ck_ssm_conv1d_llama_channel_range ( int  begin,
int  end,
void *  opaque 
)
static

Definition at line 155 of file ssm_kernels.c.

156{
157 const ck_ssm_conv1d_llama_args_t *args =
158 (const ck_ssm_conv1d_llama_args_t *)opaque;
159 const int kernel_size = args->kernel_size;
160 const int num_channels = args->num_channels;
161 const int num_tokens = args->num_tokens;
162 const size_t seq_width = (size_t)kernel_size - 1u + (size_t)num_tokens;
163 const size_t conv_seq_stride = (size_t)num_channels * seq_width;
164 const size_t out_seq_stride = (size_t)num_tokens * (size_t)num_channels;
165
166 for (int seq = 0; seq < args->num_seqs; ++seq) {
167 const float *conv_seq = args->conv_x + (size_t)seq * conv_seq_stride;
168 float *out_seq = args->out + (size_t)seq * out_seq_stride;
169
170 for (int ch = begin; ch < end; ++ch) {
171 const float *kernel_row =
172 args->kernel + (size_t)ch * (size_t)kernel_size;
173 const float *conv_channel = conv_seq + (size_t)ch * seq_width;
174 for (int tok = 0; tok < num_tokens; ++tok) {
175 const float *conv_row =
176 conv_channel + (size_t)tok;
177 float sum = 0.0f;
178 for (int k = 0; k < kernel_size; ++k) {
179 volatile float product = conv_row[k] * kernel_row[k];
180 volatile float next = sum + product;
181 sum = next;
182 }
183 out_seq[(size_t)tok * (size_t)num_channels + (size_t)ch] = sum;
184 }
185 }
186 }
187}
uint32_t end
Definition utf8.c:215

References end.

Referenced by ssm_conv1d_forward_llama_production(), and ssm_conv1d_forward_llama_production_serial().

◆ ck_ssm_conv1d_llama_fma_channel_range()

static void ck_ssm_conv1d_llama_fma_channel_range ( int  begin,
int  end,
void *  opaque 
)
static

Definition at line 240 of file ssm_kernels.c.

242{
243 const ck_ssm_conv1d_llama_args_t *args =
244 (const ck_ssm_conv1d_llama_args_t *)opaque;
245 const int kernel_size = args->kernel_size;
246 const int num_channels = args->num_channels;
247 const int num_tokens = args->num_tokens;
248 const size_t seq_width = (size_t)kernel_size - 1u + (size_t)num_tokens;
249 const size_t conv_seq_stride = (size_t)num_channels * seq_width;
250 const size_t out_seq_stride = (size_t)num_tokens * (size_t)num_channels;
251
252 for (int seq = 0; seq < args->num_seqs; ++seq) {
253 const float *conv_seq = args->conv_x + (size_t)seq * conv_seq_stride;
254 float *out_seq = args->out + (size_t)seq * out_seq_stride;
255
256 for (int ch = begin; ch < end; ++ch) {
257 const float *kernel_row =
258 args->kernel + (size_t)ch * (size_t)kernel_size;
259 const float *conv_channel = conv_seq + (size_t)ch * seq_width;
260 for (int tok = 0; tok < num_tokens; ++tok) {
261 const float *conv_row = conv_channel + (size_t)tok;
262 float sum = 0.0f;
263 for (int k = 0; k < kernel_size; ++k) {
264 sum = fmaf(conv_row[k], kernel_row[k], sum);
265 }
266 out_seq[(size_t)tok * (size_t)num_channels + (size_t)ch] = sum;
267 }
268 }
269 }
270}

References end.

Referenced by ssm_conv1d_forward_llama_fma().

◆ ssm_conv1d_backward()

void ssm_conv1d_backward ( const float *  d_out,
const float *  conv_x,
const float *  kernel,
float *  d_conv_x,
float *  d_kernel,
int  kernel_size,
int  num_channels,
int  num_tokens,
int  num_seqs 
)

Definition at line 316 of file ssm_kernels.c.

325{
326 ssm_conv1d_backward_ref(d_out, conv_x, kernel, d_conv_x, d_kernel, kernel_size, num_channels, num_tokens, num_seqs);
327}
void ssm_conv1d_backward_ref(const float *d_out, const float *conv_x, const float *kernel, float *d_conv_x, float *d_kernel, int kernel_size, int num_channels, int num_tokens, int num_seqs)
Definition ssm_kernels.c:78

References ssm_conv1d_backward_ref().

◆ ssm_conv1d_backward_ref()

void ssm_conv1d_backward_ref ( const float *  d_out,
const float *  conv_x,
const float *  kernel,
float *  d_conv_x,
float *  d_kernel,
int  kernel_size,
int  num_channels,
int  num_tokens,
int  num_seqs 
)

Definition at line 78 of file ssm_kernels.c.

87{
88 if (!d_out || !conv_x || !kernel || !d_conv_x || !d_kernel) {
89 return;
90 }
91 if (kernel_size <= 0 || num_channels <= 0 || num_tokens < 0 || num_seqs <= 0) {
92 return;
93 }
94
95 const size_t seq_width = (size_t)kernel_size - 1u + (size_t)num_tokens;
96 const size_t conv_total = (size_t)num_seqs * (size_t)num_channels * seq_width;
97 const size_t kernel_total = (size_t)num_channels * (size_t)kernel_size;
98 const size_t conv_seq_stride = (size_t)num_channels * seq_width;
99 const size_t out_seq_stride = (size_t)num_tokens * (size_t)num_channels;
100
101 memset(d_conv_x, 0, conv_total * sizeof(float));
102 memset(d_kernel, 0, kernel_total * sizeof(float));
103
104 for (int seq = 0; seq < num_seqs; ++seq) {
105 const float *d_out_seq = d_out + (size_t)seq * out_seq_stride;
106 const float *conv_seq = conv_x + (size_t)seq * conv_seq_stride;
107 float *d_conv_seq = d_conv_x + (size_t)seq * conv_seq_stride;
108
109 for (int tok = 0; tok < num_tokens; ++tok) {
110 const float *d_out_tok = d_out_seq + (size_t)tok * (size_t)num_channels;
111
112 for (int ch = 0; ch < num_channels; ++ch) {
113 const float grad = d_out_tok[ch];
114 const float *conv_row = conv_seq + (size_t)ch * seq_width + (size_t)tok;
115 float *d_conv_row = d_conv_seq + (size_t)ch * seq_width + (size_t)tok;
116 const float *kernel_row = kernel + (size_t)ch * (size_t)kernel_size;
117 float *d_kernel_row = d_kernel + (size_t)ch * (size_t)kernel_size;
118
119 for (int k = 0; k < kernel_size; ++k) {
120 d_kernel_row[k] += grad * conv_row[k];
121 d_conv_row[k] += grad * kernel_row[k];
122 }
123 }
124 }
125 }
126}

Referenced by ssm_conv1d_backward().

◆ ssm_conv1d_forward()

void ssm_conv1d_forward ( const float *  conv_x,
const float *  kernel,
float *  out,
int  kernel_size,
int  num_channels,
int  num_tokens,
int  num_seqs 
)

Definition at line 128 of file ssm_kernels.c.

135{
136 ssm_conv1d_forward_ref(conv_x, kernel, out, kernel_size, num_channels, num_tokens, num_seqs);
137}
void ssm_conv1d_forward_ref(const float *conv_x, const float *kernel, float *out, int kernel_size, int num_channels, int num_tokens, int num_seqs)
Definition ssm_kernels.c:39

References ssm_conv1d_forward_ref().

Referenced by ck_test_ssm_conv1d().

◆ ssm_conv1d_forward_llama_fma()

void ssm_conv1d_forward_llama_fma ( const float *  conv_x,
const float *  kernel,
float *  out,
int  kernel_size,
int  num_channels,
int  num_tokens,
int  num_seqs 
)

Definition at line 272 of file ssm_kernels.c.

279{
280 if (!conv_x || !kernel || !out || kernel_size <= 0 || num_channels <= 0 ||
281 num_tokens < 0 || num_seqs <= 0) {
282 return;
283 }
284 ck_ssm_conv1d_llama_args_t args = {
285 conv_x, kernel, out, kernel_size, num_channels, num_tokens, num_seqs,
286 };
287 ck_threadpool_t *pool = ck_threadpool_global();
288 const int workers = pool ? ck_threadpool_n_threads(pool) : 1;
289 const int active = workers < num_channels ? workers : num_channels;
290 if (active > 1 && num_tokens > 1) {
292 pool, active, 0, num_channels, 32,
294 } else {
295 ck_ssm_conv1d_llama_fma_channel_range(0, num_channels, &args);
296 }
297}
void ck_threadpool_parallel_for_n(ck_threadpool_t *pool, int active_threads, int begin, int end, int grain_size, ck_range_fn_t fn, void *args)
ck_threadpool_t * ck_threadpool_global(void)
int ck_threadpool_n_threads(const ck_threadpool_t *pool)
static void ck_ssm_conv1d_llama_fma_channel_range(int begin, int end, void *opaque)

References ck_ssm_conv1d_llama_fma_channel_range(), ck_threadpool_global(), ck_threadpool_n_threads(), and ck_threadpool_parallel_for_n().

◆ ssm_conv1d_forward_llama_production()

void ssm_conv1d_forward_llama_production ( const float *  conv_x,
const float *  kernel,
float *  out,
int  kernel_size,
int  num_channels,
int  num_tokens,
int  num_seqs 
)

Definition at line 207 of file ssm_kernels.c.

214{
215 if (!conv_x || !kernel || !out || kernel_size <= 0 || num_channels <= 0 ||
216 num_tokens < 0 || num_seqs <= 0) {
217 return;
218 }
219 ck_ssm_conv1d_llama_args_t args = {
220 conv_x, kernel, out, kernel_size, num_channels, num_tokens, num_seqs,
221 };
222 ck_threadpool_t *pool = ck_threadpool_global();
223 const int workers = pool ? ck_threadpool_n_threads(pool) : 1;
224 const int active = workers < num_channels ? workers : num_channels;
225 if (active > 1 && num_tokens > 1) {
227 pool, active, 0, num_channels, 32,
229 } else {
230 ck_ssm_conv1d_llama_channel_range(0, num_channels, &args);
231 }
232}
static void ck_ssm_conv1d_llama_channel_range(int begin, int end, void *opaque)

References ck_ssm_conv1d_llama_channel_range(), ck_threadpool_global(), ck_threadpool_n_threads(), and ck_threadpool_parallel_for_n().

◆ ssm_conv1d_forward_llama_production_serial()

void ssm_conv1d_forward_llama_production_serial ( const float *  conv_x,
const float *  kernel,
float *  out,
int  kernel_size,
int  num_channels,
int  num_tokens,
int  num_seqs 
)

Definition at line 189 of file ssm_kernels.c.

196{
197 if (!conv_x || !kernel || !out || kernel_size <= 0 || num_channels <= 0 ||
198 num_tokens < 0 || num_seqs <= 0) {
199 return;
200 }
201 ck_ssm_conv1d_llama_args_t args = {
202 conv_x, kernel, out, kernel_size, num_channels, num_tokens, num_seqs,
203 };
204 ck_ssm_conv1d_llama_channel_range(0, num_channels, &args);
205}

References ck_ssm_conv1d_llama_channel_range().

◆ ssm_conv1d_forward_pytorch_bf16_storage()

void ssm_conv1d_forward_pytorch_bf16_storage ( const float *  conv_x,
const float *  kernel,
float *  out,
int  kernel_size,
int  num_channels,
int  num_tokens,
int  num_seqs 
)

Definition at line 299 of file ssm_kernels.c.

306{
308 conv_x, kernel, out, kernel_size, num_channels, num_tokens, num_seqs);
309 const size_t count =
310 (size_t)num_seqs * (size_t)num_tokens * (size_t)num_channels;
311 for (size_t i = 0; i < count; ++i) {
312 out[i] = bf16_to_float(float_to_bf16(out[i]));
313 }
314}
static uint16_t float_to_bf16(float f)
Definition bf16_utils.h:90
static float bf16_to_float(uint16_t v)
Definition bf16_utils.h:38

References bf16_to_float(), float_to_bf16(), and ssm_conv1d_forward_ref().

◆ ssm_conv1d_forward_ref()

void ssm_conv1d_forward_ref ( const float *  conv_x,
const float *  kernel,
float *  out,
int  kernel_size,
int  num_channels,
int  num_tokens,
int  num_seqs 
)

Definition at line 39 of file ssm_kernels.c.

46{
47 if (!conv_x || !kernel || !out) {
48 return;
49 }
50 if (kernel_size <= 0 || num_channels <= 0 || num_tokens < 0 || num_seqs <= 0) {
51 return;
52 }
53
54 const size_t seq_width = (size_t)kernel_size - 1u + (size_t)num_tokens;
55 const size_t conv_seq_stride = (size_t)num_channels * seq_width;
56 const size_t out_seq_stride = (size_t)num_tokens * (size_t)num_channels;
57
58 for (int seq = 0; seq < num_seqs; ++seq) {
59 const float *conv_seq = conv_x + (size_t)seq * conv_seq_stride;
60 float *out_seq = out + (size_t)seq * out_seq_stride;
61
62 for (int tok = 0; tok < num_tokens; ++tok) {
63 float *out_tok = out_seq + (size_t)tok * (size_t)num_channels;
64
65 for (int ch = 0; ch < num_channels; ++ch) {
66 const float *conv_row = conv_seq + (size_t)ch * seq_width + (size_t)tok;
67 const float *kernel_row = kernel + (size_t)ch * (size_t)kernel_size;
68 float sumf = 0.0f;
69 for (int k = 0; k < kernel_size; ++k) {
70 sumf += conv_row[k] * kernel_row[k];
71 }
72 out_tok[ch] = sumf;
73 }
74 }
75 }
76}

Referenced by ssm_conv1d_forward(), and ssm_conv1d_forward_pytorch_bf16_storage().