← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
hybrid_attention_kernels.c File Reference
#include "ckernel_engine.h"
#include "bf16_utils.h"
#include "ck_threadpool.h"
#include <dlfcn.h>
#include <limits.h>
#include <math.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

Go to the source code of this file.

Typedefs

typedef float(* ck_hybrid_libm_f32_fn) (float)
 

Functions

void attn_gate_sigmoid_mul_backward (const float *d_out, const float *x, const float *gate, float *d_x, float *d_gate, int rows, int num_heads, int state_dim)
 
void attn_gate_sigmoid_mul_forward (const float *x, const float *gate, float *out, int rows, int num_heads, int state_dim)
 
void attn_gate_sigmoid_mul_pytorch_bf16_storage (const float *x, const float *gate, float *out, int rows, int num_heads, int state_dim)
 
static void attn_gate_sigmoid_mul_row_range (int begin, int end, void *opaque)
 
void attn_gate_softplus_mul_forward (const float *x, const float *gate, float *out, int rows, int num_heads, int state_dim)
 
static void ck_bind_hybrid_llama_libm (void)
 
static int hybrid_ranges_overlap (const float *lhs, const float *rhs, size_t elements)
 
static float hybrid_sigmoid (float x)
 
void split_q_gate_backward (const float *d_q, const float *d_gate, float *d_packed_qg, int rows, int q_dim, int gate_dim, int group_dim)
 
void split_q_gate_forward (const float *packed_qg, float *q, float *gate, int rows, int q_dim, int gate_dim, int group_dim)
 

Variables

static void * ck_hybrid_libm_handle = NULL
 
static pthread_once_t ck_hybrid_libm_once = PTHREAD_ONCE_INIT
 
static ck_hybrid_libm_f32_fn ck_hybrid_llama_expf = NULL
 

Typedef Documentation

◆ ck_hybrid_libm_f32_fn

typedef float(* ck_hybrid_libm_f32_fn) (float)

Definition at line 14 of file hybrid_attention_kernels.c.

Function Documentation

◆ attn_gate_sigmoid_mul_backward()

void attn_gate_sigmoid_mul_backward ( const float *  d_out,
const float *  x,
const float *  gate,
float *  d_x,
float *  d_gate,
int  rows,
int  num_heads,
int  state_dim 
)

Definition at line 253 of file hybrid_attention_kernels.c.

260 {
261 const int dim = num_heads * state_dim;
262 for (int row = 0; row < rows; ++row) {
263 const float *d_out_row = d_out + (size_t) row * (size_t) dim;
264 const float *x_row = x + (size_t) row * (size_t) dim;
265 const float *gate_row = gate + (size_t) row * (size_t) dim;
266 float *d_x_row = d_x + (size_t) row * (size_t) dim;
267 float *d_gate_row = d_gate + (size_t) row * (size_t) dim;
268 for (int col = 0; col < dim; ++col) {
269 const float sig = hybrid_sigmoid(gate_row[col]);
270 d_x_row[col] = d_out_row[col] * sig;
271 d_gate_row[col] = d_out_row[col] * x_row[col] * sig * (1.0f - sig);
272 }
273 }
274}
static float hybrid_sigmoid(float x)

References hybrid_sigmoid().

◆ attn_gate_sigmoid_mul_forward()

void attn_gate_sigmoid_mul_forward ( const float *  x,
const float *  gate,
float *  out,
int  rows,
int  num_heads,
int  state_dim 
)

Definition at line 154 of file hybrid_attention_kernels.c.

159 {
160 if (!x || !gate || !out || rows <= 0 || num_heads <= 0 ||
161 state_dim <= 0 || num_heads > INT_MAX / state_dim) {
162 return;
163 }
164 const int dim = num_heads * state_dim;
165 const size_t elements = (size_t)rows * (size_t)dim;
166 ck_attn_gate_sigmoid_mul_args_t args = {x, gate, out, dim};
167 const size_t minimum_elements_per_thread = 32768u;
168
169 const int partial_x_overlap = out != x &&
170 hybrid_ranges_overlap(out, x, elements);
171 const int gate_overlap = hybrid_ranges_overlap(out, gate, elements);
172 if (partial_x_overlap || gate_overlap ||
173 elements < 2u * minimum_elements_per_thread) {
174 attn_gate_sigmoid_mul_row_range(0, rows, &args);
175 return;
176 }
177
178 ck_threadpool_t *pool = ck_threadpool_global();
179 int active = pool ? ck_threadpool_n_threads(pool) : 1;
180 size_t useful_threads =
181 (elements + minimum_elements_per_thread - 1u) /
182 minimum_elements_per_thread;
183 if ((size_t)active > useful_threads) {
184 active = (int)useful_threads;
185 }
186 if (active > rows) {
187 active = rows;
188 }
189
190 if (active > 1 && ck_threadpool_thread_id(pool) <= 0) {
192 pool, active, 0, rows, 4,
194 } else {
195 attn_gate_sigmoid_mul_row_range(0, rows, &args);
196 }
197}
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_thread_id(const ck_threadpool_t *pool)
int ck_threadpool_n_threads(const ck_threadpool_t *pool)
static int hybrid_ranges_overlap(const float *lhs, const float *rhs, size_t elements)
static void attn_gate_sigmoid_mul_row_range(int begin, int end, void *opaque)

References attn_gate_sigmoid_mul_row_range(), ck_threadpool_global(), ck_threadpool_n_threads(), ck_threadpool_parallel_for_n(), ck_threadpool_thread_id(), and hybrid_ranges_overlap().

Referenced by ck_test_attn_gate_sigmoid_mul().

◆ attn_gate_sigmoid_mul_pytorch_bf16_storage()

void attn_gate_sigmoid_mul_pytorch_bf16_storage ( const float *  x,
const float *  gate,
float *  out,
int  rows,
int  num_heads,
int  state_dim 
)

Definition at line 199 of file hybrid_attention_kernels.c.

204 {
205 if (!x || !gate || !out || rows <= 0 || num_heads <= 0 || state_dim <= 0) {
206 return;
207 }
208 const int dim = num_heads * state_dim;
209 for (int row = 0; row < rows; ++row) {
210 const float *x_row = x + (size_t)row * (size_t)dim;
211 const float *gate_row = gate + (size_t)row * (size_t)dim;
212 float *out_row = out + (size_t)row * (size_t)dim;
213 for (int col = 0; col < dim; col += 16) {
214 const int width = dim - col < 16 ? dim - col : 16;
215 float sigmoid[16];
217 gate_row + col, sigmoid, 1, width);
218 for (int lane = 0; lane < width; ++lane) {
219 const float x_bf16 = bf16_to_float(float_to_bf16(x_row[col + lane]));
220 const float sigmoid_bf16 = bf16_to_float(float_to_bf16(sigmoid[lane]));
221 out_row[col + lane] = bf16_to_float(float_to_bf16(
222 x_bf16 * sigmoid_bf16));
223 }
224 }
225 }
226}
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
void recurrent_sigmoid_forward_pytorch_bf16_input_fp32_output(const float *x, float *out, int rows, int dim)

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

◆ attn_gate_sigmoid_mul_row_range()

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

Definition at line 126 of file hybrid_attention_kernels.c.

128 {
129 const ck_attn_gate_sigmoid_mul_args_t *args =
130 (const ck_attn_gate_sigmoid_mul_args_t *)opaque;
131 for (int row = begin; row < end; ++row) {
132 const float *x_row =
133 args->x + (size_t)row * (size_t)args->dim;
134 const float *gate_row =
135 args->gate + (size_t)row * (size_t)args->dim;
136 float *out_row =
137 args->out + (size_t)row * (size_t)args->dim;
138 const int dim = args->dim;
139 for (int col = 0; col < dim; ++col) {
140 out_row[col] = x_row[col] * hybrid_sigmoid(gate_row[col]);
141 }
142 }
143}
uint32_t end
Definition utf8.c:215

References end, and hybrid_sigmoid().

Referenced by attn_gate_sigmoid_mul_forward().

◆ attn_gate_softplus_mul_forward()

void attn_gate_softplus_mul_forward ( const float *  x,
const float *  gate,
float *  out,
int  rows,
int  num_heads,
int  state_dim 
)

Definition at line 228 of file hybrid_attention_kernels.c.

233 {
234 const int dim = num_heads * state_dim;
235 for (int row = 0; row < rows; ++row) {
236 const float *x_row = x + (size_t) row * (size_t) dim;
237 const float *gate_row = gate + (size_t) row * (size_t) num_heads;
238 float *out_row = out + (size_t) row * (size_t) dim;
239 for (int head = 0; head < num_heads; ++head) {
240 const float value = gate_row[head];
241 const float scale = value > 20.0f
242 ? value
243 : log1pf(expf(value));
244 const size_t base = (size_t) head * (size_t) state_dim;
245 for (int col = 0; col < state_dim; ++col) {
246 out_row[base + (size_t) col] =
247 x_row[base + (size_t) col] * scale;
248 }
249 }
250 }
251}

◆ ck_bind_hybrid_llama_libm()

static void ck_bind_hybrid_llama_libm ( void  )
static

Definition at line 19 of file hybrid_attention_kernels.c.

19 {
20 ck_hybrid_libm_handle = dlopen("libm.so.6", RTLD_NOW | RTLD_LOCAL);
24 }
26 fprintf(stderr,
27 "HARD KERNEL CONTRACT FAULT: llama.cpp attention gate "
28 "requires expf from libm.so.6\n");
29 abort();
30 }
31}
static void * ck_hybrid_libm_handle
static ck_hybrid_libm_f32_fn ck_hybrid_llama_expf
float(* ck_hybrid_libm_f32_fn)(float)

References ck_hybrid_libm_handle, and ck_hybrid_llama_expf.

Referenced by hybrid_sigmoid().

◆ hybrid_ranges_overlap()

static int hybrid_ranges_overlap ( const float *  lhs,
const float *  rhs,
size_t  elements 
)
static

Definition at line 145 of file hybrid_attention_kernels.c.

147 {
148 const uintptr_t lhs_begin = (uintptr_t)lhs;
149 const uintptr_t rhs_begin = (uintptr_t)rhs;
150 const size_t bytes = elements * sizeof(float);
151 return lhs_begin < rhs_begin + bytes && rhs_begin < lhs_begin + bytes;
152}

Referenced by attn_gate_sigmoid_mul_forward().

◆ hybrid_sigmoid()

static float hybrid_sigmoid ( float  x)
static

Definition at line 36 of file hybrid_attention_kernels.c.

36 {
38 return 1.0f / (1.0f + ck_hybrid_llama_expf(-x));
39}
static void ck_bind_hybrid_llama_libm(void)
static pthread_once_t ck_hybrid_libm_once

References ck_bind_hybrid_llama_libm(), ck_hybrid_libm_once, and ck_hybrid_llama_expf.

Referenced by attn_gate_sigmoid_mul_backward(), and attn_gate_sigmoid_mul_row_range().

◆ split_q_gate_backward()

void split_q_gate_backward ( const float *  d_q,
const float *  d_gate,
float *  d_packed_qg,
int  rows,
int  q_dim,
int  gate_dim,
int  group_dim 
)

Definition at line 80 of file hybrid_attention_kernels.c.

86 {
87 const int packed_dim = q_dim + gate_dim;
88 if (!d_q || !d_gate || !d_packed_qg || rows <= 0 || q_dim <= 0 || gate_dim <= 0) {
89 return;
90 }
91 if (group_dim <= 0) {
92 group_dim = q_dim;
93 }
94 const int q_groups = q_dim / group_dim;
95 const int gate_group_dim = (q_groups > 0 && gate_dim % q_groups == 0) ? (gate_dim / q_groups) : gate_dim;
96 for (int row = 0; row < rows; ++row) {
97 const float *dq_src = d_q + (size_t) row * (size_t) q_dim;
98 const float *dg_src = d_gate + (size_t) row * (size_t) gate_dim;
99 float *dst = d_packed_qg + (size_t) row * (size_t) packed_dim;
100 if (q_groups > 0 && q_groups * group_dim == q_dim && q_groups * gate_group_dim == gate_dim) {
101 for (int group = 0; group < q_groups; ++group) {
102 const size_t dst_group_off = (size_t) group * (size_t) (group_dim + gate_group_dim);
103 memcpy(
104 dst + dst_group_off,
105 dq_src + (size_t) group * (size_t) group_dim,
106 (size_t) group_dim * sizeof(float));
107 memcpy(
108 dst + dst_group_off + (size_t) group_dim,
109 dg_src + (size_t) group * (size_t) gate_group_dim,
110 (size_t) gate_group_dim * sizeof(float));
111 }
112 } else {
113 memcpy(dst, dq_src, (size_t) q_dim * sizeof(float));
114 memcpy(dst + q_dim, dg_src, (size_t) gate_dim * sizeof(float));
115 }
116 }
117}

◆ split_q_gate_forward()

void split_q_gate_forward ( const float *  packed_qg,
float *  q,
float *  gate,
int  rows,
int  q_dim,
int  gate_dim,
int  group_dim 
)

Definition at line 41 of file hybrid_attention_kernels.c.

47 {
48 const int packed_dim = q_dim + gate_dim;
49 if (!packed_qg || !q || !gate || rows <= 0 || q_dim <= 0 || gate_dim <= 0) {
50 return;
51 }
52 if (group_dim <= 0) {
53 group_dim = q_dim;
54 }
55 const int q_groups = q_dim / group_dim;
56 const int gate_group_dim = (q_groups > 0 && gate_dim % q_groups == 0) ? (gate_dim / q_groups) : gate_dim;
57 for (int row = 0; row < rows; ++row) {
58 const float *src = packed_qg + (size_t) row * (size_t) packed_dim;
59 float *q_dst = q + (size_t) row * (size_t) q_dim;
60 float *gate_dst = gate + (size_t) row * (size_t) gate_dim;
61 if (q_groups > 0 && q_groups * group_dim == q_dim && q_groups * gate_group_dim == gate_dim) {
62 for (int group = 0; group < q_groups; ++group) {
63 const size_t src_group_off = (size_t) group * (size_t) (group_dim + gate_group_dim);
64 memcpy(
65 q_dst + (size_t) group * (size_t) group_dim,
66 src + src_group_off,
67 (size_t) group_dim * sizeof(float));
68 memcpy(
69 gate_dst + (size_t) group * (size_t) gate_group_dim,
70 src + src_group_off + (size_t) group_dim,
71 (size_t) gate_group_dim * sizeof(float));
72 }
73 } else {
74 memcpy(q_dst, src, (size_t) q_dim * sizeof(float));
75 memcpy(gate_dst, src + q_dim, (size_t) gate_dim * sizeof(float));
76 }
77 }
78}

Referenced by ck_test_split_q_gate().

Variable Documentation

◆ ck_hybrid_libm_handle

void* ck_hybrid_libm_handle = NULL
static

Definition at line 16 of file hybrid_attention_kernels.c.

Referenced by ck_bind_hybrid_llama_libm().

◆ ck_hybrid_libm_once

pthread_once_t ck_hybrid_libm_once = PTHREAD_ONCE_INIT
static

Definition at line 17 of file hybrid_attention_kernels.c.

Referenced by hybrid_sigmoid().

◆ ck_hybrid_llama_expf

ck_hybrid_libm_f32_fn ck_hybrid_llama_expf = NULL
static

Definition at line 15 of file hybrid_attention_kernels.c.

Referenced by ck_bind_hybrid_llama_libm(), and hybrid_sigmoid().