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

Go to the source code of this file.

Functions

static void ck_recurrent_conv_state_channel_range (int begin, int end, void *opaque)
 
static int recurrent_conv_backward_extents (int history_len, int num_seqs, int num_tokens, int q_dim, int k_dim, int v_dim, int *channels_out, int *total_len_out, size_t *elements_out)
 
void recurrent_conv_state_update_backward (const float *d_conv_x, const float *d_state_out, float *d_state_in, float *d_q, float *d_k, float *d_v, int history_len, int num_seqs, int num_tokens, int q_dim, int k_dim, int v_dim)
 
void recurrent_conv_state_update_backward_workspace (const float *d_conv_x, const float *d_state_out, float *d_state_in, float *d_q, float *d_k, float *d_v, float *d_conv_total, int history_len, int num_seqs, int num_tokens, int q_dim, int k_dim, int v_dim)
 
void recurrent_conv_state_update_forward (const float *state_in, const float *q, const float *k, const float *v, float *conv_x, float *state_out, int history_len, int num_seqs, int num_tokens, int q_dim, int k_dim, int v_dim)
 

Function Documentation

◆ ck_recurrent_conv_state_channel_range()

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

Definition at line 25 of file recurrent_state_kernels.c.

27 {
28 const ck_recurrent_conv_state_args_t *args =
29 (const ck_recurrent_conv_state_args_t *)opaque;
30
31 const int first_seq = begin / args->channels;
32 const int last_seq = (end - 1) / args->channels;
33 for (int seq = first_seq; seq <= last_seq; ++seq) {
34 int ch_begin = begin - seq * args->channels;
35 int ch_end = end - seq * args->channels;
36 if (ch_begin < 0) ch_begin = 0;
37 if (ch_end > args->channels) ch_end = args->channels;
38
39 const size_t state_seq_offset =
40 (size_t)seq * (size_t)args->channels *
41 (size_t)args->history_len;
42 const size_t conv_seq_offset =
43 (size_t)seq * (size_t)args->channels *
44 (size_t)args->total_len;
45 for (int ch = ch_begin; ch < ch_end; ++ch) {
46 memcpy(
47 args->conv_x + conv_seq_offset +
48 (size_t)ch * (size_t)args->total_len,
49 args->state_in + state_seq_offset +
50 (size_t)ch * (size_t)args->history_len,
51 (size_t)args->history_len * sizeof(float));
52 }
53
54 const int q_begin = ch_begin;
55 const int q_end = ch_end < args->q_dim ? ch_end : args->q_dim;
56 const int k_begin = ch_begin > args->q_dim ?
57 ch_begin - args->q_dim : 0;
58 const int k_end = ch_end < args->q_dim + args->k_dim ?
59 ch_end - args->q_dim : args->k_dim;
60 const int v_begin = ch_begin > args->q_dim + args->k_dim ?
61 ch_begin - args->q_dim - args->k_dim : 0;
62 const int v_end = ch_end - args->q_dim - args->k_dim < args->v_dim ?
63 ch_end - args->q_dim - args->k_dim : args->v_dim;
64
65 for (int tok = 0; tok < args->num_tokens; ++tok) {
66 const int row = seq * args->num_tokens + tok;
67 for (int col = q_begin; col < q_end; ++col) {
68 args->conv_x[conv_seq_offset +
69 (size_t)col * (size_t)args->total_len +
70 (size_t)(args->history_len + tok)] =
71 args->q[(size_t)row * (size_t)args->q_dim + (size_t)col];
72 }
73 for (int col = k_begin; col < k_end; ++col) {
74 args->conv_x[conv_seq_offset +
75 (size_t)(args->q_dim + col) * (size_t)args->total_len +
76 (size_t)(args->history_len + tok)] =
77 args->k[(size_t)row * (size_t)args->k_dim + (size_t)col];
78 }
79 for (int col = v_begin; col < v_end; ++col) {
80 args->conv_x[conv_seq_offset +
81 (size_t)(args->q_dim + args->k_dim + col) *
82 (size_t)args->total_len +
83 (size_t)(args->history_len + tok)] =
84 args->v[(size_t)row * (size_t)args->v_dim + (size_t)col];
85 }
86 }
87
88 for (int ch = ch_begin; ch < ch_end; ++ch) {
89 memcpy(
90 args->state_out + state_seq_offset +
91 (size_t)ch * (size_t)args->history_len,
92 args->conv_x + conv_seq_offset +
93 (size_t)ch * (size_t)args->total_len +
94 (size_t)args->num_tokens,
95 (size_t)args->history_len * sizeof(float));
96 }
97 }
98}
uint32_t end
Definition utf8.c:215

References end.

Referenced by recurrent_conv_state_update_forward().

◆ recurrent_conv_backward_extents()

static int recurrent_conv_backward_extents ( int  history_len,
int  num_seqs,
int  num_tokens,
int  q_dim,
int  k_dim,
int  v_dim,
int *  channels_out,
int *  total_len_out,
size_t *  elements_out 
)
static

Definition at line 155 of file recurrent_state_kernels.c.

163 {
164 if (history_len < 0 || num_seqs <= 0 || num_tokens < 0 || q_dim < 0 ||
165 k_dim < 0 || v_dim < 0 || q_dim > INT_MAX - k_dim ||
166 q_dim + k_dim > INT_MAX - v_dim || history_len > INT_MAX - num_tokens) {
167 return 0;
168 }
169 const int channels = q_dim + k_dim + v_dim;
170 const int total_len = history_len + num_tokens;
171 if (channels == 0 || total_len == 0) {
172 return 0;
173 }
174 size_t elements = (size_t)num_seqs;
175 if ((size_t)total_len > SIZE_MAX / elements) {
176 return 0;
177 }
178 elements *= (size_t)total_len;
179 if ((size_t)channels > SIZE_MAX / elements) {
180 return 0;
181 }
182 *channels_out = channels;
183 *total_len_out = total_len;
184 *elements_out = elements * (size_t)channels;
185 return 1;
186}

Referenced by recurrent_conv_state_update_backward(), and recurrent_conv_state_update_backward_workspace().

◆ recurrent_conv_state_update_backward()

void recurrent_conv_state_update_backward ( const float *  d_conv_x,
const float *  d_state_out,
float *  d_state_in,
float *  d_q,
float *  d_k,
float *  d_v,
int  history_len,
int  num_seqs,
int  num_tokens,
int  q_dim,
int  k_dim,
int  v_dim 
)

Definition at line 257 of file recurrent_state_kernels.c.

268 {
269 int channels = 0;
270 int total_len = 0;
271 size_t elements = 0;
273 history_len, num_seqs, num_tokens, q_dim, k_dim, v_dim,
274 &channels, &total_len, &elements) ||
275 elements > SIZE_MAX / sizeof(float)) {
276 return;
277 }
278 (void)channels;
279 (void)total_len;
280 float *workspace = (float *)malloc(elements * sizeof(float));
281 if (!workspace) {
282 return;
283 }
285 d_conv_x, d_state_out, d_state_in, d_q, d_k, d_v, workspace,
286 history_len, num_seqs, num_tokens, q_dim, k_dim, v_dim);
287 free(workspace);
288}
static int recurrent_conv_backward_extents(int history_len, int num_seqs, int num_tokens, int q_dim, int k_dim, int v_dim, int *channels_out, int *total_len_out, size_t *elements_out)
void recurrent_conv_state_update_backward_workspace(const float *d_conv_x, const float *d_state_out, float *d_state_in, float *d_q, float *d_k, float *d_v, float *d_conv_total, int history_len, int num_seqs, int num_tokens, int q_dim, int k_dim, int v_dim)

References recurrent_conv_backward_extents(), and recurrent_conv_state_update_backward_workspace().

◆ recurrent_conv_state_update_backward_workspace()

void recurrent_conv_state_update_backward_workspace ( const float *  d_conv_x,
const float *  d_state_out,
float *  d_state_in,
float *  d_q,
float *  d_k,
float *  d_v,
float *  d_conv_total,
int  history_len,
int  num_seqs,
int  num_tokens,
int  q_dim,
int  k_dim,
int  v_dim 
)

Definition at line 188 of file recurrent_state_kernels.c.

200 {
201 int channels = 0;
202 int total_len = 0;
203 size_t elements = 0;
204 if (!d_conv_x || !d_state_out || !d_state_in || !d_q || !d_k || !d_v ||
205 !d_conv_total || !recurrent_conv_backward_extents(
206 history_len, num_seqs, num_tokens, q_dim, k_dim, v_dim,
207 &channels, &total_len, &elements)) {
208 return;
209 }
210 if (elements > SIZE_MAX / sizeof(float)) {
211 return;
212 }
213
214 memcpy(d_conv_total, d_conv_x, elements * sizeof(float));
215
216 for (int seq = 0; seq < num_seqs; ++seq) {
217 const float *d_state_out_seq = d_state_out + (size_t) seq * (size_t) channels * (size_t) history_len;
218 float *d_conv_seq = d_conv_total + (size_t) seq * (size_t) channels * (size_t) total_len;
219 for (int ch = 0; ch < channels; ++ch) {
220 float *dst = d_conv_seq + (size_t) ch * (size_t) total_len + (size_t) num_tokens;
221 const float *src = d_state_out_seq + (size_t) ch * (size_t) history_len;
222 for (int idx = 0; idx < history_len; ++idx) {
223 dst[idx] += src[idx];
224 }
225 }
226 }
227
228 for (int seq = 0; seq < num_seqs; ++seq) {
229 const float *d_conv_seq = d_conv_total + (size_t) seq * (size_t) channels * (size_t) total_len;
230 float *d_state_in_seq = d_state_in + (size_t) seq * (size_t) channels * (size_t) history_len;
231
232 for (int ch = 0; ch < channels; ++ch) {
233 memcpy(
234 d_state_in_seq + (size_t) ch * (size_t) history_len,
235 d_conv_seq + (size_t) ch * (size_t) total_len,
236 (size_t) history_len * sizeof(float));
237 }
238
239 for (int tok = 0; tok < num_tokens; ++tok) {
240 const int row = seq * num_tokens + tok;
241 float *d_q_row = d_q + (size_t) row * (size_t) q_dim;
242 float *d_k_row = d_k + (size_t) row * (size_t) k_dim;
243 float *d_v_row = d_v + (size_t) row * (size_t) v_dim;
244 for (int col = 0; col < q_dim; ++col) {
245 d_q_row[col] = d_conv_seq[(size_t) col * (size_t) total_len + (size_t) (history_len + tok)];
246 }
247 for (int col = 0; col < k_dim; ++col) {
248 d_k_row[col] = d_conv_seq[(size_t) (q_dim + col) * (size_t) total_len + (size_t) (history_len + tok)];
249 }
250 for (int col = 0; col < v_dim; ++col) {
251 d_v_row[col] = d_conv_seq[(size_t) (q_dim + k_dim + col) * (size_t) total_len + (size_t) (history_len + tok)];
252 }
253 }
254 }
255}

References recurrent_conv_backward_extents().

Referenced by recurrent_conv_state_update_backward().

◆ recurrent_conv_state_update_forward()

void recurrent_conv_state_update_forward ( const float *  state_in,
const float *  q,
const float *  k,
const float *  v,
float *  conv_x,
float *  state_out,
int  history_len,
int  num_seqs,
int  num_tokens,
int  q_dim,
int  k_dim,
int  v_dim 
)

Definition at line 100 of file recurrent_state_kernels.c.

111 {
112 if (!state_in || !q || !k || !v || !conv_x || !state_out ||
113 history_len < 0 || num_seqs <= 0 || num_tokens < 0 ||
114 q_dim < 0 || k_dim < 0 || v_dim < 0 ||
115 q_dim > INT_MAX - k_dim || q_dim + k_dim > INT_MAX - v_dim ||
116 history_len > INT_MAX - num_tokens) {
117 return;
118 }
119 const int channels = q_dim + k_dim + v_dim;
120 const int total_len = history_len + num_tokens;
121 if (channels <= 0 || total_len <= 0 || num_seqs > INT_MAX / channels ||
122 (num_tokens > 0 && num_seqs > INT_MAX / num_tokens)) {
123 return;
124 }
125
126 ck_recurrent_conv_state_args_t args = {
127 state_in, q, k, v, conv_x, state_out,
128 history_len, num_tokens, q_dim, k_dim, v_dim, channels, total_len,
129 };
130 const int jobs = num_seqs * channels;
131 const size_t elements = (size_t)jobs * (size_t)num_tokens;
132 const size_t minimum_elements_per_thread = 32768u;
133 if (num_tokens <= 1 || elements < 2u * minimum_elements_per_thread) {
135 return;
136 }
137
138 ck_threadpool_t *pool = ck_threadpool_global();
139 int active = pool ? ck_threadpool_n_threads(pool) : 1;
140 size_t useful_threads =
141 (elements + minimum_elements_per_thread - 1u) /
142 minimum_elements_per_thread;
143 if ((size_t)active > useful_threads) active = (int)useful_threads;
144 if (active > jobs) active = jobs;
145
146 if (active > 1 && ck_threadpool_thread_id(pool) <= 0) {
148 pool, active, 0, jobs, 32,
150 } else {
152 }
153}
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 void ck_recurrent_conv_state_channel_range(int begin, int end, void *opaque)

References ck_recurrent_conv_state_channel_range(), ck_threadpool_global(), ck_threadpool_n_threads(), ck_threadpool_parallel_for_n(), and ck_threadpool_thread_id().

Referenced by ck_test_recurrent_conv_state_update().