18#ifndef CK_ENABLE_LLAMA_CPP_PARITY
19#define CK_ENABLE_LLAMA_CPP_PARITY 0
26#if CK_ENABLE_LLAMA_CPP_PARITY
32#define RTLD_DEFAULT ((void *)0)
41#if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__) || defined(__SSE2__)
51 float *key_transpose_scratch;
57} ck_attention_query_key_f32_args_t;
61 ck_attention_query_key_f32_args_t *args =
62 (ck_attention_query_key_f32_args_t *)opaque;
63 const int rows = args->num_heads * args->head_dim;
64 for (
int row = ith; row < rows; row += nth) {
65 const int head = row / args->head_dim;
66 const int dim = row % args->head_dim;
67 const float *key_head = args->key +
68 (size_t)head * args->key_tokens * args->head_dim;
69 float *packed = args->key_transpose_scratch +
70 (size_t)row * args->key_tokens;
71 for (
int key_token = 0; key_token < args->key_tokens; ++key_token) {
73 key_head[(size_t)key_token * args->head_dim + dim];
80 ck_attention_query_key_f32_args_t *args =
81 (ck_attention_query_key_f32_args_t *)opaque;
82 for (
int q_token = ith; q_token < args->query_tokens; q_token += nth) {
83 float *scores = args->score_scratch +
84 (size_t)q_token * args->key_tokens;
85 for (
int head = 0; head < args->num_heads; ++head) {
86 const float *q_head = args->query +
87 (size_t)head * args->query_tokens * args->head_dim;
88 const float *k_head = args->key +
89 (size_t)head * args->key_tokens * args->head_dim;
90 const float *v_head = args->value +
91 (size_t)head * args->key_tokens * args->head_dim;
92 float *out_head = args->output +
93 (size_t)head * args->query_tokens * args->head_dim;
94 const float *q_row = q_head + (size_t)q_token * args->head_dim;
95 float maximum = -FLT_MAX;
97#if defined(__AVX2__) && defined(__FMA__)
98 for (; args->key_transpose_scratch != NULL &&
99 k_token + 7 < args->key_tokens; k_token += 8) {
100 __m256 dots = _mm256_setzero_ps();
101 for (
int dim = 0; dim < args->head_dim; ++dim) {
102 const float *packed = args->key_transpose_scratch +
103 ((size_t)head * args->head_dim + dim) *
104 args->key_tokens + k_token;
105 dots = _mm256_fmadd_ps(
106 _mm256_set1_ps(q_row[dim]),
107 _mm256_loadu_ps(packed), dots);
110 _mm256_storeu_ps(dot_values, dots);
111 for (
int lane = 0; lane < 8; ++lane) {
112 const float score = dot_values[lane] * args->scale;
113 scores[k_token + lane] =
score;
114 maximum = fmaxf(maximum,
score);
118 for (; k_token < args->key_tokens; ++k_token) {
119 const float *k_row = k_head +
120 (size_t)k_token * args->head_dim;
122 for (
int dim = 0; dim < args->head_dim; ++dim) {
123 dot = fmaf(q_row[dim], k_row[dim], dot);
125 const float score = dot * args->scale;
126 scores[k_token] =
score;
127 maximum = fmaxf(maximum,
score);
129 double denominator = 0.0;
130 for (
int k_token = 0; k_token < args->key_tokens; ++k_token) {
131 const float probability = expf(scores[k_token] - maximum);
132 scores[k_token] = probability;
133 denominator += (double)probability;
135 const float inverse = denominator > 0.0 ? (float)(1.0 / denominator) : 0.0f;
136 float *out_row = out_head +
137 (size_t)q_token * args->head_dim;
138 for (
int dim = 0; dim < args->head_dim; ++dim) {
141 for (
int k_token = 0; k_token < args->key_tokens; ++k_token) {
142 const float probability = scores[k_token] * inverse;
143 const float *v_row = v_head +
144 (size_t)k_token * args->head_dim;
145 for (
int dim = 0; dim < args->head_dim; ++dim) {
146 out_row[dim] = fmaf(probability, v_row[dim], out_row[dim]);
158 float *score_scratch,
159 float *key_transpose_scratch,
166 if (query == NULL || key == NULL || value == NULL || output == NULL ||
167 score_scratch == NULL) {
170 if (num_heads <= 0 || query_tokens <= 0 || key_tokens <= 0 ||
171 head_dim <= 0 || !isfinite(scale)) {
174 ck_attention_query_key_f32_args_t args = {
179 .score_scratch = score_scratch,
180 .key_transpose_scratch = key_transpose_scratch,
181 .num_heads = num_heads,
182 .query_tokens = query_tokens,
183 .key_tokens = key_tokens,
184 .head_dim = head_dim,
189 if (key_transpose_scratch != NULL) {
190 int transpose_active = active;
191 const int transpose_rows = num_heads * head_dim;
192 if (transpose_active > transpose_rows) transpose_active = transpose_rows;
193 if (pool && transpose_active > 1) {
200 if (active > query_tokens) active = query_tokens;
201 if (pool && active > 1) {
215 float *score_scratch,
223 query, key, value, output, score_scratch, NULL, num_heads,
224 query_tokens, key_tokens, head_dim, scale);
232 float *score_scratch;
238} ck_attention_query_key_f32_head_args_t;
242 ck_attention_query_key_f32_head_args_t *args =
243 (ck_attention_query_key_f32_head_args_t *)opaque;
244 const size_t query_stride =
245 (size_t)args->query_tokens * (
size_t)args->head_dim;
246 const size_t kv_stride =
247 (size_t)args->key_tokens * (
size_t)args->head_dim;
248 for (
int head = ith; head < args->num_heads; head += nth) {
250 args->query + (
size_t)head * query_stride,
251 args->key + (
size_t)head * kv_stride,
252 args->value + (
size_t)head * kv_stride,
253 args->output + (
size_t)head * query_stride,
254 args->score_scratch + (
size_t)head * args->key_tokens,
255 NULL, 1, args->query_tokens, args->key_tokens,
256 args->head_dim, args->scale);
265 float *score_scratch,
272 if (query == NULL || key == NULL || value == NULL || output == NULL ||
273 score_scratch == NULL)
return -1;
274 if (num_heads <= 0 || query_tokens <= 0 || key_tokens <= 0 ||
275 head_dim <= 0 || !isfinite(scale))
return -2;
277 ck_attention_query_key_f32_head_args_t args = {
282 .score_scratch = score_scratch,
283 .num_heads = num_heads,
284 .query_tokens = query_tokens,
285 .key_tokens = key_tokens,
286 .head_dim = head_dim,
295 if (active > num_heads) active = num_heads;
306 float *score_scratch,
307 float *key_transpose_scratch,
314 if (key_transpose_scratch == NULL)
return -1;
316 query, key, value, output, score_scratch, key_transpose_scratch,
317 num_heads, query_tokens, key_tokens, head_dim, scale);
323 if (!dst || !src)
return;
333 int aligned_head_dim)
335 return ((
size_t)h * (
size_t)num_tokens + (
size_t)t) * (size_t)aligned_head_dim
340 int num_heads,
int num_tokens,
341 int aligned_head_dim,
345 return ((
size_t)
token * (
size_t)num_heads + (
size_t)h) *
346 (size_t)aligned_head_dim;
359#if defined(__AVX2__) && defined(__F16C__)
360 for (; i + 8 <=
count; i += 8) {
361 const __m256 value = _mm256_loadu_ps(src + i);
362 const __m128i half = _mm256_cvtps_ph(
363 value, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
364 _mm256_storeu_ps(dst + i, _mm256_cvtph_ps(half));
367 for (; i <
count; ++i) {
374 if (!src || !dst || n <= 0) {
377 for (
int i = 0; i < n; ++i) {
389 if (!src || !dst || rows <= 0 || cols <= 0) {
392 for (
int r = 0; r < rows; ++r) {
394 dst + (
size_t)r * (
size_t)dst_stride,
399#if defined(__GNUC__) || defined(__clang__)
400#define CK_NOINLINE __attribute__((noinline))
405#if defined(__clang__)
406#define CK_OPTNONE __attribute__((optnone))
407#elif defined(__GNUC__)
408#define CK_OPTNONE __attribute__((optimize("O0")))
418 for (
int i = 0; i < n; ++i) {
419 volatile float prod = x[i] * y[i];
420 volatile float next = sumf + prod;
431 for (
int i = 0; i < n; ++i) {
432 volatile double prod = (double) x[i] * (
double) y[i];
433 volatile double next = sum + prod;
444 for (
int i = n - 1; i >= 0; --i) {
445 volatile float prod = x[i] * y[i];
446 volatile float next = sumf + prod;
462 uint8_t reserved[32];
477 const char *v = getenv(
"CK_STRICT_ATTN_VEC_DUMP");
478 return v && v[0] && strcmp(v,
"0") != 0;
483 const char *v = getenv(
"CK_STRICT_ATTN_DUMP_VCOLS");
484 return v && v[0] && strcmp(v,
"0") != 0;
489 const char *v = getenv(
"CK_STRICT_ATTN_REVERSE_OUT_DOT");
490 return v && v[0] && strcmp(v,
"0") != 0;
493#if CK_ENABLE_LLAMA_CPP_PARITY
496 const char *v = getenv(
"CK_STRICT_ATTN_GGML_OUT_GRAPH");
497 return v && v[0] && strcmp(v,
"0") != 0;
508 const char *v = getenv(name);
513 long parsed = strtol(v, &
end, 10);
514 if (
end == v || (
end && *
end !=
'\0') || parsed < 0 || parsed > INT32_MAX) {
536 const int trace_target = layer_id == want_layer &&
537 (!have_head || head_id == want_head) &&
538 (!have_query || query_id == want_query);
539 if (layer_id != want_layer) {
542 if (have_head && head_id != want_head) {
545 if (have_query && query_id != want_query) {
567 const char *dir = getenv(
"CK_PARITY_DIR");
568 if (!dir || !dir[0] || !name || !name[0] || !data || elem_count == 0) {
573 snprintf(path,
sizeof(path),
"%s/%s", dir,
"strict_internal.bin");
574 FILE *f = fopen(path,
"ab");
579 ck_attention_vec_dump_header_t h;
580 memset(&h, 0,
sizeof(h));
583 h.layer_id = layer_id;
584 strncpy(h.op_name, name,
sizeof(h.op_name) - 1);
587 h.shape[0] = (int64_t) elem_count;
588 h.elem_count = (uint32_t) elem_count;
589 h.token_id = query_id;
591 fwrite(&h,
sizeof(h), 1, f);
592 fwrite(data,
sizeof(
float), elem_count, f);
598 const char *enabled = getenv(
"CK_STRICT_ATTN_TRACE");
599 const char *dir = getenv(
"CK_PARITY_DIR");
600 if (!enabled || !enabled[0] || strcmp(enabled,
"0") == 0 || !dir || !dir[0] || !branch || !branch[0]) {
604 snprintf(path,
sizeof(path),
"%s/%s", dir,
"strict_trace.txt");
605 FILE *f = fopen(path,
"a");
609 fprintf(f,
"layer=%d head=%d branch=%s\n", layer_id, head_id, branch);
619 const char *enabled = getenv(
"CK_STRICT_ATTN_TRACE");
620 const char *dir = getenv(
"CK_PARITY_DIR");
621 if (!enabled || !enabled[0] || strcmp(enabled,
"0") == 0 || !dir || !dir[0] || !tag || !tag[0]) {
625 snprintf(path,
sizeof(path),
"%s/%s", dir,
"strict_trace.txt");
626 FILE *f = fopen(path,
"a");
630 fprintf(f,
"layer=%d head=%d query=%d tag=%s value=%d\n", layer_id, head_id, query_id, tag, value);
639 const char *enabled = getenv(
"CK_STRICT_ATTN_TRACE");
640 const char *dir = getenv(
"CK_PARITY_DIR");
641 if (!enabled || !enabled[0] || strcmp(enabled,
"0") == 0 || !dir || !dir[0] || !tag || !tag[0]) {
645 snprintf(path,
sizeof(path),
"%s/%s", dir,
"strict_trace.txt");
646 FILE *f = fopen(path,
"a");
650 fprintf(f,
"layer=%d head=%d tag=%s float=%.17g\n", layer_id, head_id, tag, (
double) value);
656 const float *out_vec,
669 snprintf(name,
sizeof(name),
"kq_scores_h%d_q%d", head_id, query_id);
671 snprintf(name,
sizeof(name),
"kq_soft_h%d_q%d", head_id, query_id);
673 snprintf(name,
sizeof(name),
"kqv_out_h%d_q%d", head_id, query_id);
676 snprintf(name,
sizeof(name),
"vcols_h%d_q%d", head_id, query_id);
684#if CK_ENABLE_LLAMA_CPP_PARITY
685struct ggml_compute_params;
686typedef void (*ck_ggml_vec_dot_f32_fn)(int,
float *, size_t,
const float *, size_t,
const float *, size_t, int);
687typedef double (*ck_ggml_vec_soft_max_f32_fn)(int,
float *,
const float *, float);
688typedef void (*ck_ggml_compute_forward_mul_mat_fn)(
const struct ggml_compute_params *,
struct ggml_tensor *);
689typedef void (*ck_ggml_compute_forward_soft_max_fn)(
const struct ggml_compute_params *,
struct ggml_tensor *);
693typedef struct ggml_tensor *(*ck_ggml_new_tensor_2d_fn)(
struct ggml_context *,
enum ggml_type, int64_t, int64_t);
694typedef struct ggml_tensor *(*ck_ggml_mul_mat_graph_fn)(
struct ggml_context *,
struct ggml_tensor *,
struct ggml_tensor *);
695typedef struct ggml_cgraph *(*ck_ggml_new_graph_fn)(
struct ggml_context *);
700struct ggml_threadpool;
701struct ggml_compute_params {
705 struct ggml_threadpool * threadpool;
709static void *ck_resolve_ggml_cpu_so_handle(
void)
711 static int tried = 0;
712 static void *handle = NULL;
715 const char *env_path = getenv(
"CK_GGML_CPU_SO");
716 const char *env_dir = getenv(
"CK_GGML_LIB_DIR");
717 const char *dirs[] = {
718 "/opt/app-root/src/Software/llama.cpp/build/bin",
719 "./llama.cpp/build/bin",
720 "llama.cpp/build/bin",
724 if (env_dir && env_dir[0]) {
725 snprintf(path_buf,
sizeof(path_buf),
"%s/libggml-base.so", env_dir);
726 dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
727 snprintf(path_buf,
sizeof(path_buf),
"%s/libggml.so", env_dir);
728 dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
729 snprintf(path_buf,
sizeof(path_buf),
"%s/libggml-cpu.so", env_dir);
730 handle = dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
732 for (
int i = 0; !handle && dirs[i] != NULL; ++i) {
733 snprintf(path_buf,
sizeof(path_buf),
"%s/libggml-base.so", dirs[i]);
734 dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
735 snprintf(path_buf,
sizeof(path_buf),
"%s/libggml.so", dirs[i]);
736 dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
737 snprintf(path_buf,
sizeof(path_buf),
"%s/libggml-cpu.so", dirs[i]);
738 handle = dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
743 if (!handle && env_path && env_path[0]) {
744 handle = dlopen(env_path, RTLD_NOW | RTLD_GLOBAL);
746 const char *candidates[] = {
751 for (
int i = 0; !handle && candidates[i] != NULL; ++i) {
752 handle = dlopen(candidates[i], RTLD_NOW | RTLD_GLOBAL);
758static void *ck_resolve_ggml_symbol(
const char *name)
764 void *handle = ck_resolve_ggml_cpu_so_handle();
768 return dlsym(handle, name);
771static ck_ggml_vec_dot_f32_fn ck_resolve_ggml_vec_dot_f32(
void)
773 static int tried = 0;
774 static ck_ggml_vec_dot_f32_fn fn = NULL;
777 fn = (ck_ggml_vec_dot_f32_fn) ck_resolve_ggml_symbol(
"ggml_vec_dot_f32");
782static ck_ggml_vec_soft_max_f32_fn ck_resolve_ggml_vec_soft_max_f32(
void)
784 static int tried = 0;
785 static ck_ggml_vec_soft_max_f32_fn fn = NULL;
788 fn = (ck_ggml_vec_soft_max_f32_fn) ck_resolve_ggml_symbol(
"ggml_vec_soft_max_f32");
793static ck_ggml_compute_forward_mul_mat_fn ck_resolve_ggml_compute_forward_mul_mat(
void)
795 static int tried = 0;
796 static ck_ggml_compute_forward_mul_mat_fn fn = NULL;
799 fn = (ck_ggml_compute_forward_mul_mat_fn) ck_resolve_ggml_symbol(
"ggml_compute_forward_mul_mat");
804static ck_ggml_compute_forward_soft_max_fn ck_resolve_ggml_compute_forward_soft_max(
void)
806 static int tried = 0;
807 static ck_ggml_compute_forward_soft_max_fn fn = NULL;
810 fn = (ck_ggml_compute_forward_soft_max_fn) ck_resolve_ggml_symbol(
"ggml_compute_forward_soft_max");
817 static int tried = 0;
828 static int tried = 0;
839 static int tried = 0;
850 static int tried = 0;
861 static int tried = 0;
872 static int tried = 0;
883 static int tried = 0;
894 static int tried = 0;
905 static int tried = 0;
914static inline void ck_ggml_init_tensor_f32(
struct ggml_tensor *t,
925 memset(t, 0,
sizeof(*t));
936 t->op = GGML_OP_NONE;
943#define CK_MADD128(x, y, z) _mm_fmadd_ps(x, y, z)
944#define CK_NMADD128(x, y, z) _mm_fnmadd_ps(x, y, z)
946#define CK_MADD128(x, y, z) _mm_add_ps(_mm_mul_ps(x, y), z)
947#define CK_NMADD128(x, y, z) _mm_sub_ps(z, _mm_mul_ps(x, y))
950static inline float ck_hsum128_ps(__m128 v) {
951 v = _mm_add_ps(v, _mm_movehl_ps(v, v));
952 v = _mm_add_ss(v, _mm_movehdup_ps(v));
953 return _mm_cvtss_f32(v);
957#if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__)
958static inline float ck_hsum256_ps(__m256 v) {
959 const __m128 lo = _mm256_castps256_ps128(v);
960 const __m128 hi = _mm256_extractf128_ps(v, 1);
961 return ck_hsum128_ps(_mm_add_ps(lo, hi));
965#if defined(__AVX512F__) && defined(__AVX512DQ__)
966static inline __m512 ck_ggml_v_expf512(__m512 x) {
967 const __m512 r = _mm512_set1_ps(0x1.8p23f);
968 const __m512 z = _mm512_fmadd_ps(x, _mm512_set1_ps(0x1.715476p+0f), r);
969 const __m512 n = _mm512_sub_ps(z, r);
970 const __m512 b = _mm512_fnmadd_ps(
972 _mm512_set1_ps(0x1.7f7d1cp-20f),
973 _mm512_fnmadd_ps(n, _mm512_set1_ps(0x1.62e4p-1f), x));
974 const __mmask16 d = _mm512_cmp_ps_mask(
975 _mm512_abs_ps(n), _mm512_set1_ps(192), _CMP_GT_OQ);
976 const __m512 u = _mm512_mul_ps(b, b);
977 const __m512 j = _mm512_fmadd_ps(
980 _mm512_set1_ps(0x1.0e4020p-7f),
982 _mm512_set1_ps(0x1.573e2ep-5f)),
985 _mm512_set1_ps(0x1.555e66p-3f),
987 _mm512_set1_ps(0x1.fffdb6p-2f))),
990 _mm512_set1_ps(0x1.ffffecp-1f),
992 _mm512_set1_ps(1.0f)));
993 const __m512 res = _mm512_scalef_ps(j, n);
994 if (_mm512_kortestz(d, d)) {
997 const __m512 zero = _mm512_setzero_ps();
998 const __m512 alt = _mm512_mask_blend_ps(
999 _mm512_cmp_ps_mask(n, zero, _CMP_LE_OQ),
1000 _mm512_set1_ps(INFINITY),
1002 return _mm512_mask_blend_ps(d, res, alt);
1006#if defined(__AVX2__) && defined(__FMA__)
1007static inline __m256 ck_ggml_v_expf256(__m256 x) {
1008 const __m256 r = _mm256_set1_ps(0x1.8p23f);
1009 const __m256 z = _mm256_fmadd_ps(x, _mm256_set1_ps(0x1.715476p+0f), r);
1010 const __m256 n = _mm256_sub_ps(z, r);
1011 const __m256 b = _mm256_fnmadd_ps(n, _mm256_set1_ps(0x1.7f7d1cp-20f),
1012 _mm256_fnmadd_ps(n, _mm256_set1_ps(0x1.62e4p-1f), x));
1013 const __m256i e = _mm256_slli_epi32(_mm256_castps_si256(z), 23);
1014 const __m256 k = _mm256_castsi256_ps(
1015 _mm256_add_epi32(e, _mm256_castps_si256(_mm256_set1_ps(1))));
1016 const __m256i c = _mm256_castps_si256(
1017 _mm256_cmp_ps(_mm256_andnot_ps(_mm256_set1_ps(-0.f), n),
1018 _mm256_set1_ps(126), _CMP_GT_OQ));
1019 const __m256 u = _mm256_mul_ps(b, b);
1020 const __m256 j = _mm256_fmadd_ps(
1022 _mm256_fmadd_ps(_mm256_set1_ps(0x1.0e4020p-7f), b, _mm256_set1_ps(0x1.573e2ep-5f)),
1024 _mm256_fmadd_ps(_mm256_set1_ps(0x1.555e66p-3f), b, _mm256_set1_ps(0x1.fffdb6p-2f))),
1026 _mm256_mul_ps(_mm256_set1_ps(0x1.ffffecp-1f), b));
1027 if (!_mm256_movemask_ps(_mm256_castsi256_ps(c))) {
1028 return _mm256_fmadd_ps(j, k, k);
1030 const __m256i g = _mm256_and_si256(
1031 _mm256_castps_si256(_mm256_cmp_ps(n, _mm256_setzero_ps(), _CMP_LE_OQ)),
1032 _mm256_set1_epi32(0x82000000u));
1034 _mm256_castsi256_ps(_mm256_add_epi32(g, _mm256_set1_epi32(0x7f000000u)));
1035 const __m256 s2 = _mm256_castsi256_ps(_mm256_sub_epi32(e, g));
1036 const __m256i d = _mm256_castps_si256(
1037 _mm256_cmp_ps(_mm256_andnot_ps(_mm256_set1_ps(-0.f), n),
1038 _mm256_set1_ps(192), _CMP_GT_OQ));
1039 return _mm256_or_ps(
1040 _mm256_and_ps(_mm256_castsi256_ps(d), _mm256_mul_ps(s1, s1)),
1042 _mm256_castsi256_ps(d),
1044 _mm256_and_ps(_mm256_castsi256_ps(c),
1045 _mm256_mul_ps(_mm256_fmadd_ps(s2, j, s2), s1)),
1046 _mm256_andnot_ps(_mm256_castsi256_ps(c), _mm256_fmadd_ps(k, j, k)))));
1050#if defined(__SSE2__)
1051static inline __m128 ck_ggml_v_expf128(__m128 x) {
1052 const __m128 r = _mm_set1_ps(0x1.8p23f);
1053 const __m128 z = CK_MADD128(x, _mm_set1_ps(0x1.715476p+0f), r);
1054 const __m128 n = _mm_sub_ps(z, r);
1055 const __m128 b = CK_NMADD128(n, _mm_set1_ps(0x1.7f7d1cp-20f),
1056 CK_NMADD128(n, _mm_set1_ps(0x1.62e4p-1f), x));
1057 const __m128i e = _mm_slli_epi32(_mm_castps_si128(z), 23);
1058 const __m128 k = _mm_castsi128_ps(
1059 _mm_add_epi32(e, _mm_castps_si128(_mm_set1_ps(1))));
1060 const __m128i c = _mm_castps_si128(
1061 _mm_cmpgt_ps(_mm_andnot_ps(_mm_set1_ps(-0.f), n), _mm_set1_ps(126)));
1062 const __m128 u = _mm_mul_ps(b, b);
1063 const __m128 j = CK_MADD128(
1065 CK_MADD128(_mm_set1_ps(0x1.0e4020p-7f), b, _mm_set1_ps(0x1.573e2ep-5f)),
1067 CK_MADD128(_mm_set1_ps(0x1.555e66p-3f), b, _mm_set1_ps(0x1.fffdb6p-2f))),
1069 _mm_mul_ps(_mm_set1_ps(0x1.ffffecp-1f), b));
1070 if (!_mm_movemask_ps(_mm_castsi128_ps(c))) {
1071 return CK_MADD128(j, k, k);
1073 const __m128i g = _mm_and_si128(
1074 _mm_castps_si128(_mm_cmple_ps(n, _mm_setzero_ps())),
1075 _mm_set1_epi32(0x82000000u));
1076 const __m128 s1 = _mm_castsi128_ps(_mm_add_epi32(g, _mm_set1_epi32(0x7f000000u)));
1077 const __m128 s2 = _mm_castsi128_ps(_mm_sub_epi32(e, g));
1078 const __m128i d = _mm_castps_si128(
1079 _mm_cmpgt_ps(_mm_andnot_ps(_mm_set1_ps(-0.f), n), _mm_set1_ps(192)));
1081 _mm_and_ps(_mm_castsi128_ps(d), _mm_mul_ps(s1, s1)),
1083 _mm_castsi128_ps(d),
1085 _mm_and_ps(_mm_castsi128_ps(c), _mm_mul_ps(CK_MADD128(s2, j, s2), s1)),
1086 _mm_andnot_ps(_mm_castsi128_ps(c), CK_MADD128(k, j, k)))));
1098 const int np = (n & ~31);
1100 _mm256_setzero_ps(),
1101 _mm256_setzero_ps(),
1102 _mm256_setzero_ps(),
1103 _mm256_setzero_ps(),
1106 for (
int i = 0; i < np; i += 32) {
1107 for (
int j = 0; j < 4; ++j) {
1108 const __m256 ax = _mm256_loadu_ps(x + i + j * 8);
1109 const __m256 ay = _mm256_loadu_ps(y + i + j * 8);
1111 sum[j] = _mm256_fmadd_ps(ax, ay, sum[j]);
1113 sum[j] = _mm256_add_ps(_mm256_mul_ps(ax, ay), sum[j]);
1118 sum[0] = _mm256_add_ps(sum[0], sum[2]);
1119 sum[1] = _mm256_add_ps(sum[1], sum[3]);
1120 sum[0] = _mm256_add_ps(sum[0], sum[1]);
1121 const __m128 t0 = _mm_add_ps(_mm256_castps256_ps128(sum[0]),
1122 _mm256_extractf128_ps(sum[0], 1));
1123 const __m128 t1 = _mm_hadd_ps(t0, t0);
1124 sumf = _mm_cvtss_f32(_mm_hadd_ps(t1, t1));
1126 for (
int i = np; i < n; ++i) {
1127 sumf += x[i] * y[i];
1130#elif defined(__SSE2__)
1132 const int np = (n & ~15);
1140 for (
int i = 0; i < np; i += 16) {
1141 for (
int j = 0; j < 4; ++j) {
1142 const __m128 ax = _mm_loadu_ps(x + i + j * 4);
1143 const __m128 ay = _mm_loadu_ps(y + i + j * 4);
1145 sum[j] = _mm_fmadd_ps(ax, ay, sum[j]);
1147 sum[j] = _mm_add_ps(_mm_mul_ps(ax, ay), sum[j]);
1152 sum[0] = _mm_add_ps(sum[0], sum[2]);
1153 sum[1] = _mm_add_ps(sum[1], sum[3]);
1154 sum[0] = _mm_add_ps(sum[0], sum[1]);
1155#if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__)
1156 sum[0] = _mm_add_ps(sum[0], _mm_movehl_ps(sum[0], sum[0]));
1157 sum[0] = _mm_add_ss(sum[0], _mm_movehdup_ps(sum[0]));
1159 __m128 tmp = _mm_shuffle_ps(sum[0], sum[0], _MM_SHUFFLE(2, 3, 0, 1));
1160 sum[0] = _mm_add_ps(sum[0], tmp);
1161 tmp = _mm_movehl_ps(tmp, sum[0]);
1162 sum[0] = _mm_add_ss(sum[0], tmp);
1164 sumf = _mm_cvtss_f32(sum[0]);
1166 for (
int i = np; i < n; ++i) {
1167 sumf += x[i] * y[i];
1172 for (
int i = 0; i < n; ++i) {
1173 sumf += (double) (x[i] * y[i]);
1175 return (
float) sumf;
1184#if defined(__AVX2__) && defined(__F16C__)
1185 __m256 sum0 = _mm256_setzero_ps();
1186 __m256 sum1 = _mm256_setzero_ps();
1187 __m256 sum2 = _mm256_setzero_ps();
1188 __m256 sum3 = _mm256_setzero_ps();
1189 const int n32 = n & ~31;
1190 for (; i < n32; i += 32) {
1191 const __m256 x0 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (x + i)));
1192 const __m256 y0 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (y + i)));
1193 const __m256 x1 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (x + i + 8)));
1194 const __m256 y1 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (y + i + 8)));
1195 const __m256 x2 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (x + i + 16)));
1196 const __m256 y2 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (y + i + 16)));
1197 const __m256 x3 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (x + i + 24)));
1198 const __m256 y3 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (y + i + 24)));
1200 sum0 = _mm256_fmadd_ps(x0, y0, sum0);
1201 sum1 = _mm256_fmadd_ps(x1, y1, sum1);
1202 sum2 = _mm256_fmadd_ps(x2, y2, sum2);
1203 sum3 = _mm256_fmadd_ps(x3, y3, sum3);
1205 sum0 = _mm256_add_ps(sum0, _mm256_mul_ps(x0, y0));
1206 sum1 = _mm256_add_ps(sum1, _mm256_mul_ps(x1, y1));
1207 sum2 = _mm256_add_ps(sum2, _mm256_mul_ps(x2, y2));
1208 sum3 = _mm256_add_ps(sum3, _mm256_mul_ps(x3, y3));
1211 sum0 = _mm256_add_ps(sum0, sum2);
1212 sum1 = _mm256_add_ps(sum1, sum3);
1213 sum0 = _mm256_add_ps(sum0, sum1);
1214 const __m128 pair = _mm_add_ps(
1215 _mm256_castps256_ps128(sum0),
1216 _mm256_extractf128_ps(sum0, 1));
1217 const __m128 half = _mm_hadd_ps(pair, pair);
1218 float result = _mm_cvtss_f32(_mm_hadd_ps(half, half));
1220 float result = 0.0f;
1222 for (; i < n; ++i) {
1233 volatile float hd = (float) head_dim;
1234 float (*sqrtf_fn)(float) = sqrtf;
1235 volatile float root = sqrtf_fn(hd);
1236 volatile float one = 1.0f;
1237 volatile float scale = one / root;
1245#if defined(__linux__)
1246 static void *libm_handle = NULL;
1248 static int resolved = 0;
1250 libm_handle = dlopen(
"libm.so.6", RTLD_NOW | RTLD_LOCAL);
1263#if defined(__INTEL_LLVM_COMPILER)
1265ck_attention_mul_add_rounded_f32(
float lhs,
float rhs,
float addend)
1272 volatile float product = lhs * rhs;
1273 volatile float result =
product + addend;
1286#if defined(__AVX512F__) && defined(__AVX512DQ__)
1287 for (; i + 15 < n; i += 16) {
1288 const __m512 val = ck_ggml_v_expf512(
1289 _mm512_sub_ps(_mm512_loadu_ps(x + i), _mm512_set1_ps(max)));
1290 _mm512_storeu_ps(y + i, val);
1291 sum += (double) _mm512_reduce_add_ps(val);
1293#elif defined(__AVX2__) && defined(__FMA__)
1294 for (; i + 7 < n; i += 8) {
1295 const __m256 val = ck_ggml_v_expf256(
1296 _mm256_sub_ps(_mm256_loadu_ps(x + i), _mm256_set1_ps(max)));
1297 _mm256_storeu_ps(y + i, val);
1298 __m128 val2 = _mm_add_ps(_mm256_extractf128_ps(val, 1),
1299 _mm256_castps256_ps128(val));
1300 val2 = _mm_add_ps(val2, _mm_movehl_ps(val2, val2));
1301 val2 = _mm_add_ss(val2, _mm_movehdup_ps(val2));
1302 sum += (double) _mm_cvtss_f32(val2);
1304#elif defined(__SSE2__)
1305 for (; i + 3 < n; i += 4) {
1306 const __m128 val = ck_ggml_v_expf128(
1307 _mm_sub_ps(_mm_loadu_ps(x + i), _mm_set1_ps(max)));
1308 _mm_storeu_ps(y + i, val);
1309#if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__)
1310 __m128 acc = _mm_add_ps(val, _mm_movehl_ps(val, val));
1311 acc = _mm_add_ss(acc, _mm_movehdup_ps(acc));
1313 __m128 tmp = _mm_shuffle_ps(val, val, _MM_SHUFFLE(2, 3, 0, 1));
1314 __m128 acc = _mm_add_ps(val, tmp);
1315 tmp = _mm_movehl_ps(tmp, acc);
1316 acc = _mm_add_ss(acc, tmp);
1318 sum += (double) _mm_cvtss_f32(acc);
1322 for (; i < n; ++i) {
1323 const float val = expf(x[i] - max);
1325 sum += (double) val;
1336 int aligned_context_window)
1338 return ((
size_t)h * (
size_t)aligned_context_window * (
size_t)aligned_context_window)
1339 + (size_t)i * (
size_t)aligned_context_window
1363 int aligned_head_dim,
1364 int aligned_context_window)
1366 const float scale = 1.0f / sqrtf((
float)head_dim);
1370 for (
int h = 0; h < num_heads; ++h) {
1371 for (
int i = 0; i < num_tokens; ++i) {
1372 for (
int j = 0; j <= i; ++j) {
1374 size_t base_q =
qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1375 size_t base_k =
qkv_index(h, j, 0, num_tokens, aligned_head_dim);
1377 for (
int d = 0; d < head_dim; ++d) {
1378 dot += q[base_q + d] * k[base_k + d];
1381 scores[
score_index(h, i, j, aligned_context_window)] = dot * scale;
1386 for (
int j = i + 1; j < num_tokens; ++j) {
1387 scores[
score_index(h, i, j, aligned_context_window)] = 0.0f;
1396 aligned_context_window);
1399 for (
int h = 0; h < num_heads; ++h) {
1400 for (
int i = 0; i < num_tokens; ++i) {
1401 size_t out_base =
qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1404 for (
int d = 0; d < aligned_head_dim; ++d) {
1405 output[out_base + d] = 0.0f;
1409 for (
int j = 0; j <= i; ++j) {
1410 float w = scores[
score_index(h, i, j, aligned_context_window)];
1411 size_t v_base =
qkv_index(h, j, 0, num_tokens, aligned_head_dim);
1413 for (
int d = 0; d < head_dim; ++d) {
1414 output[out_base + d] += w * v[v_base + d];
1439 int aligned_head_dim,
1440 int aligned_context_window)
1442 const float scale = 1.0f / sqrtf((
float)head_dim);
1446 for (
int h = 0; h < num_heads; ++h) {
1447 for (
int i = 0; i < num_tokens; ++i) {
1448 for (
int j = 0; j <= i; ++j) {
1450 size_t base_q =
qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1451 size_t base_k =
qkv_index(h, j, 0, num_tokens, aligned_head_dim);
1453 for (
int d = 0; d < head_dim; ++d) {
1454 dot += q[base_q + d] * k[base_k + d];
1457 scores[
score_index(h, i, j, aligned_context_window)] = dot * scale;
1462 for (
int j = i + 1; j < num_tokens; ++j) {
1463 scores[
score_index(h, i, j, aligned_context_window)] = 0.0f;
1472 aligned_context_window);
1475 for (
int h = 0; h < num_heads; ++h) {
1476 for (
int i = 0; i < num_tokens; ++i) {
1477 size_t out_base =
qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1480 for (
int d = 0; d < aligned_head_dim; ++d) {
1481 output[out_base + d] = 0.0f;
1485 for (
int j = 0; j <= i; ++j) {
1486 float w = scores[
score_index(h, i, j, aligned_context_window)];
1487 size_t v_base =
qkv_index(h, j, 0, num_tokens, aligned_head_dim);
1489 for (
int d = 0; d < head_dim; ++d) {
1490 output[out_base + d] += w * v[v_base + d];
1518 int aligned_head_dim,
1519 int aligned_context_window)
1521 const float scale = 1.0f / sqrtf((
float)head_dim);
1523 for (
int h = 0; h < num_heads; ++h) {
1524 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
1525 for (
int i = 0; i < num_tokens; ++i) {
1526 for (
int j = 0; j <= i; ++j) {
1528 size_t base_q =
qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1529 size_t base_k =
qkv_index(kv_head, j, 0, num_tokens, aligned_head_dim);
1531 for (
int d = 0; d < head_dim; ++d) {
1532 dot += q[base_q + d] * k[base_k + d];
1535 scores[
score_index(h, i, j, aligned_context_window)] = dot * scale;
1538 for (
int j = i + 1; j < num_tokens; ++j) {
1539 scores[
score_index(h, i, j, aligned_context_window)] = 0.0f;
1547 aligned_context_window);
1549 for (
int h = 0; h < num_heads; ++h) {
1550 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
1551 for (
int i = 0; i < num_tokens; ++i) {
1552 size_t out_base =
qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1553 for (
int d = 0; d < aligned_head_dim; ++d) {
1554 output[out_base + d] = 0.0f;
1557 for (
int j = 0; j <= i; ++j) {
1558 float w = scores[
score_index(h, i, j, aligned_context_window)];
1559 size_t v_base =
qkv_index(kv_head, j, 0, num_tokens, aligned_head_dim);
1561 for (
int d = 0; d < head_dim; ++d) {
1562 output[out_base + d] += w * v[v_base + d];
1588 int aligned_head_dim,
1589 int aligned_context_window)
1591 const float scale = 1.0f / sqrtf((
float)head_dim);
1593 for (
int h = 0; h < num_heads; ++h) {
1594 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
1595 for (
int i = 0; i < num_tokens; ++i) {
1596 for (
int j = 0; j <= i; ++j) {
1598 size_t base_q =
qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1599 size_t base_k =
qkv_index(kv_head, j, 0, num_tokens, aligned_head_dim);
1601 for (
int d = 0; d < head_dim; ++d) {
1602 dot += q[base_q + d] * k[base_k + d];
1605 scores[
score_index(h, i, j, aligned_context_window)] = dot * scale;
1608 for (
int j = i + 1; j < num_tokens; ++j) {
1609 scores[
score_index(h, i, j, aligned_context_window)] = 0.0f;
1618 aligned_context_window);
1620 for (
int h = 0; h < num_heads; ++h) {
1621 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
1622 for (
int i = 0; i < num_tokens; ++i) {
1623 size_t out_base =
qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1624 for (
int d = 0; d < aligned_head_dim; ++d) {
1625 output[out_base + d] = 0.0f;
1628 for (
int j = 0; j <= i; ++j) {
1629 float w = scores[
score_index(h, i, j, aligned_context_window)];
1630 size_t v_base =
qkv_index(kv_head, j, 0, num_tokens, aligned_head_dim);
1632 for (
int d = 0; d < head_dim; ++d) {
1633 output[out_base + d] += w * v[v_base + d];
1660 int aligned_head_dim,
1661 int aligned_context_window,
1666 const size_t q_elems = (size_t)num_heads * (
size_t)num_tokens * (size_t)aligned_head_dim;
1667 const size_t kv_elems = (size_t)num_kv_heads * (
size_t)num_tokens * (size_t)aligned_head_dim;
1669 if (!scratch_q || !scratch_k || !scratch_v)
return;
1679 num_heads, num_kv_heads,
1680 num_tokens, head_dim,
1681 aligned_head_dim, aligned_context_window);
1699#if defined(__AVX512F__)
1700static void attention_flash_query_causal_avx512(
const float *q_vec,
1701 const float *k_head,
1702 const float *v_head,
1705 int aligned_head_dim,
1710 float m = -INFINITY;
1715 for (; d + 16 <= aligned_head_dim; d += 16) {
1716 _mm512_storeu_ps(&out_vec[d], _mm512_setzero_ps());
1718 for (; d < aligned_head_dim; ++d) {
1722 for (
int j = 0; j < kv_tokens; ++j) {
1723 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
1724 const float *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
1727 __m512 dot_acc = _mm512_setzero_ps();
1729 for (; d + 16 <= head_dim; d += 16) {
1730 __m512 q_v = _mm512_loadu_ps(&q_vec[d]);
1731 __m512 k_v = _mm512_loadu_ps(&k_vec[d]);
1732 dot_acc = _mm512_fmadd_ps(q_v, k_v, dot_acc);
1734 float dot = _mm512_reduce_add_ps(dot_acc);
1736 for (; d < head_dim; ++d) {
1737 dot += q_vec[d] * k_vec[d];
1739 float score = dot * scale;
1742 float exp_m = (m == -INFINITY) ? 0.0f : expf(m -
score);
1746 __m512 exp_m_vec = _mm512_set1_ps(exp_m);
1748 for (; d + 16 <= head_dim; d += 16) {
1749 __m512 out_v = _mm512_loadu_ps(&out_vec[d]);
1750 __m512 v_v = _mm512_loadu_ps(&v_vec[d]);
1751 out_v = _mm512_fmadd_ps(out_v, exp_m_vec, v_v);
1752 _mm512_storeu_ps(&out_vec[d], out_v);
1754 for (; d < head_dim; ++d) {
1755 out_vec[d] = out_vec[d] * exp_m + v_vec[d];
1761 float e = expf(
score - m);
1765 __m512 e_vec = _mm512_set1_ps(e);
1767 for (; d + 16 <= head_dim; d += 16) {
1768 __m512 out_v = _mm512_loadu_ps(&out_vec[d]);
1769 __m512 v_v = _mm512_loadu_ps(&v_vec[d]);
1770 out_v = _mm512_fmadd_ps(e_vec, v_v, out_v);
1771 _mm512_storeu_ps(&out_vec[d], out_v);
1773 for (; d < head_dim; ++d) {
1774 out_vec[d] += e * v_vec[d];
1780 float inv_s = 1.0f / s;
1781 __m512 inv_s_vec = _mm512_set1_ps(inv_s);
1783 for (; d + 16 <= head_dim; d += 16) {
1784 __m512 out_v = _mm512_loadu_ps(&out_vec[d]);
1785 _mm512_storeu_ps(&out_vec[d], _mm512_mul_ps(out_v, inv_s_vec));
1787 for (; d < head_dim; ++d) {
1788 out_vec[d] *= inv_s;
1792 for (d = head_dim; d < aligned_head_dim; ++d) {
1801#if defined(__AVX2__)
1802static inline float hsum256_ps_flash(__m256 v) {
1803 __m128 hi = _mm256_extractf128_ps(v, 1);
1804 __m128 lo = _mm256_castps256_ps128(v);
1805 __m128 sum128 = _mm_add_ps(lo, hi);
1806 sum128 = _mm_hadd_ps(sum128, sum128);
1807 sum128 = _mm_hadd_ps(sum128, sum128);
1808 return _mm_cvtss_f32(sum128);
1811static void attention_flash_query_causal_avx2(
const float *q_vec,
1812 const float *k_head,
1813 const float *v_head,
1816 int aligned_head_dim,
1820 float m = -INFINITY;
1825 for (; d + 8 <= aligned_head_dim; d += 8) {
1826 _mm256_storeu_ps(&out_vec[d], _mm256_setzero_ps());
1828 for (; d < aligned_head_dim; ++d) {
1832 for (
int j = 0; j < kv_tokens; ++j) {
1833 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
1834 const float *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
1837 __m256 dot_acc = _mm256_setzero_ps();
1839 for (; d + 8 <= head_dim; d += 8) {
1840 __m256 q_v = _mm256_loadu_ps(&q_vec[d]);
1841 __m256 k_v = _mm256_loadu_ps(&k_vec[d]);
1842 dot_acc = _mm256_fmadd_ps(q_v, k_v, dot_acc);
1844 float dot = hsum256_ps_flash(dot_acc);
1845 for (; d < head_dim; ++d) {
1846 dot += q_vec[d] * k_vec[d];
1848 float score = dot * scale;
1851 float exp_m = (m == -INFINITY) ? 0.0f : expf(m -
score);
1854 __m256 exp_m_vec = _mm256_set1_ps(exp_m);
1856 for (; d + 8 <= head_dim; d += 8) {
1857 __m256 out_v = _mm256_loadu_ps(&out_vec[d]);
1858 __m256 v_v = _mm256_loadu_ps(&v_vec[d]);
1859 out_v = _mm256_fmadd_ps(out_v, exp_m_vec, v_v);
1860 _mm256_storeu_ps(&out_vec[d], out_v);
1862 for (; d < head_dim; ++d) {
1863 out_vec[d] = out_vec[d] * exp_m + v_vec[d];
1869 float e = expf(
score - m);
1872 __m256 e_vec = _mm256_set1_ps(e);
1874 for (; d + 8 <= head_dim; d += 8) {
1875 __m256 out_v = _mm256_loadu_ps(&out_vec[d]);
1876 __m256 v_v = _mm256_loadu_ps(&v_vec[d]);
1877 out_v = _mm256_fmadd_ps(e_vec, v_v, out_v);
1878 _mm256_storeu_ps(&out_vec[d], out_v);
1880 for (; d < head_dim; ++d) {
1881 out_vec[d] += e * v_vec[d];
1887 float inv_s = 1.0f / s;
1888 __m256 inv_s_vec = _mm256_set1_ps(inv_s);
1890 for (; d + 8 <= head_dim; d += 8) {
1891 __m256 out_v = _mm256_loadu_ps(&out_vec[d]);
1892 _mm256_storeu_ps(&out_vec[d], _mm256_mul_ps(out_v, inv_s_vec));
1894 for (; d < head_dim; ++d) {
1895 out_vec[d] *= inv_s;
1898 for (d = head_dim; d < aligned_head_dim; ++d) {
1907#if defined(__AVX__) && !defined(__AVX2__)
1908static inline float hsum256_ps_flash_avx(__m256 v) {
1909 __m128 hi = _mm256_extractf128_ps(v, 1);
1910 __m128 lo = _mm256_castps256_ps128(v);
1911 __m128 sum128 = _mm_add_ps(lo, hi);
1912 sum128 = _mm_hadd_ps(sum128, sum128);
1913 sum128 = _mm_hadd_ps(sum128, sum128);
1914 return _mm_cvtss_f32(sum128);
1917static void attention_flash_query_causal_avx(
const float *q_vec,
1918 const float *k_head,
1919 const float *v_head,
1922 int aligned_head_dim,
1926 float m = -INFINITY;
1931 for (; d + 8 <= aligned_head_dim; d += 8) {
1932 _mm256_storeu_ps(&out_vec[d], _mm256_setzero_ps());
1934 for (; d < aligned_head_dim; ++d) {
1938 for (
int j = 0; j < kv_tokens; ++j) {
1939 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
1940 const float *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
1943 __m256 dot_acc = _mm256_setzero_ps();
1945 for (; d + 8 <= head_dim; d += 8) {
1946 __m256 q_v = _mm256_loadu_ps(&q_vec[d]);
1947 __m256 k_v = _mm256_loadu_ps(&k_vec[d]);
1948 dot_acc = _mm256_add_ps(dot_acc, _mm256_mul_ps(q_v, k_v));
1950 float dot = hsum256_ps_flash_avx(dot_acc);
1951 for (; d < head_dim; ++d) {
1952 dot += q_vec[d] * k_vec[d];
1954 float score = dot * scale;
1957 float exp_m = (m == -INFINITY) ? 0.0f : expf(m -
score);
1960 __m256 exp_m_vec = _mm256_set1_ps(exp_m);
1962 for (; d + 8 <= head_dim; d += 8) {
1963 __m256 out_v = _mm256_loadu_ps(&out_vec[d]);
1964 __m256 v_v = _mm256_loadu_ps(&v_vec[d]);
1966 out_v = _mm256_add_ps(_mm256_mul_ps(out_v, exp_m_vec), v_v);
1967 _mm256_storeu_ps(&out_vec[d], out_v);
1969 for (; d < head_dim; ++d) {
1970 out_vec[d] = out_vec[d] * exp_m + v_vec[d];
1976 float e = expf(
score - m);
1979 __m256 e_vec = _mm256_set1_ps(e);
1981 for (; d + 8 <= head_dim; d += 8) {
1982 __m256 out_v = _mm256_loadu_ps(&out_vec[d]);
1983 __m256 v_v = _mm256_loadu_ps(&v_vec[d]);
1985 out_v = _mm256_add_ps(out_v, _mm256_mul_ps(e_vec, v_v));
1986 _mm256_storeu_ps(&out_vec[d], out_v);
1988 for (; d < head_dim; ++d) {
1989 out_vec[d] += e * v_vec[d];
1995 float inv_s = 1.0f / s;
1996 __m256 inv_s_vec = _mm256_set1_ps(inv_s);
1998 for (; d + 8 <= head_dim; d += 8) {
1999 __m256 out_v = _mm256_loadu_ps(&out_vec[d]);
2000 _mm256_storeu_ps(&out_vec[d], _mm256_mul_ps(out_v, inv_s_vec));
2002 for (; d < head_dim; ++d) {
2003 out_vec[d] *= inv_s;
2006 for (d = head_dim; d < aligned_head_dim; ++d) {
2016 const float *k_head,
2017 const float *v_head,
2020 int aligned_head_dim,
2027 float m = -INFINITY;
2030 for (
int d = 0; d < head_dim; ++d) {
2034 for (
int j = 0; j < kv_tokens; ++j) {
2035 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
2036 const float *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
2039 for (
int d = 0; d < head_dim; ++d) {
2040 dot += q_vec[d] * k_vec[d];
2042 float score = dot * scale;
2045 float exp_m = (m == -INFINITY) ? 0.0f : expf(m -
score);
2047 for (
int d = 0; d < head_dim; ++d) {
2048 out_vec[d] *= exp_m;
2051 for (
int d = 0; d < head_dim; ++d) {
2052 out_vec[d] += v_vec[d];
2056 float e = expf(
score - m);
2058 for (
int d = 0; d < head_dim; ++d) {
2059 out_vec[d] += e * v_vec[d];
2064 float inv_s = 1.0f / s;
2065 for (
int d = 0; d < head_dim; ++d) {
2066 out_vec[d] *= inv_s;
2068 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2078 const float *k_head,
2079 const float *v_head,
2082 int aligned_head_dim,
2086 if (kv_tokens <= 0) {
2087 for (
int d = 0; d < aligned_head_dim; ++d) {
2093 for (
int d = 0; d < aligned_head_dim; ++d) {
2097 float max_score = -INFINITY;
2098 for (
int j = 0; j < kv_tokens; ++j) {
2099 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
2101 for (
int d = 0; d < head_dim; ++d) {
2102 dot += q_vec[d] * k_vec[d];
2104 float score = dot * scale;
2105 if (
score > max_score) {
2111 for (
int j = 0; j < kv_tokens; ++j) {
2112 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
2113 const float *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
2115 for (
int d = 0; d < head_dim; ++d) {
2116 dot += q_vec[d] * k_vec[d];
2118 float score = dot * scale;
2119 float w = expf(
score - max_score);
2121 for (
int d = 0; d < head_dim; ++d) {
2122 out_vec[d] += w * v_vec[d];
2127 float inv_sum = 1.0f / sum;
2128 for (
int d = 0; d < head_dim; ++d) {
2129 out_vec[d] *= inv_sum;
2132 for (
int d = 0; d < head_dim; ++d) {
2136 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2142 const float *k_head,
2143 const float *out_vec,
2146 int aligned_head_dim,
2156 float *raw_scores = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
2157 float *probs = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
2158 float max_score = -INFINITY;
2159 for (
int j = 0; j < kv_tokens; ++j) {
2160 const float *k_vec = k_head + (size_t) j * (
size_t) aligned_head_dim;
2162 for (
int d = 0; d < head_dim; ++d) {
2163 dot += q_vec[d] * k_vec[d];
2165 raw_scores[j] = dot;
2166 const float scaled = dot * scale;
2168 if (scaled > max_score) {
2174 for (
int j = 0; j < kv_tokens; ++j) {
2175 probs[j] = expf(probs[j] - max_score);
2179 const float inv_sum = 1.0f / sum;
2180 for (
int j = 0; j < kv_tokens; ++j) {
2181 probs[j] *= inv_sum;
2184 memset(probs, 0, (
size_t) kv_tokens *
sizeof(
float));
2188 kv_tokens, head_dim,
2189 layer_id, head_id, query_id);
2194 const float *k_head,
2195 const float *v_head,
2198 int aligned_head_dim,
2202 if (kv_tokens <= 0) {
2203 for (
int d = 0; d < aligned_head_dim; ++d) {
2209 for (
int d = 0; d < aligned_head_dim; ++d) {
2218 float max_score = -INFINITY;
2219 for (
int j = 0; j < kv_tokens; ++j) {
2220 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
2221 const float *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
2223 for (
int d = 0; d < head_dim; ++d) {
2226 float score = dot * scale;
2228 const float prev_max = max_score;
2229 float max_scale = 1.0f;
2230 float value_scale = 1.0f;
2232 if (
score > max_score) {
2234 max_scale = isfinite(prev_max) ? expf(prev_max - max_score) : 0.0f;
2235 for (
int d = 0; d < head_dim; ++d) {
2239 value_scale = expf(
score - max_score);
2242 for (
int d = 0; d < head_dim; ++d) {
2244 const float updated = out_vec[d] + value_scale * v_rounded;
2248 sum = sum * max_scale + value_scale;
2252 float inv_sum = 1.0f / sum;
2253 for (
int d = 0; d < head_dim; ++d) {
2254 out_vec[d] *= inv_sum;
2257 for (
int d = 0; d < head_dim; ++d) {
2261 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2269 const float *q_vec,
const float *k_head,
const float *v_head,
2270 int kv_tokens,
int head_dim,
int aligned_head_dim,
float scale,
2273 if (kv_tokens <= 0) {
2274 memset(out_vec, 0, (
size_t)aligned_head_dim *
sizeof(
float));
2278 float *q_rounded = (
float *)alloca((
size_t)head_dim *
sizeof(float));
2280 memset(out_vec, 0, (
size_t)aligned_head_dim *
sizeof(
float));
2283 float max_score = -INFINITY;
2284 for (
int j = 0; j < kv_tokens; ++j) {
2285 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
2286 const float *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
2288 for (
int d = 0; d < head_dim; ++d) {
2289 dot += q_rounded[d] * k_vec[d];
2291 const float score = dot * scale;
2292 const float prev_max = max_score;
2293 float max_scale = 1.0f;
2294 float value_scale = 1.0f;
2295 if (
score > max_score) {
2297 max_scale = isfinite(prev_max) ? expf(prev_max - max_score) : 0.0f;
2298 for (
int d = 0; d < head_dim; ++d) {
2302 value_scale = expf(
score - max_score);
2304 for (
int d = 0; d < head_dim; ++d) {
2305 const float updated = out_vec[d] + value_scale * v_vec[d];
2308 sum = sum * max_scale + value_scale;
2312 const float inv_sum = 1.0f / sum;
2313 for (
int d = 0; d < head_dim; ++d) {
2314 out_vec[d] *= inv_sum;
2317 memset(out_vec, 0, (
size_t)head_dim *
sizeof(
float));
2322 const float *k_head,
2323 const float *v_cols,
2326 int aligned_head_dim,
2334 if (kv_tokens <= 0) {
2335 for (
int d = 0; d < aligned_head_dim; ++d) {
2341 for (
int j = 0; j < kv_tokens; ++j) {
2342 const float *k_vec = k_head + (size_t) j * (
size_t) aligned_head_dim;
2345 float *raw_dump = NULL;
2347 raw_dump = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
2348 memcpy(raw_dump, score_row, (
size_t) kv_tokens *
sizeof(
float));
2351 float max_score = -INFINITY;
2352 for (
int j = 0; j < kv_tokens; ++j) {
2353 const float score = score_row[j] * scale;
2354 score_row[j] =
score;
2355 if (
score > max_score) {
2361 for (
int j = 0; j < kv_tokens; ++j) {
2362 const float w = expf(score_row[j] - max_score);
2364 volatile double next = sum + (double) w;
2369 const float inv_sum = (float) (1.0 / sum);
2370 for (
int j = 0; j < kv_tokens; ++j) {
2371 score_row[j] *= inv_sum;
2373 for (
int d = 0; d < head_dim; ++d) {
2374 const float *v_col = v_cols + (size_t) d * (
size_t) kv_tokens;
2379 for (
int d = 0; d < head_dim; ++d) {
2384 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2389 layer_id, head_id, query_id);
2394 const float *k_head,
2395 const float *v_cols,
2398 int aligned_head_dim,
2406 if (kv_tokens <= 0) {
2407 for (
int d = 0; d < aligned_head_dim; ++d) {
2413 for (
int j = 0; j < kv_tokens; ++j) {
2414 const float *k_vec = k_head + (size_t) j * (
size_t) aligned_head_dim;
2417 float *raw_dump = NULL;
2419 raw_dump = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
2420 memcpy(raw_dump, score_row, (
size_t) kv_tokens *
sizeof(
float));
2423 float *logit_row = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
2424 memcpy(logit_row, score_row, (
size_t) kv_tokens *
sizeof(
float));
2429 const float inv_sum = (float) (1.0 / sum);
2431 for (
int d = 0; d < head_dim; ++d) {
2432 const float *v_col = v_cols + (size_t) d * (
size_t) kv_tokens;
2436 for (
int d = 0; d < head_dim; ++d) {
2441 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2446 layer_id, head_id, query_id);
2450#if CK_ENABLE_LLAMA_CPP_PARITY
2452 const float *k_head,
2453 const float *v_cols,
2456 int aligned_head_dim,
2461 ck_ggml_vec_dot_f32_fn dot_fn,
2462 ck_ggml_vec_soft_max_f32_fn softmax_fn,
2467 if (kv_tokens <= 0 || !dot_fn || !softmax_fn || !score_row || !prob_row) {
2468 for (
int d = 0; d < aligned_head_dim; ++d) {
2474 for (
int j = 0; j < kv_tokens; ++j) {
2475 const float *k_vec = k_head + (size_t) j * (
size_t) aligned_head_dim;
2477 dot_fn(head_dim, &dot, 0, q_vec, 0, k_vec, 0, 1);
2480 float *raw_dump = NULL;
2482 raw_dump = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
2483 memcpy(raw_dump, score_row, (
size_t) kv_tokens *
sizeof(
float));
2489 memcpy(prob_row, score_row, (
size_t) kv_tokens *
sizeof(
float));
2492 const double sum = softmax_fn(kv_tokens, score_row, prob_row, max_score);
2494 const float inv_sum = (float) (1.0 / sum);
2497 for (
int d = 0; d < head_dim; ++d) {
2498 const float *v_col = v_cols + (size_t) d * (
size_t) kv_tokens;
2499 if (reverse_out_dot) {
2503 dot_fn(kv_tokens, &dot, 0, score_row, 0, v_col, 0, 1);
2508 for (
int d = 0; d < head_dim; ++d) {
2513 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2518 layer_id, head_id, query_id);
2522static int attention_out_mul_mat_graph_block(
const float *v_cols,
2523 const float *prob_block,
2539 if (!ggml_cpu_init_fn || !ggml_init_fn || !ggml_free_fn ||
2540 !ggml_new_tensor_2d_fn || !ggml_mul_mat_fn || !ggml_new_graph_fn ||
2541 !ggml_build_forward_expand_fn || !ggml_graph_compute_with_ctx_fn ||
2542 !ggml_set_input_fn || !v_cols || !prob_block || !out_block ||
2543 kv_tokens <= 0 || head_dim <= 0 || query_block <= 0) {
2549 const size_t out_bytes = (size_t) head_dim * (
size_t) query_block *
sizeof(float);
2550 const size_t mem_size = (size_t) 8 * 1024 * 1024 + out_bytes + (
size_t) 512 * 1024;
2556 struct ggml_context *ctx = ggml_init_fn(params);
2562 struct ggml_tensor *v_tensor = ggml_new_tensor_2d_fn(ctx,
GGML_TYPE_F32, kv_tokens, head_dim);
2563 struct ggml_tensor *prob_tensor = ggml_new_tensor_2d_fn(ctx,
GGML_TYPE_F32, kv_tokens, query_block);
2564 if (!v_tensor || !prob_tensor) {
2569 v_tensor->data = (
void *) v_cols;
2570 prob_tensor->data = (
void *) prob_block;
2571 ggml_set_input_fn(v_tensor);
2572 ggml_set_input_fn(prob_tensor);
2574 struct ggml_tensor *out_tensor = ggml_mul_mat_fn(ctx, v_tensor, prob_tensor);
2575 struct ggml_cgraph *gf = out_tensor ? ggml_new_graph_fn(ctx) : NULL;
2576 if (!out_tensor || !gf) {
2581 ggml_build_forward_expand_fn(gf, out_tensor);
2583 memcpy(out_block, out_tensor->data, out_bytes);
2591static CK_NOINLINE CK_OPTNONE int attention_head_full_dyn_ggml_regular_graph_out(
const float *q_head,
2592 const float *k_head,
2593 const float *v_cols,
2596 int aligned_head_dim,
2601 ck_ggml_vec_dot_f32_fn dot_fn,
2602 ck_ggml_vec_soft_max_f32_fn softmax_fn,
2606 if (!q_head || !k_head || !v_cols || !out_head || !dot_fn || !softmax_fn ||
2607 kv_tokens <= 0 || head_dim <= 0 || aligned_head_dim < head_dim) {
2611 enum { CK_STRICT_OUT_BLOCK = 64 };
2612 float *prob_block = (
float *) alloca((
size_t) CK_STRICT_OUT_BLOCK * (size_t) kv_tokens *
sizeof(
float));
2613 float *out_block = (
float *) alloca((
size_t) CK_STRICT_OUT_BLOCK * (size_t) head_dim *
sizeof(
float));
2614 float *raw_dump = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
2615 for (
int q0 = 0; q0 < kv_tokens; q0 += CK_STRICT_OUT_BLOCK) {
2616 const int qn = (q0 + CK_STRICT_OUT_BLOCK <= kv_tokens) ? CK_STRICT_OUT_BLOCK : (kv_tokens - q0);
2617 float *block_probs = prob_block;
2618 float *block_out = out_block;
2619 int have_raw_dump = 0;
2620 int dump_query = -1;
2623 for (
int qi = 0; qi < qn; ++qi) {
2624 const int query_id = q0 + qi;
2625 const float *q_vec = q_head + (size_t) query_id * (
size_t) aligned_head_dim;
2626 float *prob_col = block_probs + (size_t) qi * (
size_t) kv_tokens;
2628 for (
int j = 0; j < kv_tokens; ++j) {
2629 const float *k_vec = k_head + (size_t) j * (
size_t) aligned_head_dim;
2631 dot_fn(head_dim, &dot, 0, q_vec, 0, k_vec, 0, 1);
2636 memcpy(raw_dump, score_row, (
size_t) kv_tokens *
sizeof(
float));
2638 dump_query = query_id;
2642 memcpy(prob_row, score_row, (
size_t) kv_tokens *
sizeof(
float));
2645 const double sum = softmax_fn(kv_tokens, prob_col, prob_row, max_score);
2647 const float inv_sum = (float) (1.0 / sum);
2650 memset(prob_col, 0, (
size_t) kv_tokens *
sizeof(
float));
2654 if (!attention_out_mul_mat_graph_block(v_cols, block_probs, kv_tokens, head_dim, qn, block_out)) {
2658 for (
int qi = 0; qi < qn; ++qi) {
2659 float *dst = out_head + (size_t) (q0 + qi) * (size_t) aligned_head_dim;
2660 const float *src = block_out + (size_t) qi * (
size_t) head_dim;
2661 memcpy(dst, src, (
size_t) head_dim *
sizeof(
float));
2662 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2667 if (have_raw_dump && dump_qi >= 0) {
2669 block_probs + (
size_t) dump_qi * (
size_t) kv_tokens,
2670 block_out + (
size_t) dump_qi * (
size_t) head_dim,
2683static CK_NOINLINE CK_OPTNONE void attention_query_full_dyn_ggml_regular_matmul_out(
const float *q_vec,
2684 const float *k_head,
2685 const float *v_cols,
2688 int aligned_head_dim,
2693 ck_ggml_vec_dot_f32_fn dot_fn,
2694 ck_ggml_vec_soft_max_f32_fn softmax_fn,
2695 ck_ggml_compute_forward_mul_mat_fn mul_mat_fn,
2700 if (kv_tokens <= 0 || !dot_fn || !softmax_fn || !mul_mat_fn || !score_row || !prob_row) {
2701 for (
int d = 0; d < aligned_head_dim; ++d) {
2707 for (
int j = 0; j < kv_tokens; ++j) {
2708 const float *k_vec = k_head + (size_t) j * (
size_t) aligned_head_dim;
2710 dot_fn(head_dim, &dot, 0, q_vec, 0, k_vec, 0, 1);
2713 float *raw_dump = NULL;
2715 raw_dump = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
2716 memcpy(raw_dump, score_row, (
size_t) kv_tokens *
sizeof(
float));
2719 memcpy(prob_row, score_row, (
size_t) kv_tokens *
sizeof(
float));
2722 const double sum = softmax_fn(kv_tokens, score_row, prob_row, max_score);
2724 const float inv_sum = (float) (1.0 / sum);
2727 const size_t prob_row_bytes = (size_t) kv_tokens *
sizeof(
float);
2728 const size_t out_row_bytes = (size_t) head_dim *
sizeof(
float);
2730 struct ggml_tensor v_tensor;
2731 struct ggml_tensor prob_tensor;
2732 struct ggml_tensor out_tensor;
2734 ck_ggml_init_tensor_f32(&v_tensor,
2735 kv_tokens, head_dim, 1, 1,
2738 prob_row_bytes * (
size_t) head_dim,
2739 prob_row_bytes * (
size_t) head_dim,
2741 ck_ggml_init_tensor_f32(&prob_tensor,
2748 ck_ggml_init_tensor_f32(&out_tensor,
2755 out_tensor.src[0] = &v_tensor;
2756 out_tensor.src[1] = &prob_tensor;
2758 memset(out_vec, 0, (
size_t) head_dim *
sizeof(
float));
2759 struct ggml_compute_params mul_params = {
2767 mul_mat_fn(&mul_params, &out_tensor);
2769 for (
int d = 0; d < head_dim; ++d) {
2774 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2779 layer_id, head_id, query_id);
2784 const float *k_head,
2785 const float *v_cols,
2788 int aligned_head_dim,
2793 ck_ggml_vec_dot_f32_fn dot_fn,
2794 ck_ggml_compute_forward_mul_mat_fn mul_mat_fn,
2795 ck_ggml_compute_forward_soft_max_fn softmax_compute_fn)
2797 if (kv_tokens <= 0 || !dot_fn || !mul_mat_fn || !softmax_compute_fn) {
2798 for (
int d = 0; d < aligned_head_dim; ++d) {
2804 const size_t k_row_bytes = (size_t) aligned_head_dim *
sizeof(
float);
2805 const size_t q_row_bytes = (size_t) head_dim *
sizeof(
float);
2806 const size_t score_row_bytes = (size_t) kv_tokens *
sizeof(
float);
2807 const size_t softmax_work_elems = (size_t) kv_tokens + 16u;
2808 float *softmax_work = (
float *) alloca(softmax_work_elems *
sizeof(
float));
2810 struct ggml_tensor k_tensor;
2811 struct ggml_tensor q_tensor;
2812 struct ggml_tensor score_tensor;
2813 struct ggml_tensor soft_tensor;
2815 ck_ggml_init_tensor_f32(&k_tensor,
2816 head_dim, kv_tokens, 1, 1,
2819 k_row_bytes * (
size_t) kv_tokens,
2820 k_row_bytes * (
size_t) kv_tokens,
2822 ck_ggml_init_tensor_f32(&q_tensor,
2829 ck_ggml_init_tensor_f32(&score_tensor,
2836 score_tensor.src[0] = &k_tensor;
2837 score_tensor.src[1] = &q_tensor;
2839 struct ggml_compute_params mul_params = {
2847 mul_mat_fn(&mul_params, &score_tensor);
2849 ck_ggml_init_tensor_f32(&soft_tensor,
2856 soft_tensor.src[0] = &score_tensor;
2858 const float max_bias = 0.0f;
2859 memcpy((
char *) soft_tensor.op_params + 0, &scale,
sizeof(
float));
2860 memcpy((
char *) soft_tensor.op_params +
sizeof(
float), &max_bias,
sizeof(
float));
2863 struct ggml_compute_params soft_params = {
2866 .wsize = softmax_work_elems *
sizeof(float),
2867 .wdata = softmax_work,
2871 softmax_compute_fn(&soft_params, &soft_tensor);
2873 for (
int d = 0; d < head_dim; ++d) {
2874 const float *v_col = v_cols + (size_t) d * (
size_t) kv_tokens;
2876 dot_fn(kv_tokens, &dot, 0, prob_row, 0, v_col, 0, 1);
2880 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2888#define CK_GGML_FA_TILE_Q 64
2889#define CK_GGML_FA_TILE_Q_LARGE 336
2890#define CK_GGML_FA_TILE_KV 64
2891#define CK_GGML_FA_TILE_Q_LARGE_MIN_TOKENS 1536
2895 for (
int i = 0; i < n; ++i) {
2902 float max_val = -INFINITY;
2903 for (
int i = 0; i < n; ++i) {
2904 if (x[i] > max_val) {
2911#if defined(__AVX512F__)
2912static inline void ck_attention_simd_gemm_ukernel_4x4(
float *c,
2919 for (
int i = 0; i < 4; ++i) {
2920 for (
int r = 0; r < 4; ++r) {
2921 acc[i][r] = _mm512_loadu_ps(
2922 c + (
size_t) i * (
size_t) n + (
size_t) r * 16u);
2926 for (
int kk = 0; kk < k; ++kk) {
2928 for (
int r = 0; r < 4; ++r) {
2929 bv[r] = _mm512_loadu_ps(
2930 b + (
size_t) kk * (
size_t) n + (
size_t) r * 16u);
2932 for (
int i = 0; i < 4; ++i) {
2933 const __m512 p = _mm512_set1_ps(
2934 a[(
size_t) i * (
size_t) k + (
size_t) kk]);
2935 for (
int r = 0; r < 4; ++r) {
2936 acc[i][r] = _mm512_fmadd_ps(bv[r], p, acc[i][r]);
2941 for (
int i = 0; i < 4; ++i) {
2942 for (
int r = 0; r < 4; ++r) {
2944 c + (
size_t) i * (
size_t) n + (
size_t) r * 16u,
2950static inline void ck_attention_simd_gemm_ukernel_4x1(
float *c,
2957 for (
int i = 0; i < 4; ++i) {
2958 acc[i] = _mm512_loadu_ps(c + (
size_t) i * (
size_t) n);
2960 for (
int kk = 0; kk < k; ++kk) {
2961 const __m512 bv = _mm512_loadu_ps(b + (
size_t) kk * (
size_t) n);
2962 for (
int i = 0; i < 4; ++i) {
2963 const __m512 p = _mm512_set1_ps(
2964 a[(
size_t) i * (
size_t) k + (
size_t) kk]);
2965 acc[i] = _mm512_fmadd_ps(bv, p, acc[i]);
2968 for (
int i = 0; i < 4; ++i) {
2969 _mm512_storeu_ps(c + (
size_t) i * (
size_t) n, acc[i]);
2973static inline void ck_attention_simd_gemm_ukernel_1x4(
float *c,
2980 for (
int r = 0; r < 4; ++r) {
2981 acc[r] = _mm512_loadu_ps(c + (
size_t) r * 16u);
2983 for (
int kk = 0; kk < k; ++kk) {
2984 const __m512 p = _mm512_set1_ps(a[kk]);
2985 for (
int r = 0; r < 4; ++r) {
2986 const __m512 bv = _mm512_loadu_ps(
2987 b + (
size_t) kk * (
size_t) n + (
size_t) r * 16u);
2988 acc[r] = _mm512_fmadd_ps(bv, p, acc[r]);
2991 for (
int r = 0; r < 4; ++r) {
2992 _mm512_storeu_ps(c + (
size_t) r * 16u, acc[r]);
2996static inline void ck_attention_simd_gemm_ukernel_1x1(
float *c,
3002 __m512 acc = _mm512_loadu_ps(c);
3003 for (
int kk = 0; kk < k; ++kk) {
3004 const __m512 bv = _mm512_loadu_ps(b + (
size_t) kk * (
size_t) n);
3005 const __m512 p = _mm512_set1_ps(a[kk]);
3006 acc = _mm512_fmadd_ps(bv, p, acc);
3008 _mm512_storeu_ps(c, acc);
3019 for (; ii + 4 <= m; ii += 4) {
3021 for (; jj + 64 <= n; jj += 64) {
3022 ck_attention_simd_gemm_ukernel_4x4(c + jj, a, b + jj, k, n);
3024 for (; jj + 16 <= n; jj += 16) {
3025 ck_attention_simd_gemm_ukernel_4x1(c + jj, a, b + jj, k, n);
3027 for (; jj < n; ++jj) {
3028 for (
int i = 0; i < 4; ++i) {
3029 float sum = c[(size_t) i * (
size_t) n + (size_t) jj];
3030 for (
int kk = 0; kk < k; ++kk) {
3031 sum += a[(size_t) i * (
size_t) k + (size_t) kk] *
3032 b[(
size_t) kk * (size_t) n + (
size_t) jj];
3034 c[(size_t) i * (
size_t) n + (size_t) jj] = sum;
3037 a += (size_t) 4 * (
size_t) k;
3038 c += (size_t) 4 * (
size_t) n;
3041 for (; ii < m; ++ii) {
3043 for (; jj + 64 <= n; jj += 64) {
3044 ck_attention_simd_gemm_ukernel_1x4(c + jj, a, b + jj, k, n);
3046 for (; jj + 16 <= n; jj += 16) {
3047 ck_attention_simd_gemm_ukernel_1x1(c + jj, a, b + jj, k, n);
3049 for (; jj < n; ++jj) {
3051 for (
int kk = 0; kk < k; ++kk) {
3052 sum += a[kk] * b[(size_t) kk * (
size_t) n + (size_t) jj];
3060#elif defined(__AVX__) || defined(__AVX2__)
3061static inline void ck_attention_simd_gemm_ukernel_6x2(
float *c,
3068 for (
int i = 0; i < 6; ++i) {
3069 acc[i][0] = _mm256_loadu_ps(c + (
size_t) i * (
size_t) n + 0);
3070 acc[i][1] = _mm256_loadu_ps(c + (
size_t) i * (
size_t) n + 8);
3073 for (
int kk = 0; kk < k; ++kk) {
3074 const __m256 bv0 = _mm256_loadu_ps(b + (
size_t) kk * (
size_t) n + 0);
3075 const __m256 bv1 = _mm256_loadu_ps(b + (
size_t) kk * (
size_t) n + 8);
3076 for (
int i = 0; i < 6; ++i) {
3077 const __m256 p = _mm256_set1_ps(a[(
size_t) i * (
size_t) k + (
size_t) kk]);
3079 acc[i][0] = _mm256_fmadd_ps(bv0, p, acc[i][0]);
3080 acc[i][1] = _mm256_fmadd_ps(bv1, p, acc[i][1]);
3082 acc[i][0] = _mm256_add_ps(_mm256_mul_ps(bv0, p), acc[i][0]);
3083 acc[i][1] = _mm256_add_ps(_mm256_mul_ps(bv1, p), acc[i][1]);
3088 for (
int i = 0; i < 6; ++i) {
3089 _mm256_storeu_ps(c + (
size_t) i * (
size_t) n + 0, acc[i][0]);
3090 _mm256_storeu_ps(c + (
size_t) i * (
size_t) n + 8, acc[i][1]);
3094static inline void ck_attention_simd_gemm_ukernel_6x1(
float *c,
3101 for (
int i = 0; i < 6; ++i) {
3102 acc[i] = _mm256_loadu_ps(c + (
size_t) i * (
size_t) n);
3105 for (
int kk = 0; kk < k; ++kk) {
3106 const __m256 bv = _mm256_loadu_ps(b + (
size_t) kk * (
size_t) n);
3107 for (
int i = 0; i < 6; ++i) {
3108 const __m256 p = _mm256_set1_ps(a[(
size_t) i * (
size_t) k + (
size_t) kk]);
3110 acc[i] = _mm256_fmadd_ps(bv, p, acc[i]);
3112 acc[i] = _mm256_add_ps(_mm256_mul_ps(bv, p), acc[i]);
3117 for (
int i = 0; i < 6; ++i) {
3118 _mm256_storeu_ps(c + (
size_t) i * (
size_t) n, acc[i]);
3122static inline void ck_attention_simd_gemm_ukernel_1x2(
float *c,
3128 __m256 acc0 = _mm256_loadu_ps(c + 0);
3129 __m256 acc1 = _mm256_loadu_ps(c + 8);
3130 for (
int kk = 0; kk < k; ++kk) {
3131 const __m256 bv0 = _mm256_loadu_ps(b + (
size_t) kk * (
size_t) n + 0);
3132 const __m256 bv1 = _mm256_loadu_ps(b + (
size_t) kk * (
size_t) n + 8);
3133 const __m256 p = _mm256_set1_ps(a[kk]);
3135 acc0 = _mm256_fmadd_ps(bv0, p, acc0);
3136 acc1 = _mm256_fmadd_ps(bv1, p, acc1);
3138 acc0 = _mm256_add_ps(_mm256_mul_ps(bv0, p), acc0);
3139 acc1 = _mm256_add_ps(_mm256_mul_ps(bv1, p), acc1);
3142 _mm256_storeu_ps(c + 0, acc0);
3143 _mm256_storeu_ps(c + 8, acc1);
3146static inline void ck_attention_simd_gemm_ukernel_1x1(
float *c,
3152 __m256 acc = _mm256_loadu_ps(c);
3153 for (
int kk = 0; kk < k; ++kk) {
3154 const __m256 bv = _mm256_loadu_ps(b + (
size_t) kk * (
size_t) n);
3155 const __m256 p = _mm256_set1_ps(a[kk]);
3157 acc = _mm256_fmadd_ps(bv, p, acc);
3159 acc = _mm256_add_ps(_mm256_mul_ps(bv, p), acc);
3162 _mm256_storeu_ps(c, acc);
3173 for (; ii + 6 <= m; ii += 6) {
3175 for (; jj + 16 <= n; jj += 16) {
3176 ck_attention_simd_gemm_ukernel_6x2(c + jj, a, b + jj, k, n);
3178 for (; jj + 8 <= n; jj += 8) {
3179 ck_attention_simd_gemm_ukernel_6x1(c + jj, a, b + jj, k, n);
3181 for (; jj < n; ++jj) {
3182 for (
int i = 0; i < 6; ++i) {
3183 float sum = c[(size_t) i * (
size_t) n + (size_t) jj];
3184 for (
int kk = 0; kk < k; ++kk) {
3185 sum += a[(size_t) i * (
size_t) k + (size_t) kk] * b[(
size_t) kk * (size_t) n + (
size_t) jj];
3187 c[(size_t) i * (
size_t) n + (size_t) jj] = sum;
3190 a += (size_t) 6 * (
size_t) k;
3191 c += (size_t) 6 * (
size_t) n;
3194 for (; ii < m; ++ii) {
3196 for (; jj + 16 <= n; jj += 16) {
3197 ck_attention_simd_gemm_ukernel_1x2(c + jj, a, b + jj, k, n);
3199 for (; jj + 8 <= n; jj += 8) {
3200 ck_attention_simd_gemm_ukernel_1x1(c + jj, a, b + jj, k, n);
3202 for (; jj < n; ++jj) {
3204 for (
int kk = 0; kk < k; ++kk) {
3205 sum += a[kk] * b[(size_t) kk * (
size_t) n + (size_t) jj];
3213#elif defined(__SSE2__)
3214static inline void ck_attention_simd_gemm_ukernel_2x2(
float *c,
3221 for (
int i = 0; i < 2; ++i) {
3222 acc[i][0] = _mm_loadu_ps(c + (
size_t) i * (
size_t) n + 0);
3223 acc[i][1] = _mm_loadu_ps(c + (
size_t) i * (
size_t) n + 4);
3226 for (
int kk = 0; kk < k; ++kk) {
3227 const __m128 bv0 = _mm_loadu_ps(b + (
size_t) kk * (
size_t) n + 0);
3228 const __m128 bv1 = _mm_loadu_ps(b + (
size_t) kk * (
size_t) n + 4);
3229 for (
int i = 0; i < 2; ++i) {
3230 const __m128 p = _mm_set1_ps(a[(
size_t) i * (
size_t) k + (
size_t) kk]);
3232 acc[i][0] = _mm_fmadd_ps(bv0, p, acc[i][0]);
3233 acc[i][1] = _mm_fmadd_ps(bv1, p, acc[i][1]);
3235 acc[i][0] = _mm_add_ps(_mm_mul_ps(bv0, p), acc[i][0]);
3236 acc[i][1] = _mm_add_ps(_mm_mul_ps(bv1, p), acc[i][1]);
3241 for (
int i = 0; i < 2; ++i) {
3242 _mm_storeu_ps(c + (
size_t) i * (
size_t) n + 0, acc[i][0]);
3243 _mm_storeu_ps(c + (
size_t) i * (
size_t) n + 4, acc[i][1]);
3247static inline void ck_attention_simd_gemm_ukernel_2x1(
float *c,
3254 for (
int i = 0; i < 2; ++i) {
3255 acc[i] = _mm_loadu_ps(c + (
size_t) i * (
size_t) n);
3258 for (
int kk = 0; kk < k; ++kk) {
3259 const __m128 bv = _mm_loadu_ps(b + (
size_t) kk * (
size_t) n);
3260 for (
int i = 0; i < 2; ++i) {
3261 const __m128 p = _mm_set1_ps(a[(
size_t) i * (
size_t) k + (
size_t) kk]);
3263 acc[i] = _mm_fmadd_ps(bv, p, acc[i]);
3265 acc[i] = _mm_add_ps(_mm_mul_ps(bv, p), acc[i]);
3270 for (
int i = 0; i < 2; ++i) {
3271 _mm_storeu_ps(c + (
size_t) i * (
size_t) n, acc[i]);
3275static inline void ck_attention_simd_gemm_ukernel_1x2(
float *c,
3281 __m128 acc0 = _mm_loadu_ps(c + 0);
3282 __m128 acc1 = _mm_loadu_ps(c + 4);
3283 for (
int kk = 0; kk < k; ++kk) {
3284 const __m128 bv0 = _mm_loadu_ps(b + (
size_t) kk * (
size_t) n + 0);
3285 const __m128 bv1 = _mm_loadu_ps(b + (
size_t) kk * (
size_t) n + 4);
3286 const __m128 p = _mm_set1_ps(a[kk]);
3288 acc0 = _mm_fmadd_ps(bv0, p, acc0);
3289 acc1 = _mm_fmadd_ps(bv1, p, acc1);
3291 acc0 = _mm_add_ps(_mm_mul_ps(bv0, p), acc0);
3292 acc1 = _mm_add_ps(_mm_mul_ps(bv1, p), acc1);
3295 _mm_storeu_ps(c + 0, acc0);
3296 _mm_storeu_ps(c + 4, acc1);
3299static inline void ck_attention_simd_gemm_ukernel_1x1(
float *c,
3305 __m128 acc = _mm_loadu_ps(c);
3306 for (
int kk = 0; kk < k; ++kk) {
3307 const __m128 bv = _mm_loadu_ps(b + (
size_t) kk * (
size_t) n);
3308 const __m128 p = _mm_set1_ps(a[kk]);
3310 acc = _mm_fmadd_ps(bv, p, acc);
3312 acc = _mm_add_ps(_mm_mul_ps(bv, p), acc);
3315 _mm_storeu_ps(c, acc);
3326 for (; ii + 2 <= m; ii += 2) {
3328 for (; jj + 8 <= n; jj += 8) {
3329 ck_attention_simd_gemm_ukernel_2x2(c + jj, a, b + jj, k, n);
3331 for (; jj + 4 <= n; jj += 4) {
3332 ck_attention_simd_gemm_ukernel_2x1(c + jj, a, b + jj, k, n);
3334 for (; jj < n; ++jj) {
3335 for (
int i = 0; i < 2; ++i) {
3336 float sum = c[(size_t) i * (
size_t) n + (size_t) jj];
3337 for (
int kk = 0; kk < k; ++kk) {
3338 sum += a[(size_t) i * (
size_t) k + (size_t) kk] * b[(
size_t) kk * (size_t) n + (
size_t) jj];
3340 c[(size_t) i * (
size_t) n + (size_t) jj] = sum;
3343 a += (size_t) 2 * (
size_t) k;
3344 c += (size_t) 2 * (
size_t) n;
3347 for (; ii < m; ++ii) {
3349 for (; jj + 8 <= n; jj += 8) {
3350 ck_attention_simd_gemm_ukernel_1x2(c + jj, a, b + jj, k, n);
3352 for (; jj + 4 <= n; jj += 4) {
3353 ck_attention_simd_gemm_ukernel_1x1(c + jj, a, b + jj, k, n);
3355 for (; jj < n; ++jj) {
3357 for (
int kk = 0; kk < k; ++kk) {
3358 sum += a[kk] * b[(size_t) kk * (
size_t) n + (size_t) jj];
3374 for (
int i = 0; i < m; ++i) {
3375 float *c_row = c + (size_t) i * (
size_t) n;
3376 const float *a_row = a + (size_t) i * (
size_t) k;
3377 for (
int kk = 0; kk < k; ++kk) {
3378 const float a_ik = a_row[kk];
3379 const float *b_row = b + (size_t) kk * (
size_t) n;
3380 for (
int j = 0; j < n; ++j) {
3381 c_row[j] += a_ik * b_row[j];
3397 int aligned_head_dim,
3398 int kv_stride_tokens,
3399 int query_tile_size,
3403 if (!q || !k || !v || !output || num_heads <= 0 || num_kv_heads <= 0 ||
3404 num_tokens <= 0 || head_dim <= 0 || aligned_head_dim < head_dim ||
3405 kv_stride_tokens < num_tokens || num_heads % num_kv_heads != 0 ||
3406 query_tile_size <= 0) {
3411 const int T = num_tokens;
3412 const size_t kv_head_stride = (size_t) kv_stride_tokens * (
size_t) aligned_head_dim;
3414 float *q_tile = (
float *) alloca((
size_t) query_tile_size * (size_t) head_dim *
sizeof(
float));
3415 float *k_tile = (
float *) alloca((
size_t) head_dim * (size_t)
CK_GGML_FA_TILE_KV *
sizeof(
float));
3416 float *v_tile = (
float *) alloca((
size_t)
CK_GGML_FA_TILE_KV * (size_t) head_dim *
sizeof(
float));
3417 float *kq = (
float *) alloca((
size_t) query_tile_size * (size_t)
CK_GGML_FA_TILE_KV *
sizeof(
float));
3418 float *vkq = (
float *) alloca((
size_t) query_tile_size * (size_t) head_dim *
sizeof(
float));
3419 float *sum_row = (
float *) alloca((
size_t) query_tile_size *
sizeof(float));
3420 float *max_row = (
float *) alloca((
size_t) query_tile_size *
sizeof(float));
3422 const int total_rows = num_heads * T;
3423 const int rows_per_worker = (total_rows + nth - 1) / nth;
3424 int ir = rows_per_worker * ith;
3425 const int ir1 = (ir + rows_per_worker) < total_rows
3426 ? (ir + rows_per_worker)
3430 const int h = ir / T;
3431 const int iq = ir - h * T;
3432 int tile_rows = ir1 - ir;
3433 if (tile_rows > query_tile_size) tile_rows = query_tile_size;
3434 if (tile_rows > T - iq) tile_rows = T - iq;
3435 const int kv_head = (int) ((
long long) h * (
long long) num_kv_heads / (
long long) num_heads);
3436 const float *k_head = k + (size_t) kv_head * kv_head_stride;
3437 const float *v_head = v + (size_t) kv_head * kv_head_stride;
3439 for (
int tq = 0; tq < query_tile_size; ++tq) {
3441 max_row[tq] = -INFINITY;
3444 memset(vkq, 0, (
size_t) query_tile_size * (
size_t) head_dim *
sizeof(
float));
3445 memset(q_tile, 0, (
size_t) query_tile_size * (
size_t) head_dim *
sizeof(
float));
3449 for (
int tq = 0; tq < tile_rows; ++tq) {
3450 const float *q_vec = q +
qkv_index(h, iq + tq, 0, T, aligned_head_dim);
3451 memcpy(q_tile + (
size_t) tq * (
size_t) head_dim, q_vec, (
size_t) head_dim *
sizeof(
float));
3456 memset(kq, 0, (
size_t) query_tile_size * (
size_t)
CK_GGML_FA_TILE_KV *
sizeof(
float));
3458 for (
int tk = 0; tk < kv_tile; ++tk) {
3459 const float *k_vec = k_head + (size_t) (ik + tk) * (size_t) aligned_head_dim;
3460 const float *v_vec = v_head + (size_t) (ik + tk) * (size_t) aligned_head_dim;
3461 for (
int d = 0; d < head_dim; ++d) {
3464 v_tile[(size_t) tk * (
size_t) head_dim + (size_t) d] =
3480 for (
int tq = 0; tq < query_tile_size; ++tq) {
3483 kq_row[tk] = -INFINITY;
3488 for (
int tq = 0; tq < tile_rows; ++tq) {
3491 if (tile_max == -INFINITY) {
3496 const float old_max = max_row[tq];
3497 const float new_max = old_max > tile_max ? old_max : tile_max;
3498 if (new_max > old_max) {
3505 max_row[tq] = new_max;
3506 sum_row[tq] = (float) (
3507 (
double) sum_row[tq] +
3520 for (
int tq = 0; tq < tile_rows; ++tq) {
3521 float *out_vec = output +
qkv_index(h, iq + tq, 0, T, aligned_head_dim);
3522 const float inv_sum = sum_row[tq] == 0.0f ? 0.0f : (1.0f / sum_row[tq]);
3523 for (
int d = 0; d < head_dim; ++d) {
3524 out_vec[d] = vkq[(size_t) tq * (
size_t) head_dim + (size_t) d] * inv_sum;
3526 for (
int d = head_dim; d < aligned_head_dim; ++d) {
3543 int aligned_head_dim;
3544 int kv_stride_tokens;
3545 int query_tile_size;
3546} ck_attention_full_tiled_f16kv_fp32_args_t;
3550 ck_attention_full_tiled_f16kv_fp32_args_t *args =
3551 (ck_attention_full_tiled_f16kv_fp32_args_t *) opaque;
3553 args->q, args->k, args->v, args->output,
3554 args->num_heads, args->num_kv_heads, args->num_tokens,
3555 args->head_dim, args->aligned_head_dim, args->kv_stride_tokens,
3556 args->query_tile_size,
3569 int aligned_head_dim,
3570 int kv_stride_tokens,
3571 int query_tile_size)
3573 if (!q || !k || !v || !output || num_heads <= 0 || num_kv_heads <= 0 ||
3574 num_tokens <= 0 || head_dim <= 0 || aligned_head_dim < head_dim ||
3575 kv_stride_tokens < num_tokens || num_heads % num_kv_heads != 0) {
3579 ck_attention_full_tiled_f16kv_fp32_args_t args = {
3584 .num_heads = num_heads,
3585 .num_kv_heads = num_kv_heads,
3586 .num_tokens = num_tokens,
3587 .head_dim = head_dim,
3588 .aligned_head_dim = aligned_head_dim,
3589 .kv_stride_tokens = kv_stride_tokens,
3590 .query_tile_size = query_tile_size,
3594 if (pool && active > 1) {
3610 int aligned_head_dim,
3611 int kv_stride_tokens)
3617 q, k, v, output, num_heads, num_kv_heads, num_tokens,
3618 head_dim, aligned_head_dim, kv_stride_tokens, query_tile_size);
3630 int aligned_head_dim,
3631 int kv_stride_tokens)
3634 q, k, v, output, num_heads, num_kv_heads, num_tokens,
3647 int aligned_head_dim,
3648 int kv_stride_tokens)
3651 q, k, v, output, num_heads, num_kv_heads, num_tokens,
3666 if (!query || !key || !value || !output || num_heads <= 0 ||
3667 query_tokens <= 0 || key_tokens != query_tokens || head_dim <= 0) {
3672 if (scale != contract_scale) {
3680 query, key, value, output,
3681 num_heads, num_heads, query_tokens,
3682 head_dim, head_dim, key_tokens, query_tile_size);
3708 int aligned_head_dim;
3709 int kv_stride_tokens;
3711 int output_token_major;
3713} ck_attention_parallel_args_t;
3716 const float *k_head,
3717 const float *v_head,
3720 int aligned_head_dim,
3724#if defined(__AVX512F__)
3725 attention_flash_query_causal_avx512(q_vec, k_head, v_head,
3726 kv_tokens, head_dim, aligned_head_dim,
3728#elif defined(__AVX2__)
3729 attention_flash_query_causal_avx2(q_vec, k_head, v_head,
3730 kv_tokens, head_dim, aligned_head_dim,
3732#elif defined(__AVX__)
3733 attention_flash_query_causal_avx(q_vec, k_head, v_head,
3734 kv_tokens, head_dim, aligned_head_dim,
3738 kv_tokens, head_dim, aligned_head_dim,
3744#if defined(__AVX512F__)
3745static int ck_attention_qblock4_enabled(
void)
3747 static int cached = -1;
3754static int ck_attention_qblock8_enabled(
void)
3756 static int cached = -1;
3763static int ck_attention_qblock_fast_exp_enabled(
void)
3765 static int cached = -1;
3772static inline float ck_attention_qblock_fast_expf(
float x)
3774 if (x > 88.0f) x = 88.0f;
3775 else if (x < -88.0f) x = -88.0f;
3777 const float log2e = 1.4426950408889634f;
3778 const float z = x * log2e;
3779 const float zf = nearbyintf(z);
3780 const float f = z - zf;
3782 const float c0 = 1.0f;
3783 const float c1 = 0.6931471805599453f;
3784 const float c2 = 0.2402265069591007f;
3785 const float c3 = 0.05550410866482158f;
3786 const float c4 = 0.009618129107628478f;
3788 float poly = ((c4 * f + c3) * f + c2) * f + c1;
3789 poly = poly * f + c0;
3791 union { uint32_t i;
float f; } u;
3792 u.i = (uint32_t)((int32_t)zf + 127) << 23;
3796static inline float ck_attention_qblock_expf(
float x)
3798 return ck_attention_qblock_fast_exp_enabled() ? ck_attention_qblock_fast_expf(x) : expf(x);
3801static inline float ck_attention_dot72_avx512(
const float *q_vec,
const float *k_vec)
3803 __m512 acc = _mm512_setzero_ps();
3804 acc = _mm512_fmadd_ps(_mm512_loadu_ps(q_vec + 0), _mm512_loadu_ps(k_vec + 0), acc);
3805 acc = _mm512_fmadd_ps(_mm512_loadu_ps(q_vec + 16), _mm512_loadu_ps(k_vec + 16), acc);
3806 acc = _mm512_fmadd_ps(_mm512_loadu_ps(q_vec + 32), _mm512_loadu_ps(k_vec + 32), acc);
3807 acc = _mm512_fmadd_ps(_mm512_loadu_ps(q_vec + 48), _mm512_loadu_ps(k_vec + 48), acc);
3808 float dot = _mm512_reduce_add_ps(acc);
3809 for (
int d = 64; d < 72; ++d) {
3810 dot += q_vec[d] * k_vec[d];
3815static void attention_flash_query4_full_avx512(
const float *q_head,
3816 const float *k_head,
3817 const float *v_head,
3821 int aligned_head_dim,
3825 float m[4] = { -INFINITY, -INFINITY, -INFINITY, -INFINITY };
3826 float ssum[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
3828 for (
int r = 0; r < q_count; ++r) {
3829 for (
int d = 0; d < 72; ++d) out[r][d] = 0.0f;
3832 const float *qv[4] = { NULL, NULL, NULL, NULL };
3833 for (
int r = 0; r < q_count; ++r) {
3834 qv[r] = q_head + (size_t)(q0 + r) * (size_t)aligned_head_dim;
3837 for (
int j = 0; j < kv_tokens; ++j) {
3838 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
3839 const float *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
3844 for (
int r = 0; r < q_count; ++r) {
3845 score[r] = ck_attention_dot72_avx512(qv[r], k_vec) * scale;
3846 if (
score[r] > m[r]) {
3847 scale_old[r] = (m[r] == -INFINITY) ? 0.0f : ck_attention_qblock_expf(m[r] -
score[r]);
3849 ssum[r] *= scale_old[r];
3853 scale_old[r] = 1.0f;
3854 scale_v[r] = ck_attention_qblock_expf(
score[r] - m[r]);
3855 ssum[r] += scale_v[r];
3859 for (
int d = 0; d < 72; d += 16) {
3860 const int width = (d + 16 <= 72) ? 16 : (72 - d);
3862 const __m512 vv = _mm512_loadu_ps(v_vec + d);
3863 for (
int r = 0; r < q_count; ++r) {
3864 __m512 ov = _mm512_loadu_ps(out[r] + d);
3865 ov = _mm512_fmadd_ps(ov, _mm512_set1_ps(scale_old[r]), _mm512_mul_ps(_mm512_set1_ps(scale_v[r]), vv));
3866 _mm512_storeu_ps(out[r] + d, ov);
3869 for (
int r = 0; r < q_count; ++r) {
3870 for (
int t = 0; t < width; ++t) {
3871 out[r][d + t] = out[r][d + t] * scale_old[r] + scale_v[r] * v_vec[d + t];
3878 for (
int r = 0; r < q_count; ++r) {
3879 float *dst = out_head + (size_t)(q0 + r) * (size_t)aligned_head_dim;
3880 const float inv = ssum[r] == 0.0f ? 0.0f : (1.0f / ssum[r]);
3881 const __m512 invv = _mm512_set1_ps(inv);
3882 for (
int d = 0; d + 16 <= 72; d += 16) {
3883 _mm512_storeu_ps(dst + d, _mm512_mul_ps(_mm512_loadu_ps(out[r] + d), invv));
3885 for (
int d = 64; d < 72; ++d) dst[d] = out[r][d] * inv;
3886 for (
int d = 72; d < aligned_head_dim; ++d) dst[d] = 0.0f;
3889static void attention_flash_query8_full_avx512(
const float *q_head,
3890 const float *k_head,
3891 const float *v_head,
3895 int aligned_head_dim,
3899 float m[8] = { -INFINITY, -INFINITY, -INFINITY, -INFINITY, -INFINITY, -INFINITY, -INFINITY, -INFINITY };
3900 float ssum[8] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
3902 for (
int r = 0; r < q_count; ++r) {
3903 for (
int d = 0; d < 72; ++d) out[r][d] = 0.0f;
3906 const float *qv[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
3907 for (
int r = 0; r < q_count; ++r) {
3908 qv[r] = q_head + (size_t)(q0 + r) * (size_t)aligned_head_dim;
3911 for (
int j = 0; j < kv_tokens; ++j) {
3912 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
3913 const float *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
3918 for (
int r = 0; r < q_count; ++r) {
3919 score[r] = ck_attention_dot72_avx512(qv[r], k_vec) * scale;
3920 if (
score[r] > m[r]) {
3921 scale_old[r] = (m[r] == -INFINITY) ? 0.0f : ck_attention_qblock_expf(m[r] -
score[r]);
3923 ssum[r] *= scale_old[r];
3927 scale_old[r] = 1.0f;
3928 scale_v[r] = ck_attention_qblock_expf(
score[r] - m[r]);
3929 ssum[r] += scale_v[r];
3933 for (
int d = 0; d < 72; d += 16) {
3934 const int width = (d + 16 <= 72) ? 16 : (72 - d);
3936 const __m512 vv = _mm512_loadu_ps(v_vec + d);
3937 for (
int r = 0; r < q_count; ++r) {
3938 __m512 ov = _mm512_loadu_ps(out[r] + d);
3939 ov = _mm512_fmadd_ps(ov, _mm512_set1_ps(scale_old[r]), _mm512_mul_ps(_mm512_set1_ps(scale_v[r]), vv));
3940 _mm512_storeu_ps(out[r] + d, ov);
3943 for (
int r = 0; r < q_count; ++r) {
3944 for (
int t = 0; t < width; ++t) {
3945 out[r][d + t] = out[r][d + t] * scale_old[r] + scale_v[r] * v_vec[d + t];
3952 for (
int r = 0; r < q_count; ++r) {
3953 float *dst = out_head + (size_t)(q0 + r) * (size_t)aligned_head_dim;
3954 const float inv = ssum[r] == 0.0f ? 0.0f : (1.0f / ssum[r]);
3955 const __m512 invv = _mm512_set1_ps(inv);
3956 for (
int d = 0; d + 16 <= 72; d += 16) {
3957 _mm512_storeu_ps(dst + d, _mm512_mul_ps(_mm512_loadu_ps(out[r] + d), invv));
3959 for (
int d = 64; d < 72; ++d) dst[d] = out[r][d] * inv;
3960 for (
int d = 72; d < aligned_head_dim; ++d) dst[d] = 0.0f;
3972 int aligned_head_dim;
3973 int kv_stride_tokens;
3975} ck_attention_qblock4_args_t;
3977static void ck_attention_full_qblock4_work(
int ith,
int nth,
void *opaque)
3979 ck_attention_qblock4_args_t *args = (ck_attention_qblock4_args_t *) opaque;
3980 const int T = args->num_tokens;
3981 const int q_blocks = (T + 3) / 4;
3982 const int total = args->num_heads * q_blocks;
3983 const size_t head_stride = (size_t)T * (
size_t)args->aligned_head_dim;
3984 const size_t kv_head_stride = (size_t)args->kv_stride_tokens * (
size_t)args->aligned_head_dim;
3986 for (
int idx = ith; idx < total; idx += nth) {
3987 const int h = idx / q_blocks;
3988 const int qb = idx - h * q_blocks;
3989 const int q0 = qb * 4;
3990 const int q_count = (q0 + 4 <= T) ? 4 : (T - q0);
3991 const int kv_head = (int)((
long long)h * (
long long)args->num_kv_heads / (
long long)args->num_heads);
3992 const float *q_head = args->q + (size_t)h * head_stride;
3993 const float *k_head = args->k + (size_t)kv_head * kv_head_stride;
3994 const float *v_head = args->v + (size_t)kv_head * kv_head_stride;
3995 float *out_head = args->output + (size_t)h * head_stride;
3996 attention_flash_query4_full_avx512(q_head, k_head, v_head,
3998 args->aligned_head_dim,
4004static void ck_attention_full_qblock8_work(
int ith,
int nth,
void *opaque)
4006 ck_attention_qblock4_args_t *args = (ck_attention_qblock4_args_t *) opaque;
4007 const int T = args->num_tokens;
4008 const int q_blocks = (T + 7) / 8;
4009 const int total = args->num_heads * q_blocks;
4010 const size_t head_stride = (size_t)T * (
size_t)args->aligned_head_dim;
4011 const size_t kv_head_stride = (size_t)args->kv_stride_tokens * (
size_t)args->aligned_head_dim;
4013 for (
int idx = ith; idx < total; idx += nth) {
4014 const int h = idx / q_blocks;
4015 const int qb = idx - h * q_blocks;
4016 const int q0 = qb * 8;
4017 const int q_count = (q0 + 8 <= T) ? 8 : (T - q0);
4018 const int kv_head = (int)((
long long)h * (
long long)args->num_kv_heads / (
long long)args->num_heads);
4019 const float *q_head = args->q + (size_t)h * head_stride;
4020 const float *k_head = args->k + (size_t)kv_head * kv_head_stride;
4021 const float *v_head = args->v + (size_t)kv_head * kv_head_stride;
4022 float *out_head = args->output + (size_t)h * head_stride;
4023 attention_flash_query8_full_avx512(q_head, k_head, v_head,
4025 args->aligned_head_dim,
4035 ck_attention_parallel_args_t *args = (ck_attention_parallel_args_t *) opaque;
4036 const int T = args->num_tokens;
4037 const int total = args->num_heads * T;
4038 const size_t kv_head_stride = (size_t) args->kv_stride_tokens * (
size_t) args->aligned_head_dim;
4040 for (
int idx = ith; idx < total; idx += nth) {
4041 const int h = idx / T;
4042 const int i = idx - h * T;
4043 const int kv_head = (int) ((
long long) h * (
long long) args->num_kv_heads / (
long long) args->num_heads);
4044 const float *k_head = args->k + (size_t) kv_head * kv_head_stride;
4045 const float *v_head = args->v + (size_t) kv_head * kv_head_stride;
4046 const float *q_vec = args->q +
qkv_index(h, i, 0, T, args->aligned_head_dim);
4048 h, i, args->num_heads, T, args->aligned_head_dim,
4049 args->output_token_major);
4050 const int kv_tokens = args->causal ? (i + 1) : T;
4054 args->aligned_head_dim,
4062 const char *disable = getenv(
"CK_DISABLE_ATTENTION_THREADPOOL");
4063 if (disable && disable[0] && strcmp(disable,
"0") != 0)
return 0;
4070 if (total_queries < 1024 || num_tokens < 128 || head_dim <= 0)
return 0;
4077 if (nth <= 1)
return 1;
4078 const char *cap_env = getenv(
"CK_ATTENTION_THREAD_CAP");
4079 int cap = cap_env && cap_env[0] ? atoi(cap_env) : 24;
4080 if (cap < 1) cap = 1;
4081 if (cap > nth) cap = nth;
4082 int active = (total_queries + 127) / 128;
4083 if (num_tokens >= 1024 && active < 8) active = 8;
4084 if (active > cap) active = cap;
4085 if (active > nth) active = nth;
4086 return active < 1 ? 1 : active;
4091 const char *value = getenv(
"CK_STRICT_ATTN_F16_UNFUSED");
4092 return !value || !value[0] || strcmp(value,
"0") != 0;
4104 int aligned_head_dim,
4105 int kv_stride_tokens,
4107 int output_token_major,
4111 const int T = num_tokens;
4112 const size_t kv_head_stride = (size_t) kv_stride_tokens * (
size_t) aligned_head_dim;
4113 const size_t kv_half_count = (size_t) T * (
size_t) aligned_head_dim;
4114 uint16_t *k_half = (uint16_t *) malloc(kv_half_count *
sizeof(uint16_t));
4115 uint16_t *v_half = (uint16_t *) malloc(kv_half_count *
sizeof(uint16_t));
4116 if (!k_half || !v_half) {
4121 uint16_t *q_half = (uint16_t *) alloca((
size_t) aligned_head_dim *
sizeof(uint16_t));
4122 uint16_t *prob_half = (uint16_t *) alloca((
size_t) T *
sizeof(uint16_t));
4123 uint16_t *v_col_half = (uint16_t *) alloca((
size_t) T *
sizeof(uint16_t));
4124 float *raw_scores = (
float *) alloca((
size_t) T *
sizeof(float));
4125 float *logits = (
float *) alloca((
size_t) T *
sizeof(float));
4126 int cached_kv_head = -1;
4128 for (
int h = 0; h < num_heads; ++h) {
4129 const int kv_head = (int) ((
long long) h * (
long long) num_kv_heads /
4130 (
long long) num_heads);
4131 const float *k_head = k + (size_t) kv_head * kv_head_stride;
4132 const float *v_head = v + (size_t) kv_head * kv_head_stride;
4133 if (kv_head != cached_kv_head) {
4134 for (
size_t idx = 0; idx < kv_half_count; ++idx) {
4138 cached_kv_head = kv_head;
4141 for (
int i = 0; i < T; ++i) {
4142 const float *q_vec = q +
qkv_index(h, i, 0, T, aligned_head_dim);
4144 h, i, num_heads, T, aligned_head_dim, output_token_major);
4145 const int kv_tokens = causal ? i + 1 : T;
4146 for (
int d = 0; d < aligned_head_dim; ++d) {
4149 for (
int j = 0; j < kv_tokens; ++j) {
4152 k_half + (
size_t) j * (
size_t) aligned_head_dim,
4154 logits[j] = raw_scores[j] * scale;
4159 const float inv_sum = sum > 0.0 ? (float) (1.0 / sum) : 0.0f;
4160 for (
int j = 0; j < kv_tokens; ++j) {
4161 logits[j] *= inv_sum;
4164 for (
int d = 0; d < head_dim; ++d) {
4165 for (
int j = 0; j < kv_tokens; ++j) {
4166 v_col_half[j] = v_half[(size_t) j * (
size_t) aligned_head_dim + (size_t) d];
4170 for (
int d = head_dim; d < aligned_head_dim; ++d) {
4174 kv_tokens, head_dim,
4175 debug_layer_id, h, i);
4191 int aligned_head_dim,
4192 int kv_stride_tokens,
4194 int round_full_kv_fp16,
4195 int output_token_major,
4198 if (!q || !k || !v || !output) {
4201 if (num_heads <= 0 || num_kv_heads <= 0 || num_tokens <= 0 ||
4202 head_dim <= 0 || aligned_head_dim < head_dim) {
4205 if (kv_stride_tokens < num_tokens) {
4209 const int T = num_tokens;
4210 const size_t kv_head_stride = (size_t)kv_stride_tokens * (
size_t)aligned_head_dim;
4220 num_heads, num_kv_heads, num_tokens,
4221 head_dim, aligned_head_dim, kv_stride_tokens,
4222 causal, output_token_major, strict_scale, debug_layer_id)) {
4226#if CK_ENABLE_LLAMA_CPP_PARITY
4227 if (!causal && !output_token_major &&
4242 float *score_row = (
float *) alloca((
size_t) T *
sizeof(float));
4243 float *logit_row = (
float *) alloca((
size_t) T *
sizeof(float));
4244 float *v_cols = (
float *) alloca((
size_t) head_dim * (size_t) T *
sizeof(
float));
4245 for (
int h = 0; h < num_heads; ++h) {
4246 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
4247 const float *k_head = k + (size_t)kv_head * kv_head_stride;
4248 const float *v_head = v + (size_t)kv_head * kv_head_stride;
4250 for (
int d = 0; d < head_dim; ++d) {
4251 float *dst_col = v_cols + (size_t) d * (
size_t) T;
4252 for (
int j = 0; j < T; ++j) {
4253 dst_col[j] = v_head[(size_t) j * (
size_t) aligned_head_dim + (size_t) d];
4257 for (
int i = 0; i < T; ++i) {
4258 const float *q_vec = q +
qkv_index(h, i, 0, T, aligned_head_dim);
4259 float *out_vec = output +
qkv_index(h, i, 0, T, aligned_head_dim);
4260 const int kv_tokens = causal ? (i + 1) : T;
4261 if (kv_tokens <= 0) {
4262 for (
int d = 0; d < aligned_head_dim; ++d) {
4267 for (
int j = 0; j < kv_tokens; ++j) {
4268 const float *k_vec = k_head + (size_t) j * (
size_t) aligned_head_dim;
4271 float *raw_dump = NULL;
4273 raw_dump = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
4274 memcpy(raw_dump, score_row, (
size_t) kv_tokens *
sizeof(
float));
4276 memcpy(logit_row, score_row, (
size_t) kv_tokens *
sizeof(
float));
4281 const float inv_sum = (float) (1.0 / sum);
4283 for (
int d = 0; d < head_dim; ++d) {
4284 const float *v_col = v_cols + (size_t) d * (
size_t) T;
4288 for (
int d = 0; d < head_dim; ++d) {
4292 for (
int d = head_dim; d < aligned_head_dim; ++d) {
4297 kv_tokens, head_dim,
4298 debug_layer_id, h, i);
4311 float *rounded_kv = NULL;
4312 const float *compute_k = k;
4313 const float *compute_v = v;
4314 if (!causal && round_full_kv_fp16) {
4315 if ((
size_t) kv_stride_tokens > SIZE_MAX / (
size_t) num_kv_heads) {
4318 const size_t rows = (size_t) num_kv_heads * (
size_t) kv_stride_tokens;
4319 if ((
size_t) aligned_head_dim > SIZE_MAX / rows) {
4322 const size_t elements = rows * (size_t) aligned_head_dim;
4323 if (elements > SIZE_MAX / (2 *
sizeof(
float))) {
4326 rounded_kv = (
float *) malloc(2 * elements *
sizeof(
float));
4330 compute_k = rounded_kv;
4331 compute_v = rounded_kv + elements;
4337#if defined(__AVX512F__)
4338 #define FLASH_QUERY_IMPL attention_flash_query_causal_avx512
4339#elif defined(__AVX2__)
4340 #define FLASH_QUERY_IMPL attention_flash_query_causal_avx2
4341#elif defined(__AVX__)
4342 #define FLASH_QUERY_IMPL attention_flash_query_causal_avx
4344 #define FLASH_QUERY_IMPL attention_flash_query_causal
4347 const int total_queries = num_heads * T;
4348#if defined(__AVX512F__)
4349 if (!causal && !output_token_major && head_dim == 72 && aligned_head_dim >= 72 && ck_attention_qblock8_enabled()) {
4351 const int q_blocks = (T + 7) / 8;
4352 const int total_blocks = num_heads * q_blocks;
4354 if (pool && active > 1) {
4355 ck_attention_qblock4_args_t args = {
4360 .num_heads = num_heads,
4361 .num_kv_heads = num_kv_heads,
4362 .num_tokens = num_tokens,
4363 .aligned_head_dim = aligned_head_dim,
4364 .kv_stride_tokens = kv_stride_tokens,
4373 if (!causal && !output_token_major && head_dim == 72 && aligned_head_dim >= 72 && ck_attention_qblock4_enabled()) {
4375 const int q_blocks = (T + 3) / 4;
4376 const int total_blocks = num_heads * q_blocks;
4378 if (pool && active > 1) {
4379 ck_attention_qblock4_args_t args = {
4384 .num_heads = num_heads,
4385 .num_kv_heads = num_kv_heads,
4386 .num_tokens = num_tokens,
4387 .aligned_head_dim = aligned_head_dim,
4388 .kv_stride_tokens = kv_stride_tokens,
4400 if (pool && active > 1) {
4401 ck_attention_parallel_args_t args = {
4406 .num_heads = num_heads,
4407 .num_kv_heads = num_kv_heads,
4408 .num_tokens = num_tokens,
4409 .head_dim = head_dim,
4410 .aligned_head_dim = aligned_head_dim,
4411 .kv_stride_tokens = kv_stride_tokens,
4413 .output_token_major = output_token_major,
4422 for (
int h = 0; h < num_heads; ++h) {
4423 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
4424 const float *k_head = compute_k + (size_t)kv_head * kv_head_stride;
4425 const float *v_head = compute_v + (size_t)kv_head * kv_head_stride;
4427 for (
int i = 0; i < T; ++i) {
4428 const float *q_vec = q +
qkv_index(h, i, 0, T, aligned_head_dim);
4430 h, i, num_heads, T, aligned_head_dim, output_token_major);
4431 const int kv_tokens = causal ? (i + 1) : T;
4434 head_dim, aligned_head_dim,
4441#undef FLASH_QUERY_IMPL
4452 int aligned_head_dim)
4455 num_heads, num_kv_heads,
4456 num_tokens, head_dim,
4462 1.0f / sqrtf((
float)head_dim));
4473 int aligned_head_dim)
4476 num_heads, num_kv_heads,
4477 num_tokens, head_dim,
4483 1.0f / sqrtf((
float)head_dim));
4504 int aligned_head_dim,
4505 int kv_stride_tokens)
4508 num_heads, num_kv_heads,
4509 num_tokens, head_dim,
4515 1.0f / sqrtf((
float)head_dim));
4527 int aligned_head_dim,
4528 int kv_stride_tokens)
4531 num_heads, num_kv_heads,
4532 num_tokens, head_dim,
4538 1.0f / sqrtf((
float)head_dim));
4549 int aligned_head_dim,
4550 int kv_stride_tokens)
4553 num_heads, num_kv_heads,
4554 num_tokens, head_dim,
4560 1.0f / sqrtf((
float)head_dim));
4566#if defined(__AVX512BF16__)
4567 __m512 acc = _mm512_setzero_ps();
4569 for (; i + 32 <=
count; i += 32) {
4570 const __m512bh av = _mm512_cvtne2ps_pbh(_mm512_loadu_ps(a + i + 16), _mm512_loadu_ps(a + i));
4571 const __m512bh bv = _mm512_cvtne2ps_pbh(_mm512_loadu_ps(b + i + 16), _mm512_loadu_ps(b + i));
4572 acc = _mm512_dpbf16_ps(acc, av, bv);
4574 float sum = _mm512_reduce_add_ps(acc);
4575 for (; i <
count; ++i) {
4583 for (
int i = 0; i <
count; ++i) {
4595 return head_dim > 0 ? (float)(1.0 / sqrt((
double)head_dim)) : 0.0f;
4598#if defined(__AVX512F__)
4599static float ck_bf16_sdpa_reduce_add_avx512(__m512 value)
4601 __m512 other = _mm512_shuffle_f32x4(value, value, 0x4E);
4602 value = _mm512_add_ps(value, other);
4603 other = _mm512_shuffle_f32x4(value, value, 0xB1);
4604 value = _mm512_add_ps(value, other);
4605 other = _mm512_shuffle_ps(value, value, 0x4E);
4606 value = _mm512_add_ps(value, other);
4607 other = _mm512_shuffle_ps(value, value, 0xB1);
4608 value = _mm512_add_ps(value, other);
4609 return _mm512_cvtss_f32(value);
4612static float ck_bf16_sdpa_reduce_max_avx512(__m512 value)
4614 __m512 other = _mm512_shuffle_f32x4(value, value, 0x4E);
4615 value = _mm512_max_ps(value, other);
4616 other = _mm512_shuffle_f32x4(value, value, 0xB1);
4617 value = _mm512_max_ps(value, other);
4618 other = _mm512_shuffle_ps(value, value, 0x4E);
4619 value = _mm512_max_ps(value, other);
4620 other = _mm512_shuffle_ps(value, value, 0xB1);
4621 value = _mm512_max_ps(value, other);
4622 return _mm512_cvtss_f32(value);
4625static __m512 ck_bf16_sdpa_exp_u20_avx512(__m512 value)
4627 const __m512 c1 = _mm512_set1_ps(0.999999701f);
4628 const __m512 c2 = _mm512_set1_ps(0.499991506f);
4629 const __m512 c3 = _mm512_set1_ps(0.166676521f);
4630 const __m512 c4 = _mm512_set1_ps(0.0418978221f);
4631 const __m512 c5 = _mm512_set1_ps(0.00828929059f);
4632 const __m512 log2e = _mm512_castsi512_ps(_mm512_set1_epi32(0x3fb8aa3b));
4633 const __m512 half = _mm512_set1_ps(0.5f);
4634 const __m512 one = _mm512_set1_ps(1.0f);
4635 const __m512 zero = _mm512_setzero_ps();
4636 const __m512 two = _mm512_set1_ps(2.0f);
4637 const __m512 ln2 = _mm512_castsi512_ps(_mm512_set1_epi32(0x3f317218));
4638 const __m512 min_log = _mm512_castsi512_ps(_mm512_set1_epi32(0xc2aeac50));
4639 const __m512 max_log = _mm512_castsi512_ps(_mm512_set1_epi32(0x42b17218));
4640 const __mmask16 underflow = _mm512_cmp_ps_mask(value, min_log, _CMP_LT_OS);
4641 __m512 source = _mm512_max_ps(_mm512_min_ps(value, max_log), min_log);
4642 __m512 exponent = _mm512_fmadd_ps(source, log2e, half);
4643 const __m512i exponent_i = _mm512_cvt_roundps_epi32(
4644 exponent, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC);
4645 exponent = _mm512_cvtepi32_ps(exponent_i);
4646 const __m512 reduced = _mm512_fnmadd_ps(exponent, ln2, source);
4647 __m512 result = _mm512_fmadd_ps(reduced, c5, c4);
4648 result = _mm512_fmadd_ps(reduced, result, c3);
4649 result = _mm512_fmadd_ps(reduced, result, c2);
4650 result = _mm512_fmadd_ps(reduced, result, c1);
4651 result = _mm512_fmadd_ps(reduced, result, one);
4652 __m512i power = _mm512_cvtps_epi32(_mm512_sub_ps(exponent, one));
4653 power = _mm512_slli_epi32(_mm512_add_epi32(power, _mm512_set1_epi32(127)), 23);
4654 __m512 scale = _mm512_castsi512_ps(power);
4655 scale = _mm512_mask_blend_ps(underflow, scale, zero);
4656 return _mm512_mul_ps(_mm512_mul_ps(result, scale), two);
4659static float ck_bf16_sdpa_scale_max_avx512(
float *row,
int count,
float scale)
4661 __m512 lane_max = _mm512_set1_ps(-INFINITY);
4662 const __m512 scale_v = _mm512_set1_ps(scale);
4663 for (
int i = 0; i <
count; i += 16) {
4664 const __m512 value = _mm512_mul_ps(_mm512_loadu_ps(row + i), scale_v);
4665 lane_max = _mm512_max_ps(lane_max, value);
4666 _mm512_storeu_ps(row + i, value);
4668 return ck_bf16_sdpa_reduce_max_avx512(lane_max);
4671static float ck_bf16_sdpa_exp_sum_avx512(
4672 const float *scores, uint16_t *probabilities,
int count,
float maximum)
4674 __m512 lane_sum = _mm512_setzero_ps();
4675 const __m512 maximum_v = _mm512_set1_ps(maximum);
4676 for (
int i = 0; i <
count; i += 16) {
4677 const __m512 exponent = ck_bf16_sdpa_exp_u20_avx512(
4678 _mm512_sub_ps(_mm512_loadu_ps(scores + i), maximum_v));
4679 lane_sum = _mm512_add_ps(lane_sum, exponent);
4681 _mm512_storeu_ps(values, exponent);
4682 for (
int lane = 0; lane < 16; ++lane) {
4686 return ck_bf16_sdpa_reduce_add_avx512(lane_sum);
4691 const float *q,
const float *k,
const float *v,
float *output,
4692 int num_heads,
int num_kv_heads,
int num_tokens,
4693 int head_dim,
int aligned_head_dim,
int kv_stride_tokens,
4694 int head_begin,
int head_step,
int output_token_major)
4696#if defined(__AVX512F__)
4705 enum { Q_BLOCK = 256, KV_BLOCK = 512, K_PAD = 72, D_PAD = 80 };
4707 (num_tokens % 16) != 0 || (kv_stride_tokens < num_tokens) ||
4708 num_heads % num_kv_heads != 0)
return 0;
4709 uint16_t *q_block = malloc((
size_t)Q_BLOCK * K_PAD *
sizeof(uint16_t));
4710 uint16_t *k_packed = malloc((
size_t)num_tokens * K_PAD *
sizeof(uint16_t));
4711 uint16_t *probabilities = malloc((
size_t)Q_BLOCK * KV_BLOCK *
sizeof(uint16_t));
4712 uint16_t *v_packed = malloc((
size_t)num_tokens * D_PAD *
sizeof(uint16_t));
4713 float *scores = malloc((
size_t)Q_BLOCK * KV_BLOCK *
sizeof(
float));
4714 float *destination = malloc((
size_t)Q_BLOCK * D_PAD *
sizeof(
float));
4715 float *row_max = malloc((
size_t)Q_BLOCK *
sizeof(
float));
4716 float *row_sum = malloc((
size_t)Q_BLOCK *
sizeof(
float));
4717 if (!q_block || !k_packed || !probabilities || !v_packed || !scores ||
4718 !destination || !row_max || !row_sum) {
4719 free(q_block); free(k_packed); free(probabilities); free(v_packed);
4720 free(scores); free(destination); free(row_max); free(row_sum);
4724 const size_t q_stride = (size_t)num_tokens * (
size_t)aligned_head_dim;
4725 const size_t kv_stride = (size_t)kv_stride_tokens * (
size_t)aligned_head_dim;
4726 for (
int h = head_begin; h < num_heads; h += head_step) {
4727 const int kv_head = (int)((
long long)h * num_kv_heads / num_heads);
4728 const float *qh = q + (size_t)h * q_stride;
4729 const float *kh = k + (size_t)kv_head * kv_stride;
4730 const float *vh = v + (size_t)kv_head * kv_stride;
4736 for (
int n = 0; n < num_tokens; n += KV_BLOCK) {
4737 const int key_count = num_tokens - n < KV_BLOCK ? num_tokens - n : KV_BLOCK;
4738 uint16_t *k_block = k_packed + (size_t)n * K_PAD;
4739 uint16_t *v_block = v_packed + (size_t)n * D_PAD;
4740 memset(k_block, 0, (
size_t)key_count * K_PAD *
sizeof(uint16_t));
4741 memset(v_block, 0, (
size_t)D_PAD * key_count *
sizeof(uint16_t));
4742 for (
int key = 0; key < key_count; ++key) {
4743 for (
int d = 0; d < head_dim; ++d) {
4744 k_block[(size_t)key * K_PAD + d] =
4745 float_to_bf16(kh[(
size_t)(n + key) * aligned_head_dim + d]);
4746 v_block[(size_t)d * key_count + key] =
4747 float_to_bf16(vh[(
size_t)(n + key) * aligned_head_dim + d]);
4751 for (
int m = 0; m < num_tokens; m += Q_BLOCK) {
4752 const int query_count = num_tokens - m < Q_BLOCK ? num_tokens - m : Q_BLOCK;
4753 memset(q_block, 0, (
size_t)query_count * K_PAD *
sizeof(uint16_t));
4754 memset(destination, 0, (
size_t)query_count * D_PAD *
sizeof(
float));
4755 for (
int row = 0; row < query_count; ++row) {
4756 for (
int d = 0; d < head_dim; ++d) {
4757 q_block[(size_t)row * K_PAD + d] =
4758 float_to_bf16(qh[(
size_t)(m + row) * aligned_head_dim + d]);
4760 row_max[row] = -INFINITY;
4761 row_sum[row] = 0.0f;
4763 for (
int n = 0; n < num_tokens; n += KV_BLOCK) {
4764 const int key_count = num_tokens - n < KV_BLOCK ? num_tokens - n : KV_BLOCK;
4765 const uint16_t *k_block = k_packed + (size_t)n * K_PAD;
4766 const uint16_t *v_block = v_packed + (size_t)n * D_PAD;
4768 q_block, k_block, scores,
4769 query_count, key_count, K_PAD, 0))
goto fail;
4770 for (
int row = 0; row < query_count; ++row) {
4771 float *score_row = scores + (size_t)row * key_count;
4772 uint16_t *prob_row = probabilities + (size_t)row * key_count;
4773 const float block_max = ck_bf16_sdpa_scale_max_avx512(
4774 score_row, key_count, scale);
4775 const float merged_max = row_max[row] > block_max
4776 ? row_max[row] : block_max;
4777 const float old_scale = isfinite(row_max[row])
4778 ? expf(row_max[row] - merged_max) : 0.0f;
4779 const float block_sum = ck_bf16_sdpa_exp_sum_avx512(
4780 score_row, prob_row, key_count, merged_max);
4781 row_sum[row] = block_sum + old_scale * row_sum[row];
4782 row_max[row] = merged_max;
4784 __m512 scale_v = _mm512_set1_ps(old_scale);
4786 for (; d + 16 <= D_PAD; d += 16) {
4787 float *dst = destination + (size_t)row * D_PAD + d;
4788 _mm512_storeu_ps(dst, _mm512_mul_ps(_mm512_loadu_ps(dst), scale_v));
4793 probabilities, v_block, destination,
4794 query_count, D_PAD, key_count, n > 0))
goto fail;
4796 for (
int row = 0; row < query_count; ++row) {
4797 const float reciprocal = row_sum[row] == 0.0f ? 1.0f : 1.0f / row_sum[row];
4798 float *out_row = output + (
4800 ? ((size_t)(m + row) * (size_t)num_heads + (
size_t)h)
4801 * (
size_t)aligned_head_dim
4802 : ((size_t)h * (
size_t)num_tokens + (size_t)(m + row))
4803 * (
size_t)aligned_head_dim);
4804 for (
int d = 0; d < head_dim; ++d) {
4806 float_to_bf16(destination[(
size_t)row * D_PAD + d] * reciprocal));
4811 free(q_block); free(k_packed); free(probabilities); free(v_packed);
4812 free(scores); free(destination); free(row_max); free(row_sum);
4815 free(q_block); free(k_packed); free(probabilities); free(v_packed);
4816 free(scores); free(destination); free(row_max); free(row_sum);
4819 (void)q; (void)k; (void)v; (void)output; (void)num_heads;
4820 (void)num_kv_heads; (void)num_tokens; (void)head_dim;
4821 (void)aligned_head_dim; (void)kv_stride_tokens; (void)head_begin; (void)head_step;
4822 (void)output_token_major;
4828 const float *q,
const float *k,
const float *v,
float *output,
4829 int num_heads,
int num_kv_heads,
int num_tokens,
4830 int head_dim,
int aligned_head_dim,
int kv_stride_tokens,
4831 int head_begin,
int head_step)
4833 if (!q || !k || !v || !output || num_heads <= 0 || num_kv_heads <= 0 ||
4834 head_dim <= 0 || num_tokens <= 0 || aligned_head_dim < head_dim ||
4835 kv_stride_tokens < num_tokens || num_heads % num_kv_heads != 0)
return 0;
4836 if ((
size_t)num_tokens > SIZE_MAX / (
size_t)head_dim)
return 0;
4837 const size_t v_col_count = (size_t)head_dim * (
size_t)num_tokens;
4838 if (v_col_count > SIZE_MAX /
sizeof(
float))
return 0;
4839 if ((
size_t)num_tokens > SIZE_MAX / (size_t)aligned_head_dim)
return 0;
4840 if ((
size_t)kv_stride_tokens > SIZE_MAX / (size_t)aligned_head_dim)
return 0;
4842 const size_t q_head_stride = (size_t)num_tokens * (
size_t)aligned_head_dim;
4843 const size_t kv_head_stride = (size_t)kv_stride_tokens * (
size_t)aligned_head_dim;
4844 if ((
size_t)num_heads > SIZE_MAX / q_head_stride)
return 0;
4845 if ((
size_t)num_kv_heads > SIZE_MAX / kv_head_stride)
return 0;
4848 float *v_cols = (
float *)malloc(v_col_count *
sizeof(
float));
4849 if (!v_cols)
return 0;
4850 for (
int h = head_begin; h < num_heads; h += head_step) {
4851 const int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
4852 const float *qh = q + (size_t)h * q_head_stride;
4853 const float *kh = k + (size_t)kv_head * kv_head_stride;
4854 const float *vh = v + (size_t)kv_head * kv_head_stride;
4855 float *oh = output + (size_t)h * q_head_stride;
4856 for (
int d = 0; d < head_dim; ++d) {
4857 float *col = v_cols + (size_t)d * (
size_t)num_tokens;
4858 for (
int t = 0; t < num_tokens; ++t) {
4859 col[t] = vh[(size_t)t * (
size_t)aligned_head_dim + (size_t)d];
4862 for (
int row = 0; row < num_tokens; ++row) {
4863 const float *qrow = qh + (size_t)row * (
size_t)aligned_head_dim;
4864 float *dst = oh + (size_t)row * (
size_t)aligned_head_dim;
4865 for (
int d = 0; d < head_dim; ++d) dst[d] = 0.0f;
4866 float running_max = -INFINITY;
4867 float running_sum = 0.0f;
4868 for (
int n = 0; n < num_tokens; n += 512) {
4869 const int block = num_tokens - n < 512 ? num_tokens - n : 512;
4870 float block_max = -INFINITY;
4871 for (
int j = 0; j < block; ++j) {
4874 kh + (
size_t)(n + j) * (
size_t)aligned_head_dim,
4876 if (scores[j] > block_max) block_max = scores[j];
4878 const float merged_max = running_max > block_max ? running_max : block_max;
4879 const float old_scale = isfinite(running_max) ? expf(running_max - merged_max) : 0.0f;
4880 float block_sum = 0.0f;
4881 for (
int j = 0; j < block; ++j) {
4882 const float p = expf(scores[j] - merged_max);
4886 for (
int d = 0; d < head_dim; ++d) {
4889 v_cols + (
size_t)d * (
size_t)num_tokens + (
size_t)n,
4891 dst[d] = dst[d] * old_scale + partial;
4893 running_sum = running_sum * old_scale + block_sum;
4894 running_max = merged_max;
4896 const float inv = running_sum > 0.0f ? 1.0f / running_sum : 0.0f;
4897 for (
int d = 0; d < head_dim; ++d) dst[d] *= inv;
4898 for (
int d = head_dim; d < aligned_head_dim; ++d) dst[d] = 0.0f;
4914 int aligned_head_dim;
4915 int kv_stride_tokens;
4916 int output_token_major;
4918} ck_attention_bf16_sdpa_args_t;
4922 ck_attention_bf16_sdpa_args_t *args = (ck_attention_bf16_sdpa_args_t *)opaque;
4924 args->q, args->k, args->v, args->output,
4925 args->num_heads, args->num_kv_heads, args->num_tokens,
4926 args->head_dim, args->aligned_head_dim, args->kv_stride_tokens,
4928 __atomic_store_n(&args->failed, 1, __ATOMIC_RELAXED);
4934 ck_attention_bf16_sdpa_args_t *args = (ck_attention_bf16_sdpa_args_t *)opaque;
4936 args->q, args->k, args->v, args->output,
4937 args->num_heads, args->num_kv_heads, args->num_tokens,
4938 args->head_dim, args->aligned_head_dim, args->kv_stride_tokens,
4939 ith, nth, args->output_token_major)) {
4940 __atomic_store_n(&args->failed, 1, __ATOMIC_RELAXED);
4945 const float *q,
const float *k,
const float *v,
float *output,
4946 int num_heads,
int num_kv_heads,
int num_tokens,
4947 int head_dim,
int aligned_head_dim,
int kv_stride_tokens,
4948 int output_token_major)
4950 ck_attention_bf16_sdpa_args_t args = {
4951 .q=q, .k=k, .v=v, .output=output,
4952 .num_heads=num_heads, .num_kv_heads=num_kv_heads,
4953 .num_tokens=num_tokens, .head_dim=head_dim,
4954 .aligned_head_dim=aligned_head_dim, .kv_stride_tokens=kv_stride_tokens,
4955 .output_token_major=output_token_major,
4960 if (active > num_heads) active = num_heads;
4961 if (pool && active > 1) {
4967 return __atomic_load_n(&args.failed, __ATOMIC_RELAXED) == 0;
4971 const float *q,
const float *k,
const float *v,
float *output,
4972 int num_heads,
int num_kv_heads,
int num_tokens,
4973 int head_dim,
int aligned_head_dim,
int kv_stride_tokens)
4975 ck_attention_bf16_sdpa_args_t args = {
4976 .q=q, .k=k, .v=v, .output=output,
4977 .num_heads=num_heads, .num_kv_heads=num_kv_heads,
4978 .num_tokens=num_tokens, .head_dim=head_dim,
4979 .aligned_head_dim=aligned_head_dim, .kv_stride_tokens=kv_stride_tokens,
4980 .output_token_major=0,
4985 if (active > num_heads) active = num_heads;
4986 if (pool && active > 1) {
4991 return __atomic_load_n(&args.failed, __ATOMIC_RELAXED) == 0;
5003 int aligned_head_dim,
5004 int kv_stride_tokens)
5008 num_heads, num_kv_heads, num_tokens, head_dim,
5009 aligned_head_dim, kv_stride_tokens,
5013 1.0f / sqrtf((
float)head_dim)
5015 const size_t count = (size_t)num_heads * (
size_t)num_tokens
5016 * (size_t)aligned_head_dim;
5017 for (
size_t i = 0; i <
count; ++i) {
5031 int aligned_head_dim,
5032 int kv_stride_tokens)
5035 q, k, v, output, num_heads, num_kv_heads, num_tokens,
5036 head_dim, aligned_head_dim, kv_stride_tokens)) {
5037 const size_t count = (size_t)num_heads * (
size_t)num_tokens
5038 * (size_t)aligned_head_dim;
5039 for (
size_t i = 0; i <
count; ++i) {
5044 fprintf(stderr,
"CK numerical contract failure: BF16 tiled SDPA received invalid dimensions or could not allocate scratch\n");
5056 int aligned_head_dim,
5057 int kv_stride_tokens)
5060 q, k, v, output, num_heads, num_kv_heads, num_tokens,
5061 head_dim, aligned_head_dim, kv_stride_tokens,
5066 "HARD KERNEL CONTRACT FAULT: PyTorch CPU-flash BF16 attention "
5067 "requires AMX-BF16, AVX-512, D=72/A=72 and a token multiple of 16; "
5068 "no numerically different fallback is permitted\n");
5081 int aligned_head_dim,
5082 int kv_stride_tokens)
5085 q, k, v, output, num_heads, num_kv_heads, num_tokens,
5086 head_dim, aligned_head_dim, kv_stride_tokens,
5091 "HARD KERNEL CONTRACT FAULT: PyTorch CPU-flash BF16 token-output "
5092 "attention requires AMX-BF16, AVX-512, D=72/A=72 and a token "
5093 "multiple of 16; no numerically different fallback is permitted\n");
5106 int aligned_head_dim,
5107 int kv_stride_tokens)
5111 num_heads, num_kv_heads,
5112 num_tokens, head_dim,
5130 int aligned_head_dim,
5131 int kv_stride_tokens)
5134 num_heads, num_kv_heads,
5135 num_tokens, head_dim,
5149 int aligned_head_dim,
5150 int kv_stride_tokens)
5153 q, q, q, output, num_heads, num_heads, num_tokens,
5154 head_dim, aligned_head_dim, kv_stride_tokens
5166 int aligned_head_dim,
5167 int kv_stride_tokens)
5171 num_heads, num_kv_heads,
5172 num_tokens, head_dim,
5191 int aligned_head_dim,
5192 int kv_stride_tokens,
5195 int output_token_major)
5197 if (!q || !k || !v || !output) {
5200 if (num_heads <= 0 || num_kv_heads <= 0 || num_tokens <= 0) {
5203 if (kv_stride_tokens < num_tokens || head_dim <= 0 || aligned_head_dim <= 0) {
5206 if (visual_start < 0 || visual_tokens <= 0 || visual_start >= num_tokens) {
5208 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
5209 aligned_head_dim, kv_stride_tokens, 1,
5210 0, output_token_major, 1.0f);
5214 int visual_end = visual_start + visual_tokens;
5215 if (visual_end > num_tokens) {
5216 visual_end = num_tokens;
5218 if (visual_end <= visual_start) {
5220 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
5221 aligned_head_dim, kv_stride_tokens, 1,
5222 0, output_token_major, 1.0f);
5226 const int T = num_tokens;
5227 const size_t kv_head_stride = (size_t)kv_stride_tokens * (
size_t)aligned_head_dim;
5228 const float scale = 1.0f;
5234 for (
int h = 0; h < num_heads; ++h) {
5235 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
5236 const float *k_head = k + (size_t)kv_head * kv_head_stride;
5237 const float *v_head = v + (size_t)kv_head * kv_head_stride;
5239 for (
int i = 0; i < T; ++i) {
5240 const float *q_vec = q +
qkv_index(h, i, 0, T, aligned_head_dim);
5242 h, i, num_heads, T, aligned_head_dim, output_token_major);
5243 const int in_visual = (i >= visual_start && i < visual_end);
5244 const int kv_tokens = in_visual ? visual_end : (i + 1);
5247 head_dim, aligned_head_dim,
5251 head_dim, aligned_head_dim,
5253 debug_layer_id, h, i);
5259#if defined(__AVX512F__)
5260 #define FLASH_QUERY_IMPL attention_flash_query_causal_avx512
5261#elif defined(__AVX2__)
5262 #define FLASH_QUERY_IMPL attention_flash_query_causal_avx2
5263#elif defined(__AVX__)
5264 #define FLASH_QUERY_IMPL attention_flash_query_causal_avx
5266 #define FLASH_QUERY_IMPL attention_flash_query_causal
5269 for (
int h = 0; h < num_heads; ++h) {
5270 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
5271 const float *k_head = k + (size_t)kv_head * kv_head_stride;
5272 const float *v_head = v + (size_t)kv_head * kv_head_stride;
5274 for (
int i = 0; i < T; ++i) {
5275 const float *q_vec = q +
qkv_index(h, i, 0, T, aligned_head_dim);
5277 h, i, num_heads, T, aligned_head_dim, output_token_major);
5278 const int in_visual = (i >= visual_start && i < visual_end);
5279 const int kv_tokens = in_visual ? visual_end : (i + 1);
5282 head_dim, aligned_head_dim,
5287#undef FLASH_QUERY_IMPL
5291 const float *q,
const float *k,
const float *v,
float *output,
5292 int num_heads,
int num_kv_heads,
int num_tokens,
int head_dim,
5293 int aligned_head_dim,
int kv_stride_tokens,
int visual_start,
5297 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
5298 aligned_head_dim, kv_stride_tokens, visual_start, visual_tokens,
5303 const float *q,
const float *k,
const float *v,
float *output,
5304 int num_heads,
int num_kv_heads,
int num_tokens,
int head_dim,
5305 int aligned_head_dim,
int kv_stride_tokens,
int visual_start,
5309 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
5310 aligned_head_dim, kv_stride_tokens, visual_start, visual_tokens,
5323 int aligned_head_dim;
5324 int kv_stride_tokens;
5325 int inputs_prerounded;
5326} ck_attention_causal_f16kv_args_t;
5330 const ck_attention_causal_f16kv_args_t *args =
5331 (
const ck_attention_causal_f16kv_args_t *)opaque;
5332 const float scale = 1.0f / sqrtf((
float)args->head_dim);
5333 const int T = args->num_tokens;
5334 const size_t kv_head_stride =
5335 (size_t)args->kv_stride_tokens * (
size_t)args->aligned_head_dim;
5337 for (
int h = ith; h < args->num_heads; h += nth) {
5338 const int kv_head = (int)((
long long)h * (
long long)args->num_kv_heads /
5339 (
long long)args->num_heads);
5340 const float *k_head = args->k + (size_t)kv_head * kv_head_stride;
5341 const float *v_head = args->v + (size_t)kv_head * kv_head_stride;
5343 for (
int i = 0; i < T; ++i) {
5344 const float *q_vec = args->q +
5345 qkv_index(h, i, 0, T, args->aligned_head_dim);
5346 float *out_vec = args->output +
5347 qkv_index(h, i, 0, T, args->aligned_head_dim);
5348 if (args->inputs_prerounded) {
5350 q_vec, k_head, v_head, i + 1,
5351 args->head_dim, args->aligned_head_dim, scale, out_vec);
5354 q_vec, k_head, v_head, i + 1,
5355 args->head_dim, args->aligned_head_dim, scale, out_vec);
5362 const float *q,
const float *k,
const float *v,
float *output,
5363 int num_heads,
int num_kv_heads,
int num_tokens,
int head_dim,
5364 int aligned_head_dim,
int kv_stride_tokens)
5366 if (!q || !k || !v || !output || num_heads <= 0 || num_kv_heads <= 0 ||
5367 num_tokens <= 0 || kv_stride_tokens < num_tokens) {
5370 ck_attention_causal_f16kv_args_t args = {
5371 q, k, v, output, num_heads, num_kv_heads, num_tokens,
5372 head_dim, aligned_head_dim, kv_stride_tokens, 0,
5378 const float *q,
const float *k,
const float *v,
float *output,
5379 int num_heads,
int num_kv_heads,
int num_tokens,
int head_dim,
5380 int aligned_head_dim,
int kv_stride_tokens,
5381 float *rounded_kv,
size_t rounded_kv_bytes)
5383 if (!q || !k || !v || !output || num_heads <= 0 || num_kv_heads <= 0 ||
5384 num_tokens <= 0 || kv_stride_tokens < num_tokens) {
5387 size_t elements = 0;
5388 if ((
size_t)num_kv_heads <= SIZE_MAX / (
size_t)kv_stride_tokens) {
5389 const size_t rows = (size_t)num_kv_heads * (
size_t)kv_stride_tokens;
5390 if (rows <= SIZE_MAX / (
size_t)aligned_head_dim) {
5391 elements = rows * (size_t)aligned_head_dim;
5394 if (elements == 0 || elements > SIZE_MAX / (2 *
sizeof(
float)) ||
5395 !rounded_kv || rounded_kv_bytes < 2 * elements *
sizeof(
float)) {
5397 "HARD KERNEL CONTRACT FAULT: FP16-KV attention workspace is too small\n");
5402 ck_attention_causal_f16kv_args_t args = {
5403 q, rounded_kv, rounded_kv + elements, output,
5404 num_heads, num_kv_heads, num_tokens,
5405 head_dim, aligned_head_dim, kv_stride_tokens, 1,
5409 const int active = workers < num_heads ? workers : num_heads;
5418 const float *q,
const float *k,
const float *v,
float *output,
5419 int num_heads,
int num_kv_heads,
int num_tokens,
int head_dim,
5420 int aligned_head_dim,
int kv_stride_tokens)
5422 size_t elements = 0;
5423 if (num_kv_heads > 0 && kv_stride_tokens > 0 && aligned_head_dim > 0 &&
5424 (
size_t)num_kv_heads <= SIZE_MAX / (
size_t)kv_stride_tokens) {
5425 const size_t rows = (size_t)num_kv_heads * (
size_t)kv_stride_tokens;
5426 if (rows <= SIZE_MAX / (
size_t)aligned_head_dim) {
5427 elements = rows * (size_t)aligned_head_dim;
5430 float *workspace = elements > 0 && elements <= SIZE_MAX / (2 *
sizeof(float))
5431 ? (
float *)malloc(2 * elements *
sizeof(
float))
5435 q, k, v, output, num_heads, num_kv_heads, num_tokens,
5436 head_dim, aligned_head_dim, kv_stride_tokens);
5440 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
5441 aligned_head_dim, kv_stride_tokens, workspace,
5442 2 * elements *
sizeof(
float));
5454 int aligned_head_dim,
5455 int kv_stride_tokens)
5457 if (!q || !k || !v || !output) {
5460 if (num_heads <= 0 || num_kv_heads <= 0 || num_tokens <= 0) {
5463 if (kv_stride_tokens < num_tokens) {
5469 : 1.0f / sqrtf((
float) head_dim);
5470 const int T = num_tokens;
5471 const size_t kv_head_stride = (size_t) kv_stride_tokens * (
size_t) aligned_head_dim;
5473 float *score_row = (
float *) alloca((
size_t) T *
sizeof(float));
5474 float *v_cols = (
float *) alloca((
size_t) head_dim * (size_t) T *
sizeof(
float));
5475 for (
int h = 0; h < num_heads; ++h) {
5476 const int kv_head = (int) ((
long long) h * (
long long) num_kv_heads / (
long long) num_heads);
5477 const float *k_head = k + (size_t) kv_head * kv_head_stride;
5478 const float *v_head = v + (size_t) kv_head * kv_head_stride;
5480#if CK_ENABLE_LLAMA_CPP_PARITY
5481 float *out_head = output + (size_t) h * (
size_t) T * (size_t) aligned_head_dim;
5484 q + (
size_t) h * (
size_t) T * (
size_t) aligned_head_dim,
5497 for (
int d = 0; d < head_dim; ++d) {
5498 float *dst_col = v_cols + (size_t) d * (
size_t) T;
5499 for (
int j = 0; j < T; ++j) {
5500 dst_col[j] = v_head[(size_t) j * (
size_t) aligned_head_dim + (size_t) d];
5504 for (
int i = 0; i < T; ++i) {
5505 const float *q_vec = q +
qkv_index(h, i, 0, T, aligned_head_dim);
5506 float *out_vec = output +
qkv_index(h, i, 0, T, aligned_head_dim);
5532 int aligned_head_dim,
5533 int kv_stride_tokens,
5535 size_t score_rows_bytes,
5537 size_t v_columns_bytes,
5538 float *probability_row,
5539 size_t probability_row_bytes)
5541 if (!q || !k || !v || !output) {
5544 if (num_heads <= 0 || num_kv_heads <= 0 || num_tokens <= 0) {
5547 if (kv_stride_tokens < num_tokens) {
5551 const size_t T = (size_t) num_tokens;
5552 if ((
size_t) num_heads > SIZE_MAX / T ||
5553 (size_t) head_dim > SIZE_MAX / T) {
5556 const size_t score_elements = (size_t) num_heads * T;
5557 const size_t columns_per_head = (size_t) head_dim * T;
5558 if ((
size_t) num_heads > SIZE_MAX / columns_per_head ||
5559 score_elements > SIZE_MAX /
sizeof(float) ||
5560 columns_per_head * (
size_t) num_heads > SIZE_MAX /
sizeof(float) ||
5561 T > SIZE_MAX /
sizeof(
float)) {
5564 const size_t column_elements = columns_per_head * (size_t) num_heads;
5565 if (!score_rows || score_rows_bytes < score_elements *
sizeof(
float) ||
5566 !v_columns || v_columns_bytes < column_elements *
sizeof(float) ||
5567 !probability_row || probability_row_bytes < T *
sizeof(
float)) {
5572 const float scale = strict
5574 : 1.0f / sqrtf((
float) head_dim);
5575 const int token_count = num_tokens;
5576 const size_t kv_head_stride = (size_t) kv_stride_tokens * (
size_t) aligned_head_dim;
5578#if CK_ENABLE_LLAMA_CPP_PARITY
5579 ck_ggml_vec_dot_f32_fn dot_fn = NULL;
5580 ck_ggml_vec_soft_max_f32_fn softmax_fn = NULL;
5581 ck_ggml_compute_forward_mul_mat_fn mul_mat_fn = NULL;
5582 ck_ggml_compute_forward_soft_max_fn softmax_compute_fn = NULL;
5597 dot_fn = ck_resolve_ggml_vec_dot_f32();
5598 softmax_fn = ck_resolve_ggml_vec_soft_max_f32();
5599 mul_mat_fn = ck_resolve_ggml_compute_forward_mul_mat();
5600 softmax_compute_fn = ck_resolve_ggml_compute_forward_soft_max();
5604 float *score_row = score_rows;
5605 float *v_cols = v_columns;
5606#if CK_ENABLE_LLAMA_CPP_PARITY
5607 float *prob_row = probability_row;
5610 for (
int h = 0; h < num_heads; ++h) {
5611 const int kv_head = (int) ((
long long) h * (
long long) num_kv_heads / (
long long) num_heads);
5612 const float *k_head = k + (size_t) kv_head * kv_head_stride;
5613 const float *v_head = v + (size_t) kv_head * kv_head_stride;
5615#if CK_ENABLE_LLAMA_CPP_PARITY
5616 float *out_head = output + (size_t) h * (
size_t) T * (size_t) aligned_head_dim;
5618 q + (
size_t) h * (size_t) T * (
size_t) aligned_head_dim,
5630 for (
int d = 0; d < head_dim; ++d) {
5631 float *dst_col = v_cols + (size_t) d * (
size_t) token_count;
5632 for (
int j = 0; j < token_count; ++j) {
5633 dst_col[j] = v_head[(size_t) j * (
size_t) aligned_head_dim + (size_t) d];
5637#if CK_ENABLE_LLAMA_CPP_PARITY
5639 if (attention_head_full_dyn_ggml_regular_graph_out(
5640 q + (
size_t) h * (size_t) T * (
size_t) aligned_head_dim,
5654 if (token_count > 0) {
5663 for (
int i = 0; i < token_count; ++i) {
5664 const float *q_vec = q +
qkv_index(h, i, 0, token_count, aligned_head_dim);
5665 float *out_vec = output +
qkv_index(h, i, 0, token_count, aligned_head_dim);
5666#if CK_ENABLE_LLAMA_CPP_PARITY
5667 if (dot_fn && softmax_fn) {
5672 attention_query_full_dyn_ggml_regular(q_vec,
5687 }
else if (dot_fn && mul_mat_fn && softmax_compute_fn) {
5691 attention_query_full_ggml_compute_regular(q_vec,
5703 softmax_compute_fn);
5728#pragma omp parallel for schedule(static) if(num_heads > 1)
5729 for (
int h = 0; h < num_heads; ++h) {
5730 float *score_row = score_rows + (size_t) h * (
size_t) token_count;
5731 float *v_cols = v_columns + (size_t) h * (
size_t) head_dim * (size_t) token_count;
5732 const int kv_head = (int) ((
long long) h * (
long long) num_kv_heads / (
long long) num_heads);
5733 const float *k_head = k + (size_t) kv_head * kv_head_stride;
5734 const float *v_head = v + (size_t) kv_head * kv_head_stride;
5737 for (
int d = 0; d < head_dim; ++d) {
5738 float *dst_col = v_cols + (size_t) d * (
size_t) token_count;
5739 for (
int j = 0; j < token_count; ++j) {
5740 dst_col[j] = v_head[(size_t) j * (
size_t) aligned_head_dim + (size_t) d];
5745 for (
int i = 0; i < token_count; ++i) {
5746 const float *q_vec = q +
qkv_index(h, i, 0, token_count, aligned_head_dim);
5747 float *out_vec = output +
qkv_index(h, i, 0, token_count, aligned_head_dim);
5772 int aligned_head_dim,
5773 int kv_stride_tokens)
5775 if (num_heads <= 0 || num_tokens <= 0 || head_dim <= 0 ||
5776 (
size_t) num_heads > SIZE_MAX / (
size_t) num_tokens ||
5777 (
size_t) head_dim > SIZE_MAX / (
size_t) num_tokens) {
5780 const size_t score_elements = (size_t) num_heads * (
size_t) num_tokens;
5781 const size_t columns_per_head = (size_t) head_dim * (
size_t) num_tokens;
5782 if ((
size_t) num_heads > SIZE_MAX / columns_per_head)
return;
5783 const size_t column_elements = (size_t) num_heads * columns_per_head;
5784 if (score_elements > SIZE_MAX - column_elements ||
5785 score_elements + column_elements > SIZE_MAX - (
size_t) num_tokens)
return;
5786 const size_t total_elements = score_elements + column_elements + (size_t) num_tokens;
5787 if (total_elements > SIZE_MAX /
sizeof(
float))
return;
5788 float *workspace = (
float *) malloc(total_elements *
sizeof(
float));
5789 if (!workspace)
return;
5790 float *score_rows = workspace;
5791 float *v_columns = score_rows + score_elements;
5792 float *probability_row = v_columns + column_elements;
5794 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
5795 aligned_head_dim, kv_stride_tokens,
5796 score_rows, score_elements *
sizeof(
float),
5797 v_columns, column_elements *
sizeof(
float),
5798 probability_row, (
size_t) num_tokens *
sizeof(
float));
5804 if (live_tokens <= 0 || capacity < live_tokens)
return 0;
5805 int padded = live_tokens < 256 ? 256 : ((live_tokens + 255) / 256) * 256;
5806 return padded < capacity ? padded : capacity;
5809#if defined(__AVX512F__)
5810static inline __m512 ck_llama_regular_round_f16x16(__m512 value)
5812 return _mm512_cvtph_ps(_mm512_cvtps_ph(value, _MM_FROUND_TO_NEAREST_INT));
5819#if defined(__AVX512F__)
5821 _mm512_setzero_ps(), _mm512_setzero_ps(),
5822 _mm512_setzero_ps(), _mm512_setzero_ps()
5824 for (; i + 64 <=
count; i += 64) {
5825 for (
int lane = 0; lane < 4; ++lane) {
5826 acc[lane] = _mm512_fmadd_ps(
5827 ck_llama_regular_round_f16x16(_mm512_loadu_ps(a + i + lane * 16)),
5828 ck_llama_regular_round_f16x16(_mm512_loadu_ps(b + i + lane * 16)),
5832 acc[0] = _mm512_add_ps(acc[0], acc[2]);
5833 acc[1] = _mm512_add_ps(acc[1], acc[3]);
5834 float sum = _mm512_reduce_add_ps(_mm512_add_ps(acc[0], acc[1]));
5835#elif defined(__AVX__)
5837 _mm256_setzero_ps(), _mm256_setzero_ps(),
5838 _mm256_setzero_ps(), _mm256_setzero_ps()
5840 for (; i + 32 <=
count; i += 32) {
5841 for (
int lane = 0; lane < 4; ++lane) {
5843 acc[lane] = _mm256_fmadd_ps(
5844 _mm256_cvtph_ps(_mm256_cvtps_ph(
5845 _mm256_loadu_ps(a + i + lane * 8), _MM_FROUND_TO_NEAREST_INT)),
5846 _mm256_cvtph_ps(_mm256_cvtps_ph(
5847 _mm256_loadu_ps(b + i + lane * 8), _MM_FROUND_TO_NEAREST_INT)),
5850 acc[lane] = _mm256_add_ps(acc[lane], _mm256_mul_ps(
5851 _mm256_cvtph_ps(_mm256_cvtps_ph(
5852 _mm256_loadu_ps(a + i + lane * 8), _MM_FROUND_TO_NEAREST_INT)),
5853 _mm256_cvtph_ps(_mm256_cvtps_ph(
5854 _mm256_loadu_ps(b + i + lane * 8), _MM_FROUND_TO_NEAREST_INT))));
5858 acc[0] = _mm256_add_ps(acc[0], acc[2]);
5859 acc[1] = _mm256_add_ps(acc[1], acc[3]);
5860 const __m256 merged = _mm256_add_ps(acc[0], acc[1]);
5861 __m128 halves = _mm_add_ps(
5862 _mm256_extractf128_ps(merged, 1), _mm256_castps256_ps128(merged));
5863 halves = _mm_add_ps(halves, _mm_movehl_ps(halves, halves));
5864 halves = _mm_add_ss(halves, _mm_movehdup_ps(halves));
5865 float sum = _mm_cvtss_f32(halves);
5867 float sums[4] = {0.0f, 0.0f, 0.0f, 0.0f};
5868 for (; i + 4 <=
count; i += 4) {
5869 for (
int lane = 0; lane < 4; ++lane) {
5872 sums[lane] = fmaf(av, bv, sums[lane]);
5875 float sum = (sums[0] + sums[2]) + (sums[1] + sums[3]);
5877 for (; i <
count; ++i) {
5880 sum = fmaf(av, bv, sum);
5886 const float *probability,
const float *value_column,
int count)
5889#if defined(__AVX512F__)
5890 __m512 acc = _mm512_setzero_ps();
5891 for (; i + 16 <=
count; i += 16) {
5892 acc = _mm512_fmadd_ps(
5893 ck_llama_regular_round_f16x16(_mm512_loadu_ps(value_column + i)),
5894 ck_llama_regular_round_f16x16(_mm512_loadu_ps(probability + i)), acc);
5896 float sum = _mm512_reduce_add_ps(acc);
5897#elif defined(__AVX__)
5898 __m256 acc = _mm256_setzero_ps();
5899 for (; i + 8 <=
count; i += 8) {
5901 acc = _mm256_fmadd_ps(
5902 _mm256_cvtph_ps(_mm256_cvtps_ph(
5903 _mm256_loadu_ps(value_column + i), _MM_FROUND_TO_NEAREST_INT)),
5904 _mm256_cvtph_ps(_mm256_cvtps_ph(
5905 _mm256_loadu_ps(probability + i), _MM_FROUND_TO_NEAREST_INT)), acc);
5907 acc = _mm256_add_ps(acc, _mm256_mul_ps(
5908 _mm256_cvtph_ps(_mm256_cvtps_ph(
5909 _mm256_loadu_ps(value_column + i), _MM_FROUND_TO_NEAREST_INT)),
5910 _mm256_cvtph_ps(_mm256_cvtps_ph(
5911 _mm256_loadu_ps(probability + i), _MM_FROUND_TO_NEAREST_INT))));
5914 __m128 halves = _mm_add_ps(
5915 _mm256_extractf128_ps(acc, 1), _mm256_castps256_ps128(acc));
5916 halves = _mm_add_ps(halves, _mm_movehl_ps(halves, halves));
5917 halves = _mm_add_ss(halves, _mm_movehdup_ps(halves));
5918 float sum = _mm_cvtss_f32(halves);
5922 for (; i <
count; ++i) {
5925 sum = fmaf(value, probability_value, sum);
5931 const float *query,
const float *key_head,
const float *value_columns,
5932 float *output,
float *scores,
float *scaled_scores,
5933 int live_tokens,
int padded_tokens,
int query_position,
5934 int head_dim,
int aligned_head_dim,
int sliding_window,
5935 int batched_prefill)
5937 const int first = sliding_window > 0 && query_position >= sliding_window
5938 ? query_position - sliding_window + 1 : 0;
5939 const int last = query_position < live_tokens ? query_position : live_tokens - 1;
5942 const float *key = key_head + (size_t)
token * (
size_t)aligned_head_dim;
5943 scores[
token] = batched_prefill
5948 memcpy(scaled_scores, scores, (
size_t)padded_tokens *
sizeof(
float));
5949 const float scale = 1.0f / sqrtf((
float)head_dim);
5953 padded_tokens, scores, scaled_scores, maximum);
5956 for (
int dim = 0; dim < head_dim; ++dim) {
5957 const float *column = value_columns + (size_t)dim * (
size_t)padded_tokens;
5958 output[dim] = batched_prefill
5963 memset(output, 0, (
size_t)head_dim *
sizeof(
float));
5965 for (
int dim = head_dim; dim < aligned_head_dim; ++dim) output[dim] = 0.0f;
5969 const float *q,
const float *k,
const float *v,
float *output,
5970 int num_heads,
int num_kv_heads,
int query_tokens,
int live_tokens,
5971 int head_dim,
int aligned_head_dim,
int kv_stride_tokens,
int sliding_window,
5972 float *scores,
size_t scores_bytes,
5973 float *value_columns,
size_t value_columns_bytes,
5974 float *scaled_scores,
size_t scaled_scores_bytes,
5975 int batched_prefill)
5977 if (!q || !k || !v || !output || !scores || !value_columns || !scaled_scores ||
5978 num_heads <= 0 || num_kv_heads <= 0 || query_tokens <= 0 || live_tokens <= 0 ||
5979 head_dim <= 0 || aligned_head_dim < head_dim || kv_stride_tokens < live_tokens)
return;
5980 size_t scratch_capacity = scores_bytes /
sizeof(float);
5981 const size_t scaled_capacity = scaled_scores_bytes /
sizeof(float);
5982 const size_t value_capacity = value_columns_bytes /
5983 ((size_t)head_dim *
sizeof(
float));
5984 if (scaled_capacity < scratch_capacity) scratch_capacity = scaled_capacity;
5985 if (value_capacity < scratch_capacity) scratch_capacity = value_capacity;
5986 if (!batched_prefill && (
size_t)kv_stride_tokens < scratch_capacity) {
5987 scratch_capacity = (size_t)kv_stride_tokens;
5989 const int padded = scratch_capacity > (size_t)INT_MAX ? 0 :
5991 if (padded <= 0 || scores_bytes < (
size_t)padded *
sizeof(
float) ||
5992 scaled_scores_bytes < (
size_t)padded *
sizeof(
float) ||
5993 value_columns_bytes < (
size_t)head_dim * (
size_t)padded *
sizeof(
float))
return;
5995 const size_t kv_head_stride = (size_t)kv_stride_tokens * (
size_t)aligned_head_dim;
5998 int packed_kv_head = -1;
5999 for (
int head = 0; head < num_heads; ++head) {
6000 const int kv_head = (int)((
long long)head * num_kv_heads / num_heads);
6001 const float *key_head = k + (size_t)kv_head * kv_head_stride;
6002 const float *value_head = v + (size_t)kv_head * kv_head_stride;
6003 if (kv_head != packed_kv_head) {
6004 for (
int dim = 0; dim < head_dim; ++dim) {
6005 float *column = value_columns + (size_t)dim * (
size_t)padded;
6008 column[
token] = value_head[(size_t)
token * aligned_head_dim + dim];
6012 packed_kv_head = kv_head;
6014 for (
int query = 0; query < query_tokens; ++query) {
6015 const int position = batched_prefill ? query : live_tokens - 1;
6017 q + ((
size_t)head * query_tokens + query) * aligned_head_dim,
6018 key_head, value_columns,
6019 output + ((
size_t)head * query_tokens + query) * aligned_head_dim,
6020 scores, scaled_scores, live_tokens, padded, position,
6021 head_dim, aligned_head_dim, sliding_window, batched_prefill);
6022 if (debug_layer_id >= 0 &&
6025 scaled_scores, scores,
6026 output + ((
size_t)head * query_tokens + query) * aligned_head_dim,
6027 value_columns, padded, head_dim,
6028 debug_layer_id, head, query);
6037 const float *value_columns;
6040 float *scaled_scores;
6045 int aligned_head_dim;
6046 int kv_stride_tokens;
6050} ck_llama_regular_prefill_args_t;
6054 ck_llama_regular_prefill_args_t *a =
6055 (ck_llama_regular_prefill_args_t *)opaque;
6056 float *worker_scores = a->scores + (size_t)ith * (
size_t)a->padded;
6057 float *worker_scaled =
6058 a->scaled_scores + (size_t)ith * (
size_t)a->padded;
6059 const size_t worker_kv_stride =
6060 (size_t)a->kv_stride_tokens * (
size_t)a->aligned_head_dim;
6061 const int jobs = a->num_heads * a->num_tokens;
6067 const int job = atomic_fetch_add_explicit(
6068 &a->next_job, 1, memory_order_relaxed);
6069 if (job >= jobs)
break;
6070 const int head = job / a->num_tokens;
6071 const int query = job - head * a->num_tokens;
6073 (int)((
long long)head * a->num_kv_heads / a->num_heads);
6075 a->q + ((
size_t)head * a->num_tokens + query) * a->aligned_head_dim,
6076 a->k + (
size_t)kv_head * worker_kv_stride,
6078 (
size_t)kv_head * (
size_t)a->head_dim * (
size_t)a->padded,
6080 ((
size_t)head * a->num_tokens + query) * a->aligned_head_dim,
6081 worker_scores, worker_scaled, a->num_tokens, a->padded, query,
6082 a->head_dim, a->aligned_head_dim, a->sliding_window, 1);
6087 const float *q,
const float *k,
const float *v,
float *output,
6088 int num_heads,
int num_kv_heads,
int num_tokens,
int head_dim,
6089 int aligned_head_dim,
int kv_stride_tokens,
int sliding_window,
6090 float *scores,
size_t scores_bytes,
6091 float *value_columns,
size_t value_columns_bytes,
6092 float *scaled_scores,
size_t scaled_scores_bytes)
6094 if (!q || !k || !v || !output || !scores || !value_columns || !scaled_scores ||
6095 num_heads <= 0 || num_kv_heads <= 0 || num_tokens <= 0 || head_dim <= 0 ||
6096 aligned_head_dim < head_dim || kv_stride_tokens < num_tokens ||
6097 num_heads > INT_MAX / num_tokens)
return;
6099 const size_t score_elements = scores_bytes /
sizeof(float);
6100 const size_t scaled_elements = scaled_scores_bytes /
sizeof(float);
6101 const size_t value_elements = value_columns_bytes /
sizeof(float);
6102 if ((
size_t)num_kv_heads > SIZE_MAX / (size_t)head_dim)
return;
6103 const size_t value_rows = (size_t)num_kv_heads * (
size_t)head_dim;
6104 const size_t value_capacity = value_rows > 0 ? value_elements / value_rows : 0;
6105 const size_t padded_size = num_tokens < 256
6106 ? 256 : (((size_t)num_tokens + 255) / 256) * 256;
6107 const int padded = padded_size > (size_t)INT_MAX ? 0 : (int)padded_size;
6111 if (padded <= 0 || value_capacity < (
size_t)padded ||
6112 score_elements < (size_t)padded * 2 ||
6113 scaled_elements < (
size_t)padded * 2 ||
6114 value_elements < value_rows * (size_t)padded) {
6116 q, k, v, output, num_heads, num_kv_heads, num_tokens, num_tokens,
6117 head_dim, aligned_head_dim, kv_stride_tokens, sliding_window,
6118 scores, scores_bytes, value_columns, value_columns_bytes,
6119 scaled_scores, scaled_scores_bytes, 1);
6125 q, k, v, output, num_heads, num_kv_heads, num_tokens, num_tokens,
6126 head_dim, aligned_head_dim, kv_stride_tokens, sliding_window,
6127 scores, (
size_t)padded *
sizeof(
float),
6128 value_columns, (
size_t)head_dim * (
size_t)padded *
sizeof(
float),
6129 scaled_scores, (
size_t)padded *
sizeof(
float), 1);
6133 const size_t kv_head_stride =
6134 (size_t)kv_stride_tokens * (
size_t)aligned_head_dim;
6135 for (
int kv_head = 0; kv_head < num_kv_heads; ++kv_head) {
6136 const float *value_head = v + (size_t)kv_head * kv_head_stride;
6137 float *packed_head = value_columns +
6138 (size_t)kv_head * (
size_t)head_dim * (size_t)padded;
6139 for (
int dim = 0; dim < head_dim; ++dim) {
6140 float *column = packed_head + (size_t)dim * (
size_t)padded;
6144 value_head[(size_t)
token * (
size_t)aligned_head_dim + (size_t)dim];
6150 ck_llama_regular_prefill_args_t args = {
6153 .value_columns = value_columns,
6156 .scaled_scores = scaled_scores,
6157 .num_heads = num_heads,
6158 .num_kv_heads = num_kv_heads,
6159 .num_tokens = num_tokens,
6160 .head_dim = head_dim,
6161 .aligned_head_dim = aligned_head_dim,
6162 .kv_stride_tokens = kv_stride_tokens,
6163 .sliding_window = sliding_window,
6166 atomic_init(&args.next_job, 0);
6168 size_t scratch_lanes = score_elements / (size_t)padded;
6169 const size_t scaled_lanes = scaled_elements / (size_t)padded;
6170 if (scaled_lanes < scratch_lanes) scratch_lanes = scaled_lanes;
6171 int active = scratch_lanes > (size_t)INT_MAX ? INT_MAX : (int)scratch_lanes;
6172 const int jobs = num_heads * num_tokens;
6173 if (active > jobs) active = jobs;
6176 if (active > pool_threads) active = pool_threads;
6177 if (active < 1) active = 1;
6178 if (pool && active > 1) {
6186 const float *q,
const float *k,
const float *v,
float *output,
6187 int num_heads,
int num_kv_heads,
int live_tokens,
int kv_stride_tokens,
6188 int head_dim,
int aligned_head_dim,
int sliding_window,
6189 float *scores,
size_t scores_bytes,
6190 float *value_columns,
size_t value_columns_bytes,
6191 float *scaled_scores,
size_t scaled_scores_bytes)
6194 q, k, v, output, num_heads, num_kv_heads, 1, live_tokens,
6195 head_dim, aligned_head_dim, kv_stride_tokens, sliding_window,
6196 scores, scores_bytes, value_columns, value_columns_bytes,
6197 scaled_scores, scaled_scores_bytes, 0);
6213 const float *k_cache,
6214 const float *v_cache,
6221 int aligned_head_dim)
6223 if (!q_token || !k_cache || !v_cache || !out_token) {
6226 if (num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
6229 if (kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
6233 const float scale = 1.0f / sqrtf((
float)head_dim);
6234 const size_t head_stride = (size_t)cache_capacity * (
size_t)aligned_head_dim;
6236 for (
int h = 0; h < num_heads; ++h) {
6237 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
6238 const float *q_head = q_token + (size_t)h * (
size_t)aligned_head_dim;
6239 const float *k_head = k_cache + (size_t)kv_head * head_stride;
6240 const float *v_head = v_cache + (size_t)kv_head * head_stride;
6241 float *out_head = out_token + (size_t)h * (
size_t)aligned_head_dim;
6257 const float *k_cache,
6258 const float *v_cache,
6265 int aligned_head_dim)
6267 if (!q_token || !k_cache || !v_cache || !out_token) {
6270 if (num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
6273 if (kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
6277 const float scale = 1.0f;
6278 const size_t head_stride = (size_t)cache_capacity * (
size_t)aligned_head_dim;
6280 for (
int h = 0; h < num_heads; ++h) {
6281 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
6282 const float *q_head = q_token + (size_t)h * (
size_t)aligned_head_dim;
6283 const float *k_head = k_cache + (size_t)kv_head * head_stride;
6284 const float *v_head = v_cache + (size_t)kv_head * head_stride;
6285 float *out_head = out_token + (size_t)h * (
size_t)aligned_head_dim;
6300 const float *k_cache,
6301 const float *v_cache,
6309 int aligned_head_dim)
6311 if (!q_chunk || !k_cache || !v_cache || !out_chunk) {
6314 if (num_heads <= 0 || num_kv_heads <= 0 || q_tokens <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
6317 if (kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
6321 const float scale = 1.0f;
6322 const size_t cache_head_stride = (size_t)cache_capacity * (
size_t)aligned_head_dim;
6323 const size_t q_head_stride = (size_t)q_tokens * (
size_t)aligned_head_dim;
6325 for (
int h = 0; h < num_heads; ++h) {
6326 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
6327 const float *k_head = k_cache + (size_t)kv_head * cache_head_stride;
6328 const float *v_head = v_cache + (size_t)kv_head * cache_head_stride;
6329 for (
int t = 0; t < q_tokens; ++t) {
6330 const float *q_head = q_chunk + (size_t)h * q_head_stride + (
size_t)t * (size_t)aligned_head_dim;
6331 float *out_head = out_chunk + (size_t)h * q_head_stride + (
size_t)t * (size_t)aligned_head_dim;
6346 const float *k_cache,
6347 const float *v_cache,
6353 int aligned_head_dim)
6356 q_token, k_cache, v_cache, out_token, num_heads, num_heads,
6357 kv_tokens, cache_capacity, head_dim, aligned_head_dim
6362 const float *k_cache,
6363 const float *v_cache,
6370 int aligned_head_dim)
6372 if (!q_token || !k_cache || !v_cache || !out_token) {
6375 if (num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
6378 if (kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
6382 const float scale = 1.0f / sqrtf((
float)head_dim);
6383 const size_t head_stride = (size_t)cache_capacity * (
size_t)aligned_head_dim;
6385 for (
int h = 0; h < num_heads; ++h) {
6386 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
6387 const float *q_head = q_token + (size_t)h * (
size_t)aligned_head_dim;
6388 const float *k_head = k_cache + (size_t)kv_head * head_stride;
6389 const float *v_head = v_cache + (size_t)kv_head * head_stride;
6390 float *out_head = out_token + (size_t)h * (
size_t)aligned_head_dim;
6404 const float *q_token;
6405 const uint16_t *k_cache;
6406 const uint16_t *v_cache;
6414 int aligned_head_dim;
6416 int scheduled_chunks;
6417 int partition_tokens;
6418 float attention_scale;
6419} ck_attention_f16_split_args_t;
6431#if defined(__AVX512F__)
6434 __m512 sum0 = _mm512_setzero_ps();
6435 __m512 sum1 = _mm512_setzero_ps();
6436 __m512 sum2 = _mm512_setzero_ps();
6437 __m512 sum3 = _mm512_setzero_ps();
6438 const int n64 = n & ~63;
6439 for (; i < n64; i += 64) {
6440 const __m512 x0 = _mm512_cvtph_ps(_mm256_loadu_si256((
const __m256i *) (x + i)));
6441 const __m512 y0 = _mm512_cvtph_ps(_mm256_loadu_si256((
const __m256i *) (y + i)));
6442 const __m512 x1 = _mm512_cvtph_ps(_mm256_loadu_si256((
const __m256i *) (x + i + 16)));
6443 const __m512 y1 = _mm512_cvtph_ps(_mm256_loadu_si256((
const __m256i *) (y + i + 16)));
6444 const __m512 x2 = _mm512_cvtph_ps(_mm256_loadu_si256((
const __m256i *) (x + i + 32)));
6445 const __m512 y2 = _mm512_cvtph_ps(_mm256_loadu_si256((
const __m256i *) (y + i + 32)));
6446 const __m512 x3 = _mm512_cvtph_ps(_mm256_loadu_si256((
const __m256i *) (x + i + 48)));
6447 const __m512 y3 = _mm512_cvtph_ps(_mm256_loadu_si256((
const __m256i *) (y + i + 48)));
6448 sum0 = _mm512_fmadd_ps(x0, y0, sum0);
6449 sum1 = _mm512_fmadd_ps(x1, y1, sum1);
6450 sum2 = _mm512_fmadd_ps(x2, y2, sum2);
6451 sum3 = _mm512_fmadd_ps(x3, y3, sum3);
6453 sum0 = _mm512_add_ps(sum0, sum2);
6454 sum1 = _mm512_add_ps(sum1, sum3);
6455 sum0 = _mm512_add_ps(sum0, sum1);
6456 const float vector_result = _mm512_reduce_add_ps(sum0);
6457#elif defined(__AVX2__) && defined(__F16C__)
6460 __m256 sum0 = _mm256_setzero_ps();
6461 __m256 sum1 = _mm256_setzero_ps();
6462 __m256 sum2 = _mm256_setzero_ps();
6463 __m256 sum3 = _mm256_setzero_ps();
6464 const int n32 = n & ~31;
6465 for (; i < n32; i += 32) {
6466 const __m256 x0 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (x + i)));
6467 const __m256 y0 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (y + i)));
6468 const __m256 x1 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (x + i + 8)));
6469 const __m256 y1 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (y + i + 8)));
6470 const __m256 x2 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (x + i + 16)));
6471 const __m256 y2 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (y + i + 16)));
6472 const __m256 x3 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (x + i + 24)));
6473 const __m256 y3 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (y + i + 24)));
6475 sum0 = _mm256_fmadd_ps(x0, y0, sum0);
6476 sum1 = _mm256_fmadd_ps(x1, y1, sum1);
6477 sum2 = _mm256_fmadd_ps(x2, y2, sum2);
6478 sum3 = _mm256_fmadd_ps(x3, y3, sum3);
6480 sum0 = _mm256_add_ps(sum0, _mm256_mul_ps(x0, y0));
6481 sum1 = _mm256_add_ps(sum1, _mm256_mul_ps(x1, y1));
6482 sum2 = _mm256_add_ps(sum2, _mm256_mul_ps(x2, y2));
6483 sum3 = _mm256_add_ps(sum3, _mm256_mul_ps(x3, y3));
6486 sum0 = _mm256_add_ps(sum0, sum2);
6487 sum1 = _mm256_add_ps(sum1, sum3);
6488 sum0 = _mm256_add_ps(sum0, sum1);
6489 const __m128 pair = _mm_add_ps(
6490 _mm256_castps256_ps128(sum0),
6491 _mm256_extractf128_ps(sum0, 1));
6492 const __m128 half = _mm_hadd_ps(pair, pair);
6493 const float vector_result = _mm_cvtss_f32(_mm_hadd_ps(half, half));
6495 const float vector_result = 0.0f;
6501 double result = (double) vector_result;
6502 for (; i < n; ++i) {
6506 return (
float) result;
6512#if defined(__AVX512F__)
6513 const __m512 factor = _mm512_set1_ps(scale);
6514 for (; i + 63 < n; i += 64) {
6515 for (
int lane = 0; lane < 4; ++lane) {
6516 const int offset = i + lane * 16;
6517 __m512 value = _mm512_cvtph_ps(
6518 _mm256_loadu_si256((
const __m256i *) (y + offset)));
6519 value = _mm512_mul_ps(value, factor);
6520 _mm256_storeu_si256(
6521 (__m256i *) (y + offset), _mm512_cvtps_ph(value, 0));
6524#elif defined(__AVX2__) && defined(__F16C__)
6525 const __m256 factor = _mm256_set1_ps(scale);
6526 for (; i + 31 < n; i += 32) {
6527 for (
int lane = 0; lane < 4; ++lane) {
6528 const int offset = i + lane * 8;
6529 __m256 value = _mm256_cvtph_ps(
6530 _mm_loadu_si128((
const __m128i *) (y + offset)));
6531 value = _mm256_mul_ps(value, factor);
6533 (__m128i *) (y + offset), _mm256_cvtps_ph(value, 0));
6537 for (; i < n; ++i) {
6549#if defined(__AVX512F__)
6550 const __m512 factor = _mm512_set1_ps(scale);
6551 for (; i + 63 < n; i += 64) {
6552 for (
int lane = 0; lane < 4; ++lane) {
6553 const int offset = i + lane * 16;
6554 const __m512 xv = _mm512_cvtph_ps(
6555 _mm256_loadu_si256((
const __m256i *) (x + offset)));
6556 __m512 yv = _mm512_cvtph_ps(
6557 _mm256_loadu_si256((
const __m256i *) (y + offset)));
6558 yv = _mm512_fmadd_ps(xv, factor, yv);
6559 _mm256_storeu_si256(
6560 (__m256i *) (y + offset), _mm512_cvtps_ph(yv, 0));
6563#elif defined(__AVX2__) && defined(__F16C__)
6564 const __m256 factor = _mm256_set1_ps(scale);
6565 for (; i + 31 < n; i += 32) {
6566 for (
int lane = 0; lane < 4; ++lane) {
6567 const int offset = i + lane * 8;
6568 const __m256 xv = _mm256_cvtph_ps(
6569 _mm_loadu_si128((
const __m128i *) (x + offset)));
6570 __m256 yv = _mm256_cvtph_ps(
6571 _mm_loadu_si128((
const __m128i *) (y + offset)));
6573 yv = _mm256_fmadd_ps(xv, factor, yv);
6575 yv = _mm256_add_ps(yv, _mm256_mul_ps(xv, factor));
6578 (__m128i *) (y + offset), _mm256_cvtps_ph(yv, 0));
6582 for (; i < n; ++i) {
6591 ck_attention_f16_split_args_t *args = (ck_attention_f16_split_args_t *) opaque;
6592 const int partial_stride = args->aligned_head_dim + 2;
6593 const int total_jobs = args->num_heads * args->scheduled_chunks;
6594 const int chunk_size =
6595 (args->partition_tokens + args->split_chunks - 1) / args->split_chunks;
6596 const size_t head_stride = (size_t) args->cache_capacity * (
size_t) args->aligned_head_dim;
6597 const float scale = args->attention_scale;
6598 uint16_t *q_half = (uint16_t *) alloca((
size_t) args->aligned_head_dim *
sizeof(uint16_t));
6599 uint16_t *acc_half = (uint16_t *) alloca((
size_t) args->aligned_head_dim *
sizeof(uint16_t));
6601 for (
int job = ith; job < total_jobs; job += nth) {
6602 const int h = job / args->scheduled_chunks;
6603 const int chunk = job % args->scheduled_chunks;
6604 const int kv_head = (int) ((
long long) h * (
long long) args->num_kv_heads /
6605 (
long long) args->num_heads);
6606 const int begin = args->kv_start + chunk * chunk_size;
6607 const int end = begin < args->kv_tokens
6608 ? (begin + chunk_size < args->kv_tokens ? begin + chunk_size : args->kv_tokens)
6610 const float *q_head = args->q_token + (size_t) h * (
size_t) args->aligned_head_dim;
6611 const uint16_t *k_head = args->k_cache + (size_t) kv_head * head_stride;
6612 const uint16_t *v_head = args->v_cache + (size_t) kv_head * head_stride;
6613 float *partial = args->partials + (size_t) job * (
size_t) partial_stride;
6615 for (
int d = 0; d < args->aligned_head_dim; ++d) {
6621 float max_score = -INFINITY;
6622 for (
int j = begin; j <
end; ++j) {
6623 const uint16_t *k_vec = k_head + (size_t) j * (
size_t) args->aligned_head_dim;
6624 const uint16_t *v_vec = v_head + (size_t) j * (
size_t) args->aligned_head_dim;
6626 const float score = dot * scale;
6627 const float old_max = max_score;
6628 float max_scale = 1.0f;
6629 float value_scale = 1.0f;
6631 if (
score > max_score) {
6633 max_scale = isfinite(old_max)
6642 acc_half, v_vec, value_scale, args->head_dim);
6643#if defined(__INTEL_LLVM_COMPILER)
6644 sum = ck_attention_mul_add_rounded_f32(
6645 sum, max_scale, value_scale);
6647 sum = fmaf(sum, max_scale, value_scale);
6651 partial[0] = max_score;
6653 for (
int d = 0; d < args->head_dim; ++d) {
6656 for (
int d = args->head_dim; d < args->aligned_head_dim; ++d) {
6657 partial[2 + d] = 0.0f;
6663 const float *q_token,
6664 const uint16_t *k_cache,
6665 const uint16_t *v_cache,
6672 int aligned_head_dim,
6674 int partition_tokens,
6676 float attention_scale)
6678 if (!q_token || !k_cache || !v_cache || !out_token ||
6679 num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 ||
6680 cache_capacity <= 0 || kv_tokens > cache_capacity ||
6681 kv_start < 0 || kv_start >= kv_tokens ||
6682 head_dim <= 0 || aligned_head_dim < head_dim ||
6683 partition_tokens < kv_tokens - kv_start || !isfinite(attention_scale)) {
6687 const int live_tokens = kv_tokens - kv_start;
6689 if (split_chunks < 1) {
6692 if (split_chunks > live_tokens) {
6693 split_chunks = live_tokens;
6696 const int partial_stride = aligned_head_dim + 2;
6697 const size_t max_partial_bytes = 1024u * 1024u;
6698 while (split_chunks > 1 &&
6699 (
size_t) num_heads * (
size_t) split_chunks * (
size_t) partial_stride *
sizeof(
float) >
6700 max_partial_bytes) {
6701 split_chunks = (split_chunks + 1) / 2;
6704 const int chunk_size = (partition_tokens + split_chunks - 1) / split_chunks;
6705 const int scheduled_chunks = (live_tokens + chunk_size - 1) / chunk_size;
6706 const size_t resolved_count =
6707 (size_t) num_heads * (
size_t) scheduled_chunks * (size_t) partial_stride;
6708 float *partials = (
float *) alloca(resolved_count *
sizeof(
float));
6709 ck_attention_f16_split_args_t args = {
6713 .partials = partials,
6714 .num_heads = num_heads,
6715 .num_kv_heads = num_kv_heads,
6716 .kv_start = kv_start,
6717 .kv_tokens = kv_tokens,
6718 .cache_capacity = cache_capacity,
6719 .head_dim = head_dim,
6720 .aligned_head_dim = aligned_head_dim,
6721 .split_chunks = split_chunks,
6722 .scheduled_chunks = scheduled_chunks,
6723 .partition_tokens = partition_tokens,
6724 .attention_scale = attention_scale,
6729 const int total_jobs = num_heads * scheduled_chunks;
6730 if (active_threads > total_jobs) {
6731 active_threads = total_jobs;
6733 if (pool && active_threads > 1) {
6739 for (
int h = 0; h < num_heads; ++h) {
6740 float *out_head = out_token + (size_t) h * (
size_t) aligned_head_dim;
6741 float final_max = -INFINITY;
6742 float final_sum = 0.0f;
6743 for (
int d = 0; d < aligned_head_dim; ++d) {
6747 for (
int chunk = 0; chunk < scheduled_chunks; ++chunk) {
6748 const float *partial = partials +
6749 ((size_t) h * (
size_t) scheduled_chunks + (size_t) chunk) * (size_t) partial_stride;
6750 const float chunk_max = partial[0];
6751 const float chunk_sum = partial[1];
6752 if (chunk_sum == 0.0f) {
6755 const float new_max = fmaxf(final_max, chunk_max);
6756 const float old_scale = isfinite(final_max)
6759 const float chunk_scale =
6761 for (
int d = 0; d < head_dim; ++d) {
6762 const float chunk_term = partial[2 + d] * chunk_scale;
6763 out_head[d] = fmaf(out_head[d], old_scale, chunk_term);
6765#if defined(__INTEL_LLVM_COMPILER)
6766 const float scaled_chunk_sum = chunk_sum * chunk_scale;
6767 final_sum = fmaf(final_sum, old_scale, scaled_chunk_sum);
6770 final_sum, old_scale, chunk_sum * chunk_scale);
6772 final_max = new_max;
6775 if (final_sum > 0.0f) {
6776 const float inv_sum = 1.0f / final_sum;
6777 for (
int d = 0; d < head_dim; ++d) {
6778 out_head[d] *= inv_sum;
6785 const uint16_t *k_cache,
6786 const uint16_t *v_cache,
6793 int aligned_head_dim,
6796 const int partition_alignment = 256;
6797 const int partition_tokens =
6798 ((kv_tokens + partition_alignment - 1) / partition_alignment) * partition_alignment;
6800 q_token, k_cache, v_cache, out_token,
6801 num_heads, num_kv_heads, kv_tokens, cache_capacity,
6802 head_dim, aligned_head_dim, split_chunks, partition_tokens, 0,
6807 const float *q_token,
6808 const uint16_t *k_cache,
6809 const uint16_t *v_cache,
6816 int aligned_head_dim,
6820 if (!q_token || !k_cache || !v_cache || !out_token ||
6821 num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 ||
6822 cache_capacity <= 0 || kv_tokens > cache_capacity ||
6823 head_dim <= 0 || aligned_head_dim < head_dim || sliding_window < 0) {
6828 q_token, k_cache, v_cache, out_token, num_heads, num_kv_heads,
6829 kv_tokens, cache_capacity, head_dim, aligned_head_dim, sliding_window);
6834 const int kv_start = sliding_window > 0 && kv_tokens > sliding_window
6835 ? kv_tokens - sliding_window : 0;
6836 const int live_tokens = kv_tokens - kv_start;
6838 q_token, k_cache, v_cache, out_token,
6839 num_heads, num_kv_heads, kv_tokens, cache_capacity,
6840 head_dim, aligned_head_dim, 1, live_tokens, kv_start, 1.0f);
6845 const float *q_token,
6846 const uint16_t *k_cache,
6847 const uint16_t *v_cache,
6854 int aligned_head_dim,
6857 if (!q_token || !k_cache || !v_cache || !out_token ||
6858 num_heads <= 0 || num_kv_heads <= 0 || num_heads % num_kv_heads != 0 ||
6859 kv_tokens <= 0 || cache_capacity <= 0 || kv_tokens > cache_capacity ||
6860 head_dim <= 0 || head_dim > 4096 || aligned_head_dim < head_dim ||
6861 sliding_window < 0 ||
6862 (
size_t) cache_capacity > SIZE_MAX / (
size_t) aligned_head_dim) {
6866 const size_t cache_head_stride = (size_t) cache_capacity * (
size_t) aligned_head_dim;
6867 const int first_token = sliding_window > 0 && kv_tokens > sliding_window
6868 ? kv_tokens - sliding_window : 0;
6869 uint16_t *q_half = (uint16_t *) alloca((
size_t) head_dim *
sizeof(uint16_t));
6870 for (
int h = 0; h < num_heads; ++h) {
6871 const int kv_head = h / (num_heads / num_kv_heads);
6872 const float *q_head = q_token + (size_t) h * (
size_t) aligned_head_dim;
6873 const uint16_t *k_head = k_cache + (size_t) kv_head * cache_head_stride;
6874 const uint16_t *v_head = v_cache + (size_t) kv_head * cache_head_stride;
6875 float *out_head = out_token + (size_t) h * (
size_t) aligned_head_dim;
6876 for (
int d = 0; d < head_dim; ++d) q_half[d] =
CK_FP32_TO_FP16(q_head[d]);
6878 float maximum = -INFINITY;
6881 q_half, k_head + (
size_t)
token * (
size_t) aligned_head_dim, head_dim);
6889 q_half, k_head + (
size_t)
token * (
size_t) aligned_head_dim, head_dim);
6894 for (
int d = 0; d < head_dim; ++d) out_head[d] = 0.0f;
6897 q_half, k_head + (
size_t)
token * (
size_t) aligned_head_dim, head_dim);
6900 const uint16_t *v_row = v_head + (size_t)
token * (
size_t) aligned_head_dim;
6901 for (
int d = 0; d < head_dim; ++d) {
6902 out_head[d] = fmaf(rounded_probability,
CK_FP16_TO_FP32(v_row[d]), out_head[d]);
6905 for (
int d = head_dim; d < aligned_head_dim; ++d) out_head[d] = 0.0f;
6911 const float *q_token,
const uint16_t *k_cache,
const uint16_t *v_cache,
6912 float *out_token,
int num_heads,
int num_kv_heads,
int kv_tokens,
6913 int cache_capacity,
int head_dim,
int aligned_head_dim,
6917 q_token, k_cache, v_cache, out_token, num_heads, num_kv_heads,
6918 kv_tokens, cache_capacity, head_dim, aligned_head_dim, 0, reduction);
6922 const float *q_token,
const uint16_t *k_cache,
const uint16_t *v_cache,
6923 float *out_token,
int num_heads,
int num_kv_heads,
int kv_tokens,
6924 int cache_capacity,
int head_dim,
int aligned_head_dim,
int sliding_window,
6928 q_token, k_cache, v_cache, out_token, num_heads, num_kv_heads,
6929 kv_tokens, cache_capacity, head_dim, aligned_head_dim,
6930 sliding_window, reduction);
6934 const float *q_token,
6935 const uint16_t *k_cache,
6936 const uint16_t *v_cache,
6943 int aligned_head_dim,
6946 if (!q_token || !k_cache || !v_cache || !out_token ||
6947 num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 ||
6948 cache_capacity <= 0 || kv_tokens > cache_capacity ||
6949 head_dim <= 0 || aligned_head_dim < head_dim) {
6953 switch (reduction) {
6956 q_token, k_cache, v_cache, out_token,
6957 num_heads, num_kv_heads, kv_tokens, cache_capacity,
6958 head_dim, aligned_head_dim);
6962 const int partition_alignment = 256;
6963 const int partition_tokens =
6964 ((kv_tokens + partition_alignment - 1) / partition_alignment) * partition_alignment;
6967 q_token, k_cache, v_cache, out_token,
6968 num_heads, num_kv_heads, kv_tokens, cache_capacity,
6969 head_dim, aligned_head_dim, split_chunks);
6975 q_token, k_cache, v_cache, out_token,
6976 num_heads, num_kv_heads, kv_tokens, cache_capacity,
6977 head_dim, aligned_head_dim, 1);
6987 const uint16_t *k_cache;
6988 const uint16_t *v_cache;
6996 int aligned_head_dim;
6998 float attention_scale;
7000 size_t q_head_stride;
7001 size_t output_head_stride;
7002} ck_attention_f16_prefill_qtile64_args_t;
7005 _Alignas(64) int arrived;
7006 _Alignas(64)
int phase;
7008} ck_attention_gqa_team_barrier_t;
7011 ck_attention_f16_prefill_qtile64_args_t base;
7012 float *shared_k_tiles;
7013 float *shared_v_tiles;
7014 ck_attention_gqa_team_barrier_t *barriers;
7015 unsigned char *worker_workspace;
7016 size_t worker_workspace_stride;
7017 int query_tile_size;
7018 int concurrent_query_tiles;
7019} ck_attention_f16_prefill_gqa_reuse_args_t;
7023 return (value + 63u) & ~(size_t) 63u;
7031 int query_tile_size,
7032 int concurrent_query_tiles)
7034 if (num_heads <= 0 || num_kv_heads <= 0 ||
7035 num_heads % num_kv_heads != 0 || workers < num_kv_heads ||
7036 workers % num_kv_heads != 0 || head_dim <= 0 ||
7037 query_tile_size <= 0 || concurrent_query_tiles <= 0) {
7040 const int lanes = workers / num_kv_heads;
7041 const int group_jobs =
7042 (num_heads / num_kv_heads) * concurrent_query_tiles;
7043 const size_t local_capacity =
7044 (size_t) (group_jobs + lanes - 1) / (size_t) lanes;
7047 3u * local_capacity *
sizeof(int);
7049 local_capacity * (size_t) query_tile_size * (
size_t) head_dim *
7055 local_capacity * (size_t) query_tile_size * (
size_t) head_dim *
7058 local_capacity * (size_t) query_tile_size *
sizeof(
float);
7060 local_capacity * (size_t) query_tile_size *
sizeof(
float);
7069 int query_tile_size,
7070 int concurrent_query_tiles)
7072 const size_t worker_bytes =
7074 num_heads, num_kv_heads, head_dim, workers,
7075 query_tile_size, concurrent_query_tiles);
7076 if (worker_bytes == 0)
return 0;
7085 (size_t) num_kv_heads *
sizeof(ck_attention_gqa_team_barrier_t);
7087 (size_t) workers * worker_bytes;
7092 ck_attention_gqa_team_barrier_t *barrier)
7094 const int phase = __atomic_load_n(&barrier->phase, __ATOMIC_RELAXED);
7095 if (__atomic_fetch_add(&barrier->arrived, 1, __ATOMIC_ACQ_REL) ==
7096 barrier->lanes - 1) {
7097 __atomic_store_n(&barrier->arrived, 0, __ATOMIC_RELAXED);
7098 __atomic_store_n(&barrier->phase, phase + 1, __ATOMIC_RELEASE);
7101 while (__atomic_load_n(&barrier->phase, __ATOMIC_ACQUIRE) == phase) {
7102#if defined(__i386__) || defined(__x86_64__)
7115 const ck_attention_f16_prefill_qtile64_args_t *args =
7116 (
const ck_attention_f16_prefill_qtile64_args_t *) opaque;
7117 const int query_tiles =
7119 const int total_jobs = args->num_heads * query_tiles;
7124 nth >= args->num_kv_heads) {
7125 const int kv_group = (ith * args->num_kv_heads) / nth;
7126 const int worker_begin =
7127 (kv_group * nth + args->num_kv_heads - 1) / args->num_kv_heads;
7128 const int worker_end =
7129 ((kv_group + 1) * nth + args->num_kv_heads - 1) /
7131 const int lane = ith - worker_begin;
7132 const int lanes = worker_end - worker_begin;
7133 const int head_begin =
7134 (kv_group * args->num_heads + args->num_kv_heads - 1) /
7136 const int head_end =
7137 ((kv_group + 1) * args->num_heads + args->num_kv_heads - 1) /
7139 const int group_jobs = (head_end - head_begin) * query_tiles;
7140 job_begin = head_begin * query_tiles + (group_jobs * lane) / lanes;
7141 job_end = head_begin * query_tiles + (group_jobs * (lane + 1)) / lanes;
7143 job_begin = (total_jobs * ith) / nth;
7144 job_end = (total_jobs * (ith + 1)) / nth;
7146 const int head_begin = (args->num_heads * ith) / nth;
7147 const int head_end = (args->num_heads * (ith + 1)) / nth;
7148 job_begin = head_begin * query_tiles;
7149 job_end = head_end * query_tiles;
7151 if (job_begin >= job_end)
return;
7153 const int kv_tokens = args->past_tokens + args->q_tokens;
7154 const float scale = args->attention_scale != 0.0f
7156 const size_t kv_head_stride =
7157 (size_t) args->cache_capacity * (
size_t) args->aligned_head_dim;
7159 float *q_tile = (
float *) alloca(
7161 float *k_tile = (
float *) alloca(
7163 float *v_tile = (
float *) alloca(
7165 float *kq = (
float *) alloca(
7167 float *vkq = (
float *) alloca(
7170 for (
int job = job_begin; job < job_end; ++job) {
7171 const int h = job / query_tiles;
7174 (int) ((
long long) h * (
long long) args->num_kv_heads /
7175 (
long long) args->num_heads);
7176 const uint16_t *k_head = args->k_cache + (size_t) kv_head * kv_head_stride;
7177 const uint16_t *v_head = args->v_cache + (size_t) kv_head * kv_head_stride;
7179 const int tile_rows =
7181 ? (args->q_tokens - iq)
7188 max_row[tq] = -INFINITY;
7195 for (
int tq = 0; tq < tile_rows; ++tq) {
7196 const float *q_vec = args->q +
7197 (size_t) h * args->q_head_stride +
7198 (
size_t) (iq + tq) * (
size_t) args->aligned_head_dim;
7199 memcpy(q_tile + (
size_t) tq * (
size_t) args->head_dim,
7201 (
size_t) args->head_dim *
sizeof(
float));
7216 for (
int tk = 0; tk < kv_tile; ++tk) {
7217 const uint16_t *k_vec = k_head +
7218 (size_t) (ik + tk) * (size_t) args->aligned_head_dim;
7219 const uint16_t *v_vec = v_head +
7220 (size_t) (ik + tk) * (size_t) args->aligned_head_dim;
7221 for (
int d = 0; d < args->head_dim; ++d) {
7224 v_tile[(size_t) tk * (
size_t) args->head_dim + (size_t) d] =
7236 float *kq_row = kq +
7238 const int last_valid_key = args->past_tokens + iq + tq;
7240 const int key = ik + tk;
7241 if (tk >= kv_tile || tq >= tile_rows || key > last_valid_key) {
7242 kq_row[tk] = -INFINITY;
7246 const float tile_max =
7248 if (tile_max == -INFINITY) {
7254 const float old_max = max_row[tq];
7255 const float new_max = old_max > tile_max ? old_max : tile_max;
7256 if (new_max > old_max) {
7259 vkq + (
size_t) tq * (
size_t) args->head_dim,
7260 args->head_dim, ms);
7263 max_row[tq] = new_max;
7264 sum_row[tq] = (float) (
7265 (
double) sum_row[tq] +
7275 for (
int tq = 0; tq < tile_rows; ++tq) {
7276 float *out_vec = args->output +
7277 (size_t) h * args->output_head_stride +
7278 (
size_t) (iq + tq) * (
size_t) args->aligned_head_dim;
7279 const float inv_sum =
7280 sum_row[tq] == 0.0f ? 0.0f : 1.0f / sum_row[tq];
7281 for (
int d = 0; d < args->head_dim; ++d) {
7283 vkq[(size_t) tq * (
size_t) args->head_dim + (size_t) d] * inv_sum;
7285 for (
int d = args->head_dim; d < args->aligned_head_dim; ++d) {
7294 const ck_attention_f16_prefill_gqa_reuse_args_t *args =
7295 (
const ck_attention_f16_prefill_gqa_reuse_args_t *) opaque;
7296 const ck_attention_f16_prefill_qtile64_args_t *base = &args->base;
7297 const int lanes = nth / base->num_kv_heads;
7298 const int kv_group = ith / lanes;
7299 const int lane = ith % lanes;
7300 const int heads_per_group = base->num_heads / base->num_kv_heads;
7301 const int head_begin = kv_group * heads_per_group;
7302 const int query_tiles =
7303 (base->q_tokens + args->query_tile_size - 1) / args->query_tile_size;
7304 const int kv_tokens = base->past_tokens + base->q_tokens;
7306 const size_t kv_head_stride =
7307 (size_t) base->cache_capacity * (
size_t) base->aligned_head_dim;
7308 const uint16_t *k_head =
7309 base->k_cache + (size_t) kv_group * kv_head_stride;
7310 const uint16_t *v_head =
7311 base->v_cache + (size_t) kv_group * kv_head_stride;
7312 float *shared_k = args->shared_k_tiles +
7314 float *shared_v = args->shared_v_tiles +
7316 ck_attention_gqa_team_barrier_t *barrier = &args->barriers[kv_group];
7317 const int max_group_jobs =
7318 heads_per_group * args->concurrent_query_tiles;
7319 const int local_capacity = (max_group_jobs + lanes - 1) / lanes;
7320 unsigned char *worker = args->worker_workspace +
7321 (size_t) ith * args->worker_workspace_stride;
7324 int *local_heads = (
int *) (worker + cursor);
7325 cursor += (size_t) local_capacity *
sizeof(
int);
7326 int *local_iq = (
int *) (worker + cursor);
7327 cursor += (size_t) local_capacity *
sizeof(
int);
7328 int *local_rows = (
int *) (worker + cursor);
7329 cursor += (size_t) local_capacity *
sizeof(
int);
7331 float *q_tiles = (
float *) (worker + cursor);
7332 cursor += (size_t) local_capacity * (
size_t) args->query_tile_size *
7333 (size_t) base->head_dim *
sizeof(
float);
7335 float *kq_tiles = (
float *) (worker + cursor);
7336 cursor += (size_t) local_capacity * (
size_t) args->query_tile_size *
7339 float *vkq_tiles = (
float *) (worker + cursor);
7340 cursor += (size_t) local_capacity * (
size_t) args->query_tile_size *
7341 (size_t) base->head_dim *
sizeof(
float);
7343 float *sum_rows = (
float *) (worker + cursor);
7344 cursor += (size_t) local_capacity * (
size_t) args->query_tile_size *
7347 float *max_rows = (
float *) (worker + cursor);
7349 for (
int query_tile_begin = 0; query_tile_begin < query_tiles;
7350 query_tile_begin += args->concurrent_query_tiles) {
7351 int batch_tiles = query_tiles - query_tile_begin;
7352 if (batch_tiles > args->concurrent_query_tiles) {
7353 batch_tiles = args->concurrent_query_tiles;
7355 const int group_jobs = heads_per_group * batch_tiles;
7358 for (
int group_job = lane; group_job < group_jobs; group_job += lanes) {
7359 const int local = local_jobs++;
7360 const int group_head = group_job / batch_tiles;
7361 const int batch_tile = group_job % batch_tiles;
7362 const int h = head_begin + group_head;
7364 (query_tile_begin + batch_tile) * args->query_tile_size;
7365 int tile_rows = base->q_tokens - iq;
7366 if (tile_rows > args->query_tile_size) {
7367 tile_rows = args->query_tile_size;
7369 local_heads[local] = h;
7370 local_iq[local] = iq;
7371 local_rows[local] = tile_rows;
7373 float *q_tile = q_tiles +
7374 (size_t) local * (
size_t) args->query_tile_size *
7375 (size_t) base->head_dim;
7376 float *vkq = vkq_tiles +
7377 (size_t) local * (
size_t) args->query_tile_size *
7378 (size_t) base->head_dim;
7379 float *sum_row = sum_rows +
7380 (size_t) local * (
size_t) args->query_tile_size;
7381 float *max_row = max_rows +
7382 (size_t) local * (
size_t) args->query_tile_size;
7384 (
size_t) args->query_tile_size * (
size_t) base->head_dim *
7387 (
size_t) args->query_tile_size * (
size_t) base->head_dim *
7389 for (
int tq = 0; tq < args->query_tile_size; ++tq) {
7391 max_row[tq] = -INFINITY;
7393 for (
int tq = 0; tq < tile_rows; ++tq) {
7394 const float *q_vec = base->q +
7395 (size_t) h * base->q_head_stride +
7396 (
size_t) (iq + tq) * (
size_t) base->aligned_head_dim;
7397 memcpy(q_tile + (
size_t) tq * (
size_t) base->head_dim,
7398 q_vec, (
size_t) base->head_dim *
sizeof(
float));
7402 int kv_limit = base->past_tokens +
7403 (query_tile_begin + batch_tiles) * args->query_tile_size;
7404 if (kv_limit > kv_tokens) kv_limit = kv_tokens;
7407 int kv_tile = kv_limit - ik;
7410 for (
int flat = lane; flat < packed_elems; flat += lanes) {
7411 const int tk = flat / base->head_dim;
7412 const int d = flat % base->head_dim;
7413 float k_value = 0.0f;
7414 float v_value = 0.0f;
7416 const uint16_t *k_vec = k_head +
7417 (size_t) (ik + tk) * (size_t) base->aligned_head_dim;
7418 const uint16_t *v_vec = v_head +
7419 (size_t) (ik + tk) * (size_t) base->aligned_head_dim;
7421 k_vec[d], base->cache_is_bf16);
7423 v_vec[d], base->cache_is_bf16);
7427 shared_v[(size_t) tk * (
size_t) base->head_dim + (size_t) d] =
7432 for (
int local = 0; local < local_jobs; ++local) {
7433 const int iq = local_iq[local];
7434 const int tile_rows = local_rows[local];
7435 float *q_tile = q_tiles +
7436 (size_t) local * (
size_t) args->query_tile_size *
7437 (size_t) base->head_dim;
7438 float *kq = kq_tiles +
7439 (size_t) local * (
size_t) args->query_tile_size *
7441 float *vkq = vkq_tiles +
7442 (size_t) local * (
size_t) args->query_tile_size *
7443 (size_t) base->head_dim;
7444 float *sum_row = sum_rows +
7445 (size_t) local * (
size_t) args->query_tile_size;
7446 float *max_row = max_rows +
7447 (size_t) local * (
size_t) args->query_tile_size;
7452 kq, q_tile, shared_k, args->query_tile_size,
7457 for (
int tq = 0; tq < args->query_tile_size; ++tq) {
7459 const int last_valid_key = base->past_tokens + iq + tq;
7461 const int key = ik + tk;
7462 if (tk >= kv_tile || tq >= tile_rows || key > last_valid_key) {
7463 kq_row[tk] = -INFINITY;
7466 const float tile_max =
7468 if (tile_max == -INFINITY) {
7473 const float old_max = max_row[tq];
7474 const float new_max = old_max > tile_max ? old_max : tile_max;
7475 if (new_max > old_max) {
7479 vkq + (
size_t) tq * (
size_t) base->head_dim,
7480 base->head_dim, ms);
7483 max_row[tq] = new_max;
7484 sum_row[tq] = (float) (
7485 (
double) sum_row[tq] +
7490 vkq, kq, shared_v, args->query_tile_size,
7496 for (
int local = 0; local < local_jobs; ++local) {
7497 const int h = local_heads[local];
7498 const int iq = local_iq[local];
7499 const int tile_rows = local_rows[local];
7500 float *vkq = vkq_tiles +
7501 (size_t) local * (
size_t) args->query_tile_size *
7502 (size_t) base->head_dim;
7503 float *sum_row = sum_rows +
7504 (size_t) local * (
size_t) args->query_tile_size;
7505 for (
int tq = 0; tq < tile_rows; ++tq) {
7506 float *out_vec = base->output +
7507 (size_t) h * base->output_head_stride +
7508 (
size_t) (iq + tq) * (
size_t) base->aligned_head_dim;
7509 const float inv_sum =
7510 sum_row[tq] == 0.0f ? 0.0f : 1.0f / sum_row[tq];
7511 for (
int d = 0; d < base->head_dim; ++d) {
7513 (size_t) tq * (
size_t) base->head_dim + (size_t) d] *
7516 for (
int d = base->head_dim; d < base->aligned_head_dim; ++d) {
7526 const uint16_t *k_cache,
7527 const uint16_t *v_cache,
7535 int aligned_head_dim,
7537 float attention_scale,
7538 size_t q_head_stride,
7539 size_t output_head_stride,
7546 ck_attention_f16_prefill_qtile64_args_t args = {
7551 .num_heads = num_heads,
7552 .num_kv_heads = num_kv_heads,
7553 .q_tokens = q_tokens,
7554 .past_tokens = past_tokens,
7555 .cache_capacity = cache_capacity,
7556 .head_dim = head_dim,
7557 .aligned_head_dim = aligned_head_dim,
7558 .cache_is_bf16 = cache_is_bf16,
7559 .attention_scale = attention_scale,
7560 .schedule = schedule,
7561 .q_head_stride = q_head_stride,
7562 .output_head_stride = output_head_stride,
7566 const int query_tiles =
7568 int available_jobs = num_heads;
7570 available_jobs = num_kv_heads;
7573 available_jobs = num_heads * query_tiles;
7575 if (active > available_jobs) active = available_jobs;
7587 const uint16_t *k_cache,
7588 const uint16_t *v_cache,
7596 int aligned_head_dim,
7597 int query_tile_size,
7598 int concurrent_query_tiles,
7600 size_t workspace_bytes)
7602 if (!q || !k_cache || !v_cache || !output || !workspace || num_heads <= 0 ||
7603 num_kv_heads <= 0 || num_heads % num_kv_heads != 0 ||
7604 query_tile_size <= 0 || q_tokens < query_tile_size || past_tokens < 0 ||
7605 past_tokens + q_tokens > cache_capacity || head_dim <= 0 ||
7606 aligned_head_dim < head_dim || query_tile_size < 16 ||
7607 query_tile_size > 128 || query_tile_size % 16 != 0 ||
7608 concurrent_query_tiles <= 0 || concurrent_query_tiles > 4) {
7614 if (!pool || active < num_kv_heads || active % num_kv_heads != 0 ||
7618 const size_t required_workspace =
7620 num_heads, num_kv_heads, head_dim, active,
7621 query_tile_size, concurrent_query_tiles);
7622 if (required_workspace == 0 || workspace_bytes < required_workspace) {
7625 const int lanes = active / num_kv_heads;
7626 const size_t tile_elems =
7628 uintptr_t workspace_address = (uintptr_t) workspace;
7629 workspace_address = (workspace_address + 63u) & ~(uintptr_t) 63u;
7630 unsigned char *workspace_base = (
unsigned char *) workspace_address;
7632 float *shared_k_tiles = (
float *) (workspace_base + cursor);
7633 cursor += tile_elems *
sizeof(float);
7635 float *shared_v_tiles = (
float *) (workspace_base + cursor);
7636 cursor += tile_elems *
sizeof(float);
7638 ck_attention_gqa_team_barrier_t *barriers =
7639 (ck_attention_gqa_team_barrier_t *) (workspace_base + cursor);
7640 cursor += (size_t) num_kv_heads *
sizeof(*barriers);
7642 unsigned char *worker_workspace = workspace_base + cursor;
7643 const size_t worker_workspace_stride =
7645 num_heads, num_kv_heads, head_dim, active,
7646 query_tile_size, concurrent_query_tiles);
7647 for (
int group = 0; group < num_kv_heads; ++group) {
7648 __atomic_store_n(&barriers[group].arrived, 0, __ATOMIC_RELAXED);
7649 __atomic_store_n(&barriers[group].phase, 0, __ATOMIC_RELAXED);
7650 barriers[group].lanes = lanes;
7653 ck_attention_f16_prefill_gqa_reuse_args_t args = {
7659 .num_heads = num_heads,
7660 .num_kv_heads = num_kv_heads,
7661 .q_tokens = q_tokens,
7662 .past_tokens = past_tokens,
7663 .cache_capacity = cache_capacity,
7664 .head_dim = head_dim,
7665 .aligned_head_dim = aligned_head_dim,
7669 (size_t) q_tokens * (
size_t) aligned_head_dim,
7670 .output_head_stride =
7671 (size_t) q_tokens * (
size_t) aligned_head_dim,
7673 .shared_k_tiles = shared_k_tiles,
7674 .shared_v_tiles = shared_v_tiles,
7675 .barriers = barriers,
7676 .worker_workspace = worker_workspace,
7677 .worker_workspace_stride = worker_workspace_stride,
7678 .query_tile_size = query_tile_size,
7679 .concurrent_query_tiles = concurrent_query_tiles,
7688 const uint16_t *k_cache,
7689 const uint16_t *v_cache,
7697 int aligned_head_dim,
7699 float *token_workspace,
7700 size_t token_workspace_bytes,
7701 void *gqa_workspace,
7702 size_t gqa_workspace_bytes,
7703 int route_num_heads,
7704 int route_num_kv_heads,
7706 int route_query_tokens,
7707 int route_min_kv_tokens,
7709 int route_query_tile_size,
7710 int route_concurrent_query_tiles)
7712 if (route_num_heads <= 0 || route_num_kv_heads <= 0 ||
7713 route_num_heads % route_num_kv_heads != 0 || route_head_dim <= 0 ||
7714 route_query_tokens <= 0 || route_min_kv_tokens < route_query_tokens ||
7715 route_workers < route_num_kv_heads ||
7716 route_workers % route_num_kv_heads != 0 ||
7717 route_query_tile_size < 16 || route_query_tile_size > 128 ||
7718 route_query_tile_size % 16 != 0 ||
7719 route_concurrent_query_tiles <= 0 ||
7720 route_concurrent_query_tiles > 4) {
7725 const int kv_tokens = past_tokens + q_tokens;
7727 num_heads == route_num_heads && num_kv_heads == route_num_kv_heads &&
7728 head_dim == route_head_dim && aligned_head_dim == route_head_dim &&
7729 q_tokens == route_query_tokens && kv_tokens >= route_min_kv_tokens &&
7730 active == route_workers) {
7732 q, k_cache, v_cache, output, num_heads, num_kv_heads,
7733 q_tokens, past_tokens, cache_capacity, head_dim, aligned_head_dim,
7734 route_query_tile_size, route_concurrent_query_tiles,
7735 gqa_workspace, gqa_workspace_bytes);
7738 q, k_cache, v_cache, output, num_heads, num_kv_heads,
7739 q_tokens, past_tokens, cache_capacity, head_dim, aligned_head_dim,
7740 reduction, token_workspace, token_workspace_bytes);
7745 const uint16_t *k_cache,
7746 const uint16_t *v_cache,
7754 int aligned_head_dim,
7757 if (!q || !k_cache || !v_cache || !output || num_heads <= 0 ||
7759 past_tokens + q_tokens > cache_capacity || head_dim <= 0 ||
7760 aligned_head_dim < head_dim) {
7764 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
7765 past_tokens, cache_capacity, head_dim, aligned_head_dim, 0, 0.0f,
7766 (
size_t) q_tokens * (
size_t) aligned_head_dim,
7767 (
size_t) q_tokens * (
size_t) aligned_head_dim, schedule);
7772 const uint16_t *k_cache,
7773 const uint16_t *v_cache,
7781 int aligned_head_dim,
7783 float *token_workspace,
7784 size_t token_workspace_bytes)
7786 if (!q || !k_cache || !v_cache || !output ||
7787 num_heads <= 0 || num_kv_heads <= 0 || q_tokens <= 0 ||
7788 past_tokens < 0 || past_tokens + q_tokens > cache_capacity ||
7789 head_dim <= 0 || aligned_head_dim < head_dim) {
7800 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
7801 past_tokens, cache_capacity, head_dim, aligned_head_dim, 0, 0.0f,
7802 (
size_t) q_tokens * (
size_t) aligned_head_dim,
7803 (
size_t) q_tokens * (
size_t) aligned_head_dim,
7813 const size_t token_elems = (size_t) num_heads * (
size_t) aligned_head_dim;
7814 if (token_elems > SIZE_MAX / (2 *
sizeof(
float))) {
7817 const size_t required_bytes = 2 * token_elems *
sizeof(float);
7818 if (!token_workspace || token_workspace_bytes < required_bytes) {
7821 float *q_token = token_workspace;
7822 float *out_token = token_workspace + token_elems;
7825 for (
int t = 0; t < q_tokens; ++t) {
7826 for (
int h = 0; h < num_heads; ++h) {
7827 const float *src = q +
7828 ((size_t) h * (
size_t) q_tokens + (size_t) t) * (size_t) aligned_head_dim;
7829 memcpy(q_token + (
size_t) h * (
size_t) aligned_head_dim,
7831 (
size_t) aligned_head_dim *
sizeof(
float));
7835 q_token, k_cache, v_cache, out_token,
7836 num_heads, num_kv_heads, past_tokens + t + 1, cache_capacity,
7837 head_dim, aligned_head_dim, reduction);
7842 for (
int h = 0; h < num_heads; ++h) {
7843 float *dst = output +
7844 ((size_t) h * (
size_t) q_tokens + (size_t) t) * (size_t) aligned_head_dim;
7846 out_token + (
size_t) h * (
size_t) aligned_head_dim,
7847 (
size_t) aligned_head_dim *
sizeof(
float));
7856 const uint16_t *k_cache,
7857 const uint16_t *v_cache,
7865 int aligned_head_dim,
7868 float *token_workspace,
7869 size_t token_workspace_bytes,
7870 const int *segment_lengths,
7873 if (!q || !k_cache || !v_cache || !output || num_heads <= 0 ||
7874 num_kv_heads <= 0 || q_tokens <= 0 || past_tokens < 0 ||
7875 cache_capacity <= 0 || past_tokens > cache_capacity ||
7876 q_tokens > cache_capacity - past_tokens || head_dim <= 0 ||
7877 aligned_head_dim < head_dim || sliding_window < 0) {
7880 int one_segment = q_tokens;
7881 if (!segment_lengths && num_segments == 0) {
7882 segment_lengths = &one_segment;
7885 if (!segment_lengths || num_segments <= 0 ||
7886 (num_segments > q_tokens && num_segments > 3)) {
7889 int planned_rows = 0;
7890 for (
int s = 0; s < num_segments; ++s) {
7891 if (segment_lengths[s] < 0 || segment_lengths[s] > q_tokens - planned_rows) {
7894 planned_rows += segment_lengths[s];
7897 if ((
size_t) num_heads > SIZE_MAX / (
size_t) aligned_head_dim) {
7900 const size_t token_elems = (size_t) num_heads * (
size_t) aligned_head_dim;
7901 if (token_elems > SIZE_MAX / (2 *
sizeof(
float)) || !token_workspace ||
7902 token_workspace_bytes < 2 * token_elems *
sizeof(float)) {
7905 float *q_token = token_workspace;
7906 float *out_token = token_workspace + token_elems;
7908 for (
int s = 0; s < num_segments; ++s) {
7909 const int rows = segment_lengths[s];
7910 if (rows == 0)
continue;
7914 (sliding_window == 0 || past_tokens + row_offset + rows <= sliding_window)) {
7916 q + (
size_t) row_offset * (
size_t) aligned_head_dim,
7918 output + (
size_t) row_offset * (
size_t) aligned_head_dim,
7919 num_heads, num_kv_heads, rows, past_tokens + row_offset,
7920 cache_capacity, head_dim, aligned_head_dim, 0, 1.0f,
7921 (
size_t) q_tokens * (
size_t) aligned_head_dim,
7922 (
size_t) q_tokens * (
size_t) aligned_head_dim,
7933 for (
int local_row = 0; local_row < rows; ++local_row) {
7934 const int t = row_offset + local_row;
7935 for (
int h = 0; h < num_heads; ++h) {
7936 const float *src = q +
7937 ((size_t) h * (
size_t) q_tokens + (size_t) t) *
7938 (size_t) aligned_head_dim;
7939 memcpy(q_token + (
size_t) h * (
size_t) aligned_head_dim, src,
7940 (
size_t) aligned_head_dim *
sizeof(
float));
7943 q_token, k_cache, v_cache, out_token, num_heads, num_kv_heads,
7944 past_tokens + t + 1, cache_capacity, head_dim, aligned_head_dim,
7945 sliding_window, selected);
7949 for (
int h = 0; h < num_heads; ++h) {
7950 float *dst = output +
7951 ((size_t) h * (
size_t) q_tokens + (size_t) t) *
7952 (size_t) aligned_head_dim;
7953 memcpy(dst, out_token + (
size_t) h * (
size_t) aligned_head_dim,
7954 (
size_t) aligned_head_dim *
sizeof(
float));
7963 const float *q,
const uint16_t *k_cache,
const uint16_t *v_cache,
7964 float *output,
int num_heads,
int num_kv_heads,
int q_tokens,
7965 int past_tokens,
int cache_capacity,
int head_dim,
int aligned_head_dim,
7967 size_t token_workspace_bytes)
7970 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
7971 past_tokens, cache_capacity, head_dim, aligned_head_dim, 0, reduction,
7972 token_workspace, token_workspace_bytes, NULL, 0);
7976 const float *q,
const uint16_t *k_cache,
const uint16_t *v_cache,
7977 float *output,
int num_heads,
int num_kv_heads,
int q_tokens,
7978 int past_tokens,
int cache_capacity,
int head_dim,
int aligned_head_dim,
7980 float *token_workspace,
size_t token_workspace_bytes)
7983 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
7984 past_tokens, cache_capacity, head_dim, aligned_head_dim, sliding_window,
7985 reduction, token_workspace, token_workspace_bytes, NULL, 0);
7989 const float *q,
const uint16_t *k_cache,
const uint16_t *v_cache,
7990 float *output,
int num_heads,
int num_kv_heads,
int q_tokens,
7991 int past_tokens,
int cache_capacity,
int head_dim,
int aligned_head_dim,
7993 float *token_workspace,
size_t token_workspace_bytes,
7994 const int *segment_lengths,
int num_segments)
7997 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
7998 past_tokens, cache_capacity, head_dim, aligned_head_dim, sliding_window,
7999 reduction, token_workspace, token_workspace_bytes,
8000 segment_lengths, num_segments);
8004 const float *q,
const uint16_t *k_cache,
const uint16_t *v_cache,
8005 float *output,
int num_heads,
int num_kv_heads,
int q_tokens,
8006 int past_tokens,
int cache_capacity,
int head_dim,
int aligned_head_dim,
8008 size_t token_workspace_bytes,
const int *segment_lengths,
int num_segments)
8011 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
8012 past_tokens, cache_capacity, head_dim, aligned_head_dim, 0,
8013 reduction, token_workspace, token_workspace_bytes,
8014 segment_lengths, num_segments);
8019 const uint16_t *k_cache,
8020 const uint16_t *v_cache,
8028 int aligned_head_dim,
8030 float *token_workspace,
8031 size_t token_workspace_bytes,
8032 const int *segment_lengths,
8036 if (!q || !k_cache || !v_cache || !output || !segment_lengths ||
8037 num_segments <= 0 || num_heads <= 0 || num_kv_heads <= 0 ||
8038 q_tokens <= 0 || past_tokens < 0 || past_tokens + q_tokens > cache_capacity ||
8039 head_dim <= 0 || aligned_head_dim < head_dim) {
8042 int planned_rows = 0;
8043 for (
int s = 0; s < num_segments; ++s) {
8044 if (segment_lengths[s] < 0 || segment_lengths[s] > q_tokens - planned_rows) {
8047 planned_rows += segment_lengths[s];
8051 const size_t head_stride = (size_t) q_tokens * (
size_t) aligned_head_dim;
8052 const size_t token_elems = (size_t) num_heads * (
size_t) aligned_head_dim;
8053 if (!token_workspace || token_workspace_bytes < 2 * token_elems *
sizeof(
float)) {
8058 for (
int s = 0; s < num_segments; ++s) {
8059 const int rows = segment_lengths[s];
8060 if (rows == 0)
continue;
8063 ck_attention_f16_prefill_qtile64_args_t args = {
8064 .q = q + (size_t) row_offset * (
size_t) aligned_head_dim,
8067 .output = output + (size_t) row_offset * (
size_t) aligned_head_dim,
8068 .num_heads = num_heads,
8069 .num_kv_heads = num_kv_heads,
8071 .past_tokens = past_tokens + row_offset,
8072 .cache_capacity = cache_capacity,
8073 .head_dim = head_dim,
8074 .aligned_head_dim = aligned_head_dim,
8076 .schedule = schedule,
8077 .q_head_stride = head_stride,
8078 .output_head_stride = head_stride,
8082 const int query_tiles =
8084 const int available_jobs =
8087 : num_heads * query_tiles;
8088 if (active > available_jobs) active = available_jobs;
8096 float *q_token = token_workspace;
8097 float *out_token = token_workspace + token_elems;
8102 for (
int t = 0; t < rows; ++t) {
8103 for (
int h = 0; h < num_heads; ++h) {
8105 q_token + (
size_t) h * (
size_t) aligned_head_dim,
8106 q + (
size_t) h * head_stride +
8107 (
size_t) (row_offset + t) * (
size_t) aligned_head_dim,
8108 (
size_t) aligned_head_dim *
sizeof(
float));
8112 q_token, k_cache, v_cache, out_token,
8113 num_heads, num_kv_heads, past_tokens + row_offset + t + 1,
8114 cache_capacity, head_dim, aligned_head_dim, selected);
8116 for (
int h = 0; h < num_heads; ++h) {
8118 output + (
size_t) h * head_stride +
8119 (
size_t) (row_offset + t) * (
size_t) aligned_head_dim,
8120 out_token + (
size_t) h * (
size_t) aligned_head_dim,
8121 (
size_t) aligned_head_dim *
sizeof(
float));
8132 const uint16_t *k_cache,
8133 const uint16_t *v_cache,
8141 int aligned_head_dim,
8143 float *token_workspace,
8144 size_t token_workspace_bytes,
8145 const int *segment_lengths,
8149 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
8150 past_tokens, cache_capacity, head_dim, aligned_head_dim, reduction,
8151 token_workspace, token_workspace_bytes, segment_lengths, num_segments,
8157 const uint16_t *k_cache,
8158 const uint16_t *v_cache,
8166 int aligned_head_dim,
8172 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
8173 past_tokens, cache_capacity, head_dim, aligned_head_dim, reduction,
8177 if (num_heads <= 0 || aligned_head_dim <= 0 ||
8178 (
size_t) num_heads > SIZE_MAX / (
size_t) aligned_head_dim) {
8181 const size_t token_elements = (size_t) num_heads * (
size_t) aligned_head_dim;
8182 if (token_elements > SIZE_MAX / (2 *
sizeof(
float))) {
8185 const size_t workspace_bytes = 2 * token_elements *
sizeof(float);
8186 float *workspace = (
float *) malloc(workspace_bytes);
8192 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
8193 past_tokens, cache_capacity, head_dim, aligned_head_dim, reduction,
8194 workspace, workspace_bytes);
8199#if defined(__AVX512F__)
8200typedef void (*ck_mkl_gemm_bf16_fn)(
8201 const char *,
const char *,
const int *,
const int *,
const int *,
8202 const float *,
const uint16_t *,
const int *,
const uint16_t *,
const int *,
8203 const float *,
float *,
const int *);
8204typedef void (*ck_mkl_cblas_sgemm_fn)(
8205 int, int, int, int, int, int, float,
8206 const float *, int,
const float *, int, float,
float *, int);
8207typedef void (*ck_mkl_cblas_sgemm_batch_fn)(
8208 int,
const int *,
const int *,
const int *,
const int *,
const int *,
8209 const float *,
const float **,
const int *,
const float **,
const int *,
8210 const float *,
float **,
const int *, int,
const int *);
8211typedef __m512 (*ck_sleef_expf16_fn)(__m512);
8213static ck_mkl_gemm_bf16_fn ck_pytorch_bf16_gemm = NULL;
8214static ck_mkl_cblas_sgemm_fn ck_pytorch_sgemm = NULL;
8215static ck_mkl_cblas_sgemm_batch_fn ck_pytorch_sgemm_batch = NULL;
8216static ck_sleef_expf16_fn ck_pytorch_attention_expf16 = NULL;
8217static void *ck_pytorch_mkl_handle = NULL;
8218static void *ck_pytorch_attention_sleef_handle = NULL;
8219static pthread_once_t ck_pytorch_attention_once = PTHREAD_ONCE_INIT;
8221static void ck_bind_pytorch_attention_primitives(
void)
8223 const char *mkl_library = getenv(
"CK_MKL_LIBRARY");
8224 if (mkl_library && *mkl_library) {
8225 ck_pytorch_mkl_handle = dlopen(mkl_library, RTLD_NOW | RTLD_LOCAL);
8226 if (ck_pytorch_mkl_handle) {
8227 ck_pytorch_bf16_gemm = (ck_mkl_gemm_bf16_fn)dlsym(
8228 ck_pytorch_mkl_handle,
"gemm_bf16bf16f32");
8229 ck_pytorch_sgemm = (ck_mkl_cblas_sgemm_fn)dlsym(
8230 ck_pytorch_mkl_handle,
"cblas_sgemm");
8231 ck_pytorch_sgemm_batch = (ck_mkl_cblas_sgemm_batch_fn)dlsym(
8232 ck_pytorch_mkl_handle,
"cblas_sgemm_batch");
8235 ck_pytorch_bf16_gemm =
8236 (ck_mkl_gemm_bf16_fn)dlsym(
RTLD_DEFAULT,
"gemm_bf16bf16f32");
8238 (ck_mkl_cblas_sgemm_fn)dlsym(
RTLD_DEFAULT,
"cblas_sgemm");
8239 ck_pytorch_sgemm_batch =
8240 (ck_mkl_cblas_sgemm_batch_fn)dlsym(
RTLD_DEFAULT,
"cblas_sgemm_batch");
8241 if (!ck_pytorch_bf16_gemm || !ck_pytorch_sgemm ||
8242 !ck_pytorch_sgemm_batch) {
8243 mkl_library =
"libmkl_rt.so.2";
8244 ck_pytorch_mkl_handle = dlopen(mkl_library, RTLD_NOW | RTLD_LOCAL);
8245 if (ck_pytorch_mkl_handle) {
8246 ck_pytorch_bf16_gemm = (ck_mkl_gemm_bf16_fn)dlsym(
8247 ck_pytorch_mkl_handle,
"gemm_bf16bf16f32");
8248 ck_pytorch_sgemm = (ck_mkl_cblas_sgemm_fn)dlsym(
8249 ck_pytorch_mkl_handle,
"cblas_sgemm");
8250 ck_pytorch_sgemm_batch = (ck_mkl_cblas_sgemm_batch_fn)dlsym(
8251 ck_pytorch_mkl_handle,
"cblas_sgemm_batch");
8256 const char *sleef_library = getenv(
"CK_SLEEF_LIBRARY");
8257 if (sleef_library && *sleef_library) {
8258 ck_pytorch_attention_sleef_handle =
8259 dlopen(sleef_library, RTLD_NOW | RTLD_LOCAL);
8260 if (ck_pytorch_attention_sleef_handle) {
8261 ck_pytorch_attention_expf16 = (ck_sleef_expf16_fn)dlsym(
8262 ck_pytorch_attention_sleef_handle,
"Sleef_expf16_u10");
8265 ck_pytorch_attention_expf16 =
8266 (ck_sleef_expf16_fn)dlsym(
RTLD_DEFAULT,
"Sleef_expf16_u10");
8270static float ck_pytorch_scale_max_f32(
float *scores,
int count,
float scale)
8272 const __m512 scale_v = _mm512_set1_ps(scale);
8273 __m512 maximum_v = _mm512_set1_ps(-INFINITY);
8275 for (; i + 16 <=
count; i += 16) {
8276 __m512 values = _mm512_mul_ps(_mm512_loadu_ps(scores + i), scale_v);
8277 maximum_v = _mm512_max_ps(maximum_v, values);
8278 _mm512_storeu_ps(scores + i, values);
8280 float maximum = _mm512_reduce_max_ps(maximum_v);
8281 for (; i <
count; ++i) {
8283 maximum = fmaxf(maximum, scores[i]);
8288static float ck_pytorch_reduce_add_f32x16(__m512 values)
8290 __m512 shuffled = _mm512_shuffle_f32x4(values, values, 0x4e);
8291 values = _mm512_add_ps(values, shuffled);
8292 shuffled = _mm512_shuffle_f32x4(values, values, 0xb1);
8293 values = _mm512_add_ps(values, shuffled);
8294 shuffled = _mm512_shuffle_ps(values, values, 0x4e);
8295 values = _mm512_add_ps(values, shuffled);
8296 shuffled = _mm512_shuffle_ps(values, values, 0xb1);
8297 values = _mm512_add_ps(values, shuffled);
8298 return _mm512_cvtss_f32(values);
8301static inline __m512 ck_pytorch_flash_fexp_u20_f32x16(__m512 values)
8303 const __m512 c0 = _mm512_set1_ps(0.00010703434948458272f);
8304 const __m512 c1 = _mm512_set1_ps(0.30354260500649682f);
8305 const __m512 c2 = _mm512_set1_ps(-0.22433836478672356f);
8306 const __m512 c3 = _mm512_set1_ps(-0.079204240219773236f);
8307 const __m512 log2e = _mm512_castsi512_ps(_mm512_set1_epi32(0x3fb8aa3b));
8308 const __m512 exponent_scale = _mm512_set1_ps(8388608.0f);
8309 const __m512 exponent_bias = _mm512_set1_ps(8388608.0f * 127.0f);
8310 const __m512 min_input =
8311 _mm512_castsi512_ps(_mm512_set1_epi32(0xc2aeac50));
8312 const __m512 max_input =
8313 _mm512_castsi512_ps(_mm512_set1_epi32(0x42b17218));
8315 const __mmask16 below_min =
8316 _mm512_cmp_ps_mask(values, min_input, _CMP_LT_OS);
8317 const __mmask16 above_max =
8318 _mm512_cmp_ps_mask(values, max_input, _CMP_GT_OS);
8319 __m512 base2 = _mm512_mul_ps(values, log2e);
8320 const __m512 fractional = _mm512_sub_ps(base2, _mm512_floor_ps(base2));
8321 __m512 correction = _mm512_fmadd_ps(fractional, c3, c2);
8322 correction = _mm512_fmadd_ps(fractional, correction, c1);
8323 correction = _mm512_fmadd_ps(fractional, correction, c0);
8324 base2 = _mm512_sub_ps(base2, correction);
8325 const __m512 encoded =
8326 _mm512_fmadd_ps(exponent_scale, base2, exponent_bias);
8327 __m512i result = _mm512_cvttps_epi32(encoded);
8328 result = _mm512_mask_mov_epi32(result, below_min, _mm512_setzero_epi32());
8329 result = _mm512_mask_mov_epi32(
8330 result, above_max, _mm512_set1_epi32(0x7f800000));
8331 return _mm512_castsi512_ps(result);
8334static float ck_pytorch_exp_sum_bf16(
8335 float *scores, uint16_t *probabilities,
int count,
float maximum)
8337 const __m512 maximum_v = _mm512_set1_ps(maximum);
8338 __m512 sum_lo_v = _mm512_setzero_ps();
8339 __m512 sum_hi_v = _mm512_setzero_ps();
8340 __m512 sum_tail_v = _mm512_setzero_ps();
8342 for (; i + 32 <=
count; i += 32) {
8343 __m512 values_lo = _mm512_sub_ps(
8344 _mm512_loadu_ps(scores + i), maximum_v);
8345 __m512 values_hi = _mm512_sub_ps(
8346 _mm512_loadu_ps(scores + i + 16), maximum_v);
8347 values_lo = ck_pytorch_flash_fexp_u20_f32x16(values_lo);
8348 values_hi = ck_pytorch_flash_fexp_u20_f32x16(values_hi);
8349 sum_lo_v = _mm512_add_ps(sum_lo_v, values_lo);
8350 sum_hi_v = _mm512_add_ps(sum_hi_v, values_hi);
8352 _mm512_store_ps(lanes, values_lo);
8353 for (
int lane = 0; lane < 16; ++lane) {
8356 _mm512_store_ps(lanes, values_hi);
8357 for (
int lane = 0; lane < 16; ++lane) {
8361 for (; i + 16 <=
count; i += 16) {
8362 __m512 values = _mm512_sub_ps(_mm512_loadu_ps(scores + i), maximum_v);
8363 values = ck_pytorch_flash_fexp_u20_f32x16(values);
8364 sum_tail_v = _mm512_add_ps(sum_tail_v, values);
8366 _mm512_store_ps(lanes, values);
8367 for (
int lane = 0; lane < 16; ++lane) {
8371 sum_lo_v = _mm512_add_ps(sum_lo_v, sum_tail_v);
8372 float sum = ck_pytorch_reduce_add_f32x16(
8373 _mm512_add_ps(sum_lo_v, sum_hi_v));
8374 for (; i <
count; ++i) {
8375 const float value = expf(scores[i] - maximum);
8382static inline float ck_pytorch_reduce_max_f32x16(__m512 value)
8384 __m512 shuffled = _mm512_shuffle_f32x4(value, value, 0x4e);
8385 value = _mm512_max_ps(value, shuffled);
8386 shuffled = _mm512_shuffle_f32x4(value, value, 0xb1);
8387 value = _mm512_max_ps(value, shuffled);
8388 shuffled = _mm512_shuffle_ps(value, value, 0x4e);
8389 value = _mm512_max_ps(value, shuffled);
8390 shuffled = _mm512_shuffle_ps(value, value, 0xb1);
8391 value = _mm512_max_ps(value, shuffled);
8392 return _mm512_cvtss_f32(value);
8395static inline float ck_pytorch_reduce_sum_f32x16(__m512 value)
8397 __m512 shuffled = _mm512_shuffle_f32x4(value, value, 0x4e);
8398 value = _mm512_add_ps(value, shuffled);
8399 shuffled = _mm512_shuffle_f32x4(value, value, 0xb1);
8400 value = _mm512_add_ps(value, shuffled);
8401 shuffled = _mm512_shuffle_ps(value, value, 0x4e);
8402 value = _mm512_add_ps(value, shuffled);
8403 shuffled = _mm512_shuffle_ps(value, value, 0xb1);
8404 value = _mm512_add_ps(value, shuffled);
8405 return _mm512_cvtss_f32(value);
8408static float ck_pytorch_softmax_f32(
float *scores,
int count)
8414 float maximum = scores[0];
8415 for (
int i = 1; i <
count; ++i) {
8416 maximum = fmaxf(maximum, scores[i]);
8419 for (
int i = 0; i <
count; ++i) {
8420 scores[i] = expf(scores[i] - maximum);
8423 const float reciprocal = 1.0f / sum;
8424 for (
int i = 0; i <
count; ++i) {
8425 scores[i] *= reciprocal;
8430 __m512 maximum_v = _mm512_set1_ps(-INFINITY);
8432 for (; i + 16 <=
count; i += 16) {
8433 maximum_v = _mm512_max_ps(maximum_v, _mm512_loadu_ps(scores + i));
8436 const __mmask16 tail_mask = (__mmask16)((1u << (
count - i)) - 1u);
8437 maximum_v = _mm512_max_ps(
8439 _mm512_mask_loadu_ps(_mm512_set1_ps(-INFINITY), tail_mask, scores + i));
8441 const float maximum = ck_pytorch_reduce_max_f32x16(maximum_v);
8443 const __m512 maximum_broadcast = _mm512_set1_ps(maximum);
8444 __m512 sum_v = _mm512_setzero_ps();
8446 for (; i + 16 <=
count; i += 16) {
8447 __m512 values = _mm512_sub_ps(_mm512_loadu_ps(scores + i), maximum_broadcast);
8448 values = ck_pytorch_attention_expf16(values);
8449 _mm512_storeu_ps(scores + i, values);
8450 sum_v = _mm512_add_ps(sum_v, values);
8453 const __mmask16 tail_mask = (__mmask16)((1u << (
count - i)) - 1u);
8454 __m512 values = _mm512_mask_loadu_ps(
8455 _mm512_set1_ps(-INFINITY), tail_mask, scores + i);
8456 values = ck_pytorch_attention_expf16(
8457 _mm512_sub_ps(values, maximum_broadcast));
8458 values = _mm512_maskz_mov_ps(tail_mask, values);
8459 _mm512_mask_storeu_ps(scores + i, tail_mask, values);
8460 sum_v = _mm512_add_ps(sum_v, values);
8462 const float sum = ck_pytorch_reduce_sum_f32x16(sum_v);
8464 const float reciprocal = 1.0f / sum;
8465 const __m512 reciprocal_broadcast = _mm512_set1_ps(reciprocal);
8467 for (; i + 16 <=
count; i += 16) {
8471 _mm512_loadu_ps(scores + i), reciprocal_broadcast));
8474 const __mmask16 tail_mask = (__mmask16)((1u << (
count - i)) - 1u);
8475 const __m512 values = _mm512_maskz_loadu_ps(tail_mask, scores + i);
8476 _mm512_mask_storeu_ps(
8477 scores + i, tail_mask,
8478 _mm512_mul_ps(values, reciprocal_broadcast));
8484 const float *q_token,
8485 const uint16_t *k_cache,
8486 const uint16_t *v_cache,
8493 int aligned_head_dim)
8495 enum { CBLAS_ROW_MAJOR = 101, CBLAS_NO_TRANS = 111, CBLAS_TRANS = 112 };
8496 if (!ck_pytorch_sgemm_batch || !ck_pytorch_attention_expf16) {
8498 "CK BF16 PyTorch GQA math provider requires MKL cblas_sgemm_batch "
8499 "and SLEEF Sleef_expf16_u10\n");
8503 const size_t matrix_count =
8504 (size_t)num_heads * (
size_t)kv_tokens * (size_t)head_dim;
8505 float *k_scaled = (
float *)malloc(matrix_count *
sizeof(
float));
8506 float *v_f32 = (
float *)malloc(matrix_count *
sizeof(
float));
8507 float *scores = (
float *)malloc(
8508 (
size_t)num_heads * (size_t)kv_tokens *
sizeof(
float));
8509 float *q_scaled = (
float *)malloc(
8510 (
size_t)num_heads * (size_t)head_dim *
sizeof(
float));
8511 float *destination = (
float *)malloc(
8512 (
size_t)num_heads * (size_t)head_dim *
sizeof(
float));
8513 const float **q_batch = (
const float **)malloc(
8514 (
size_t)num_heads *
sizeof(*q_batch));
8515 const float **k_batch = (
const float **)malloc(
8516 (
size_t)num_heads *
sizeof(*k_batch));
8517 float **score_batch = (
float **)malloc(
8518 (
size_t)num_heads *
sizeof(*score_batch));
8519 const float **probability_batch = (
const float **)malloc(
8520 (
size_t)num_heads *
sizeof(*probability_batch));
8521 const float **v_batch = (
const float **)malloc(
8522 (
size_t)num_heads *
sizeof(*v_batch));
8523 float **destination_batch = (
float **)malloc(
8524 (
size_t)num_heads *
sizeof(*destination_batch));
8525 if (!k_scaled || !v_f32 || !scores || !q_scaled || !destination ||
8526 !q_batch || !k_batch || !score_batch || !probability_batch ||
8527 !v_batch || !destination_batch) {
8528 free(destination_batch);
8530 free(probability_batch);
8545 const float split_scale = (float)sqrt(sqrt(1.0 / (
double)head_dim));
8546 const size_t cache_head_stride =
8547 (size_t)cache_capacity * (
size_t)aligned_head_dim;
8548 const int heads_per_kv = num_heads / num_kv_heads;
8550 for (
int h = 0; h < num_heads; ++h) {
8551 const int kv_head = h / heads_per_kv;
8552 const uint16_t *k_head = k_cache + (size_t)kv_head * cache_head_stride;
8553 const uint16_t *v_head = v_cache + (size_t)kv_head * cache_head_stride;
8554 float *k_repeated = k_scaled +
8555 (size_t)h * (
size_t)kv_tokens * (size_t)head_dim;
8556 float *v_repeated = v_f32 +
8557 (size_t)h * (
size_t)kv_tokens * (size_t)head_dim;
8559 for (
int d = 0; d < head_dim; ++d) {
8560 const size_t compact = (size_t)
token * (
size_t)head_dim + (size_t)d;
8561 const size_t cached =
8562 (size_t)
token * (
size_t)aligned_head_dim + (size_t)d;
8563 k_repeated[compact] =
bf16_to_float(k_head[cached]) * split_scale;
8568 const float *q_head = q_token + (size_t)h * (
size_t)aligned_head_dim;
8569 float *q_row = q_scaled + (size_t)h * (
size_t)head_dim;
8570 for (
int d = 0; d < head_dim; ++d) {
8574 k_batch[h] = k_repeated;
8575 score_batch[h] = scores + (size_t)h * (
size_t)kv_tokens;
8576 probability_batch[h] = score_batch[h];
8577 v_batch[h] = v_repeated;
8578 destination_batch[h] = destination + (size_t)h * (
size_t)head_dim;
8581 const int group_count = 1;
8582 const int group_size = num_heads;
8583 const float alpha = 1.0f;
8584 const float beta = 0.0f;
8585 int transpose_a = CBLAS_NO_TRANS;
8586 int transpose_b = CBLAS_TRANS;
8592 int ldc = kv_tokens;
8593 ck_pytorch_sgemm_batch(
8594 CBLAS_ROW_MAJOR, &transpose_a, &transpose_b, &m, &n, &k,
8595 &alpha, q_batch, &lda, k_batch, &ldb, &beta, score_batch, &ldc,
8596 group_count, &group_size);
8598 for (
int h = 0; h < num_heads; ++h) {
8599 (void)ck_pytorch_softmax_f32(score_batch[h], kv_tokens);
8602 transpose_b = CBLAS_NO_TRANS;
8608 ck_pytorch_sgemm_batch(
8609 CBLAS_ROW_MAJOR, &transpose_a, &transpose_b, &m, &n, &k,
8610 &alpha, probability_batch, &lda, v_batch, &ldb,
8611 &beta, destination_batch, &ldc, group_count, &group_size);
8613 for (
int h = 0; h < num_heads; ++h) {
8614 float *out_head = out_token + (size_t)h * (
size_t)aligned_head_dim;
8615 const float *source = destination + (size_t)h * (
size_t)head_dim;
8616 for (
int d = 0; d < head_dim; ++d) {
8619 for (
int d = head_dim; d < aligned_head_dim; ++d) out_head[d] = 0.0f;
8622 free(destination_batch);
8624 free(probability_batch);
8638 const uint16_t *k_cache,
8639 const uint16_t *v_cache,
8647 int aligned_head_dim)
8649 enum { CBLAS_ROW_MAJOR = 101, CBLAS_NO_TRANS = 111, CBLAS_TRANS = 112 };
8650 if (!ck_pytorch_sgemm_batch || !ck_pytorch_attention_expf16) {
8652 "CK BF16 PyTorch full-matrix provider requires MKL "
8653 "cblas_sgemm_batch and SLEEF Sleef_expf16_u10\n");
8657 const int kv_tokens = past_tokens + q_tokens;
8658 const size_t q_matrix_count =
8659 (size_t)num_heads * (
size_t)q_tokens * (size_t)head_dim;
8660 const size_t kv_matrix_count =
8661 (size_t)num_heads * (
size_t)kv_tokens * (size_t)head_dim;
8662 const size_t score_count =
8663 (size_t)num_heads * (
size_t)q_tokens * (size_t)kv_tokens;
8664 float *q_scaled = (
float *)malloc(q_matrix_count *
sizeof(
float));
8665 float *k_scaled = (
float *)malloc(kv_matrix_count *
sizeof(
float));
8666 float *v_f32 = (
float *)malloc(kv_matrix_count *
sizeof(
float));
8667 float *scores = (
float *)malloc(score_count *
sizeof(
float));
8668 float *destination = (
float *)malloc(q_matrix_count *
sizeof(
float));
8669 const float **q_batch =
8670 (
const float **)malloc((
size_t)num_heads *
sizeof(*q_batch));
8671 const float **k_batch =
8672 (
const float **)malloc((
size_t)num_heads *
sizeof(*k_batch));
8673 float **score_batch =
8674 (
float **)malloc((
size_t)num_heads *
sizeof(*score_batch));
8675 const float **probability_batch =
8676 (
const float **)malloc((
size_t)num_heads *
sizeof(*probability_batch));
8677 const float **v_batch =
8678 (
const float **)malloc((
size_t)num_heads *
sizeof(*v_batch));
8679 float **destination_batch =
8680 (
float **)malloc((
size_t)num_heads *
sizeof(*destination_batch));
8681 if (!q_scaled || !k_scaled || !v_f32 || !scores || !destination ||
8682 !q_batch || !k_batch || !score_batch || !probability_batch ||
8683 !v_batch || !destination_batch) {
8684 free(destination_batch);
8686 free(probability_batch);
8698 const float split_scale = (float)sqrt(sqrt(1.0 / (
double)head_dim));
8699 const size_t cache_head_stride =
8700 (size_t)cache_capacity * (
size_t)aligned_head_dim;
8701 const int heads_per_kv = num_heads / num_kv_heads;
8702 for (
int h = 0; h < num_heads; ++h) {
8703 const int kv_head = h / heads_per_kv;
8704 const uint16_t *k_head =
8705 k_cache + (size_t)kv_head * cache_head_stride;
8706 const uint16_t *v_head =
8707 v_cache + (size_t)kv_head * cache_head_stride;
8709 q_scaled + (size_t)h * (
size_t)q_tokens * (size_t)head_dim;
8711 k_scaled + (size_t)h * (
size_t)kv_tokens * (size_t)head_dim;
8713 v_f32 + (size_t)h * (
size_t)kv_tokens * (size_t)head_dim;
8715 const float *q_row = q +
8716 ((size_t)h * (
size_t)q_tokens + (size_t)
token) *
8717 (size_t)aligned_head_dim;
8719 q_head + (size_t)
token * (
size_t)head_dim;
8720 for (
int d = 0; d < head_dim; ++d) {
8726 const uint16_t *k_row =
8727 k_head + (size_t)
token * (
size_t)aligned_head_dim;
8728 const uint16_t *v_row =
8729 v_head + (size_t)
token * (
size_t)aligned_head_dim;
8731 k_head_f32 + (size_t)
token * (
size_t)head_dim;
8733 v_head_f32 + (size_t)
token * (
size_t)head_dim;
8734 for (
int d = 0; d < head_dim; ++d) {
8739 q_batch[h] = q_head;
8740 k_batch[h] = k_head_f32;
8742 scores + (size_t)h * (
size_t)q_tokens * (size_t)kv_tokens;
8743 probability_batch[h] = score_batch[h];
8744 v_batch[h] = v_head_f32;
8745 destination_batch[h] =
8746 destination + (size_t)h * (
size_t)q_tokens * (size_t)head_dim;
8749 const int group_count = 1;
8750 const int group_size = num_heads;
8751 const float alpha = 1.0f;
8752 const float beta = 0.0f;
8753 int transpose_a = CBLAS_NO_TRANS;
8754 int transpose_b = CBLAS_TRANS;
8760 int ldc = kv_tokens;
8761 ck_pytorch_sgemm_batch(
8762 CBLAS_ROW_MAJOR, &transpose_a, &transpose_b, &m, &n, &k,
8763 &alpha, q_batch, &lda, k_batch, &ldb, &beta, score_batch, &ldc,
8764 group_count, &group_size);
8769 for (
int h = 0; h < num_heads; ++h) {
8770 float *score_head = score_batch[h];
8773 score_head + (size_t)
token * (
size_t)kv_tokens;
8774 const int valid = past_tokens +
token + 1;
8775 for (
int key_token = valid; key_token < kv_tokens; ++key_token) {
8776 score_row[key_token] = -INFINITY;
8778 (void)ck_pytorch_softmax_f32(score_row, kv_tokens);
8782 transpose_b = CBLAS_NO_TRANS;
8788 ck_pytorch_sgemm_batch(
8789 CBLAS_ROW_MAJOR, &transpose_a, &transpose_b, &m, &n, &k,
8790 &alpha, probability_batch, &lda, v_batch, &ldb,
8791 &beta, destination_batch, &ldc, group_count, &group_size);
8793 for (
int h = 0; h < num_heads; ++h) {
8794 const float *source =
8795 destination + (size_t)h * (
size_t)q_tokens * (size_t)head_dim;
8797 float *out_row = output +
8798 ((size_t)h * (
size_t)q_tokens + (size_t)
token) *
8799 (size_t)aligned_head_dim;
8800 const float *source_row =
8801 source + (size_t)
token * (
size_t)head_dim;
8802 for (
int d = 0; d < head_dim; ++d) {
8806 for (
int d = head_dim; d < aligned_head_dim; ++d) {
8812 free(destination_batch);
8814 free(probability_batch);
8827 const float *q_token,
8828 const uint16_t *k_cache,
8829 const uint16_t *v_cache,
8831 const float *selected_indices,
8832 int selection_width,
8838 int aligned_head_dim)
8840 enum { CK_PYTORCH_KV_SPLIT = 512, CK_PYTORCH_MAX_HEAD_DIM = 512 };
8841 if (head_dim > CK_PYTORCH_MAX_HEAD_DIM || aligned_head_dim > CK_PYTORCH_MAX_HEAD_DIM) {
8844 pthread_once(&ck_pytorch_attention_once, ck_bind_pytorch_attention_primitives);
8845 if (!ck_pytorch_bf16_gemm || !ck_pytorch_attention_expf16) {
8847 "CK BF16 PyTorch SDPA provider requires MKL gemm_bf16bf16f32 "
8848 "and SLEEF Sleef_expf16_u10; set CK_MKL_LIBRARY and "
8849 "CK_SLEEF_LIBRARY\n");
8853 const float scale = 1.0f / sqrtf((
float)head_dim);
8854 const size_t head_stride = (size_t)cache_capacity * (
size_t)aligned_head_dim;
8855 for (
int h = 0; h < num_heads; ++h) {
8856 const int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
8857 const float *q_head = q_token + (size_t)h * (
size_t)aligned_head_dim;
8858 const uint16_t *k_head = k_cache + (size_t)kv_head * head_stride;
8859 const uint16_t *v_head = v_cache + (size_t)kv_head * head_stride;
8860 float *out_head = out_token + (size_t)h * (
size_t)aligned_head_dim;
8861 uint16_t q_bf16[CK_PYTORCH_MAX_HEAD_DIM]
__attribute__((aligned(64)));
8862 uint16_t probabilities[CK_PYTORCH_KV_SPLIT]
__attribute__((aligned(64)));
8863 float scores[CK_PYTORCH_KV_SPLIT]
__attribute__((aligned(64)));
8864 float destination[CK_PYTORCH_MAX_HEAD_DIM]
__attribute__((aligned(64)));
8865 for (
int d = 0; d < head_dim; ++d) q_bf16[d] =
float_to_bf16(q_head[d]);
8867 float running_max = -INFINITY;
8868 float running_sum = 0.0f;
8869 int has_destination = 0;
8870 for (
int start = 0;
start < kv_tokens;
start += CK_PYTORCH_KV_SPLIT) {
8871 const int block = kv_tokens -
start < CK_PYTORCH_KV_SPLIT
8872 ? kv_tokens -
start : CK_PYTORCH_KV_SPLIT;
8873 const char transpose =
'T';
8874 const char no_transpose =
'N';
8876 const float one_f = 1.0f;
8877 const float zero_f = 0.0f;
8878 ck_pytorch_bf16_gemm(
8879 &transpose, &no_transpose, &block, &one, &head_dim,
8880 &one_f, k_head + (
size_t)
start * (
size_t)aligned_head_dim,
8881 &aligned_head_dim, q_bf16, &aligned_head_dim,
8882 &zero_f, scores, &block);
8884 if (selected_indices) {
8887 while (cursor < selection_width &&
8888 (
int)selected_indices[cursor] <
start) {
8893 while (cursor < selection_width &&
8894 selected_indices[cursor] >= 0.0f &&
8895 (
int)selected_indices[cursor] < absolute_token) {
8898 if (cursor < selection_width &&
8899 (
int)selected_indices[cursor] == absolute_token) {
8903 scores[
token] = -INFINITY;
8906 if (selected == 0 && !has_destination)
continue;
8909 const float block_max = ck_pytorch_scale_max_f32(scores, block, scale);
8910 const float maximum = running_max > block_max ? running_max : block_max;
8911 const float block_sum = ck_pytorch_exp_sum_bf16(
8912 scores, probabilities, block, maximum);
8913 const float previous_scale = expf(running_max - maximum);
8914 running_sum = block_sum + previous_scale * running_sum;
8915 if (has_destination) {
8916 const __m512 previous_scale_v = _mm512_set1_ps(previous_scale);
8918 for (; d + 16 <= head_dim; d += 16) {
8921 _mm512_mul_ps(_mm512_loadu_ps(destination + d), previous_scale_v));
8923 for (; d < head_dim; ++d) destination[d] *= previous_scale;
8925 const float beta = has_destination ? 1.0f : 0.0f;
8926 ck_pytorch_bf16_gemm(
8927 &no_transpose, &no_transpose, &head_dim, &one, &block,
8928 &one_f, v_head + (
size_t)
start * (
size_t)aligned_head_dim,
8929 &aligned_head_dim, probabilities, &block,
8930 &beta, destination, &head_dim);
8931 running_max = maximum;
8932 has_destination = 1;
8935 if (!has_destination) {
8938 const float reciprocal = running_sum != 0.0f ? 1.0f / running_sum : 1.0f;
8939 for (
int d = 0; d < head_dim; ++d) {
8942 for (
int d = head_dim; d < aligned_head_dim; ++d) out_head[d] = 0.0f;
8948 const float *q_token,
8949 const uint16_t *k_cache,
8950 const uint16_t *v_cache,
8957 int aligned_head_dim)
8959 return ck_attention_decode_bf16_pytorch_cpu_flash_masked(
8960 q_token, k_cache, v_cache, out_token, NULL, 0,
8961 num_heads, num_kv_heads, kv_tokens, cache_capacity,
8962 head_dim, aligned_head_dim);
8968 const uint16_t *key_cache,
8969 const uint16_t *value_cache,
8970 const float *selected_indices,
8972 float *score_scratch,
8977 int selection_width,
8981 (void)score_scratch;
8982 if (!query || !key_cache || !value_cache || !selected_indices || !output ||
8983 rows <= 0 || query_heads <= 0 || kv_heads <= 0 || head_dim <= 0 ||
8984 selection_width <= 0 || context_length <= 0 || position < 0 ||
8985 position + rows > context_length || query_heads % kv_heads != 0) {
8986 fprintf(stderr,
"CK sparse BF16 CPU-flash attention: invalid contract\n");
8990#if defined(__AVX512F__)
8991 for (
int row = 0; row < rows; ++row) {
8992 const int visible_tokens = position + row + 1;
8994 ck_attention_decode_bf16_pytorch_cpu_flash_masked(
8995 query + (
size_t)row * (
size_t)query_heads * (
size_t)head_dim,
8996 key_cache, value_cache,
8997 output + (
size_t)row * (
size_t)query_heads * (
size_t)head_dim,
8998 selected_indices + (
size_t)row * (
size_t)selection_width,
8999 selection_width, query_heads, kv_heads, visible_tokens,
9000 context_length, head_dim, head_dim);
9003 "CK sparse BF16 CPU-flash attention unavailable (status=%d)\n",
9010 "CK sparse BF16 CPU-flash attention requires AVX-512F; "
9011 "no numerically different fallback is permitted\n");
9018#if defined(__AVX512F__)
9027#if defined(__AVX512F__)
9028 pthread_once(&ck_pytorch_attention_once, ck_bind_pytorch_attention_primitives);
9029 return ck_pytorch_sgemm_batch != NULL &&
9030 ck_pytorch_attention_expf16 != NULL;
9037 size_t left,
size_t right,
const char *label)
9041 "HARD KERNEL CONTRACT FAULT: Muse eager attention %s "
9042 "size overflow\n", label);
9051#define CK_MUSE_PREFILL_QUERY_TILE 1024
9062 int kv_stride_tokens,
9064 int aligned_head_dim,
9067 size_t scores_bytes,
9069 size_t key_rows_bytes,
9070 uint16_t *value_columns,
9071 size_t value_columns_bytes,
9072 uint16_t *gemm_rows,
9073 size_t gemm_rows_bytes,
9074 uint16_t *gemm_scores,
9075 size_t gemm_scores_bytes)
9077#if defined(__AVX512F__) && defined(USE_ONEDNN)
9078 if (!q || !k || !v || !output || num_heads <= 0 || num_kv_heads <= 0 ||
9079 query_tokens <= 0 || kv_tokens < query_tokens ||
9080 kv_stride_tokens < kv_tokens || head_dim <= 0 ||
9081 aligned_head_dim != head_dim || num_heads % num_kv_heads != 0) {
9082 fprintf(stderr,
"HARD KERNEL CONTRACT FAULT: invalid Muse eager attention dimensions\n");
9089 (
size_t)workspace_rows, (
size_t)kv_tokens,
"score");
9091 (
size_t)kv_tokens, (
size_t)head_dim,
"KV matrix");
9093 (
size_t)workspace_rows, (
size_t)head_dim,
"row matrix");
9094 if (score_count > SIZE_MAX /
sizeof(*scores) ||
9095 kv_matrix_count > SIZE_MAX /
sizeof(*key_rows) ||
9096 row_count > SIZE_MAX /
sizeof(*gemm_rows)) {
9098 "HARD KERNEL CONTRACT FAULT: Muse eager attention workspace "
9099 "byte size overflow\n");
9102 if (!scores || scores_bytes < score_count *
sizeof(*scores) ||
9103 !key_rows || key_rows_bytes < kv_matrix_count *
sizeof(*key_rows) ||
9105 value_columns_bytes < kv_matrix_count *
sizeof(*value_columns) ||
9106 !gemm_rows || gemm_rows_bytes < row_count *
sizeof(*gemm_rows) ||
9108 gemm_scores_bytes < score_count *
sizeof(*gemm_scores)) {
9110 "HARD KERNEL CONTRACT FAULT: Muse eager attention received "
9111 "an undersized planner-owned workspace\n");
9114 pthread_once(&ck_pytorch_attention_once, ck_bind_pytorch_attention_primitives);
9115 if (!ck_pytorch_attention_expf16) {
9117 "HARD KERNEL CONTRACT FAULT: Muse eager attention requires "
9118 "Sleef_expf16_u10 from CK_SLEEF_LIBRARY\n");
9122 const float scale = 1.0f / sqrtf((
float)head_dim);
9123 const int heads_per_kv = num_heads / num_kv_heads;
9124 const int query_position_offset = kv_tokens - query_tokens;
9126 (
size_t)query_tokens, (
size_t)aligned_head_dim,
"query stride");
9128 (
size_t)kv_stride_tokens, (
size_t)aligned_head_dim,
"KV stride");
9130 (
size_t)num_heads, query_head_stride,
"query tensor");
9132 (
size_t)num_kv_heads, kv_head_stride,
"KV tensor");
9134 for (
int head = 0; head < num_heads; ++head) {
9135 const int kv_head = head / heads_per_kv;
9136 const float *key_head = k + (size_t)kv_head * kv_head_stride;
9137 const float *value_head = v + (size_t)kv_head * kv_head_stride;
9139 const float *key_row = key_head +
9140 (size_t)
token * (
size_t)aligned_head_dim;
9141 const float *value_row = value_head +
9142 (size_t)
token * (
size_t)aligned_head_dim;
9143 for (
int dim = 0; dim < head_dim; ++dim) {
9144 key_rows[(size_t)
token * (
size_t)head_dim + (size_t)dim] =
9146 value_columns[(size_t)dim * (
size_t)kv_tokens + (size_t)
token] =
9151 const float *query_head = q + (size_t)head * query_head_stride;
9152 float *output_head = output + (size_t)head * query_head_stride;
9153 for (
int query_start = 0; query_start < query_tokens;
9158 query_head + (
size_t)query_start * (
size_t)head_dim,
9159 key_rows, NULL, scores,
9160 tile_rows, kv_tokens, head_dim,
9161 gemm_rows, gemm_rows_bytes, gemm_scores, gemm_scores_bytes,
9164 for (
int query_token = 0; query_token < tile_rows; ++query_token) {
9165 const int query_position = query_position_offset + query_start + query_token;
9166 const int visible_end = query_position + 1;
9167 int visible_begin = 0;
9168 if (sliding_window > 0 && visible_end > sliding_window) {
9169 visible_begin = visible_end - sliding_window;
9171 float *score_row = scores +
9172 (size_t)query_token * (
size_t)kv_tokens;
9176 if (token < visible_begin || token >= visible_end) {
9177 score_row[
token] = -INFINITY;
9180 (void)ck_pytorch_softmax_f32(score_row, kv_tokens);
9183 scores, value_columns, NULL,
9184 output_head + (
size_t)query_start * (
size_t)head_dim,
9185 tile_rows, head_dim, kv_tokens,
9186 gemm_scores, gemm_scores_bytes, gemm_rows, gemm_rows_bytes,
9191 (void)q; (void)k; (void)v; (void)output; (void)num_heads;
9192 (void)num_kv_heads; (void)query_tokens; (void)kv_tokens;
9193 (void)kv_stride_tokens; (void)head_dim; (void)aligned_head_dim;
9194 (void)sliding_window;
9195 (void)scores; (void)scores_bytes; (void)key_rows; (void)key_rows_bytes;
9196 (void)value_columns; (void)value_columns_bytes;
9197 (void)gemm_rows; (void)gemm_rows_bytes;
9198 (void)gemm_scores; (void)gemm_scores_bytes;
9200 "HARD KERNEL CONTRACT FAULT: Muse eager attention requires "
9201 "AVX-512 and USE_ONEDNN=1\n");
9207 const float *q,
const float *k,
const float *v,
float *output,
9208 int num_heads,
int num_kv_heads,
int num_tokens,
int head_dim,
9209 int aligned_head_dim,
int kv_stride_tokens,
9210 float *scores,
size_t scores_bytes,
9211 uint16_t *key_rows,
size_t key_rows_bytes,
9212 uint16_t *value_columns,
size_t value_columns_bytes,
9213 uint16_t *gemm_rows,
size_t gemm_rows_bytes,
9214 uint16_t *gemm_scores,
size_t gemm_scores_bytes)
9217 q, k, v, output, num_heads, num_kv_heads, num_tokens, num_tokens,
9218 kv_stride_tokens, head_dim, aligned_head_dim, 0,
9219 scores, scores_bytes, key_rows, key_rows_bytes,
9220 value_columns, value_columns_bytes, gemm_rows, gemm_rows_bytes,
9221 gemm_scores, gemm_scores_bytes);
9225 const float *q,
const float *k,
const float *v,
float *output,
9226 int num_heads,
int num_kv_heads,
int num_tokens,
int head_dim,
9227 int aligned_head_dim,
int kv_stride_tokens,
int sliding_window,
9228 float *scores,
size_t scores_bytes,
9229 uint16_t *key_rows,
size_t key_rows_bytes,
9230 uint16_t *value_columns,
size_t value_columns_bytes,
9231 uint16_t *gemm_rows,
size_t gemm_rows_bytes,
9232 uint16_t *gemm_scores,
size_t gemm_scores_bytes)
9235 q, k, v, output, num_heads, num_kv_heads, num_tokens, num_tokens,
9236 kv_stride_tokens, head_dim, aligned_head_dim, sliding_window,
9237 scores, scores_bytes, key_rows, key_rows_bytes,
9238 value_columns, value_columns_bytes, gemm_rows, gemm_rows_bytes,
9239 gemm_scores, gemm_scores_bytes);
9243 const float *q_token,
const float *k_cache,
const float *v_cache,
9244 float *out_token,
int num_heads,
int num_kv_heads,
int kv_tokens,
9245 int cache_capacity,
int head_dim,
int aligned_head_dim,
9246 float *scores,
size_t scores_bytes,
9247 uint16_t *key_rows,
size_t key_rows_bytes,
9248 uint16_t *value_columns,
size_t value_columns_bytes,
9249 uint16_t *gemm_rows,
size_t gemm_rows_bytes,
9250 uint16_t *gemm_scores,
size_t gemm_scores_bytes)
9253 q_token, k_cache, v_cache, out_token, num_heads, num_kv_heads,
9254 1, kv_tokens, cache_capacity, head_dim, aligned_head_dim, 0,
9255 scores, scores_bytes, key_rows, key_rows_bytes,
9256 value_columns, value_columns_bytes, gemm_rows, gemm_rows_bytes,
9257 gemm_scores, gemm_scores_bytes);
9261 const float *q_token,
const float *k_cache,
const float *v_cache,
9262 float *out_token,
int num_heads,
int num_kv_heads,
int kv_tokens,
9263 int cache_capacity,
int head_dim,
int aligned_head_dim,
int sliding_window,
9264 float *scores,
size_t scores_bytes,
9265 uint16_t *key_rows,
size_t key_rows_bytes,
9266 uint16_t *value_columns,
size_t value_columns_bytes,
9267 uint16_t *gemm_rows,
size_t gemm_rows_bytes,
9268 uint16_t *gemm_scores,
size_t gemm_scores_bytes)
9271 q_token, k_cache, v_cache, out_token, num_heads, num_kv_heads,
9272 1, kv_tokens, cache_capacity, head_dim, aligned_head_dim,
9273 sliding_window, scores, scores_bytes, key_rows, key_rows_bytes,
9274 value_columns, value_columns_bytes, gemm_rows, gemm_rows_bytes,
9275 gemm_scores, gemm_scores_bytes);
9279 const float *q_token,
9280 const uint16_t *k_cache,
9281 const uint16_t *v_cache,
9288 int aligned_head_dim,
9291 if (!q_token || !k_cache || !v_cache || !out_token ||
9292 num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 ||
9293 cache_capacity <= 0 || kv_tokens > cache_capacity ||
9294 head_dim <= 0 || aligned_head_dim < head_dim ||
9295 num_heads % num_kv_heads != 0) {
9302#if defined(__AVX512F__)
9303 pthread_once(&ck_pytorch_attention_once, ck_bind_pytorch_attention_primitives);
9304 return ck_attention_decode_bf16_pytorch_math_gqa(
9305 q_token, k_cache, v_cache, out_token, num_heads, num_kv_heads,
9306 kv_tokens, cache_capacity, head_dim, aligned_head_dim);
9308 const float scale = 1.0f / sqrtf((
float)head_dim);
9309 const size_t head_stride = (size_t)cache_capacity * (
size_t)aligned_head_dim;
9310 for (
int h = 0; h < num_heads; ++h) {
9311 const int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
9312 const float *q_head = q_token + (size_t)h * (
size_t)aligned_head_dim;
9313 const uint16_t *k_head = k_cache + (size_t)kv_head * head_stride;
9314 const uint16_t *v_head = v_cache + (size_t)kv_head * head_stride;
9315 float *out_head = out_token + (size_t)h * (
size_t)aligned_head_dim;
9317 float maximum = -INFINITY;
9319 const uint16_t *k_row = k_head + (size_t)
token * (
size_t)aligned_head_dim;
9321 for (
int d = 0; d < head_dim; ++d) {
9324 const float score = dot * scale;
9328 for (
int d = 0; d < aligned_head_dim; ++d) out_head[d] = 0.0f;
9329 float denominator = 0.0f;
9331 const uint16_t *k_row = k_head + (size_t)
token * (
size_t)aligned_head_dim;
9332 const uint16_t *v_row = v_head + (size_t)
token * (
size_t)aligned_head_dim;
9334 for (
int d = 0; d < head_dim; ++d) {
9337 const float probability = expf(dot * scale - maximum);
9338 denominator += probability;
9339 for (
int d = 0; d < head_dim; ++d) {
9340 out_head[d] = fmaf(probability,
bf16_to_float(v_row[d]), out_head[d]);
9343 const float inverse = denominator > 0.0f ? 1.0f / denominator : 0.0f;
9344 for (
int d = 0; d < head_dim; ++d) {
9354 const uint16_t *k_cache,
9355 const uint16_t *v_cache,
9363 int aligned_head_dim,
9365 float *token_workspace,
9366 size_t token_workspace_bytes)
9368 if (!q || !k_cache || !v_cache || !output ||
9369 num_heads <= 0 || num_kv_heads <= 0 || q_tokens <= 0 ||
9370 past_tokens < 0 || past_tokens + q_tokens > cache_capacity ||
9371 head_dim <= 0 || aligned_head_dim < head_dim) {
9379 ck_attention_f16_prefill_qtile64_args_t args = {
9380 .q = q, .k_cache = k_cache, .v_cache = v_cache, .output = output,
9381 .num_heads = num_heads, .num_kv_heads = num_kv_heads,
9382 .q_tokens = q_tokens, .past_tokens = past_tokens,
9383 .cache_capacity = cache_capacity, .head_dim = head_dim,
9384 .aligned_head_dim = aligned_head_dim, .cache_is_bf16 = 1,
9388 if (active > num_kv_heads) active = num_kv_heads;
9394 const size_t count = (size_t)num_heads * (
size_t)q_tokens * (size_t)aligned_head_dim;
9395 for (
size_t i = 0; i <
count; ++i) {
9401 const size_t token_elems = (size_t)num_heads * (
size_t)aligned_head_dim;
9402 if (token_elems > SIZE_MAX / (2 *
sizeof(
float)) ||
9403 !token_workspace || token_workspace_bytes < 2 * token_elems *
sizeof(float)) {
9406 float *q_token = token_workspace;
9407 float *out_token = token_workspace + token_elems;
9409 for (
int t = 0; t < q_tokens; ++t) {
9410 for (
int h = 0; h < num_heads; ++h) {
9411 memcpy(q_token + (
size_t)h * (
size_t)aligned_head_dim,
9412 q + ((
size_t)h * (
size_t)q_tokens + (
size_t)t) * (
size_t)aligned_head_dim,
9413 (
size_t)aligned_head_dim *
sizeof(
float));
9416 q_token, k_cache, v_cache, out_token,
9417 num_heads, num_kv_heads, past_tokens + t + 1, cache_capacity,
9418 head_dim, aligned_head_dim, reduction);
9420 for (
int h = 0; h < num_heads; ++h) {
9421 memcpy(output + ((
size_t)h * (
size_t)q_tokens + (
size_t)t) * (
size_t)aligned_head_dim,
9422 out_token + (
size_t)h * (
size_t)aligned_head_dim,
9423 (
size_t)aligned_head_dim *
sizeof(
float));
9431 const uint16_t *k_cache,
9432 const uint16_t *v_cache,
9440 int aligned_head_dim,
9445 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
9446 past_tokens, cache_capacity, head_dim, aligned_head_dim, reduction,
9449 if (num_heads <= 0 || aligned_head_dim <= 0 ||
9450 (
size_t) num_heads > SIZE_MAX / (
size_t) aligned_head_dim) {
9453 const size_t token_elements = (size_t) num_heads * (
size_t) aligned_head_dim;
9454 if (token_elements > SIZE_MAX / (2 *
sizeof(
float))) {
9457 const size_t workspace_bytes = 2 * token_elements *
sizeof(float);
9458 float *workspace = (
float *) malloc(workspace_bytes);
9462 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
9463 past_tokens, cache_capacity, head_dim, aligned_head_dim, reduction,
9464 workspace, workspace_bytes);
9471 const uint16_t *k_cache,
9472 const uint16_t *v_cache,
9480 int aligned_head_dim,
9483 if (!q || !k_cache || !v_cache || !output ||
9484 num_heads <= 0 || num_kv_heads <= 0 ||
9485 num_heads % num_kv_heads != 0 ||
9486 q_tokens <= 0 || past_tokens < 0 ||
9487 past_tokens + q_tokens > cache_capacity ||
9488 head_dim <= 0 || aligned_head_dim < head_dim) {
9495#if defined(__AVX512F__)
9496 pthread_once(&ck_pytorch_attention_once, ck_bind_pytorch_attention_primitives);
9497 return ck_attention_prefill_bf16_pytorch_math_gqa_full(
9498 q, k_cache, v_cache, output,
9499 num_heads, num_kv_heads, q_tokens, past_tokens, cache_capacity,
9500 head_dim, aligned_head_dim);
9507 const uint16_t *k_cache,
9508 const uint16_t *v_cache,
9515 int aligned_head_dim)
9517 if (!q_token || !k_cache || !v_cache || !out_token) {
9520 if (num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
9523 if (kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
9527 const float scale = 1.0f / sqrtf((
float)head_dim);
9528 const size_t head_stride = (size_t)cache_capacity * (
size_t)aligned_head_dim;
9529 const size_t scratch_elems = (size_t)kv_tokens * (
size_t)aligned_head_dim;
9530 const size_t scratch_bytes = scratch_elems *
sizeof(float);
9531 const size_t max_stack_bytes = 1024u * 1024u;
9533 if (scratch_bytes * 2u > max_stack_bytes) {
9534 for (
int h = 0; h < num_heads; ++h) {
9535 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
9536 const float *q_head = q_token + (size_t)h * (
size_t)aligned_head_dim;
9537 const uint16_t *k_head = k_cache + (size_t)kv_head * head_stride;
9538 const uint16_t *v_head = v_cache + (size_t)kv_head * head_stride;
9539 float *out_head = out_token + (size_t)h * (
size_t)aligned_head_dim;
9541 for (
int d = 0; d < aligned_head_dim; ++d) {
9545 float max_score = -INFINITY;
9546 for (
int j = 0; j < kv_tokens; ++j) {
9547 const uint16_t *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
9549 for (
int d = 0; d < head_dim; ++d) {
9552 const float score = dot * scale;
9553 if (
score > max_score) {
9559 for (
int j = 0; j < kv_tokens; ++j) {
9560 const uint16_t *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
9561 const uint16_t *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
9563 for (
int d = 0; d < head_dim; ++d) {
9566 const float w = expf(dot * scale - max_score);
9568 for (
int d = 0; d < head_dim; ++d) {
9574 const float inv_sum = 1.0f / sum;
9575 for (
int d = 0; d < head_dim; ++d) {
9576 out_head[d] *= inv_sum;
9579 for (
int d = head_dim; d < aligned_head_dim; ++d) {
9586 float *k_head_fp32 = (
float *)alloca(scratch_bytes);
9587 float *v_head_fp32 = (
float *)alloca(scratch_bytes);
9589 for (
int kv_head = 0; kv_head < num_kv_heads; ++kv_head) {
9590 const uint16_t *k_head = k_cache + (size_t)kv_head * head_stride;
9591 const uint16_t *v_head = v_cache + (size_t)kv_head * head_stride;
9592 const int q_begin = (int)((
long long)kv_head * (
long long)num_heads / (
long long)num_kv_heads);
9593 const int q_end = (int)((
long long)(kv_head + 1) * (
long long)num_heads / (
long long)num_kv_heads);
9598 for (
int h = q_begin; h < q_end; ++h) {
9599 const float *q_head = q_token + (size_t)h * (
size_t)aligned_head_dim;
9600 float *out_head = out_token + (size_t)h * (
size_t)aligned_head_dim;
9630 const float *k_cache,
9631 const float *v_cache,
9638 int aligned_head_dim)
9640 if (!q_token || !k_cache || !v_cache || !out_token) {
9643 if (num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
9646 if (kv_tokens > cache_capacity) {
9651 const float scale = strict
9653 : 1.0f / sqrtf((
float) head_dim);
9654 const size_t head_stride = (size_t)cache_capacity * (
size_t)aligned_head_dim;
9657#if defined(__AVX512F__)
9658 #define FLASH_QUERY_IMPL_DECODE attention_flash_query_causal_avx512
9659#elif defined(__AVX2__)
9660 #define FLASH_QUERY_IMPL_DECODE attention_flash_query_causal_avx2
9661#elif defined(__AVX__)
9662 #define FLASH_QUERY_IMPL_DECODE attention_flash_query_causal_avx
9664 #define FLASH_QUERY_IMPL_DECODE attention_flash_query_causal
9667#pragma omp parallel for schedule(static) if(num_heads > 1)
9668 for (
int h = 0; h < num_heads; ++h) {
9669 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
9670 const float *q_vec = q_token + (size_t)h * (
size_t)aligned_head_dim;
9671 const float *k_head = k_cache + (size_t)kv_head * head_stride;
9672 const float *v_head = v_cache + (size_t)kv_head * head_stride;
9673 float *out_vec = out_token + (size_t)h * (
size_t)aligned_head_dim;
9688 kv_tokens, head_dim, aligned_head_dim,
9692#undef FLASH_QUERY_IMPL_DECODE
9740 const uint16_t *d_output,
9745 const float *attn_weights,
9754 int aligned_head_dim,
9755 int aligned_context_window,
9756 float *scratch_d_output,
9762 const size_t head_elems = (size_t)num_heads * (
size_t)num_tokens * (size_t)aligned_head_dim;
9763 const size_t kv_elems = (size_t)num_kv_heads * (
size_t)num_tokens * (size_t)aligned_head_dim;
9765 if (!scratch_d_output || !scratch_q || !scratch_k || !scratch_v)
return;
9774 d_q, d_k, d_v, d_scores,
9775 num_heads, num_kv_heads,
9776 num_tokens, head_dim,
9777 aligned_head_dim, aligned_context_window);
9793 const float *d_output,
9797 const float *attn_weights,
9806 int aligned_head_dim,
9807 int aligned_context_window)
9809 const float scale = 1.0f / sqrtf((
float)head_dim);
9812 int H_kv = num_kv_heads;
9814 int ad = aligned_head_dim;
9815 int aw = aligned_context_window;
9817 const size_t d_q_elems = (size_t)H * (
size_t)T * (size_t)ad;
9818 const size_t kv_elems = (size_t)H_kv * (
size_t)T * (size_t)ad;
9820 for (
size_t idx = 0; idx < d_q_elems; ++idx) {
9823 for (
size_t idx = 0; idx < kv_elems; ++idx) {
9829 for (
int h = 0; h < H; ++h) {
9831 int kv_h = (int)((
long long)h * (
long long)H_kv / (
long long)H);
9839 for (
int i = 0; i < T; ++i) {
9840 size_t d_out_base =
qkv_index(h, i, 0, T, ad);
9842 for (
int j = 0; j <= i; ++j) {
9843 size_t v_base =
qkv_index(kv_h, j, 0, T, ad);
9845 float w = attn_weights[w_idx];
9849 for (
int dd = 0; dd < hd; ++dd) {
9850 dot += d_output[d_out_base + dd] * v[v_base + dd];
9852 d_scores[w_idx] = dot;
9855 for (
int dd = 0; dd < hd; ++dd) {
9856 d_v[v_base + dd] += w * d_output[d_out_base + dd];
9861 for (
int j = i + 1; j < T; ++j) {
9865 for (
int j = T; j < aw; ++j) {
9876 for (
int i = 0; i < T; ++i) {
9877 int base = h * aw * aw + i * aw;
9880 float dot_product = 0.0f;
9881 for (
int j = 0; j <= i; ++j) {
9882 float wt = attn_weights[base + j];
9883 float dw = d_scores[base + j];
9884 dot_product += wt * dw;
9888 for (
int j = 0; j <= i; ++j) {
9889 float wt = attn_weights[base + j];
9890 float dw = d_scores[base + j];
9891 d_scores[base + j] = wt * (dw - dot_product);
9900 for (
int i = 0; i < T; ++i) {
9901 size_t d_q_base =
qkv_index(h, i, 0, T, ad);
9902 size_t q_base =
qkv_index(h, i, 0, T, ad);
9906 for (
int j = 0; j <= i; ++j) {
9907 size_t k_base =
qkv_index(kv_h, j, 0, T, ad);
9908 size_t d_k_base =
qkv_index(kv_h, j, 0, T, ad);
9909 float ds = d_scores[
score_index(h, i, j, aw)] * scale;
9911 for (
int dd = 0; dd < hd; ++dd) {
9912 d_q[d_q_base + dd] += ds * k[k_base + dd];
9913 d_k[d_k_base + dd] += ds * q[q_base + dd];
9932 const float *d_output,
9936 const float *attn_weights,
9944 int aligned_head_dim,
9945 int aligned_context_window)
9948 d_output, q, k, v, attn_weights,
9949 d_q, d_k, d_v, d_scores,
9950 num_heads, num_heads,
9951 num_tokens, head_dim, aligned_head_dim, aligned_context_window);
static size_t qkv_index(int h, int t, int d, int num_tokens, int aligned_head_dim)
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_segmented_f16cache_sliding_gemma4_workspace(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int sliding_window, ck_attention_reduction_t reduction, float *token_workspace, size_t token_workspace_bytes, const int *segment_lengths, int num_segments)
static double ck_ggml_vec_soft_max_row(int n, float *y, const float *x, float max)
float ck_attention_pytorch_sdpa_scale_f32(int head_dim)
void attention_forward_causal_head_major_gqa_bf16(const uint16_t *q, const uint16_t *k, const uint16_t *v, float *scores, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window, float *scratch_q, float *scratch_k, float *scratch_v)
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_sliding_gemma4_workspace(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int sliding_window, ck_attention_reduction_t reduction, float *token_workspace, size_t token_workspace_bytes)
void attention_forward_causal_head_major_gqa_exact(const float *q, const float *k, const float *v, float *scores, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window)
#define CK_GGML_FA_TILE_KV
static void attention_forward_decode_head_major_gqa_flash_f16cache_split_partitioned(const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int split_chunks, int partition_tokens, int kv_start, float attention_scale)
void attention_forward_decode_head_major_gqa_flash_f16cache(const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_qtile64_schedule(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_prefill_schedule_t schedule)
static void ck_attention_vec_dump_exact_query(const float *q_vec, const float *k_head, const float *out_vec, int kv_tokens, int head_dim, int aligned_head_dim, float scale, int layer_id, int head_id, int query_id)
static void ck_attention_query_key_f32_head_work(int ith, int nth, void *opaque)
void attention_forward_causal_head_major_gqa_flash_strided(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
void attention_forward_decode_head_major_shared_kv_gemma4(const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
static int ck_attention_vec_dump_next_layer_id(void)
static ck_attention_status_t ck_attention_forward_decode_f16cache_gemma4(const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int sliding_window, ck_attention_reduction_t reduction)
static void ck_llama_regular_prefill_work(int ith, int nth, void *opaque)
static void attention_query_full_exact_regular(const float *q_vec, const float *k_head, const float *v_cols, int kv_tokens, int head_dim, int aligned_head_dim, float scale, float *score_row, float *out_vec, int layer_id, int head_id, int query_id)
static void ck_attention_query_key_f32_transpose_work(int ith, int nth, void *opaque)
void attention_forward_full_head_major_gqa_tiled336_f16kv_fp32_strided(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
static float ck_attention_strict_scale_f32(int head_dim)
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_bf16cache_pytorch_contract(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction)
static const char ck_attention_vec_dump_magic[8]
static float ck_llama_regular_gemm_f16(const float *probability, const float *value_column, int count)
static void ck_attention_vec_dump_tensor(const char *name, int layer_id, int query_id, const float *data, size_t elem_count)
ck_attention_status_t attention_forward_decode_head_major_gqa_f16cache_regular_noscale(const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int sliding_window)
void attention_forward_causal_head_major_gqa_flash_strided_f16kv_workspace(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, float *rounded_kv, size_t rounded_kv_bytes)
static void attention_flash_query_causal_exact(const float *q_vec, const float *k_head, const float *v_head, int kv_tokens, int head_dim, int aligned_head_dim, float scale, float *out_vec)
void attention_forward_full_head_major_gqa_flash_strided_bf16_storage(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
static void ck_attention_trace_float(const char *tag, int layer_id, int head_id, float value)
void attention_forward_decode_head_major_gqa_flash_gemma4(const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
void attention_forward_decode_head_major_gqa_flash_f16kv(const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
int attention_forward_query_key_head_major_f32_decode_heads(const float *query, const float *key, const float *value, float *output, float *score_scratch, int num_heads, int query_tokens, int key_tokens, int head_dim, float scale)
static float ck_vec_dot_f32_strict(const float *x, const float *y, int n)
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_auto_workspace(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction, float *token_workspace, size_t token_workspace_bytes, void *gqa_workspace, size_t gqa_workspace_bytes, int route_num_heads, int route_num_kv_heads, int route_head_dim, int route_query_tokens, int route_min_kv_tokens, int route_workers, int route_query_tile_size, int route_concurrent_query_tiles)
void attention_backward_causal_head_major_gqa_bf16(const uint16_t *d_output, float *d_x, const uint16_t *q, const uint16_t *k, const uint16_t *v, const float *attn_weights, float *d_q, float *d_k, float *d_v, float *d_scores, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window, float *scratch_d_output, float *scratch_q, float *scratch_k, float *scratch_v)
static void ck_attention_f16_prefill_gqa_reuse_work(int ith, int nth, void *opaque)
static void ck_vec_scale_f32_inplace(float *x, int n, float scale)
static size_t attention_output_index(int h, int token, int num_heads, int num_tokens, int aligned_head_dim, int token_major)
void attention_forward_full_head_major_gqa_exact_strided(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
#define CK_GGML_FA_TILE_Q
void attention_forward_causal_head_major(const float *q, const float *k, const float *v, float *scores, float *output, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window)
void attention_forward_mixed_visual_chunk_head_major_gqa_flash_strided_gemma4(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int visual_start, int visual_tokens)
void attention_forward_causal_head_major_gqa(const float *q, const float *k, const float *v, float *scores, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window)
static float ck_attention_u16_cache_to_f32(uint16_t value, int cache_is_bf16)
static void ck_attention_flash_query_auto(const float *q_vec, const float *k_head, const float *v_head, int kv_tokens, int head_dim, int aligned_head_dim, float scale, float *out_vec)
ck_attention_status_t attention_forward_decode_head_major_gqa_f16cache_gemma4_contract(const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction)
void attention_forward_full_head_major_gqa_flash_strided(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
static float ck_vec_dot_f32x_f32_to_f32_via_f64(const float *x, const float *y, int n)
static float ck_vec_max_f32_contig(const float *x, int n)
static void ck_attention_mad_f16_llama(uint16_t *y, const uint16_t *x, float scale, int n)
static int ck_attention_strict_unfused_f16_enabled(void)
int attention_forward_query_key_head_major_f32_packed_k(const float *query, const float *key, const float *value, float *output, float *score_scratch, float *key_transpose_scratch, int num_heads, int query_tokens, int key_tokens, int head_dim, float scale)
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_bf16cache_pytorch_contract_workspace(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction, float *token_workspace, size_t token_workspace_bytes)
static ck_attention_status_t ck_attention_forward_causal_head_major_gqa_prefill_segmented_f16cache_schedule_workspace(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction, float *token_workspace, size_t token_workspace_bytes, const int *segment_lengths, int num_segments, ck_attention_prefill_schedule_t schedule)
static int ck_attention_vec_dump_enabled(void)
void attention_forward_causal_head_major_gqa_flash_strided_gemma4(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
void attention_forward_causal_head_major_gqa_muse_eager_bf16_storage(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, float *scores, size_t scores_bytes, uint16_t *key_rows, size_t key_rows_bytes, uint16_t *value_columns, size_t value_columns_bytes, uint16_t *gemm_rows, size_t gemm_rows_bytes, uint16_t *gemm_scores, size_t gemm_scores_bytes)
void attention_forward_full_head_major_gqa_flash(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim)
void attention_forward_chunk_head_major_gqa_flash_gemma4(const float *q_chunk, const float *k_cache, const float *v_cache, float *out_chunk, int num_heads, int num_kv_heads, int q_tokens, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
void attention_forward_causal_head_major_exact(const float *q, const float *k, const float *v, float *scores, float *output, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window)
int attention_forward_query_key_head_major_f32(const float *query, const float *key, const float *value, float *output, float *score_scratch, int num_heads, int query_tokens, int key_tokens, int head_dim, float scale)
static void ck_attention_bf16_sdpa_work(int ith, int nth, void *opaque)
static void ck_round_fp16_buffer(const float *src, float *dst, size_t count)
static void ck_attention_full_tiled_f16kv_fp32_work(int ith, int nth, void *opaque)
void attention_forward_causal_head_major_shared_kv_gemma4(const float *q, float *output, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
void attention_forward_full_head_major_gqa_tiled_f16kv_fp32_strided(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_contract(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction)
static void ck_local_fp16_to_fp32_row(const uint16_t *src, float *dst, int n)
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_segmented_f16cache_gemma4_workspace(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction, float *token_workspace, size_t token_workspace_bytes, const int *segment_lengths, int num_segments)
static int ck_attention_reverse_out_dot_enabled(void)
void attention_forward_full_head_major_gqa_ggml_strided(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
static float ck_attention_reference_expf(float value)
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_full_bf16cache_pytorch_contract(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction)
static void ck_attention_matmul_f32_accum(float *c, const float *a, const float *b, int m, int k, int n)
void attention_forward_full_head_major_gqa_pytorch_cpu_flash_bf16_storage(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
void attention_forward_decode_head_major_gqa_muse_eager_bf16_storage(const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, float *scores, size_t scores_bytes, uint16_t *key_rows, size_t key_rows_bytes, uint16_t *value_columns, size_t value_columns_bytes, uint16_t *gemm_rows, size_t gemm_rows_bytes, uint16_t *gemm_scores, size_t gemm_scores_bytes)
static int ck_attention_ggml_out_graph_enabled(void)
static size_t score_index(int h, int i, int j, int aligned_context_window)
static float ck_round_fp16_scalar(float x)
static int ck_llama_kv_pad_256(int live_tokens, int capacity)
void attention_forward_full_head_major_gqa_flash_strided_gemma4(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
static float ck_attention_dot_f16_unfused_llama(const uint16_t *x, const uint16_t *y, int n)
static void attention_query_full_ggml_regular(const float *q_vec, const float *k_head, const float *v_cols, int kv_tokens, int head_dim, int aligned_head_dim, float scale, float *score_row, float *out_vec, int layer_id, int head_id, int query_id)
void attention_forward_causal_head_major_gqa_llama_regular_strided_sliding_workspace(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int sliding_window, float *scores, size_t scores_bytes, float *value_columns, size_t value_columns_bytes, float *scaled_scores, size_t scaled_scores_bytes)
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_gqa_reuse_config(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int query_tile_size, int concurrent_query_tiles, void *workspace, size_t workspace_bytes)
static void ck_attention_scale_f16_llama(uint16_t *y, float scale, int n)
static void attention_forward_mixed_visual_chunk_head_major_gqa_flash_strided_gemma4_impl(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int visual_start, int visual_tokens, int output_token_major)
static void ck_attention_bf16_pytorch_flash_work(int ith, int nth, void *opaque)
static void attention_forward_head_major_gqa_flash_impl(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int causal, int round_full_kv_fp16, int output_token_major, float scale)
static int ck_attention_pick_active_threads(const ck_threadpool_t *pool, int total_queries, int num_tokens)
void attention_forward_decode_head_major_gqa_flash(const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
static float ck_attention_dot_f16_llama(const uint16_t *x, const uint16_t *y, int n)
static int ck_attention_full_bf16_sdpa_tiled(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
static void ck_attention_llama_regular_query(const float *query, const float *key_head, const float *value_columns, float *output, float *scores, float *scaled_scores, int live_tokens, int padded_tokens, int query_position, int head_dim, int aligned_head_dim, int sliding_window, int batched_prefill)
static void ck_attention_query_key_f32_work(int ith, int nth, void *opaque)
static int ck_attention_full_bf16_sdpa_tiled_range(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int head_begin, int head_step)
size_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_gqa_reuse_workspace_bytes(int num_heads, int num_kv_heads, int head_dim, int workers, int query_tile_size, int concurrent_query_tiles)
static void ck_attention_trace_query(const char *tag, int layer_id, int head_id, int query_id, int value)
static int ck_attention_vec_dump_parse_env_int(const char *name, int *out)
void attention_forward_decode_head_major_gqa_regular(const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
WARNING: This is NOT true flash attention!
void attention_forward_causal_head_major_gqa_flash_strided_f16kv(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
static void ck_attention_f16_prefill_qtile64_work(int ith, int nth, void *opaque)
static float ck_ggml_vec_dot_f32_contig(const float *x, const float *y, int n)
static void ck_attention_full_tiled_f16kv_fp32_range(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int query_tile_size, int ith, int nth)
#define CK_GGML_FA_TILE_Q_LARGE
void attention_forward_decode_head_major_gqa_muse_eager_bf16_storage_sliding(const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int sliding_window, float *scores, size_t scores_bytes, uint16_t *key_rows, size_t key_rows_bytes, uint16_t *value_columns, size_t value_columns_bytes, uint16_t *gemm_rows, size_t gemm_rows_bytes, uint16_t *gemm_scores, size_t gemm_scores_bytes)
static ck_attention_status_t ck_attention_f16_prefill_qtile64_dispatch(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int cache_is_bf16, float attention_scale, size_t q_head_stride, size_t output_head_stride, ck_attention_prefill_schedule_t schedule)
static ck_attention_status_t ck_attention_prefill_append_f16cache_gemma4_workspace(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int sliding_window, ck_attention_reduction_t reduction, float *token_workspace, size_t token_workspace_bytes, const int *segment_lengths, int num_segments)
float(* ck_attention_math_f32_fn)(float)
static void attention_flash_query_causal(const float *q_vec, const float *k_head, const float *v_head, int kv_tokens, int head_dim, int aligned_head_dim, float scale, float *out_vec)
#define CK_MUSE_PREFILL_QUERY_TILE
void attention_forward_sparse_token_major_gqa_bf16cache_pytorch_cpu_flash_contract(const float *query, const uint16_t *key_cache, const uint16_t *value_cache, const float *selected_indices, float *output, float *score_scratch, int rows, int query_heads, int kv_heads, int head_dim, int selection_width, int context_length, int position)
static void ck_attention_trace(const char *branch, int layer_id, int head_id)
static int ck_attention_full_bf16_pytorch_flash(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int output_token_major)
void attention_forward_decode_head_major_gqa_llama_regular_sliding_workspace(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int live_tokens, int kv_stride_tokens, int head_dim, int aligned_head_dim, int sliding_window, float *scores, size_t scores_bytes, float *value_columns, size_t value_columns_bytes, float *scaled_scores, size_t scaled_scores_bytes)
int attention_forward_query_key_head_major_tiled_f16kv_fp32(const float *query, const float *key, const float *value, float *output, int num_heads, int query_tokens, int key_tokens, int head_dim, float scale)
static float ck_llama_regular_dot_f16(const float *a, const float *b, int count)
static const uint32_t ck_attention_vec_dump_version
static float ck_vec_dot_f32_reverse_strict(const float *x, const float *y, int n)
static void ck_attention_gqa_team_barrier_wait(ck_attention_gqa_team_barrier_t *barrier)
void attention_forward_causal_head_major_gqa_flash(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim)
static void ck_attention_vec_dump_selected_query(const float *raw_scores, const float *probs, const float *out_vec, const float *v_cols, int kv_tokens, int head_dim, int layer_id, int head_id, int query_id)
ck_attention_status_t attention_forward_decode_head_major_gqa_bf16cache_pytorch_contract(const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction)
void attention_forward_full_head_major_gqa_ggml_strided_workspace(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, float *score_rows, size_t score_rows_bytes, float *v_columns, size_t v_columns_bytes, float *probability_row, size_t probability_row_bytes)
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_gemma4_workspace(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction, float *token_workspace, size_t token_workspace_bytes)
static void attention_flash_query_causal_exact_f16kv(const float *q_vec, const float *k_head, const float *v_head, int kv_tokens, int head_dim, int aligned_head_dim, float scale, float *out_vec)
void attention_forward_mixed_visual_chunk_head_major_gqa_flash_strided_gemma4_token_output(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int visual_start, int visual_tokens)
static size_t ck_attention_f16_prefill_gqa_reuse_worker_bytes(int num_heads, int num_kv_heads, int head_dim, int workers, int query_tile_size, int concurrent_query_tiles)
#define FLASH_QUERY_IMPL_DECODE
static int ck_attention_vec_dump_vcols_enabled(void)
void attention_forward_causal_head_major_gqa_flash_strided_gemma4_token_output(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
ck_attention_status_t attention_forward_decode_head_major_gqa_f16cache_sliding_gemma4_contract(const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int sliding_window, ck_attention_reduction_t reduction)
static void ck_attention_muse_eager_bf16_storage_impl(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int query_tokens, int kv_tokens, int kv_stride_tokens, int head_dim, int aligned_head_dim, int sliding_window, float *scores, size_t scores_bytes, uint16_t *key_rows, size_t key_rows_bytes, uint16_t *value_columns, size_t value_columns_bytes, uint16_t *gemm_rows, size_t gemm_rows_bytes, uint16_t *gemm_scores, size_t gemm_scores_bytes)
void attention_forward_full_head_major_gqa_tiled64_f16kv_fp32_strided(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
#define CK_GGML_FA_TILE_Q_LARGE_MIN_TOKENS
void attention_forward_causal_head_major_gqa_muse_eager_bf16_storage_sliding(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int sliding_window, float *scores, size_t scores_bytes, uint16_t *key_rows, size_t key_rows_bytes, uint16_t *value_columns, size_t value_columns_bytes, uint16_t *gemm_rows, size_t gemm_rows_bytes, uint16_t *gemm_scores, size_t gemm_scores_bytes)
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_append_f16cache_contract_workspace(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction, float *token_workspace, size_t token_workspace_bytes)
static void attention_flash_query_causal_exact_prerounded_f16kv(const float *q_vec, const float *k_head, const float *v_head, int kv_tokens, int head_dim, int aligned_head_dim, float scale, float *out_vec)
static void ck_attention_full_grid_work(int ith, int nth, void *opaque)
void attention_backward_causal_head_major(const float *d_output, const float *q, const float *k, const float *v, const float *attn_weights, float *d_q, float *d_k, float *d_v, float *d_scores, int num_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window)
void attention_forward_decode_head_major_gqa_flash_f16cache_split(const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, int split_chunks)
void attention_forward_causal_head_major_gqa_flash_strided_f16kv_serial(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
int ck_attention_sparse_bf16_pytorch_gqa_available(void)
void attention_backward_causal_head_major_gqa(const float *d_output, const float *q, const float *k, const float *v, const float *attn_weights, float *d_q, float *d_k, float *d_v, float *d_scores, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window)
static float ck_attention_f16_reduce_expf(float value)
static int ck_attention_full_bf16_sdpa_amx_range(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int head_begin, int head_step, int output_token_major)
ck_attention_status_t attention_forward_causal_head_major_gqa_prefill_segmented_f16cache_contract_workspace(const float *q, const uint16_t *k_cache, const uint16_t *v_cache, float *output, int num_heads, int num_kv_heads, int q_tokens, int past_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction, float *token_workspace, size_t token_workspace_bytes, const int *segment_lengths, int num_segments)
void attention_forward_full_head_major_gqa_sdpa_bf16_storage(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
static void ck_attention_llama_regular_impl(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int query_tokens, int live_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int sliding_window, float *scores, size_t scores_bytes, float *value_columns, size_t value_columns_bytes, float *scaled_scores, size_t scaled_scores_bytes, int batched_prefill)
static void ck_local_fp16_to_fp32_2d(const uint16_t *src, float *dst, int rows, int cols, int src_stride, int dst_stride)
static size_t ck_attention_align64_size(size_t value)
ck_attention_status_t attention_forward_decode_head_major_gqa_flash_f16cache_contract(const float *q_token, const uint16_t *k_cache, const uint16_t *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim, ck_attention_reduction_t reduction)
static int attention_forward_head_major_gqa_unfused_f16_strict(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int causal, int output_token_major, float scale, int debug_layer_id)
static int ck_attention_vec_dump_layer_seq
static void ck_attention_causal_f16kv_work(int ith, int nth, void *opaque)
void attention_forward_causal_head_major_gqa_flash_strided_token_output(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
static int ck_attention_vec_dump_should_emit(int layer_id, int head_id, int query_id)
static float ck_bf16_dot_contract(const float *a, const float *b, int count)
void attention_forward_full_head_major_gqa_pytorch_cpu_flash_bf16_storage_token_output(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens)
static void ck_attention_forward_full_head_major_gqa_tiled_f16kv_fp32_strided(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, int query_tile_size)
static void convert_bf16_tensor_to_buf(const uint16_t *src, float *dst, size_t count)
static void ck_attention_f16_split_work(int ith, int nth, void *opaque)
int ck_attention_bf16_pytorch_gqa_available(void)
static int ck_attention_forward_query_key_head_major_f32_run(const float *query, const float *key, const float *value, float *output, float *score_scratch, float *key_transpose_scratch, int num_heads, int query_tokens, int key_tokens, int head_dim, float scale)
static int ck_attention_parallel_enabled(int total_queries, int num_tokens, int head_dim)
static size_t ck_muse_attention_checked_product(size_t left, size_t right, const char *label)
static ck_ggml_mul_mat_graph_fn ck_resolve_ggml_mul_mat_graph(void)
void(* ck_ggml_cpu_init_fn)(void)
struct ggml_tensor *(* ck_ggml_new_tensor_2d_fn)(struct ggml_context *, enum ggml_type, int64_t, int64_t)
struct ggml_cgraph *(* ck_ggml_new_graph_fn)(struct ggml_context *)
void(* ck_ggml_set_input_fn)(struct ggml_tensor *)
enum ggml_status(* ck_ggml_graph_compute_with_ctx_fn)(struct ggml_context *, struct ggml_cgraph *, int)
static ck_ggml_new_tensor_2d_fn ck_resolve_ggml_new_tensor_2d(void)
static ck_ggml_build_forward_expand_fn ck_resolve_ggml_build_forward_expand(void)
void(* ck_ggml_free_fn)(struct ggml_context *)
void(* ck_ggml_build_forward_expand_fn)(struct ggml_cgraph *, struct ggml_tensor *)
struct ggml_tensor *(* ck_ggml_mul_mat_graph_fn)(struct ggml_context *, struct ggml_tensor *, struct ggml_tensor *)
static ck_ggml_graph_compute_with_ctx_fn ck_resolve_ggml_graph_compute_with_ctx(void)
static ck_ggml_set_input_fn ck_resolve_ggml_set_input(void)
int ck_attention_head_full_ggml_graph_oracle_regular(const float *q_head, const float *k_head, const float *v_head, float *out_head, int num_tokens, int head_dim, int aligned_head_dim, float scale)
static ck_ggml_new_graph_fn ck_resolve_ggml_new_graph(void)
static ck_ggml_free_fn ck_resolve_ggml_free(void)
struct ggml_context *(* ck_ggml_init_fn)(struct ggml_init_params)
int ck_attention_full_ggml_graph_oracle_multihead(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int kv_stride_tokens, float scale)
static ck_ggml_init_fn ck_resolve_ggml_init(void)
static ck_ggml_cpu_init_fn ck_resolve_ggml_cpu_init(void)
static int product(size_t a, size_t b, size_t *out)
static uint16_t float_to_bf16(float f)
static float bf16_to_float(uint16_t v)
static void bf16_tensor_to_float(const uint16_t *src, float *dst, size_t count)
static int ck_env_truthy_or_qwen3vl_ocr_profile(const char *name)
Persistent pthread thread pool for CK-Engine inference.
void ck_threadpool_dispatch_n(ck_threadpool_t *pool, int active_threads, ck_work_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 const char * op_name(CKOpType op)
ck_attention_prefill_schedule_t
@ CK_ATTN_PREFILL_SCHEDULE_QUERY_TILES
@ CK_ATTN_PREFILL_SCHEDULE_KV_HEADS
@ CK_ATTN_PREFILL_SCHEDULE_GQA_SHARED_KV_TILES
@ CK_ATTN_PREFILL_SCHEDULE_KV_GROUP_QUERY_TILES
void attention_flash_decode(float *out, const float *q, const float *k, const float *v, int T_q, int T_k, int H, int D_h, float scale)
Main flash attention function with SIMD dispatch.
void gemm_nt_bf16_pytorch_onednn_3_12_brgemm_bf16_storage_workspace(const float *A, const void *B, const float *bias, float *C, int M, int N, int K, uint16_t *input_bf16, size_t input_bf16_bytes, uint16_t *output_bf16, size_t output_bf16_bytes, uint16_t *bias_bf16, size_t bias_bf16_bytes)
int ck_gemm_bf16_amx_available(void)
void causal_softmax_head_major_exact(float *scores, int num_heads, int num_tokens, int aligned_context_window)
void causal_softmax_head_major(float *scores, int num_heads, int num_tokens, int aligned_context_window)
int ck_gemm_bf16_fp32out_amx_raw(const uint16_t *A, const uint16_t *B, float *C, int M, int N, int K, int accumulate)
@ CK_ATTN_REDUCTION_BF16_PYTORCH_SDPA
@ CK_ATTN_REDUCTION_F16_FLASH_AUTO_QTILE64_REGULAR_TAIL_NOSCALE
@ CK_ATTN_REDUCTION_F16_REGULAR_NOSCALE
@ CK_ATTN_REDUCTION_F16_ONLINE_FP32_MERGE
@ CK_ATTN_REDUCTION_F16_FLASH_AUTO_QTILE64
@ CK_ATTN_REDUCTION_F16_ONLINE_SINGLE_RANGE
@ CK_ATTN_REDUCTION_FP32_ONLINE
@ CK_ATTENTION_STATUS_UNSUPPORTED_CONTRACT
@ CK_ATTENTION_STATUS_INVALID_ARGUMENT
@ CK_ATTENTION_STATUS_INSUFFICIENT_WORKSPACE
int ck_get_num_threads(void)
int ck_strict_parity_enabled(void)
#define CK_FP16_TO_FP32(x)
#define CK_FP32_TO_FP16(x)
__attribute__((visibility("default"))) CKTokenizer *ck_tokenizer_create(CKTokenizerType type)
const uint8_t size_t count
const char const char * right