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,
233 float *key_transpose_scratch,
240 if (key_transpose_scratch == NULL)
return -1;
242 query, key, value, output, score_scratch, key_transpose_scratch,
243 num_heads, query_tokens, key_tokens, head_dim, scale);
249 if (!dst || !src)
return;
259 int aligned_head_dim)
261 return ((
size_t)h * (
size_t)num_tokens + (
size_t)t) * (size_t)aligned_head_dim
266 int num_heads,
int num_tokens,
267 int aligned_head_dim,
271 return ((
size_t)
token * (
size_t)num_heads + (
size_t)h) *
272 (size_t)aligned_head_dim;
285#if defined(__AVX2__) && defined(__F16C__)
286 for (; i + 8 <= count; i += 8) {
287 const __m256 value = _mm256_loadu_ps(src + i);
288 const __m128i half = _mm256_cvtps_ph(
289 value, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
290 _mm256_storeu_ps(dst + i, _mm256_cvtph_ps(half));
293 for (; i < count; ++i) {
300 if (!src || !dst || n <= 0) {
303 for (
int i = 0; i < n; ++i) {
315 if (!src || !dst || rows <= 0 || cols <= 0) {
318 for (
int r = 0; r < rows; ++r) {
320 dst + (
size_t)r * (
size_t)dst_stride,
325#if defined(__GNUC__) || defined(__clang__)
326#define CK_NOINLINE __attribute__((noinline))
331#if defined(__clang__)
332#define CK_OPTNONE __attribute__((optnone))
333#elif defined(__GNUC__)
334#define CK_OPTNONE __attribute__((optimize("O0")))
344 for (
int i = 0; i < n; ++i) {
345 volatile float prod = x[i] * y[i];
346 volatile float next = sumf + prod;
357 for (
int i = 0; i < n; ++i) {
358 volatile double prod = (double) x[i] * (
double) y[i];
359 volatile double next = sum + prod;
370 for (
int i = n - 1; i >= 0; --i) {
371 volatile float prod = x[i] * y[i];
372 volatile float next = sumf + prod;
388 uint8_t reserved[32];
403 const char *v = getenv(
"CK_STRICT_ATTN_VEC_DUMP");
404 return v && v[0] && strcmp(v,
"0") != 0;
409 const char *v = getenv(
"CK_STRICT_ATTN_DUMP_VCOLS");
410 return v && v[0] && strcmp(v,
"0") != 0;
415 const char *v = getenv(
"CK_STRICT_ATTN_REVERSE_OUT_DOT");
416 return v && v[0] && strcmp(v,
"0") != 0;
419#if CK_ENABLE_LLAMA_CPP_PARITY
422 const char *v = getenv(
"CK_STRICT_ATTN_GGML_OUT_GRAPH");
423 return v && v[0] && strcmp(v,
"0") != 0;
434 const char *v = getenv(name);
439 long parsed = strtol(v, &
end, 10);
440 if (
end == v || (
end && *
end !=
'\0') || parsed < 0 || parsed > INT32_MAX) {
462 const int trace_target = layer_id == want_layer &&
463 (!have_head || head_id == want_head) &&
464 (!have_query || query_id == want_query);
465 if (layer_id != want_layer) {
468 if (have_head && head_id != want_head) {
471 if (have_query && query_id != want_query) {
493 const char *dir = getenv(
"CK_PARITY_DIR");
494 if (!dir || !dir[0] || !name || !name[0] || !data || elem_count == 0) {
499 snprintf(path,
sizeof(path),
"%s/%s", dir,
"strict_internal.bin");
500 FILE *f = fopen(path,
"ab");
505 ck_attention_vec_dump_header_t h;
506 memset(&h, 0,
sizeof(h));
509 h.layer_id = layer_id;
510 strncpy(h.op_name, name,
sizeof(h.op_name) - 1);
513 h.shape[0] = (int64_t) elem_count;
514 h.elem_count = (uint32_t) elem_count;
515 h.token_id = query_id;
517 fwrite(&h,
sizeof(h), 1, f);
518 fwrite(data,
sizeof(
float), elem_count, f);
524 const char *enabled = getenv(
"CK_STRICT_ATTN_TRACE");
525 const char *dir = getenv(
"CK_PARITY_DIR");
526 if (!enabled || !enabled[0] || strcmp(enabled,
"0") == 0 || !dir || !dir[0] || !branch || !branch[0]) {
530 snprintf(path,
sizeof(path),
"%s/%s", dir,
"strict_trace.txt");
531 FILE *f = fopen(path,
"a");
535 fprintf(f,
"layer=%d head=%d branch=%s\n", layer_id, head_id, branch);
545 const char *enabled = getenv(
"CK_STRICT_ATTN_TRACE");
546 const char *dir = getenv(
"CK_PARITY_DIR");
547 if (!enabled || !enabled[0] || strcmp(enabled,
"0") == 0 || !dir || !dir[0] || !tag || !tag[0]) {
551 snprintf(path,
sizeof(path),
"%s/%s", dir,
"strict_trace.txt");
552 FILE *f = fopen(path,
"a");
556 fprintf(f,
"layer=%d head=%d query=%d tag=%s value=%d\n", layer_id, head_id, query_id, tag, value);
565 const char *enabled = getenv(
"CK_STRICT_ATTN_TRACE");
566 const char *dir = getenv(
"CK_PARITY_DIR");
567 if (!enabled || !enabled[0] || strcmp(enabled,
"0") == 0 || !dir || !dir[0] || !tag || !tag[0]) {
571 snprintf(path,
sizeof(path),
"%s/%s", dir,
"strict_trace.txt");
572 FILE *f = fopen(path,
"a");
576 fprintf(f,
"layer=%d head=%d tag=%s float=%.17g\n", layer_id, head_id, tag, (
double) value);
582 const float *out_vec,
595 snprintf(name,
sizeof(name),
"kq_scores_h%d_q%d", head_id, query_id);
597 snprintf(name,
sizeof(name),
"kq_soft_h%d_q%d", head_id, query_id);
599 snprintf(name,
sizeof(name),
"kqv_out_h%d_q%d", head_id, query_id);
602 snprintf(name,
sizeof(name),
"vcols_h%d_q%d", head_id, query_id);
610#if CK_ENABLE_LLAMA_CPP_PARITY
611struct ggml_compute_params;
612typedef void (*ck_ggml_vec_dot_f32_fn)(int,
float *, size_t,
const float *, size_t,
const float *, size_t, int);
613typedef double (*ck_ggml_vec_soft_max_f32_fn)(int,
float *,
const float *, float);
614typedef void (*ck_ggml_compute_forward_mul_mat_fn)(
const struct ggml_compute_params *,
struct ggml_tensor *);
615typedef void (*ck_ggml_compute_forward_soft_max_fn)(
const struct ggml_compute_params *,
struct ggml_tensor *);
619typedef struct ggml_tensor *(*ck_ggml_new_tensor_2d_fn)(
struct ggml_context *,
enum ggml_type, int64_t, int64_t);
620typedef struct ggml_tensor *(*ck_ggml_mul_mat_graph_fn)(
struct ggml_context *,
struct ggml_tensor *,
struct ggml_tensor *);
621typedef struct ggml_cgraph *(*ck_ggml_new_graph_fn)(
struct ggml_context *);
626struct ggml_threadpool;
627struct ggml_compute_params {
631 struct ggml_threadpool * threadpool;
635static void *ck_resolve_ggml_cpu_so_handle(
void)
637 static int tried = 0;
638 static void *handle = NULL;
641 const char *env_path = getenv(
"CK_GGML_CPU_SO");
642 const char *env_dir = getenv(
"CK_GGML_LIB_DIR");
643 const char *dirs[] = {
644 "/opt/app-root/src/Software/llama.cpp/build/bin",
645 "./llama.cpp/build/bin",
646 "llama.cpp/build/bin",
650 if (env_dir && env_dir[0]) {
651 snprintf(path_buf,
sizeof(path_buf),
"%s/libggml-base.so", env_dir);
652 dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
653 snprintf(path_buf,
sizeof(path_buf),
"%s/libggml.so", env_dir);
654 dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
655 snprintf(path_buf,
sizeof(path_buf),
"%s/libggml-cpu.so", env_dir);
656 handle = dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
658 for (
int i = 0; !handle && dirs[i] != NULL; ++i) {
659 snprintf(path_buf,
sizeof(path_buf),
"%s/libggml-base.so", dirs[i]);
660 dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
661 snprintf(path_buf,
sizeof(path_buf),
"%s/libggml.so", dirs[i]);
662 dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
663 snprintf(path_buf,
sizeof(path_buf),
"%s/libggml-cpu.so", dirs[i]);
664 handle = dlopen(path_buf, RTLD_NOW | RTLD_GLOBAL);
669 if (!handle && env_path && env_path[0]) {
670 handle = dlopen(env_path, RTLD_NOW | RTLD_GLOBAL);
672 const char *candidates[] = {
677 for (
int i = 0; !handle && candidates[i] != NULL; ++i) {
678 handle = dlopen(candidates[i], RTLD_NOW | RTLD_GLOBAL);
684static void *ck_resolve_ggml_symbol(
const char *name)
690 void *handle = ck_resolve_ggml_cpu_so_handle();
694 return dlsym(handle, name);
697static ck_ggml_vec_dot_f32_fn ck_resolve_ggml_vec_dot_f32(
void)
699 static int tried = 0;
700 static ck_ggml_vec_dot_f32_fn fn = NULL;
703 fn = (ck_ggml_vec_dot_f32_fn) ck_resolve_ggml_symbol(
"ggml_vec_dot_f32");
708static ck_ggml_vec_soft_max_f32_fn ck_resolve_ggml_vec_soft_max_f32(
void)
710 static int tried = 0;
711 static ck_ggml_vec_soft_max_f32_fn fn = NULL;
714 fn = (ck_ggml_vec_soft_max_f32_fn) ck_resolve_ggml_symbol(
"ggml_vec_soft_max_f32");
719static ck_ggml_compute_forward_mul_mat_fn ck_resolve_ggml_compute_forward_mul_mat(
void)
721 static int tried = 0;
722 static ck_ggml_compute_forward_mul_mat_fn fn = NULL;
725 fn = (ck_ggml_compute_forward_mul_mat_fn) ck_resolve_ggml_symbol(
"ggml_compute_forward_mul_mat");
730static ck_ggml_compute_forward_soft_max_fn ck_resolve_ggml_compute_forward_soft_max(
void)
732 static int tried = 0;
733 static ck_ggml_compute_forward_soft_max_fn fn = NULL;
736 fn = (ck_ggml_compute_forward_soft_max_fn) ck_resolve_ggml_symbol(
"ggml_compute_forward_soft_max");
743 static int tried = 0;
754 static int tried = 0;
765 static int tried = 0;
776 static int tried = 0;
787 static int tried = 0;
798 static int tried = 0;
809 static int tried = 0;
820 static int tried = 0;
831 static int tried = 0;
840static inline void ck_ggml_init_tensor_f32(
struct ggml_tensor *t,
851 memset(t, 0,
sizeof(*t));
862 t->op = GGML_OP_NONE;
869#define CK_MADD128(x, y, z) _mm_fmadd_ps(x, y, z)
870#define CK_NMADD128(x, y, z) _mm_fnmadd_ps(x, y, z)
872#define CK_MADD128(x, y, z) _mm_add_ps(_mm_mul_ps(x, y), z)
873#define CK_NMADD128(x, y, z) _mm_sub_ps(z, _mm_mul_ps(x, y))
876static inline float ck_hsum128_ps(__m128 v) {
877 v = _mm_add_ps(v, _mm_movehl_ps(v, v));
878 v = _mm_add_ss(v, _mm_movehdup_ps(v));
879 return _mm_cvtss_f32(v);
883#if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__)
884static inline float ck_hsum256_ps(__m256 v) {
885 const __m128 lo = _mm256_castps256_ps128(v);
886 const __m128 hi = _mm256_extractf128_ps(v, 1);
887 return ck_hsum128_ps(_mm_add_ps(lo, hi));
891#if defined(__AVX512F__) && defined(__AVX512DQ__)
892static inline __m512 ck_ggml_v_expf512(__m512 x) {
893 const __m512 r = _mm512_set1_ps(0x1.8p23f);
894 const __m512 z = _mm512_fmadd_ps(x, _mm512_set1_ps(0x1.715476p+0f), r);
895 const __m512 n = _mm512_sub_ps(z, r);
896 const __m512 b = _mm512_fnmadd_ps(
898 _mm512_set1_ps(0x1.7f7d1cp-20f),
899 _mm512_fnmadd_ps(n, _mm512_set1_ps(0x1.62e4p-1f), x));
900 const __mmask16 d = _mm512_cmp_ps_mask(
901 _mm512_abs_ps(n), _mm512_set1_ps(192), _CMP_GT_OQ);
902 const __m512 u = _mm512_mul_ps(b, b);
903 const __m512 j = _mm512_fmadd_ps(
906 _mm512_set1_ps(0x1.0e4020p-7f),
908 _mm512_set1_ps(0x1.573e2ep-5f)),
911 _mm512_set1_ps(0x1.555e66p-3f),
913 _mm512_set1_ps(0x1.fffdb6p-2f))),
916 _mm512_set1_ps(0x1.ffffecp-1f),
918 _mm512_set1_ps(1.0f)));
919 const __m512 res = _mm512_scalef_ps(j, n);
920 if (_mm512_kortestz(d, d)) {
923 const __m512 zero = _mm512_setzero_ps();
924 const __m512 alt = _mm512_mask_blend_ps(
925 _mm512_cmp_ps_mask(n, zero, _CMP_LE_OQ),
926 _mm512_set1_ps(INFINITY),
928 return _mm512_mask_blend_ps(d, res, alt);
932#if defined(__AVX2__) && defined(__FMA__)
933static inline __m256 ck_ggml_v_expf256(__m256 x) {
934 const __m256 r = _mm256_set1_ps(0x1.8p23f);
935 const __m256 z = _mm256_fmadd_ps(x, _mm256_set1_ps(0x1.715476p+0f), r);
936 const __m256 n = _mm256_sub_ps(z, r);
937 const __m256 b = _mm256_fnmadd_ps(n, _mm256_set1_ps(0x1.7f7d1cp-20f),
938 _mm256_fnmadd_ps(n, _mm256_set1_ps(0x1.62e4p-1f), x));
939 const __m256i e = _mm256_slli_epi32(_mm256_castps_si256(z), 23);
940 const __m256 k = _mm256_castsi256_ps(
941 _mm256_add_epi32(e, _mm256_castps_si256(_mm256_set1_ps(1))));
942 const __m256i c = _mm256_castps_si256(
943 _mm256_cmp_ps(_mm256_andnot_ps(_mm256_set1_ps(-0.f), n),
944 _mm256_set1_ps(126), _CMP_GT_OQ));
945 const __m256 u = _mm256_mul_ps(b, b);
946 const __m256 j = _mm256_fmadd_ps(
948 _mm256_fmadd_ps(_mm256_set1_ps(0x1.0e4020p-7f), b, _mm256_set1_ps(0x1.573e2ep-5f)),
950 _mm256_fmadd_ps(_mm256_set1_ps(0x1.555e66p-3f), b, _mm256_set1_ps(0x1.fffdb6p-2f))),
952 _mm256_mul_ps(_mm256_set1_ps(0x1.ffffecp-1f), b));
953 if (!_mm256_movemask_ps(_mm256_castsi256_ps(c))) {
954 return _mm256_fmadd_ps(j, k, k);
956 const __m256i g = _mm256_and_si256(
957 _mm256_castps_si256(_mm256_cmp_ps(n, _mm256_setzero_ps(), _CMP_LE_OQ)),
958 _mm256_set1_epi32(0x82000000u));
960 _mm256_castsi256_ps(_mm256_add_epi32(g, _mm256_set1_epi32(0x7f000000u)));
961 const __m256 s2 = _mm256_castsi256_ps(_mm256_sub_epi32(e, g));
962 const __m256i d = _mm256_castps_si256(
963 _mm256_cmp_ps(_mm256_andnot_ps(_mm256_set1_ps(-0.f), n),
964 _mm256_set1_ps(192), _CMP_GT_OQ));
966 _mm256_and_ps(_mm256_castsi256_ps(d), _mm256_mul_ps(s1, s1)),
968 _mm256_castsi256_ps(d),
970 _mm256_and_ps(_mm256_castsi256_ps(c),
971 _mm256_mul_ps(_mm256_fmadd_ps(s2, j, s2), s1)),
972 _mm256_andnot_ps(_mm256_castsi256_ps(c), _mm256_fmadd_ps(k, j, k)))));
977static inline __m128 ck_ggml_v_expf128(__m128 x) {
978 const __m128 r = _mm_set1_ps(0x1.8p23f);
979 const __m128 z = CK_MADD128(x, _mm_set1_ps(0x1.715476p+0f), r);
980 const __m128 n = _mm_sub_ps(z, r);
981 const __m128 b = CK_NMADD128(n, _mm_set1_ps(0x1.7f7d1cp-20f),
982 CK_NMADD128(n, _mm_set1_ps(0x1.62e4p-1f), x));
983 const __m128i e = _mm_slli_epi32(_mm_castps_si128(z), 23);
984 const __m128 k = _mm_castsi128_ps(
985 _mm_add_epi32(e, _mm_castps_si128(_mm_set1_ps(1))));
986 const __m128i c = _mm_castps_si128(
987 _mm_cmpgt_ps(_mm_andnot_ps(_mm_set1_ps(-0.f), n), _mm_set1_ps(126)));
988 const __m128 u = _mm_mul_ps(b, b);
989 const __m128 j = CK_MADD128(
991 CK_MADD128(_mm_set1_ps(0x1.0e4020p-7f), b, _mm_set1_ps(0x1.573e2ep-5f)),
993 CK_MADD128(_mm_set1_ps(0x1.555e66p-3f), b, _mm_set1_ps(0x1.fffdb6p-2f))),
995 _mm_mul_ps(_mm_set1_ps(0x1.ffffecp-1f), b));
996 if (!_mm_movemask_ps(_mm_castsi128_ps(c))) {
997 return CK_MADD128(j, k, k);
999 const __m128i g = _mm_and_si128(
1000 _mm_castps_si128(_mm_cmple_ps(n, _mm_setzero_ps())),
1001 _mm_set1_epi32(0x82000000u));
1002 const __m128 s1 = _mm_castsi128_ps(_mm_add_epi32(g, _mm_set1_epi32(0x7f000000u)));
1003 const __m128 s2 = _mm_castsi128_ps(_mm_sub_epi32(e, g));
1004 const __m128i d = _mm_castps_si128(
1005 _mm_cmpgt_ps(_mm_andnot_ps(_mm_set1_ps(-0.f), n), _mm_set1_ps(192)));
1007 _mm_and_ps(_mm_castsi128_ps(d), _mm_mul_ps(s1, s1)),
1009 _mm_castsi128_ps(d),
1011 _mm_and_ps(_mm_castsi128_ps(c), _mm_mul_ps(CK_MADD128(s2, j, s2), s1)),
1012 _mm_andnot_ps(_mm_castsi128_ps(c), CK_MADD128(k, j, k)))));
1024 const int np = (n & ~31);
1026 _mm256_setzero_ps(),
1027 _mm256_setzero_ps(),
1028 _mm256_setzero_ps(),
1029 _mm256_setzero_ps(),
1032 for (
int i = 0; i < np; i += 32) {
1033 for (
int j = 0; j < 4; ++j) {
1034 const __m256 ax = _mm256_loadu_ps(x + i + j * 8);
1035 const __m256 ay = _mm256_loadu_ps(y + i + j * 8);
1037 sum[j] = _mm256_fmadd_ps(ax, ay, sum[j]);
1039 sum[j] = _mm256_add_ps(_mm256_mul_ps(ax, ay), sum[j]);
1044 sum[0] = _mm256_add_ps(sum[0], sum[2]);
1045 sum[1] = _mm256_add_ps(sum[1], sum[3]);
1046 sum[0] = _mm256_add_ps(sum[0], sum[1]);
1047 const __m128 t0 = _mm_add_ps(_mm256_castps256_ps128(sum[0]),
1048 _mm256_extractf128_ps(sum[0], 1));
1049 const __m128 t1 = _mm_hadd_ps(t0, t0);
1050 sumf = _mm_cvtss_f32(_mm_hadd_ps(t1, t1));
1052 for (
int i = np; i < n; ++i) {
1053 sumf += x[i] * y[i];
1056#elif defined(__SSE2__)
1058 const int np = (n & ~15);
1066 for (
int i = 0; i < np; i += 16) {
1067 for (
int j = 0; j < 4; ++j) {
1068 const __m128 ax = _mm_loadu_ps(x + i + j * 4);
1069 const __m128 ay = _mm_loadu_ps(y + i + j * 4);
1071 sum[j] = _mm_fmadd_ps(ax, ay, sum[j]);
1073 sum[j] = _mm_add_ps(_mm_mul_ps(ax, ay), sum[j]);
1078 sum[0] = _mm_add_ps(sum[0], sum[2]);
1079 sum[1] = _mm_add_ps(sum[1], sum[3]);
1080 sum[0] = _mm_add_ps(sum[0], sum[1]);
1081#if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__)
1082 sum[0] = _mm_add_ps(sum[0], _mm_movehl_ps(sum[0], sum[0]));
1083 sum[0] = _mm_add_ss(sum[0], _mm_movehdup_ps(sum[0]));
1085 __m128 tmp = _mm_shuffle_ps(sum[0], sum[0], _MM_SHUFFLE(2, 3, 0, 1));
1086 sum[0] = _mm_add_ps(sum[0], tmp);
1087 tmp = _mm_movehl_ps(tmp, sum[0]);
1088 sum[0] = _mm_add_ss(sum[0], tmp);
1090 sumf = _mm_cvtss_f32(sum[0]);
1092 for (
int i = np; i < n; ++i) {
1093 sumf += x[i] * y[i];
1098 for (
int i = 0; i < n; ++i) {
1099 sumf += (double) (x[i] * y[i]);
1101 return (
float) sumf;
1110#if defined(__AVX2__) && defined(__F16C__)
1111 __m256 sum0 = _mm256_setzero_ps();
1112 __m256 sum1 = _mm256_setzero_ps();
1113 __m256 sum2 = _mm256_setzero_ps();
1114 __m256 sum3 = _mm256_setzero_ps();
1115 const int n32 = n & ~31;
1116 for (; i < n32; i += 32) {
1117 const __m256 x0 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (x + i)));
1118 const __m256 y0 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (y + i)));
1119 const __m256 x1 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (x + i + 8)));
1120 const __m256 y1 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (y + i + 8)));
1121 const __m256 x2 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (x + i + 16)));
1122 const __m256 y2 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (y + i + 16)));
1123 const __m256 x3 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (x + i + 24)));
1124 const __m256 y3 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (y + i + 24)));
1126 sum0 = _mm256_fmadd_ps(x0, y0, sum0);
1127 sum1 = _mm256_fmadd_ps(x1, y1, sum1);
1128 sum2 = _mm256_fmadd_ps(x2, y2, sum2);
1129 sum3 = _mm256_fmadd_ps(x3, y3, sum3);
1131 sum0 = _mm256_add_ps(sum0, _mm256_mul_ps(x0, y0));
1132 sum1 = _mm256_add_ps(sum1, _mm256_mul_ps(x1, y1));
1133 sum2 = _mm256_add_ps(sum2, _mm256_mul_ps(x2, y2));
1134 sum3 = _mm256_add_ps(sum3, _mm256_mul_ps(x3, y3));
1137 sum0 = _mm256_add_ps(sum0, sum2);
1138 sum1 = _mm256_add_ps(sum1, sum3);
1139 sum0 = _mm256_add_ps(sum0, sum1);
1140 const __m128 pair = _mm_add_ps(
1141 _mm256_castps256_ps128(sum0),
1142 _mm256_extractf128_ps(sum0, 1));
1143 const __m128 half = _mm_hadd_ps(pair, pair);
1144 float result = _mm_cvtss_f32(_mm_hadd_ps(half, half));
1146 float result = 0.0f;
1148 for (; i < n; ++i) {
1159 volatile float hd = (float) head_dim;
1160 float (*sqrtf_fn)(float) = sqrtf;
1161 volatile float root = sqrtf_fn(hd);
1162 volatile float one = 1.0f;
1163 volatile float scale = one / root;
1171#if defined(__linux__)
1172 static void *libm_handle = NULL;
1174 static int resolved = 0;
1176 libm_handle = dlopen(
"libm.so.6", RTLD_NOW | RTLD_LOCAL);
1189#if defined(__INTEL_LLVM_COMPILER)
1191ck_attention_mul_add_rounded_f32(
float lhs,
float rhs,
float addend)
1198 volatile float product = lhs * rhs;
1199 volatile float result = product + addend;
1212#if defined(__AVX512F__) && defined(__AVX512DQ__)
1213 for (; i + 15 < n; i += 16) {
1214 const __m512 val = ck_ggml_v_expf512(
1215 _mm512_sub_ps(_mm512_loadu_ps(x + i), _mm512_set1_ps(max)));
1216 _mm512_storeu_ps(y + i, val);
1217 sum += (double) _mm512_reduce_add_ps(val);
1219#elif defined(__AVX2__) && defined(__FMA__)
1220 for (; i + 7 < n; i += 8) {
1221 const __m256 val = ck_ggml_v_expf256(
1222 _mm256_sub_ps(_mm256_loadu_ps(x + i), _mm256_set1_ps(max)));
1223 _mm256_storeu_ps(y + i, val);
1224 __m128 val2 = _mm_add_ps(_mm256_extractf128_ps(val, 1),
1225 _mm256_castps256_ps128(val));
1226 val2 = _mm_add_ps(val2, _mm_movehl_ps(val2, val2));
1227 val2 = _mm_add_ss(val2, _mm_movehdup_ps(val2));
1228 sum += (double) _mm_cvtss_f32(val2);
1230#elif defined(__SSE2__)
1231 for (; i + 3 < n; i += 4) {
1232 const __m128 val = ck_ggml_v_expf128(
1233 _mm_sub_ps(_mm_loadu_ps(x + i), _mm_set1_ps(max)));
1234 _mm_storeu_ps(y + i, val);
1235#if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__)
1236 __m128 acc = _mm_add_ps(val, _mm_movehl_ps(val, val));
1237 acc = _mm_add_ss(acc, _mm_movehdup_ps(acc));
1239 __m128 tmp = _mm_shuffle_ps(val, val, _MM_SHUFFLE(2, 3, 0, 1));
1240 __m128 acc = _mm_add_ps(val, tmp);
1241 tmp = _mm_movehl_ps(tmp, acc);
1242 acc = _mm_add_ss(acc, tmp);
1244 sum += (double) _mm_cvtss_f32(acc);
1248 for (; i < n; ++i) {
1249 const float val = expf(x[i] - max);
1251 sum += (double) val;
1262 int aligned_context_window)
1264 return ((
size_t)h * (
size_t)aligned_context_window * (
size_t)aligned_context_window)
1265 + (size_t)i * (
size_t)aligned_context_window
1289 int aligned_head_dim,
1290 int aligned_context_window)
1292 const float scale = 1.0f / sqrtf((
float)head_dim);
1296 for (
int h = 0; h < num_heads; ++h) {
1297 for (
int i = 0; i < num_tokens; ++i) {
1298 for (
int j = 0; j <= i; ++j) {
1300 size_t base_q =
qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1301 size_t base_k =
qkv_index(h, j, 0, num_tokens, aligned_head_dim);
1303 for (
int d = 0; d < head_dim; ++d) {
1304 dot += q[base_q + d] * k[base_k + d];
1307 scores[
score_index(h, i, j, aligned_context_window)] = dot * scale;
1312 for (
int j = i + 1; j < num_tokens; ++j) {
1313 scores[
score_index(h, i, j, aligned_context_window)] = 0.0f;
1322 aligned_context_window);
1325 for (
int h = 0; h < num_heads; ++h) {
1326 for (
int i = 0; i < num_tokens; ++i) {
1327 size_t out_base =
qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1330 for (
int d = 0; d < aligned_head_dim; ++d) {
1331 output[out_base + d] = 0.0f;
1335 for (
int j = 0; j <= i; ++j) {
1336 float w = scores[
score_index(h, i, j, aligned_context_window)];
1337 size_t v_base =
qkv_index(h, j, 0, num_tokens, aligned_head_dim);
1339 for (
int d = 0; d < head_dim; ++d) {
1340 output[out_base + d] += w * v[v_base + d];
1365 int aligned_head_dim,
1366 int aligned_context_window)
1368 const float scale = 1.0f / sqrtf((
float)head_dim);
1372 for (
int h = 0; h < num_heads; ++h) {
1373 for (
int i = 0; i < num_tokens; ++i) {
1374 for (
int j = 0; j <= i; ++j) {
1376 size_t base_q =
qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1377 size_t base_k =
qkv_index(h, j, 0, num_tokens, aligned_head_dim);
1379 for (
int d = 0; d < head_dim; ++d) {
1380 dot += q[base_q + d] * k[base_k + d];
1383 scores[
score_index(h, i, j, aligned_context_window)] = dot * scale;
1388 for (
int j = i + 1; j < num_tokens; ++j) {
1389 scores[
score_index(h, i, j, aligned_context_window)] = 0.0f;
1398 aligned_context_window);
1401 for (
int h = 0; h < num_heads; ++h) {
1402 for (
int i = 0; i < num_tokens; ++i) {
1403 size_t out_base =
qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1406 for (
int d = 0; d < aligned_head_dim; ++d) {
1407 output[out_base + d] = 0.0f;
1411 for (
int j = 0; j <= i; ++j) {
1412 float w = scores[
score_index(h, i, j, aligned_context_window)];
1413 size_t v_base =
qkv_index(h, j, 0, num_tokens, aligned_head_dim);
1415 for (
int d = 0; d < head_dim; ++d) {
1416 output[out_base + d] += w * v[v_base + d];
1444 int aligned_head_dim,
1445 int aligned_context_window)
1447 const float scale = 1.0f / sqrtf((
float)head_dim);
1449 for (
int h = 0; h < num_heads; ++h) {
1450 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
1451 for (
int i = 0; i < num_tokens; ++i) {
1452 for (
int j = 0; j <= i; ++j) {
1454 size_t base_q =
qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1455 size_t base_k =
qkv_index(kv_head, j, 0, num_tokens, aligned_head_dim);
1457 for (
int d = 0; d < head_dim; ++d) {
1458 dot += q[base_q + d] * k[base_k + d];
1461 scores[
score_index(h, i, j, aligned_context_window)] = dot * scale;
1464 for (
int j = i + 1; j < num_tokens; ++j) {
1465 scores[
score_index(h, i, j, aligned_context_window)] = 0.0f;
1473 aligned_context_window);
1475 for (
int h = 0; h < num_heads; ++h) {
1476 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
1477 for (
int i = 0; i < num_tokens; ++i) {
1478 size_t out_base =
qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1479 for (
int d = 0; d < aligned_head_dim; ++d) {
1480 output[out_base + d] = 0.0f;
1483 for (
int j = 0; j <= i; ++j) {
1484 float w = scores[
score_index(h, i, j, aligned_context_window)];
1485 size_t v_base =
qkv_index(kv_head, j, 0, num_tokens, aligned_head_dim);
1487 for (
int d = 0; d < head_dim; ++d) {
1488 output[out_base + d] += w * v[v_base + d];
1514 int aligned_head_dim,
1515 int aligned_context_window)
1517 const float scale = 1.0f / sqrtf((
float)head_dim);
1519 for (
int h = 0; h < num_heads; ++h) {
1520 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
1521 for (
int i = 0; i < num_tokens; ++i) {
1522 for (
int j = 0; j <= i; ++j) {
1524 size_t base_q =
qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1525 size_t base_k =
qkv_index(kv_head, j, 0, num_tokens, aligned_head_dim);
1527 for (
int d = 0; d < head_dim; ++d) {
1528 dot += q[base_q + d] * k[base_k + d];
1531 scores[
score_index(h, i, j, aligned_context_window)] = dot * scale;
1534 for (
int j = i + 1; j < num_tokens; ++j) {
1535 scores[
score_index(h, i, j, aligned_context_window)] = 0.0f;
1544 aligned_context_window);
1546 for (
int h = 0; h < num_heads; ++h) {
1547 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
1548 for (
int i = 0; i < num_tokens; ++i) {
1549 size_t out_base =
qkv_index(h, i, 0, num_tokens, aligned_head_dim);
1550 for (
int d = 0; d < aligned_head_dim; ++d) {
1551 output[out_base + d] = 0.0f;
1554 for (
int j = 0; j <= i; ++j) {
1555 float w = scores[
score_index(h, i, j, aligned_context_window)];
1556 size_t v_base =
qkv_index(kv_head, j, 0, num_tokens, aligned_head_dim);
1558 for (
int d = 0; d < head_dim; ++d) {
1559 output[out_base + d] += w * v[v_base + d];
1586 int aligned_head_dim,
1587 int aligned_context_window,
1592 const size_t q_elems = (size_t)num_heads * (
size_t)num_tokens * (size_t)aligned_head_dim;
1593 const size_t kv_elems = (size_t)num_kv_heads * (
size_t)num_tokens * (size_t)aligned_head_dim;
1595 if (!scratch_q || !scratch_k || !scratch_v)
return;
1605 num_heads, num_kv_heads,
1606 num_tokens, head_dim,
1607 aligned_head_dim, aligned_context_window);
1625#if defined(__AVX512F__)
1626static void attention_flash_query_causal_avx512(
const float *q_vec,
1627 const float *k_head,
1628 const float *v_head,
1631 int aligned_head_dim,
1636 float m = -INFINITY;
1641 for (; d + 16 <= aligned_head_dim; d += 16) {
1642 _mm512_storeu_ps(&out_vec[d], _mm512_setzero_ps());
1644 for (; d < aligned_head_dim; ++d) {
1648 for (
int j = 0; j < kv_tokens; ++j) {
1649 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
1650 const float *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
1653 __m512 dot_acc = _mm512_setzero_ps();
1655 for (; d + 16 <= head_dim; d += 16) {
1656 __m512 q_v = _mm512_loadu_ps(&q_vec[d]);
1657 __m512 k_v = _mm512_loadu_ps(&k_vec[d]);
1658 dot_acc = _mm512_fmadd_ps(q_v, k_v, dot_acc);
1660 float dot = _mm512_reduce_add_ps(dot_acc);
1662 for (; d < head_dim; ++d) {
1663 dot += q_vec[d] * k_vec[d];
1665 float score = dot * scale;
1668 float exp_m = (m == -INFINITY) ? 0.0f : expf(m -
score);
1672 __m512 exp_m_vec = _mm512_set1_ps(exp_m);
1674 for (; d + 16 <= head_dim; d += 16) {
1675 __m512 out_v = _mm512_loadu_ps(&out_vec[d]);
1676 __m512 v_v = _mm512_loadu_ps(&v_vec[d]);
1677 out_v = _mm512_fmadd_ps(out_v, exp_m_vec, v_v);
1678 _mm512_storeu_ps(&out_vec[d], out_v);
1680 for (; d < head_dim; ++d) {
1681 out_vec[d] = out_vec[d] * exp_m + v_vec[d];
1687 float e = expf(
score - m);
1691 __m512 e_vec = _mm512_set1_ps(e);
1693 for (; d + 16 <= head_dim; d += 16) {
1694 __m512 out_v = _mm512_loadu_ps(&out_vec[d]);
1695 __m512 v_v = _mm512_loadu_ps(&v_vec[d]);
1696 out_v = _mm512_fmadd_ps(e_vec, v_v, out_v);
1697 _mm512_storeu_ps(&out_vec[d], out_v);
1699 for (; d < head_dim; ++d) {
1700 out_vec[d] += e * v_vec[d];
1706 float inv_s = 1.0f / s;
1707 __m512 inv_s_vec = _mm512_set1_ps(inv_s);
1709 for (; d + 16 <= head_dim; d += 16) {
1710 __m512 out_v = _mm512_loadu_ps(&out_vec[d]);
1711 _mm512_storeu_ps(&out_vec[d], _mm512_mul_ps(out_v, inv_s_vec));
1713 for (; d < head_dim; ++d) {
1714 out_vec[d] *= inv_s;
1718 for (d = head_dim; d < aligned_head_dim; ++d) {
1727#if defined(__AVX2__)
1728static inline float hsum256_ps_flash(__m256 v) {
1729 __m128 hi = _mm256_extractf128_ps(v, 1);
1730 __m128 lo = _mm256_castps256_ps128(v);
1731 __m128 sum128 = _mm_add_ps(lo, hi);
1732 sum128 = _mm_hadd_ps(sum128, sum128);
1733 sum128 = _mm_hadd_ps(sum128, sum128);
1734 return _mm_cvtss_f32(sum128);
1737static void attention_flash_query_causal_avx2(
const float *q_vec,
1738 const float *k_head,
1739 const float *v_head,
1742 int aligned_head_dim,
1746 float m = -INFINITY;
1751 for (; d + 8 <= aligned_head_dim; d += 8) {
1752 _mm256_storeu_ps(&out_vec[d], _mm256_setzero_ps());
1754 for (; d < aligned_head_dim; ++d) {
1758 for (
int j = 0; j < kv_tokens; ++j) {
1759 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
1760 const float *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
1763 __m256 dot_acc = _mm256_setzero_ps();
1765 for (; d + 8 <= head_dim; d += 8) {
1766 __m256 q_v = _mm256_loadu_ps(&q_vec[d]);
1767 __m256 k_v = _mm256_loadu_ps(&k_vec[d]);
1768 dot_acc = _mm256_fmadd_ps(q_v, k_v, dot_acc);
1770 float dot = hsum256_ps_flash(dot_acc);
1771 for (; d < head_dim; ++d) {
1772 dot += q_vec[d] * k_vec[d];
1774 float score = dot * scale;
1777 float exp_m = (m == -INFINITY) ? 0.0f : expf(m -
score);
1780 __m256 exp_m_vec = _mm256_set1_ps(exp_m);
1782 for (; d + 8 <= head_dim; d += 8) {
1783 __m256 out_v = _mm256_loadu_ps(&out_vec[d]);
1784 __m256 v_v = _mm256_loadu_ps(&v_vec[d]);
1785 out_v = _mm256_fmadd_ps(out_v, exp_m_vec, v_v);
1786 _mm256_storeu_ps(&out_vec[d], out_v);
1788 for (; d < head_dim; ++d) {
1789 out_vec[d] = out_vec[d] * exp_m + v_vec[d];
1795 float e = expf(
score - m);
1798 __m256 e_vec = _mm256_set1_ps(e);
1800 for (; d + 8 <= head_dim; d += 8) {
1801 __m256 out_v = _mm256_loadu_ps(&out_vec[d]);
1802 __m256 v_v = _mm256_loadu_ps(&v_vec[d]);
1803 out_v = _mm256_fmadd_ps(e_vec, v_v, out_v);
1804 _mm256_storeu_ps(&out_vec[d], out_v);
1806 for (; d < head_dim; ++d) {
1807 out_vec[d] += e * v_vec[d];
1813 float inv_s = 1.0f / s;
1814 __m256 inv_s_vec = _mm256_set1_ps(inv_s);
1816 for (; d + 8 <= head_dim; d += 8) {
1817 __m256 out_v = _mm256_loadu_ps(&out_vec[d]);
1818 _mm256_storeu_ps(&out_vec[d], _mm256_mul_ps(out_v, inv_s_vec));
1820 for (; d < head_dim; ++d) {
1821 out_vec[d] *= inv_s;
1824 for (d = head_dim; d < aligned_head_dim; ++d) {
1833#if defined(__AVX__) && !defined(__AVX2__)
1834static inline float hsum256_ps_flash_avx(__m256 v) {
1835 __m128 hi = _mm256_extractf128_ps(v, 1);
1836 __m128 lo = _mm256_castps256_ps128(v);
1837 __m128 sum128 = _mm_add_ps(lo, hi);
1838 sum128 = _mm_hadd_ps(sum128, sum128);
1839 sum128 = _mm_hadd_ps(sum128, sum128);
1840 return _mm_cvtss_f32(sum128);
1843static void attention_flash_query_causal_avx(
const float *q_vec,
1844 const float *k_head,
1845 const float *v_head,
1848 int aligned_head_dim,
1852 float m = -INFINITY;
1857 for (; d + 8 <= aligned_head_dim; d += 8) {
1858 _mm256_storeu_ps(&out_vec[d], _mm256_setzero_ps());
1860 for (; d < aligned_head_dim; ++d) {
1864 for (
int j = 0; j < kv_tokens; ++j) {
1865 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
1866 const float *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
1869 __m256 dot_acc = _mm256_setzero_ps();
1871 for (; d + 8 <= head_dim; d += 8) {
1872 __m256 q_v = _mm256_loadu_ps(&q_vec[d]);
1873 __m256 k_v = _mm256_loadu_ps(&k_vec[d]);
1874 dot_acc = _mm256_add_ps(dot_acc, _mm256_mul_ps(q_v, k_v));
1876 float dot = hsum256_ps_flash_avx(dot_acc);
1877 for (; d < head_dim; ++d) {
1878 dot += q_vec[d] * k_vec[d];
1880 float score = dot * scale;
1883 float exp_m = (m == -INFINITY) ? 0.0f : expf(m -
score);
1886 __m256 exp_m_vec = _mm256_set1_ps(exp_m);
1888 for (; d + 8 <= head_dim; d += 8) {
1889 __m256 out_v = _mm256_loadu_ps(&out_vec[d]);
1890 __m256 v_v = _mm256_loadu_ps(&v_vec[d]);
1892 out_v = _mm256_add_ps(_mm256_mul_ps(out_v, exp_m_vec), v_v);
1893 _mm256_storeu_ps(&out_vec[d], out_v);
1895 for (; d < head_dim; ++d) {
1896 out_vec[d] = out_vec[d] * exp_m + v_vec[d];
1902 float e = expf(
score - m);
1905 __m256 e_vec = _mm256_set1_ps(e);
1907 for (; d + 8 <= head_dim; d += 8) {
1908 __m256 out_v = _mm256_loadu_ps(&out_vec[d]);
1909 __m256 v_v = _mm256_loadu_ps(&v_vec[d]);
1911 out_v = _mm256_add_ps(out_v, _mm256_mul_ps(e_vec, v_v));
1912 _mm256_storeu_ps(&out_vec[d], out_v);
1914 for (; d < head_dim; ++d) {
1915 out_vec[d] += e * v_vec[d];
1921 float inv_s = 1.0f / s;
1922 __m256 inv_s_vec = _mm256_set1_ps(inv_s);
1924 for (; d + 8 <= head_dim; d += 8) {
1925 __m256 out_v = _mm256_loadu_ps(&out_vec[d]);
1926 _mm256_storeu_ps(&out_vec[d], _mm256_mul_ps(out_v, inv_s_vec));
1928 for (; d < head_dim; ++d) {
1929 out_vec[d] *= inv_s;
1932 for (d = head_dim; d < aligned_head_dim; ++d) {
1942 const float *k_head,
1943 const float *v_head,
1946 int aligned_head_dim,
1953 float m = -INFINITY;
1956 for (
int d = 0; d < head_dim; ++d) {
1960 for (
int j = 0; j < kv_tokens; ++j) {
1961 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
1962 const float *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
1965 for (
int d = 0; d < head_dim; ++d) {
1966 dot += q_vec[d] * k_vec[d];
1968 float score = dot * scale;
1971 float exp_m = (m == -INFINITY) ? 0.0f : expf(m -
score);
1973 for (
int d = 0; d < head_dim; ++d) {
1974 out_vec[d] *= exp_m;
1977 for (
int d = 0; d < head_dim; ++d) {
1978 out_vec[d] += v_vec[d];
1982 float e = expf(
score - m);
1984 for (
int d = 0; d < head_dim; ++d) {
1985 out_vec[d] += e * v_vec[d];
1990 float inv_s = 1.0f / s;
1991 for (
int d = 0; d < head_dim; ++d) {
1992 out_vec[d] *= inv_s;
1994 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2004 const float *k_head,
2005 const float *v_head,
2008 int aligned_head_dim,
2012 if (kv_tokens <= 0) {
2013 for (
int d = 0; d < aligned_head_dim; ++d) {
2019 for (
int d = 0; d < aligned_head_dim; ++d) {
2023 float max_score = -INFINITY;
2024 for (
int j = 0; j < kv_tokens; ++j) {
2025 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
2027 for (
int d = 0; d < head_dim; ++d) {
2028 dot += q_vec[d] * k_vec[d];
2030 float score = dot * scale;
2031 if (
score > max_score) {
2037 for (
int j = 0; j < kv_tokens; ++j) {
2038 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
2039 const float *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
2041 for (
int d = 0; d < head_dim; ++d) {
2042 dot += q_vec[d] * k_vec[d];
2044 float score = dot * scale;
2045 float w = expf(
score - max_score);
2047 for (
int d = 0; d < head_dim; ++d) {
2048 out_vec[d] += w * v_vec[d];
2053 float inv_sum = 1.0f / sum;
2054 for (
int d = 0; d < head_dim; ++d) {
2055 out_vec[d] *= inv_sum;
2058 for (
int d = 0; d < head_dim; ++d) {
2062 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2068 const float *k_head,
2069 const float *out_vec,
2072 int aligned_head_dim,
2082 float *raw_scores = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
2083 float *probs = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
2084 float max_score = -INFINITY;
2085 for (
int j = 0; j < kv_tokens; ++j) {
2086 const float *k_vec = k_head + (size_t) j * (
size_t) aligned_head_dim;
2088 for (
int d = 0; d < head_dim; ++d) {
2089 dot += q_vec[d] * k_vec[d];
2091 raw_scores[j] = dot;
2092 const float scaled = dot * scale;
2094 if (scaled > max_score) {
2100 for (
int j = 0; j < kv_tokens; ++j) {
2101 probs[j] = expf(probs[j] - max_score);
2105 const float inv_sum = 1.0f / sum;
2106 for (
int j = 0; j < kv_tokens; ++j) {
2107 probs[j] *= inv_sum;
2110 memset(probs, 0, (
size_t) kv_tokens *
sizeof(
float));
2114 kv_tokens, head_dim,
2115 layer_id, head_id, query_id);
2120 const float *k_head,
2121 const float *v_head,
2124 int aligned_head_dim,
2128 if (kv_tokens <= 0) {
2129 for (
int d = 0; d < aligned_head_dim; ++d) {
2135 for (
int d = 0; d < aligned_head_dim; ++d) {
2144 float max_score = -INFINITY;
2145 for (
int j = 0; j < kv_tokens; ++j) {
2146 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
2147 const float *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
2149 for (
int d = 0; d < head_dim; ++d) {
2152 float score = dot * scale;
2154 const float prev_max = max_score;
2155 float max_scale = 1.0f;
2156 float value_scale = 1.0f;
2158 if (
score > max_score) {
2160 max_scale = isfinite(prev_max) ? expf(prev_max - max_score) : 0.0f;
2161 for (
int d = 0; d < head_dim; ++d) {
2165 value_scale = expf(
score - max_score);
2168 for (
int d = 0; d < head_dim; ++d) {
2170 const float updated = out_vec[d] + value_scale * v_rounded;
2174 sum = sum * max_scale + value_scale;
2178 float inv_sum = 1.0f / sum;
2179 for (
int d = 0; d < head_dim; ++d) {
2180 out_vec[d] *= inv_sum;
2183 for (
int d = 0; d < head_dim; ++d) {
2187 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2195 const float *q_vec,
const float *k_head,
const float *v_head,
2196 int kv_tokens,
int head_dim,
int aligned_head_dim,
float scale,
2199 if (kv_tokens <= 0) {
2200 memset(out_vec, 0, (
size_t)aligned_head_dim *
sizeof(
float));
2204 float *q_rounded = (
float *)alloca((
size_t)head_dim *
sizeof(float));
2206 memset(out_vec, 0, (
size_t)aligned_head_dim *
sizeof(
float));
2209 float max_score = -INFINITY;
2210 for (
int j = 0; j < kv_tokens; ++j) {
2211 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
2212 const float *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
2214 for (
int d = 0; d < head_dim; ++d) {
2215 dot += q_rounded[d] * k_vec[d];
2217 const float score = dot * scale;
2218 const float prev_max = max_score;
2219 float max_scale = 1.0f;
2220 float value_scale = 1.0f;
2221 if (
score > max_score) {
2223 max_scale = isfinite(prev_max) ? expf(prev_max - max_score) : 0.0f;
2224 for (
int d = 0; d < head_dim; ++d) {
2228 value_scale = expf(
score - max_score);
2230 for (
int d = 0; d < head_dim; ++d) {
2231 const float updated = out_vec[d] + value_scale * v_vec[d];
2234 sum = sum * max_scale + value_scale;
2238 const float inv_sum = 1.0f / sum;
2239 for (
int d = 0; d < head_dim; ++d) {
2240 out_vec[d] *= inv_sum;
2243 memset(out_vec, 0, (
size_t)head_dim *
sizeof(
float));
2248 const float *k_head,
2249 const float *v_cols,
2252 int aligned_head_dim,
2260 if (kv_tokens <= 0) {
2261 for (
int d = 0; d < aligned_head_dim; ++d) {
2267 for (
int j = 0; j < kv_tokens; ++j) {
2268 const float *k_vec = k_head + (size_t) j * (
size_t) aligned_head_dim;
2271 float *raw_dump = NULL;
2273 raw_dump = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
2274 memcpy(raw_dump, score_row, (
size_t) kv_tokens *
sizeof(
float));
2277 float max_score = -INFINITY;
2278 for (
int j = 0; j < kv_tokens; ++j) {
2279 const float score = score_row[j] * scale;
2280 score_row[j] =
score;
2281 if (
score > max_score) {
2287 for (
int j = 0; j < kv_tokens; ++j) {
2288 const float w = expf(score_row[j] - max_score);
2290 volatile double next = sum + (double) w;
2295 const float inv_sum = (float) (1.0 / sum);
2296 for (
int j = 0; j < kv_tokens; ++j) {
2297 score_row[j] *= inv_sum;
2299 for (
int d = 0; d < head_dim; ++d) {
2300 const float *v_col = v_cols + (size_t) d * (
size_t) kv_tokens;
2305 for (
int d = 0; d < head_dim; ++d) {
2310 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2315 layer_id, head_id, query_id);
2320 const float *k_head,
2321 const float *v_cols,
2324 int aligned_head_dim,
2332 if (kv_tokens <= 0) {
2333 for (
int d = 0; d < aligned_head_dim; ++d) {
2339 for (
int j = 0; j < kv_tokens; ++j) {
2340 const float *k_vec = k_head + (size_t) j * (
size_t) aligned_head_dim;
2343 float *raw_dump = NULL;
2345 raw_dump = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
2346 memcpy(raw_dump, score_row, (
size_t) kv_tokens *
sizeof(
float));
2349 float *logit_row = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
2350 memcpy(logit_row, score_row, (
size_t) kv_tokens *
sizeof(
float));
2355 const float inv_sum = (float) (1.0 / sum);
2357 for (
int d = 0; d < head_dim; ++d) {
2358 const float *v_col = v_cols + (size_t) d * (
size_t) kv_tokens;
2362 for (
int d = 0; d < head_dim; ++d) {
2367 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2372 layer_id, head_id, query_id);
2376#if CK_ENABLE_LLAMA_CPP_PARITY
2378 const float *k_head,
2379 const float *v_cols,
2382 int aligned_head_dim,
2387 ck_ggml_vec_dot_f32_fn dot_fn,
2388 ck_ggml_vec_soft_max_f32_fn softmax_fn,
2393 if (kv_tokens <= 0 || !dot_fn || !softmax_fn || !score_row || !prob_row) {
2394 for (
int d = 0; d < aligned_head_dim; ++d) {
2400 for (
int j = 0; j < kv_tokens; ++j) {
2401 const float *k_vec = k_head + (size_t) j * (
size_t) aligned_head_dim;
2403 dot_fn(head_dim, &dot, 0, q_vec, 0, k_vec, 0, 1);
2406 float *raw_dump = NULL;
2408 raw_dump = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
2409 memcpy(raw_dump, score_row, (
size_t) kv_tokens *
sizeof(
float));
2415 memcpy(prob_row, score_row, (
size_t) kv_tokens *
sizeof(
float));
2418 const double sum = softmax_fn(kv_tokens, score_row, prob_row, max_score);
2420 const float inv_sum = (float) (1.0 / sum);
2423 for (
int d = 0; d < head_dim; ++d) {
2424 const float *v_col = v_cols + (size_t) d * (
size_t) kv_tokens;
2425 if (reverse_out_dot) {
2429 dot_fn(kv_tokens, &dot, 0, score_row, 0, v_col, 0, 1);
2434 for (
int d = 0; d < head_dim; ++d) {
2439 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2444 layer_id, head_id, query_id);
2448static int attention_out_mul_mat_graph_block(
const float *v_cols,
2449 const float *prob_block,
2465 if (!ggml_cpu_init_fn || !ggml_init_fn || !ggml_free_fn ||
2466 !ggml_new_tensor_2d_fn || !ggml_mul_mat_fn || !ggml_new_graph_fn ||
2467 !ggml_build_forward_expand_fn || !ggml_graph_compute_with_ctx_fn ||
2468 !ggml_set_input_fn || !v_cols || !prob_block || !out_block ||
2469 kv_tokens <= 0 || head_dim <= 0 || query_block <= 0) {
2475 const size_t out_bytes = (size_t) head_dim * (
size_t) query_block *
sizeof(float);
2476 const size_t mem_size = (size_t) 8 * 1024 * 1024 + out_bytes + (
size_t) 512 * 1024;
2482 struct ggml_context *ctx = ggml_init_fn(params);
2488 struct ggml_tensor *v_tensor = ggml_new_tensor_2d_fn(ctx,
GGML_TYPE_F32, kv_tokens, head_dim);
2489 struct ggml_tensor *prob_tensor = ggml_new_tensor_2d_fn(ctx,
GGML_TYPE_F32, kv_tokens, query_block);
2490 if (!v_tensor || !prob_tensor) {
2495 v_tensor->data = (
void *) v_cols;
2496 prob_tensor->data = (
void *) prob_block;
2497 ggml_set_input_fn(v_tensor);
2498 ggml_set_input_fn(prob_tensor);
2500 struct ggml_tensor *out_tensor = ggml_mul_mat_fn(ctx, v_tensor, prob_tensor);
2501 struct ggml_cgraph *gf = out_tensor ? ggml_new_graph_fn(ctx) : NULL;
2502 if (!out_tensor || !gf) {
2507 ggml_build_forward_expand_fn(gf, out_tensor);
2509 memcpy(out_block, out_tensor->data, out_bytes);
2517static CK_NOINLINE CK_OPTNONE int attention_head_full_dyn_ggml_regular_graph_out(
const float *q_head,
2518 const float *k_head,
2519 const float *v_cols,
2522 int aligned_head_dim,
2527 ck_ggml_vec_dot_f32_fn dot_fn,
2528 ck_ggml_vec_soft_max_f32_fn softmax_fn,
2532 if (!q_head || !k_head || !v_cols || !out_head || !dot_fn || !softmax_fn ||
2533 kv_tokens <= 0 || head_dim <= 0 || aligned_head_dim < head_dim) {
2537 enum { CK_STRICT_OUT_BLOCK = 64 };
2538 float *prob_block = (
float *) alloca((
size_t) CK_STRICT_OUT_BLOCK * (size_t) kv_tokens *
sizeof(
float));
2539 float *out_block = (
float *) alloca((
size_t) CK_STRICT_OUT_BLOCK * (size_t) head_dim *
sizeof(
float));
2540 float *raw_dump = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
2541 for (
int q0 = 0; q0 < kv_tokens; q0 += CK_STRICT_OUT_BLOCK) {
2542 const int qn = (q0 + CK_STRICT_OUT_BLOCK <= kv_tokens) ? CK_STRICT_OUT_BLOCK : (kv_tokens - q0);
2543 float *block_probs = prob_block;
2544 float *block_out = out_block;
2545 int have_raw_dump = 0;
2546 int dump_query = -1;
2549 for (
int qi = 0; qi < qn; ++qi) {
2550 const int query_id = q0 + qi;
2551 const float *q_vec = q_head + (size_t) query_id * (
size_t) aligned_head_dim;
2552 float *prob_col = block_probs + (size_t) qi * (
size_t) kv_tokens;
2554 for (
int j = 0; j < kv_tokens; ++j) {
2555 const float *k_vec = k_head + (size_t) j * (
size_t) aligned_head_dim;
2557 dot_fn(head_dim, &dot, 0, q_vec, 0, k_vec, 0, 1);
2562 memcpy(raw_dump, score_row, (
size_t) kv_tokens *
sizeof(
float));
2564 dump_query = query_id;
2568 memcpy(prob_row, score_row, (
size_t) kv_tokens *
sizeof(
float));
2571 const double sum = softmax_fn(kv_tokens, prob_col, prob_row, max_score);
2573 const float inv_sum = (float) (1.0 / sum);
2576 memset(prob_col, 0, (
size_t) kv_tokens *
sizeof(
float));
2580 if (!attention_out_mul_mat_graph_block(v_cols, block_probs, kv_tokens, head_dim, qn, block_out)) {
2584 for (
int qi = 0; qi < qn; ++qi) {
2585 float *dst = out_head + (size_t) (q0 + qi) * (size_t) aligned_head_dim;
2586 const float *src = block_out + (size_t) qi * (
size_t) head_dim;
2587 memcpy(dst, src, (
size_t) head_dim *
sizeof(
float));
2588 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2593 if (have_raw_dump && dump_qi >= 0) {
2595 block_probs + (
size_t) dump_qi * (
size_t) kv_tokens,
2596 block_out + (
size_t) dump_qi * (
size_t) head_dim,
2609static CK_NOINLINE CK_OPTNONE void attention_query_full_dyn_ggml_regular_matmul_out(
const float *q_vec,
2610 const float *k_head,
2611 const float *v_cols,
2614 int aligned_head_dim,
2619 ck_ggml_vec_dot_f32_fn dot_fn,
2620 ck_ggml_vec_soft_max_f32_fn softmax_fn,
2621 ck_ggml_compute_forward_mul_mat_fn mul_mat_fn,
2626 if (kv_tokens <= 0 || !dot_fn || !softmax_fn || !mul_mat_fn || !score_row || !prob_row) {
2627 for (
int d = 0; d < aligned_head_dim; ++d) {
2633 for (
int j = 0; j < kv_tokens; ++j) {
2634 const float *k_vec = k_head + (size_t) j * (
size_t) aligned_head_dim;
2636 dot_fn(head_dim, &dot, 0, q_vec, 0, k_vec, 0, 1);
2639 float *raw_dump = NULL;
2641 raw_dump = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
2642 memcpy(raw_dump, score_row, (
size_t) kv_tokens *
sizeof(
float));
2645 memcpy(prob_row, score_row, (
size_t) kv_tokens *
sizeof(
float));
2648 const double sum = softmax_fn(kv_tokens, score_row, prob_row, max_score);
2650 const float inv_sum = (float) (1.0 / sum);
2653 const size_t prob_row_bytes = (size_t) kv_tokens *
sizeof(
float);
2654 const size_t out_row_bytes = (size_t) head_dim *
sizeof(
float);
2656 struct ggml_tensor v_tensor;
2657 struct ggml_tensor prob_tensor;
2658 struct ggml_tensor out_tensor;
2660 ck_ggml_init_tensor_f32(&v_tensor,
2661 kv_tokens, head_dim, 1, 1,
2664 prob_row_bytes * (
size_t) head_dim,
2665 prob_row_bytes * (
size_t) head_dim,
2667 ck_ggml_init_tensor_f32(&prob_tensor,
2674 ck_ggml_init_tensor_f32(&out_tensor,
2681 out_tensor.src[0] = &v_tensor;
2682 out_tensor.src[1] = &prob_tensor;
2684 memset(out_vec, 0, (
size_t) head_dim *
sizeof(
float));
2685 struct ggml_compute_params mul_params = {
2693 mul_mat_fn(&mul_params, &out_tensor);
2695 for (
int d = 0; d < head_dim; ++d) {
2700 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2705 layer_id, head_id, query_id);
2710 const float *k_head,
2711 const float *v_cols,
2714 int aligned_head_dim,
2719 ck_ggml_vec_dot_f32_fn dot_fn,
2720 ck_ggml_compute_forward_mul_mat_fn mul_mat_fn,
2721 ck_ggml_compute_forward_soft_max_fn softmax_compute_fn)
2723 if (kv_tokens <= 0 || !dot_fn || !mul_mat_fn || !softmax_compute_fn) {
2724 for (
int d = 0; d < aligned_head_dim; ++d) {
2730 const size_t k_row_bytes = (size_t) aligned_head_dim *
sizeof(
float);
2731 const size_t q_row_bytes = (size_t) head_dim *
sizeof(
float);
2732 const size_t score_row_bytes = (size_t) kv_tokens *
sizeof(
float);
2733 const size_t softmax_work_elems = (size_t) kv_tokens + 16u;
2734 float *softmax_work = (
float *) alloca(softmax_work_elems *
sizeof(
float));
2736 struct ggml_tensor k_tensor;
2737 struct ggml_tensor q_tensor;
2738 struct ggml_tensor score_tensor;
2739 struct ggml_tensor soft_tensor;
2741 ck_ggml_init_tensor_f32(&k_tensor,
2742 head_dim, kv_tokens, 1, 1,
2745 k_row_bytes * (
size_t) kv_tokens,
2746 k_row_bytes * (
size_t) kv_tokens,
2748 ck_ggml_init_tensor_f32(&q_tensor,
2755 ck_ggml_init_tensor_f32(&score_tensor,
2762 score_tensor.src[0] = &k_tensor;
2763 score_tensor.src[1] = &q_tensor;
2765 struct ggml_compute_params mul_params = {
2773 mul_mat_fn(&mul_params, &score_tensor);
2775 ck_ggml_init_tensor_f32(&soft_tensor,
2782 soft_tensor.src[0] = &score_tensor;
2784 const float max_bias = 0.0f;
2785 memcpy((
char *) soft_tensor.op_params + 0, &scale,
sizeof(
float));
2786 memcpy((
char *) soft_tensor.op_params +
sizeof(
float), &max_bias,
sizeof(
float));
2789 struct ggml_compute_params soft_params = {
2792 .wsize = softmax_work_elems *
sizeof(float),
2793 .wdata = softmax_work,
2797 softmax_compute_fn(&soft_params, &soft_tensor);
2799 for (
int d = 0; d < head_dim; ++d) {
2800 const float *v_col = v_cols + (size_t) d * (
size_t) kv_tokens;
2802 dot_fn(kv_tokens, &dot, 0, prob_row, 0, v_col, 0, 1);
2806 for (
int d = head_dim; d < aligned_head_dim; ++d) {
2814#define CK_GGML_FA_TILE_Q 64
2815#define CK_GGML_FA_TILE_Q_LARGE 336
2816#define CK_GGML_FA_TILE_KV 64
2817#define CK_GGML_FA_TILE_Q_LARGE_MIN_TOKENS 1536
2821 for (
int i = 0; i < n; ++i) {
2828 float max_val = -INFINITY;
2829 for (
int i = 0; i < n; ++i) {
2830 if (x[i] > max_val) {
2837#if defined(__AVX512F__)
2838static inline void ck_attention_simd_gemm_ukernel_4x4(
float *c,
2845 for (
int i = 0; i < 4; ++i) {
2846 for (
int r = 0; r < 4; ++r) {
2847 acc[i][r] = _mm512_loadu_ps(
2848 c + (
size_t) i * (
size_t) n + (
size_t) r * 16u);
2852 for (
int kk = 0; kk < k; ++kk) {
2854 for (
int r = 0; r < 4; ++r) {
2855 bv[r] = _mm512_loadu_ps(
2856 b + (
size_t) kk * (
size_t) n + (
size_t) r * 16u);
2858 for (
int i = 0; i < 4; ++i) {
2859 const __m512 p = _mm512_set1_ps(
2860 a[(
size_t) i * (
size_t) k + (
size_t) kk]);
2861 for (
int r = 0; r < 4; ++r) {
2862 acc[i][r] = _mm512_fmadd_ps(bv[r], p, acc[i][r]);
2867 for (
int i = 0; i < 4; ++i) {
2868 for (
int r = 0; r < 4; ++r) {
2870 c + (
size_t) i * (
size_t) n + (
size_t) r * 16u,
2876static inline void ck_attention_simd_gemm_ukernel_4x1(
float *c,
2883 for (
int i = 0; i < 4; ++i) {
2884 acc[i] = _mm512_loadu_ps(c + (
size_t) i * (
size_t) n);
2886 for (
int kk = 0; kk < k; ++kk) {
2887 const __m512 bv = _mm512_loadu_ps(b + (
size_t) kk * (
size_t) n);
2888 for (
int i = 0; i < 4; ++i) {
2889 const __m512 p = _mm512_set1_ps(
2890 a[(
size_t) i * (
size_t) k + (
size_t) kk]);
2891 acc[i] = _mm512_fmadd_ps(bv, p, acc[i]);
2894 for (
int i = 0; i < 4; ++i) {
2895 _mm512_storeu_ps(c + (
size_t) i * (
size_t) n, acc[i]);
2899static inline void ck_attention_simd_gemm_ukernel_1x4(
float *c,
2906 for (
int r = 0; r < 4; ++r) {
2907 acc[r] = _mm512_loadu_ps(c + (
size_t) r * 16u);
2909 for (
int kk = 0; kk < k; ++kk) {
2910 const __m512 p = _mm512_set1_ps(a[kk]);
2911 for (
int r = 0; r < 4; ++r) {
2912 const __m512 bv = _mm512_loadu_ps(
2913 b + (
size_t) kk * (
size_t) n + (
size_t) r * 16u);
2914 acc[r] = _mm512_fmadd_ps(bv, p, acc[r]);
2917 for (
int r = 0; r < 4; ++r) {
2918 _mm512_storeu_ps(c + (
size_t) r * 16u, acc[r]);
2922static inline void ck_attention_simd_gemm_ukernel_1x1(
float *c,
2928 __m512 acc = _mm512_loadu_ps(c);
2929 for (
int kk = 0; kk < k; ++kk) {
2930 const __m512 bv = _mm512_loadu_ps(b + (
size_t) kk * (
size_t) n);
2931 const __m512 p = _mm512_set1_ps(a[kk]);
2932 acc = _mm512_fmadd_ps(bv, p, acc);
2934 _mm512_storeu_ps(c, acc);
2945 for (; ii + 4 <= m; ii += 4) {
2947 for (; jj + 64 <= n; jj += 64) {
2948 ck_attention_simd_gemm_ukernel_4x4(c + jj, a, b + jj, k, n);
2950 for (; jj + 16 <= n; jj += 16) {
2951 ck_attention_simd_gemm_ukernel_4x1(c + jj, a, b + jj, k, n);
2953 for (; jj < n; ++jj) {
2954 for (
int i = 0; i < 4; ++i) {
2955 float sum = c[(size_t) i * (
size_t) n + (size_t) jj];
2956 for (
int kk = 0; kk < k; ++kk) {
2957 sum += a[(size_t) i * (
size_t) k + (size_t) kk] *
2958 b[(
size_t) kk * (size_t) n + (
size_t) jj];
2960 c[(size_t) i * (
size_t) n + (size_t) jj] = sum;
2963 a += (size_t) 4 * (
size_t) k;
2964 c += (size_t) 4 * (
size_t) n;
2967 for (; ii < m; ++ii) {
2969 for (; jj + 64 <= n; jj += 64) {
2970 ck_attention_simd_gemm_ukernel_1x4(c + jj, a, b + jj, k, n);
2972 for (; jj + 16 <= n; jj += 16) {
2973 ck_attention_simd_gemm_ukernel_1x1(c + jj, a, b + jj, k, n);
2975 for (; jj < n; ++jj) {
2977 for (
int kk = 0; kk < k; ++kk) {
2978 sum += a[kk] * b[(size_t) kk * (
size_t) n + (size_t) jj];
2986#elif defined(__AVX__) || defined(__AVX2__)
2987static inline void ck_attention_simd_gemm_ukernel_6x2(
float *c,
2994 for (
int i = 0; i < 6; ++i) {
2995 acc[i][0] = _mm256_loadu_ps(c + (
size_t) i * (
size_t) n + 0);
2996 acc[i][1] = _mm256_loadu_ps(c + (
size_t) i * (
size_t) n + 8);
2999 for (
int kk = 0; kk < k; ++kk) {
3000 const __m256 bv0 = _mm256_loadu_ps(b + (
size_t) kk * (
size_t) n + 0);
3001 const __m256 bv1 = _mm256_loadu_ps(b + (
size_t) kk * (
size_t) n + 8);
3002 for (
int i = 0; i < 6; ++i) {
3003 const __m256 p = _mm256_set1_ps(a[(
size_t) i * (
size_t) k + (
size_t) kk]);
3005 acc[i][0] = _mm256_fmadd_ps(bv0, p, acc[i][0]);
3006 acc[i][1] = _mm256_fmadd_ps(bv1, p, acc[i][1]);
3008 acc[i][0] = _mm256_add_ps(_mm256_mul_ps(bv0, p), acc[i][0]);
3009 acc[i][1] = _mm256_add_ps(_mm256_mul_ps(bv1, p), acc[i][1]);
3014 for (
int i = 0; i < 6; ++i) {
3015 _mm256_storeu_ps(c + (
size_t) i * (
size_t) n + 0, acc[i][0]);
3016 _mm256_storeu_ps(c + (
size_t) i * (
size_t) n + 8, acc[i][1]);
3020static inline void ck_attention_simd_gemm_ukernel_6x1(
float *c,
3027 for (
int i = 0; i < 6; ++i) {
3028 acc[i] = _mm256_loadu_ps(c + (
size_t) i * (
size_t) n);
3031 for (
int kk = 0; kk < k; ++kk) {
3032 const __m256 bv = _mm256_loadu_ps(b + (
size_t) kk * (
size_t) n);
3033 for (
int i = 0; i < 6; ++i) {
3034 const __m256 p = _mm256_set1_ps(a[(
size_t) i * (
size_t) k + (
size_t) kk]);
3036 acc[i] = _mm256_fmadd_ps(bv, p, acc[i]);
3038 acc[i] = _mm256_add_ps(_mm256_mul_ps(bv, p), acc[i]);
3043 for (
int i = 0; i < 6; ++i) {
3044 _mm256_storeu_ps(c + (
size_t) i * (
size_t) n, acc[i]);
3048static inline void ck_attention_simd_gemm_ukernel_1x2(
float *c,
3054 __m256 acc0 = _mm256_loadu_ps(c + 0);
3055 __m256 acc1 = _mm256_loadu_ps(c + 8);
3056 for (
int kk = 0; kk < k; ++kk) {
3057 const __m256 bv0 = _mm256_loadu_ps(b + (
size_t) kk * (
size_t) n + 0);
3058 const __m256 bv1 = _mm256_loadu_ps(b + (
size_t) kk * (
size_t) n + 8);
3059 const __m256 p = _mm256_set1_ps(a[kk]);
3061 acc0 = _mm256_fmadd_ps(bv0, p, acc0);
3062 acc1 = _mm256_fmadd_ps(bv1, p, acc1);
3064 acc0 = _mm256_add_ps(_mm256_mul_ps(bv0, p), acc0);
3065 acc1 = _mm256_add_ps(_mm256_mul_ps(bv1, p), acc1);
3068 _mm256_storeu_ps(c + 0, acc0);
3069 _mm256_storeu_ps(c + 8, acc1);
3072static inline void ck_attention_simd_gemm_ukernel_1x1(
float *c,
3078 __m256 acc = _mm256_loadu_ps(c);
3079 for (
int kk = 0; kk < k; ++kk) {
3080 const __m256 bv = _mm256_loadu_ps(b + (
size_t) kk * (
size_t) n);
3081 const __m256 p = _mm256_set1_ps(a[kk]);
3083 acc = _mm256_fmadd_ps(bv, p, acc);
3085 acc = _mm256_add_ps(_mm256_mul_ps(bv, p), acc);
3088 _mm256_storeu_ps(c, acc);
3099 for (; ii + 6 <= m; ii += 6) {
3101 for (; jj + 16 <= n; jj += 16) {
3102 ck_attention_simd_gemm_ukernel_6x2(c + jj, a, b + jj, k, n);
3104 for (; jj + 8 <= n; jj += 8) {
3105 ck_attention_simd_gemm_ukernel_6x1(c + jj, a, b + jj, k, n);
3107 for (; jj < n; ++jj) {
3108 for (
int i = 0; i < 6; ++i) {
3109 float sum = c[(size_t) i * (
size_t) n + (size_t) jj];
3110 for (
int kk = 0; kk < k; ++kk) {
3111 sum += a[(size_t) i * (
size_t) k + (size_t) kk] * b[(
size_t) kk * (size_t) n + (
size_t) jj];
3113 c[(size_t) i * (
size_t) n + (size_t) jj] = sum;
3116 a += (size_t) 6 * (
size_t) k;
3117 c += (size_t) 6 * (
size_t) n;
3120 for (; ii < m; ++ii) {
3122 for (; jj + 16 <= n; jj += 16) {
3123 ck_attention_simd_gemm_ukernel_1x2(c + jj, a, b + jj, k, n);
3125 for (; jj + 8 <= n; jj += 8) {
3126 ck_attention_simd_gemm_ukernel_1x1(c + jj, a, b + jj, k, n);
3128 for (; jj < n; ++jj) {
3130 for (
int kk = 0; kk < k; ++kk) {
3131 sum += a[kk] * b[(size_t) kk * (
size_t) n + (size_t) jj];
3139#elif defined(__SSE2__)
3140static inline void ck_attention_simd_gemm_ukernel_2x2(
float *c,
3147 for (
int i = 0; i < 2; ++i) {
3148 acc[i][0] = _mm_loadu_ps(c + (
size_t) i * (
size_t) n + 0);
3149 acc[i][1] = _mm_loadu_ps(c + (
size_t) i * (
size_t) n + 4);
3152 for (
int kk = 0; kk < k; ++kk) {
3153 const __m128 bv0 = _mm_loadu_ps(b + (
size_t) kk * (
size_t) n + 0);
3154 const __m128 bv1 = _mm_loadu_ps(b + (
size_t) kk * (
size_t) n + 4);
3155 for (
int i = 0; i < 2; ++i) {
3156 const __m128 p = _mm_set1_ps(a[(
size_t) i * (
size_t) k + (
size_t) kk]);
3158 acc[i][0] = _mm_fmadd_ps(bv0, p, acc[i][0]);
3159 acc[i][1] = _mm_fmadd_ps(bv1, p, acc[i][1]);
3161 acc[i][0] = _mm_add_ps(_mm_mul_ps(bv0, p), acc[i][0]);
3162 acc[i][1] = _mm_add_ps(_mm_mul_ps(bv1, p), acc[i][1]);
3167 for (
int i = 0; i < 2; ++i) {
3168 _mm_storeu_ps(c + (
size_t) i * (
size_t) n + 0, acc[i][0]);
3169 _mm_storeu_ps(c + (
size_t) i * (
size_t) n + 4, acc[i][1]);
3173static inline void ck_attention_simd_gemm_ukernel_2x1(
float *c,
3180 for (
int i = 0; i < 2; ++i) {
3181 acc[i] = _mm_loadu_ps(c + (
size_t) i * (
size_t) n);
3184 for (
int kk = 0; kk < k; ++kk) {
3185 const __m128 bv = _mm_loadu_ps(b + (
size_t) kk * (
size_t) n);
3186 for (
int i = 0; i < 2; ++i) {
3187 const __m128 p = _mm_set1_ps(a[(
size_t) i * (
size_t) k + (
size_t) kk]);
3189 acc[i] = _mm_fmadd_ps(bv, p, acc[i]);
3191 acc[i] = _mm_add_ps(_mm_mul_ps(bv, p), acc[i]);
3196 for (
int i = 0; i < 2; ++i) {
3197 _mm_storeu_ps(c + (
size_t) i * (
size_t) n, acc[i]);
3201static inline void ck_attention_simd_gemm_ukernel_1x2(
float *c,
3207 __m128 acc0 = _mm_loadu_ps(c + 0);
3208 __m128 acc1 = _mm_loadu_ps(c + 4);
3209 for (
int kk = 0; kk < k; ++kk) {
3210 const __m128 bv0 = _mm_loadu_ps(b + (
size_t) kk * (
size_t) n + 0);
3211 const __m128 bv1 = _mm_loadu_ps(b + (
size_t) kk * (
size_t) n + 4);
3212 const __m128 p = _mm_set1_ps(a[kk]);
3214 acc0 = _mm_fmadd_ps(bv0, p, acc0);
3215 acc1 = _mm_fmadd_ps(bv1, p, acc1);
3217 acc0 = _mm_add_ps(_mm_mul_ps(bv0, p), acc0);
3218 acc1 = _mm_add_ps(_mm_mul_ps(bv1, p), acc1);
3221 _mm_storeu_ps(c + 0, acc0);
3222 _mm_storeu_ps(c + 4, acc1);
3225static inline void ck_attention_simd_gemm_ukernel_1x1(
float *c,
3231 __m128 acc = _mm_loadu_ps(c);
3232 for (
int kk = 0; kk < k; ++kk) {
3233 const __m128 bv = _mm_loadu_ps(b + (
size_t) kk * (
size_t) n);
3234 const __m128 p = _mm_set1_ps(a[kk]);
3236 acc = _mm_fmadd_ps(bv, p, acc);
3238 acc = _mm_add_ps(_mm_mul_ps(bv, p), acc);
3241 _mm_storeu_ps(c, acc);
3252 for (; ii + 2 <= m; ii += 2) {
3254 for (; jj + 8 <= n; jj += 8) {
3255 ck_attention_simd_gemm_ukernel_2x2(c + jj, a, b + jj, k, n);
3257 for (; jj + 4 <= n; jj += 4) {
3258 ck_attention_simd_gemm_ukernel_2x1(c + jj, a, b + jj, k, n);
3260 for (; jj < n; ++jj) {
3261 for (
int i = 0; i < 2; ++i) {
3262 float sum = c[(size_t) i * (
size_t) n + (size_t) jj];
3263 for (
int kk = 0; kk < k; ++kk) {
3264 sum += a[(size_t) i * (
size_t) k + (size_t) kk] * b[(
size_t) kk * (size_t) n + (
size_t) jj];
3266 c[(size_t) i * (
size_t) n + (size_t) jj] = sum;
3269 a += (size_t) 2 * (
size_t) k;
3270 c += (size_t) 2 * (
size_t) n;
3273 for (; ii < m; ++ii) {
3275 for (; jj + 8 <= n; jj += 8) {
3276 ck_attention_simd_gemm_ukernel_1x2(c + jj, a, b + jj, k, n);
3278 for (; jj + 4 <= n; jj += 4) {
3279 ck_attention_simd_gemm_ukernel_1x1(c + jj, a, b + jj, k, n);
3281 for (; jj < n; ++jj) {
3283 for (
int kk = 0; kk < k; ++kk) {
3284 sum += a[kk] * b[(size_t) kk * (
size_t) n + (size_t) jj];
3300 for (
int i = 0; i < m; ++i) {
3301 float *c_row = c + (size_t) i * (
size_t) n;
3302 const float *a_row = a + (size_t) i * (
size_t) k;
3303 for (
int kk = 0; kk < k; ++kk) {
3304 const float a_ik = a_row[kk];
3305 const float *b_row = b + (size_t) kk * (
size_t) n;
3306 for (
int j = 0; j < n; ++j) {
3307 c_row[j] += a_ik * b_row[j];
3323 int aligned_head_dim,
3324 int kv_stride_tokens,
3325 int query_tile_size,
3329 if (!q || !k || !v || !output || num_heads <= 0 || num_kv_heads <= 0 ||
3330 num_tokens <= 0 || head_dim <= 0 || aligned_head_dim < head_dim ||
3331 kv_stride_tokens < num_tokens || num_heads % num_kv_heads != 0 ||
3332 query_tile_size <= 0) {
3337 const int T = num_tokens;
3338 const size_t kv_head_stride = (size_t) kv_stride_tokens * (
size_t) aligned_head_dim;
3340 float *q_tile = (
float *) alloca((
size_t) query_tile_size * (size_t) head_dim *
sizeof(
float));
3341 float *k_tile = (
float *) alloca((
size_t) head_dim * (size_t)
CK_GGML_FA_TILE_KV *
sizeof(
float));
3342 float *v_tile = (
float *) alloca((
size_t)
CK_GGML_FA_TILE_KV * (size_t) head_dim *
sizeof(
float));
3343 float *kq = (
float *) alloca((
size_t) query_tile_size * (size_t)
CK_GGML_FA_TILE_KV *
sizeof(
float));
3344 float *vkq = (
float *) alloca((
size_t) query_tile_size * (size_t) head_dim *
sizeof(
float));
3345 float *sum_row = (
float *) alloca((
size_t) query_tile_size *
sizeof(float));
3346 float *max_row = (
float *) alloca((
size_t) query_tile_size *
sizeof(float));
3348 const int total_rows = num_heads * T;
3349 const int rows_per_worker = (total_rows + nth - 1) / nth;
3350 int ir = rows_per_worker * ith;
3351 const int ir1 = (ir + rows_per_worker) < total_rows
3352 ? (ir + rows_per_worker)
3356 const int h = ir / T;
3357 const int iq = ir - h * T;
3358 int tile_rows = ir1 - ir;
3359 if (tile_rows > query_tile_size) tile_rows = query_tile_size;
3360 if (tile_rows > T - iq) tile_rows = T - iq;
3361 const int kv_head = (int) ((
long long) h * (
long long) num_kv_heads / (
long long) num_heads);
3362 const float *k_head = k + (size_t) kv_head * kv_head_stride;
3363 const float *v_head = v + (size_t) kv_head * kv_head_stride;
3365 for (
int tq = 0; tq < query_tile_size; ++tq) {
3367 max_row[tq] = -INFINITY;
3370 memset(vkq, 0, (
size_t) query_tile_size * (
size_t) head_dim *
sizeof(
float));
3371 memset(q_tile, 0, (
size_t) query_tile_size * (
size_t) head_dim *
sizeof(
float));
3375 for (
int tq = 0; tq < tile_rows; ++tq) {
3376 const float *q_vec = q +
qkv_index(h, iq + tq, 0, T, aligned_head_dim);
3377 memcpy(q_tile + (
size_t) tq * (
size_t) head_dim, q_vec, (
size_t) head_dim *
sizeof(
float));
3382 memset(kq, 0, (
size_t) query_tile_size * (
size_t)
CK_GGML_FA_TILE_KV *
sizeof(
float));
3384 for (
int tk = 0; tk < kv_tile; ++tk) {
3385 const float *k_vec = k_head + (size_t) (ik + tk) * (size_t) aligned_head_dim;
3386 const float *v_vec = v_head + (size_t) (ik + tk) * (size_t) aligned_head_dim;
3387 for (
int d = 0; d < head_dim; ++d) {
3390 v_tile[(size_t) tk * (
size_t) head_dim + (size_t) d] =
3406 for (
int tq = 0; tq < query_tile_size; ++tq) {
3409 kq_row[tk] = -INFINITY;
3414 for (
int tq = 0; tq < tile_rows; ++tq) {
3417 if (tile_max == -INFINITY) {
3422 const float old_max = max_row[tq];
3423 const float new_max = old_max > tile_max ? old_max : tile_max;
3424 if (new_max > old_max) {
3431 max_row[tq] = new_max;
3432 sum_row[tq] = (float) (
3433 (
double) sum_row[tq] +
3446 for (
int tq = 0; tq < tile_rows; ++tq) {
3447 float *out_vec = output +
qkv_index(h, iq + tq, 0, T, aligned_head_dim);
3448 const float inv_sum = sum_row[tq] == 0.0f ? 0.0f : (1.0f / sum_row[tq]);
3449 for (
int d = 0; d < head_dim; ++d) {
3450 out_vec[d] = vkq[(size_t) tq * (
size_t) head_dim + (size_t) d] * inv_sum;
3452 for (
int d = head_dim; d < aligned_head_dim; ++d) {
3469 int aligned_head_dim;
3470 int kv_stride_tokens;
3471 int query_tile_size;
3472} ck_attention_full_tiled_f16kv_fp32_args_t;
3476 ck_attention_full_tiled_f16kv_fp32_args_t *args =
3477 (ck_attention_full_tiled_f16kv_fp32_args_t *) opaque;
3479 args->q, args->k, args->v, args->output,
3480 args->num_heads, args->num_kv_heads, args->num_tokens,
3481 args->head_dim, args->aligned_head_dim, args->kv_stride_tokens,
3482 args->query_tile_size,
3495 int aligned_head_dim,
3496 int kv_stride_tokens,
3497 int query_tile_size)
3499 if (!q || !k || !v || !output || num_heads <= 0 || num_kv_heads <= 0 ||
3500 num_tokens <= 0 || head_dim <= 0 || aligned_head_dim < head_dim ||
3501 kv_stride_tokens < num_tokens || num_heads % num_kv_heads != 0) {
3505 ck_attention_full_tiled_f16kv_fp32_args_t args = {
3510 .num_heads = num_heads,
3511 .num_kv_heads = num_kv_heads,
3512 .num_tokens = num_tokens,
3513 .head_dim = head_dim,
3514 .aligned_head_dim = aligned_head_dim,
3515 .kv_stride_tokens = kv_stride_tokens,
3516 .query_tile_size = query_tile_size,
3520 if (pool && active > 1) {
3536 int aligned_head_dim,
3537 int kv_stride_tokens)
3543 q, k, v, output, num_heads, num_kv_heads, num_tokens,
3544 head_dim, aligned_head_dim, kv_stride_tokens, query_tile_size);
3556 int aligned_head_dim,
3557 int kv_stride_tokens)
3560 q, k, v, output, num_heads, num_kv_heads, num_tokens,
3573 int aligned_head_dim,
3574 int kv_stride_tokens)
3577 q, k, v, output, num_heads, num_kv_heads, num_tokens,
3592 if (!query || !key || !value || !output || num_heads <= 0 ||
3593 query_tokens <= 0 || key_tokens != query_tokens || head_dim <= 0) {
3598 if (scale != contract_scale) {
3606 query, key, value, output,
3607 num_heads, num_heads, query_tokens,
3608 head_dim, head_dim, key_tokens, query_tile_size);
3634 int aligned_head_dim;
3635 int kv_stride_tokens;
3637 int output_token_major;
3639} ck_attention_parallel_args_t;
3642 const float *k_head,
3643 const float *v_head,
3646 int aligned_head_dim,
3650#if defined(__AVX512F__)
3651 attention_flash_query_causal_avx512(q_vec, k_head, v_head,
3652 kv_tokens, head_dim, aligned_head_dim,
3654#elif defined(__AVX2__)
3655 attention_flash_query_causal_avx2(q_vec, k_head, v_head,
3656 kv_tokens, head_dim, aligned_head_dim,
3658#elif defined(__AVX__)
3659 attention_flash_query_causal_avx(q_vec, k_head, v_head,
3660 kv_tokens, head_dim, aligned_head_dim,
3664 kv_tokens, head_dim, aligned_head_dim,
3670#if defined(__AVX512F__)
3671static int ck_attention_qblock4_enabled(
void)
3673 static int cached = -1;
3680static int ck_attention_qblock8_enabled(
void)
3682 static int cached = -1;
3689static int ck_attention_qblock_fast_exp_enabled(
void)
3691 static int cached = -1;
3698static inline float ck_attention_qblock_fast_expf(
float x)
3700 if (x > 88.0f) x = 88.0f;
3701 else if (x < -88.0f) x = -88.0f;
3703 const float log2e = 1.4426950408889634f;
3704 const float z = x * log2e;
3705 const float zf = nearbyintf(z);
3706 const float f = z - zf;
3708 const float c0 = 1.0f;
3709 const float c1 = 0.6931471805599453f;
3710 const float c2 = 0.2402265069591007f;
3711 const float c3 = 0.05550410866482158f;
3712 const float c4 = 0.009618129107628478f;
3714 float poly = ((c4 * f + c3) * f + c2) * f + c1;
3715 poly = poly * f + c0;
3717 union { uint32_t i;
float f; } u;
3718 u.i = (uint32_t)((int32_t)zf + 127) << 23;
3722static inline float ck_attention_qblock_expf(
float x)
3724 return ck_attention_qblock_fast_exp_enabled() ? ck_attention_qblock_fast_expf(x) : expf(x);
3727static inline float ck_attention_dot72_avx512(
const float *q_vec,
const float *k_vec)
3729 __m512 acc = _mm512_setzero_ps();
3730 acc = _mm512_fmadd_ps(_mm512_loadu_ps(q_vec + 0), _mm512_loadu_ps(k_vec + 0), acc);
3731 acc = _mm512_fmadd_ps(_mm512_loadu_ps(q_vec + 16), _mm512_loadu_ps(k_vec + 16), acc);
3732 acc = _mm512_fmadd_ps(_mm512_loadu_ps(q_vec + 32), _mm512_loadu_ps(k_vec + 32), acc);
3733 acc = _mm512_fmadd_ps(_mm512_loadu_ps(q_vec + 48), _mm512_loadu_ps(k_vec + 48), acc);
3734 float dot = _mm512_reduce_add_ps(acc);
3735 for (
int d = 64; d < 72; ++d) {
3736 dot += q_vec[d] * k_vec[d];
3741static void attention_flash_query4_full_avx512(
const float *q_head,
3742 const float *k_head,
3743 const float *v_head,
3747 int aligned_head_dim,
3751 float m[4] = { -INFINITY, -INFINITY, -INFINITY, -INFINITY };
3752 float ssum[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
3754 for (
int r = 0; r < q_count; ++r) {
3755 for (
int d = 0; d < 72; ++d) out[r][d] = 0.0f;
3758 const float *qv[4] = { NULL, NULL, NULL, NULL };
3759 for (
int r = 0; r < q_count; ++r) {
3760 qv[r] = q_head + (size_t)(q0 + r) * (size_t)aligned_head_dim;
3763 for (
int j = 0; j < kv_tokens; ++j) {
3764 const float *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
3765 const float *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
3770 for (
int r = 0; r < q_count; ++r) {
3771 score[r] = ck_attention_dot72_avx512(qv[r], k_vec) * scale;
3772 if (
score[r] > m[r]) {
3773 scale_old[r] = (m[r] == -INFINITY) ? 0.0f : ck_attention_qblock_expf(m[r] -
score[r]);
3775 ssum[r] *= scale_old[r];
3779 scale_old[r] = 1.0f;
3780 scale_v[r] = ck_attention_qblock_expf(
score[r] - m[r]);
3781 ssum[r] += scale_v[r];
3785 for (
int d = 0; d < 72; d += 16) {
3786 const int width = (d + 16 <= 72) ? 16 : (72 - d);
3788 const __m512 vv = _mm512_loadu_ps(v_vec + d);
3789 for (
int r = 0; r < q_count; ++r) {
3790 __m512 ov = _mm512_loadu_ps(out[r] + d);
3791 ov = _mm512_fmadd_ps(ov, _mm512_set1_ps(scale_old[r]), _mm512_mul_ps(_mm512_set1_ps(scale_v[r]), vv));
3792 _mm512_storeu_ps(out[r] + d, ov);
3795 for (
int r = 0; r < q_count; ++r) {
3796 for (
int t = 0; t < width; ++t) {
3797 out[r][d + t] = out[r][d + t] * scale_old[r] + scale_v[r] * v_vec[d + t];
3804 for (
int r = 0; r < q_count; ++r) {
3805 float *dst = out_head + (size_t)(q0 + r) * (size_t)aligned_head_dim;
3806 const float inv = ssum[r] == 0.0f ? 0.0f : (1.0f / ssum[r]);
3807 const __m512 invv = _mm512_set1_ps(inv);
3808 for (
int d = 0; d + 16 <= 72; d += 16) {
3809 _mm512_storeu_ps(dst + d, _mm512_mul_ps(_mm512_loadu_ps(out[r] + d), invv));
3811 for (
int d = 64; d < 72; ++d) dst[d] = out[r][d] * inv;
3812 for (
int d = 72; d < aligned_head_dim; ++d) dst[d] = 0.0f;
3815static void attention_flash_query8_full_avx512(
const float *q_head,
3816 const float *k_head,
3817 const float *v_head,
3821 int aligned_head_dim,
3825 float m[8] = { -INFINITY, -INFINITY, -INFINITY, -INFINITY, -INFINITY, -INFINITY, -INFINITY, -INFINITY };
3826 float ssum[8] = { 0.0f, 0.0f, 0.0f, 0.0f, 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[8] = { NULL, NULL, NULL, NULL, 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;
3898 int aligned_head_dim;
3899 int kv_stride_tokens;
3901} ck_attention_qblock4_args_t;
3903static void ck_attention_full_qblock4_work(
int ith,
int nth,
void *opaque)
3905 ck_attention_qblock4_args_t *args = (ck_attention_qblock4_args_t *) opaque;
3906 const int T = args->num_tokens;
3907 const int q_blocks = (T + 3) / 4;
3908 const int total = args->num_heads * q_blocks;
3909 const size_t head_stride = (size_t)T * (
size_t)args->aligned_head_dim;
3910 const size_t kv_head_stride = (size_t)args->kv_stride_tokens * (
size_t)args->aligned_head_dim;
3912 for (
int idx = ith; idx < total; idx += nth) {
3913 const int h = idx / q_blocks;
3914 const int qb = idx - h * q_blocks;
3915 const int q0 = qb * 4;
3916 const int q_count = (q0 + 4 <= T) ? 4 : (T - q0);
3917 const int kv_head = (int)((
long long)h * (
long long)args->num_kv_heads / (
long long)args->num_heads);
3918 const float *q_head = args->q + (size_t)h * head_stride;
3919 const float *k_head = args->k + (size_t)kv_head * kv_head_stride;
3920 const float *v_head = args->v + (size_t)kv_head * kv_head_stride;
3921 float *out_head = args->output + (size_t)h * head_stride;
3922 attention_flash_query4_full_avx512(q_head, k_head, v_head,
3924 args->aligned_head_dim,
3930static void ck_attention_full_qblock8_work(
int ith,
int nth,
void *opaque)
3932 ck_attention_qblock4_args_t *args = (ck_attention_qblock4_args_t *) opaque;
3933 const int T = args->num_tokens;
3934 const int q_blocks = (T + 7) / 8;
3935 const int total = args->num_heads * q_blocks;
3936 const size_t head_stride = (size_t)T * (
size_t)args->aligned_head_dim;
3937 const size_t kv_head_stride = (size_t)args->kv_stride_tokens * (
size_t)args->aligned_head_dim;
3939 for (
int idx = ith; idx < total; idx += nth) {
3940 const int h = idx / q_blocks;
3941 const int qb = idx - h * q_blocks;
3942 const int q0 = qb * 8;
3943 const int q_count = (q0 + 8 <= T) ? 8 : (T - q0);
3944 const int kv_head = (int)((
long long)h * (
long long)args->num_kv_heads / (
long long)args->num_heads);
3945 const float *q_head = args->q + (size_t)h * head_stride;
3946 const float *k_head = args->k + (size_t)kv_head * kv_head_stride;
3947 const float *v_head = args->v + (size_t)kv_head * kv_head_stride;
3948 float *out_head = args->output + (size_t)h * head_stride;
3949 attention_flash_query8_full_avx512(q_head, k_head, v_head,
3951 args->aligned_head_dim,
3961 ck_attention_parallel_args_t *args = (ck_attention_parallel_args_t *) opaque;
3962 const int T = args->num_tokens;
3963 const int total = args->num_heads * T;
3964 const size_t kv_head_stride = (size_t) args->kv_stride_tokens * (
size_t) args->aligned_head_dim;
3966 for (
int idx = ith; idx < total; idx += nth) {
3967 const int h = idx / T;
3968 const int i = idx - h * T;
3969 const int kv_head = (int) ((
long long) h * (
long long) args->num_kv_heads / (
long long) args->num_heads);
3970 const float *k_head = args->k + (size_t) kv_head * kv_head_stride;
3971 const float *v_head = args->v + (size_t) kv_head * kv_head_stride;
3972 const float *q_vec = args->q +
qkv_index(h, i, 0, T, args->aligned_head_dim);
3974 h, i, args->num_heads, T, args->aligned_head_dim,
3975 args->output_token_major);
3976 const int kv_tokens = args->causal ? (i + 1) : T;
3980 args->aligned_head_dim,
3988 const char *disable = getenv(
"CK_DISABLE_ATTENTION_THREADPOOL");
3989 if (disable && disable[0] && strcmp(disable,
"0") != 0)
return 0;
3996 if (total_queries < 1024 || num_tokens < 128 || head_dim <= 0)
return 0;
4003 if (nth <= 1)
return 1;
4004 const char *cap_env = getenv(
"CK_ATTENTION_THREAD_CAP");
4005 int cap = cap_env && cap_env[0] ? atoi(cap_env) : 24;
4006 if (cap < 1) cap = 1;
4007 if (cap > nth) cap = nth;
4008 int active = (total_queries + 127) / 128;
4009 if (num_tokens >= 1024 && active < 8) active = 8;
4010 if (active > cap) active = cap;
4011 if (active > nth) active = nth;
4012 return active < 1 ? 1 : active;
4017 const char *value = getenv(
"CK_STRICT_ATTN_F16_UNFUSED");
4018 return !value || !value[0] || strcmp(value,
"0") != 0;
4030 int aligned_head_dim,
4031 int kv_stride_tokens,
4033 int output_token_major,
4037 const int T = num_tokens;
4038 const size_t kv_head_stride = (size_t) kv_stride_tokens * (
size_t) aligned_head_dim;
4039 const size_t kv_half_count = (size_t) T * (
size_t) aligned_head_dim;
4040 uint16_t *k_half = (uint16_t *) malloc(kv_half_count *
sizeof(uint16_t));
4041 uint16_t *v_half = (uint16_t *) malloc(kv_half_count *
sizeof(uint16_t));
4042 if (!k_half || !v_half) {
4047 uint16_t *q_half = (uint16_t *) alloca((
size_t) aligned_head_dim *
sizeof(uint16_t));
4048 uint16_t *prob_half = (uint16_t *) alloca((
size_t) T *
sizeof(uint16_t));
4049 uint16_t *v_col_half = (uint16_t *) alloca((
size_t) T *
sizeof(uint16_t));
4050 float *raw_scores = (
float *) alloca((
size_t) T *
sizeof(float));
4051 float *logits = (
float *) alloca((
size_t) T *
sizeof(float));
4052 int cached_kv_head = -1;
4054 for (
int h = 0; h < num_heads; ++h) {
4055 const int kv_head = (int) ((
long long) h * (
long long) num_kv_heads /
4056 (
long long) num_heads);
4057 const float *k_head = k + (size_t) kv_head * kv_head_stride;
4058 const float *v_head = v + (size_t) kv_head * kv_head_stride;
4059 if (kv_head != cached_kv_head) {
4060 for (
size_t idx = 0; idx < kv_half_count; ++idx) {
4064 cached_kv_head = kv_head;
4067 for (
int i = 0; i < T; ++i) {
4068 const float *q_vec = q +
qkv_index(h, i, 0, T, aligned_head_dim);
4070 h, i, num_heads, T, aligned_head_dim, output_token_major);
4071 const int kv_tokens = causal ? i + 1 : T;
4072 for (
int d = 0; d < aligned_head_dim; ++d) {
4075 for (
int j = 0; j < kv_tokens; ++j) {
4078 k_half + (
size_t) j * (
size_t) aligned_head_dim,
4080 logits[j] = raw_scores[j] * scale;
4085 const float inv_sum = sum > 0.0 ? (float) (1.0 / sum) : 0.0f;
4086 for (
int j = 0; j < kv_tokens; ++j) {
4087 logits[j] *= inv_sum;
4090 for (
int d = 0; d < head_dim; ++d) {
4091 for (
int j = 0; j < kv_tokens; ++j) {
4092 v_col_half[j] = v_half[(size_t) j * (
size_t) aligned_head_dim + (size_t) d];
4096 for (
int d = head_dim; d < aligned_head_dim; ++d) {
4100 kv_tokens, head_dim,
4101 debug_layer_id, h, i);
4117 int aligned_head_dim,
4118 int kv_stride_tokens,
4120 int round_full_kv_fp16,
4121 int output_token_major,
4124 if (!q || !k || !v || !output) {
4127 if (num_heads <= 0 || num_kv_heads <= 0 || num_tokens <= 0 ||
4128 head_dim <= 0 || aligned_head_dim < head_dim) {
4131 if (kv_stride_tokens < num_tokens) {
4135 const int T = num_tokens;
4136 const size_t kv_head_stride = (size_t)kv_stride_tokens * (
size_t)aligned_head_dim;
4146 num_heads, num_kv_heads, num_tokens,
4147 head_dim, aligned_head_dim, kv_stride_tokens,
4148 causal, output_token_major, strict_scale, debug_layer_id)) {
4152#if CK_ENABLE_LLAMA_CPP_PARITY
4153 if (!causal && !output_token_major &&
4168 float *score_row = (
float *) alloca((
size_t) T *
sizeof(float));
4169 float *logit_row = (
float *) alloca((
size_t) T *
sizeof(float));
4170 float *v_cols = (
float *) alloca((
size_t) head_dim * (size_t) T *
sizeof(
float));
4171 for (
int h = 0; h < num_heads; ++h) {
4172 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
4173 const float *k_head = k + (size_t)kv_head * kv_head_stride;
4174 const float *v_head = v + (size_t)kv_head * kv_head_stride;
4176 for (
int d = 0; d < head_dim; ++d) {
4177 float *dst_col = v_cols + (size_t) d * (
size_t) T;
4178 for (
int j = 0; j < T; ++j) {
4179 dst_col[j] = v_head[(size_t) j * (
size_t) aligned_head_dim + (size_t) d];
4183 for (
int i = 0; i < T; ++i) {
4184 const float *q_vec = q +
qkv_index(h, i, 0, T, aligned_head_dim);
4185 float *out_vec = output +
qkv_index(h, i, 0, T, aligned_head_dim);
4186 const int kv_tokens = causal ? (i + 1) : T;
4187 if (kv_tokens <= 0) {
4188 for (
int d = 0; d < aligned_head_dim; ++d) {
4193 for (
int j = 0; j < kv_tokens; ++j) {
4194 const float *k_vec = k_head + (size_t) j * (
size_t) aligned_head_dim;
4197 float *raw_dump = NULL;
4199 raw_dump = (
float *) alloca((
size_t) kv_tokens *
sizeof(float));
4200 memcpy(raw_dump, score_row, (
size_t) kv_tokens *
sizeof(
float));
4202 memcpy(logit_row, score_row, (
size_t) kv_tokens *
sizeof(
float));
4207 const float inv_sum = (float) (1.0 / sum);
4209 for (
int d = 0; d < head_dim; ++d) {
4210 const float *v_col = v_cols + (size_t) d * (
size_t) T;
4214 for (
int d = 0; d < head_dim; ++d) {
4218 for (
int d = head_dim; d < aligned_head_dim; ++d) {
4223 kv_tokens, head_dim,
4224 debug_layer_id, h, i);
4237 float *rounded_kv = NULL;
4238 const float *compute_k = k;
4239 const float *compute_v = v;
4240 if (!causal && round_full_kv_fp16) {
4241 if ((
size_t) kv_stride_tokens > SIZE_MAX / (
size_t) num_kv_heads) {
4244 const size_t rows = (size_t) num_kv_heads * (
size_t) kv_stride_tokens;
4245 if ((
size_t) aligned_head_dim > SIZE_MAX / rows) {
4248 const size_t elements = rows * (size_t) aligned_head_dim;
4249 if (elements > SIZE_MAX / (2 *
sizeof(
float))) {
4252 rounded_kv = (
float *) malloc(2 * elements *
sizeof(
float));
4256 compute_k = rounded_kv;
4257 compute_v = rounded_kv + elements;
4263#if defined(__AVX512F__)
4264 #define FLASH_QUERY_IMPL attention_flash_query_causal_avx512
4265#elif defined(__AVX2__)
4266 #define FLASH_QUERY_IMPL attention_flash_query_causal_avx2
4267#elif defined(__AVX__)
4268 #define FLASH_QUERY_IMPL attention_flash_query_causal_avx
4270 #define FLASH_QUERY_IMPL attention_flash_query_causal
4273 const int total_queries = num_heads * T;
4274#if defined(__AVX512F__)
4275 if (!causal && !output_token_major && head_dim == 72 && aligned_head_dim >= 72 && ck_attention_qblock8_enabled()) {
4277 const int q_blocks = (T + 7) / 8;
4278 const int total_blocks = num_heads * q_blocks;
4280 if (pool && active > 1) {
4281 ck_attention_qblock4_args_t args = {
4286 .num_heads = num_heads,
4287 .num_kv_heads = num_kv_heads,
4288 .num_tokens = num_tokens,
4289 .aligned_head_dim = aligned_head_dim,
4290 .kv_stride_tokens = kv_stride_tokens,
4299 if (!causal && !output_token_major && head_dim == 72 && aligned_head_dim >= 72 && ck_attention_qblock4_enabled()) {
4301 const int q_blocks = (T + 3) / 4;
4302 const int total_blocks = num_heads * q_blocks;
4304 if (pool && active > 1) {
4305 ck_attention_qblock4_args_t args = {
4310 .num_heads = num_heads,
4311 .num_kv_heads = num_kv_heads,
4312 .num_tokens = num_tokens,
4313 .aligned_head_dim = aligned_head_dim,
4314 .kv_stride_tokens = kv_stride_tokens,
4326 if (pool && active > 1) {
4327 ck_attention_parallel_args_t args = {
4332 .num_heads = num_heads,
4333 .num_kv_heads = num_kv_heads,
4334 .num_tokens = num_tokens,
4335 .head_dim = head_dim,
4336 .aligned_head_dim = aligned_head_dim,
4337 .kv_stride_tokens = kv_stride_tokens,
4339 .output_token_major = output_token_major,
4348 for (
int h = 0; h < num_heads; ++h) {
4349 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
4350 const float *k_head = compute_k + (size_t)kv_head * kv_head_stride;
4351 const float *v_head = compute_v + (size_t)kv_head * kv_head_stride;
4353 for (
int i = 0; i < T; ++i) {
4354 const float *q_vec = q +
qkv_index(h, i, 0, T, aligned_head_dim);
4356 h, i, num_heads, T, aligned_head_dim, output_token_major);
4357 const int kv_tokens = causal ? (i + 1) : T;
4360 head_dim, aligned_head_dim,
4367#undef FLASH_QUERY_IMPL
4378 int aligned_head_dim)
4381 num_heads, num_kv_heads,
4382 num_tokens, head_dim,
4388 1.0f / sqrtf((
float)head_dim));
4399 int aligned_head_dim)
4402 num_heads, num_kv_heads,
4403 num_tokens, head_dim,
4409 1.0f / sqrtf((
float)head_dim));
4430 int aligned_head_dim,
4431 int kv_stride_tokens)
4434 num_heads, num_kv_heads,
4435 num_tokens, head_dim,
4441 1.0f / sqrtf((
float)head_dim));
4453 int aligned_head_dim,
4454 int kv_stride_tokens)
4457 num_heads, num_kv_heads,
4458 num_tokens, head_dim,
4464 1.0f / sqrtf((
float)head_dim));
4475 int aligned_head_dim,
4476 int kv_stride_tokens)
4479 num_heads, num_kv_heads,
4480 num_tokens, head_dim,
4486 1.0f / sqrtf((
float)head_dim));
4492#if defined(__AVX512BF16__)
4493 __m512 acc = _mm512_setzero_ps();
4495 for (; i + 32 <= count; i += 32) {
4496 const __m512bh av = _mm512_cvtne2ps_pbh(_mm512_loadu_ps(a + i + 16), _mm512_loadu_ps(a + i));
4497 const __m512bh bv = _mm512_cvtne2ps_pbh(_mm512_loadu_ps(b + i + 16), _mm512_loadu_ps(b + i));
4498 acc = _mm512_dpbf16_ps(acc, av, bv);
4500 float sum = _mm512_reduce_add_ps(acc);
4501 for (; i < count; ++i) {
4509 for (
int i = 0; i < count; ++i) {
4521 return head_dim > 0 ? (float)(1.0 / sqrt((
double)head_dim)) : 0.0f;
4524#if defined(__AVX512F__)
4525static float ck_bf16_sdpa_reduce_add_avx512(__m512 value)
4527 __m512 other = _mm512_shuffle_f32x4(value, value, 0x4E);
4528 value = _mm512_add_ps(value, other);
4529 other = _mm512_shuffle_f32x4(value, value, 0xB1);
4530 value = _mm512_add_ps(value, other);
4531 other = _mm512_shuffle_ps(value, value, 0x4E);
4532 value = _mm512_add_ps(value, other);
4533 other = _mm512_shuffle_ps(value, value, 0xB1);
4534 value = _mm512_add_ps(value, other);
4535 return _mm512_cvtss_f32(value);
4538static float ck_bf16_sdpa_reduce_max_avx512(__m512 value)
4540 __m512 other = _mm512_shuffle_f32x4(value, value, 0x4E);
4541 value = _mm512_max_ps(value, other);
4542 other = _mm512_shuffle_f32x4(value, value, 0xB1);
4543 value = _mm512_max_ps(value, other);
4544 other = _mm512_shuffle_ps(value, value, 0x4E);
4545 value = _mm512_max_ps(value, other);
4546 other = _mm512_shuffle_ps(value, value, 0xB1);
4547 value = _mm512_max_ps(value, other);
4548 return _mm512_cvtss_f32(value);
4551static __m512 ck_bf16_sdpa_exp_u20_avx512(__m512 value)
4553 const __m512 c1 = _mm512_set1_ps(0.999999701f);
4554 const __m512 c2 = _mm512_set1_ps(0.499991506f);
4555 const __m512 c3 = _mm512_set1_ps(0.166676521f);
4556 const __m512 c4 = _mm512_set1_ps(0.0418978221f);
4557 const __m512 c5 = _mm512_set1_ps(0.00828929059f);
4558 const __m512 log2e = _mm512_castsi512_ps(_mm512_set1_epi32(0x3fb8aa3b));
4559 const __m512 half = _mm512_set1_ps(0.5f);
4560 const __m512 one = _mm512_set1_ps(1.0f);
4561 const __m512 zero = _mm512_setzero_ps();
4562 const __m512 two = _mm512_set1_ps(2.0f);
4563 const __m512 ln2 = _mm512_castsi512_ps(_mm512_set1_epi32(0x3f317218));
4564 const __m512 min_log = _mm512_castsi512_ps(_mm512_set1_epi32(0xc2aeac50));
4565 const __m512 max_log = _mm512_castsi512_ps(_mm512_set1_epi32(0x42b17218));
4566 const __mmask16 underflow = _mm512_cmp_ps_mask(value, min_log, _CMP_LT_OS);
4567 __m512 source = _mm512_max_ps(_mm512_min_ps(value, max_log), min_log);
4568 __m512 exponent = _mm512_fmadd_ps(source, log2e, half);
4569 const __m512i exponent_i = _mm512_cvt_roundps_epi32(
4570 exponent, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC);
4571 exponent = _mm512_cvtepi32_ps(exponent_i);
4572 const __m512 reduced = _mm512_fnmadd_ps(exponent, ln2, source);
4573 __m512 result = _mm512_fmadd_ps(reduced, c5, c4);
4574 result = _mm512_fmadd_ps(reduced, result, c3);
4575 result = _mm512_fmadd_ps(reduced, result, c2);
4576 result = _mm512_fmadd_ps(reduced, result, c1);
4577 result = _mm512_fmadd_ps(reduced, result, one);
4578 __m512i power = _mm512_cvtps_epi32(_mm512_sub_ps(exponent, one));
4579 power = _mm512_slli_epi32(_mm512_add_epi32(power, _mm512_set1_epi32(127)), 23);
4580 __m512 scale = _mm512_castsi512_ps(power);
4581 scale = _mm512_mask_blend_ps(underflow, scale, zero);
4582 return _mm512_mul_ps(_mm512_mul_ps(result, scale), two);
4585static float ck_bf16_sdpa_scale_max_avx512(
float *row,
int count,
float scale)
4587 __m512 lane_max = _mm512_set1_ps(-INFINITY);
4588 const __m512 scale_v = _mm512_set1_ps(scale);
4589 for (
int i = 0; i < count; i += 16) {
4590 const __m512 value = _mm512_mul_ps(_mm512_loadu_ps(row + i), scale_v);
4591 lane_max = _mm512_max_ps(lane_max, value);
4592 _mm512_storeu_ps(row + i, value);
4594 return ck_bf16_sdpa_reduce_max_avx512(lane_max);
4597static float ck_bf16_sdpa_exp_sum_avx512(
4598 const float *scores, uint16_t *probabilities,
int count,
float maximum)
4600 __m512 lane_sum = _mm512_setzero_ps();
4601 const __m512 maximum_v = _mm512_set1_ps(maximum);
4602 for (
int i = 0; i < count; i += 16) {
4603 const __m512 exponent = ck_bf16_sdpa_exp_u20_avx512(
4604 _mm512_sub_ps(_mm512_loadu_ps(scores + i), maximum_v));
4605 lane_sum = _mm512_add_ps(lane_sum, exponent);
4607 _mm512_storeu_ps(values, exponent);
4608 for (
int lane = 0; lane < 16; ++lane) {
4612 return ck_bf16_sdpa_reduce_add_avx512(lane_sum);
4617 const float *q,
const float *k,
const float *v,
float *output,
4618 int num_heads,
int num_kv_heads,
int num_tokens,
4619 int head_dim,
int aligned_head_dim,
int kv_stride_tokens,
4620 int head_begin,
int head_step,
int output_token_major)
4622#if defined(__AVX512F__)
4631 enum { Q_BLOCK = 256, KV_BLOCK = 512, K_PAD = 72, D_PAD = 80 };
4633 (num_tokens % 16) != 0 || (kv_stride_tokens < num_tokens) ||
4634 num_heads % num_kv_heads != 0)
return 0;
4635 uint16_t *q_block = malloc((
size_t)Q_BLOCK * K_PAD *
sizeof(uint16_t));
4636 uint16_t *k_packed = malloc((
size_t)num_tokens * K_PAD *
sizeof(uint16_t));
4637 uint16_t *probabilities = malloc((
size_t)Q_BLOCK * KV_BLOCK *
sizeof(uint16_t));
4638 uint16_t *v_packed = malloc((
size_t)num_tokens * D_PAD *
sizeof(uint16_t));
4639 float *scores = malloc((
size_t)Q_BLOCK * KV_BLOCK *
sizeof(
float));
4640 float *destination = malloc((
size_t)Q_BLOCK * D_PAD *
sizeof(
float));
4641 float *row_max = malloc((
size_t)Q_BLOCK *
sizeof(
float));
4642 float *row_sum = malloc((
size_t)Q_BLOCK *
sizeof(
float));
4643 if (!q_block || !k_packed || !probabilities || !v_packed || !scores ||
4644 !destination || !row_max || !row_sum) {
4645 free(q_block); free(k_packed); free(probabilities); free(v_packed);
4646 free(scores); free(destination); free(row_max); free(row_sum);
4650 const size_t q_stride = (size_t)num_tokens * (
size_t)aligned_head_dim;
4651 const size_t kv_stride = (size_t)kv_stride_tokens * (
size_t)aligned_head_dim;
4652 for (
int h = head_begin; h < num_heads; h += head_step) {
4653 const int kv_head = (int)((
long long)h * num_kv_heads / num_heads);
4654 const float *qh = q + (size_t)h * q_stride;
4655 const float *kh = k + (size_t)kv_head * kv_stride;
4656 const float *vh = v + (size_t)kv_head * kv_stride;
4662 for (
int n = 0; n < num_tokens; n += KV_BLOCK) {
4663 const int key_count = num_tokens - n < KV_BLOCK ? num_tokens - n : KV_BLOCK;
4664 uint16_t *k_block = k_packed + (size_t)n * K_PAD;
4665 uint16_t *v_block = v_packed + (size_t)n * D_PAD;
4666 memset(k_block, 0, (
size_t)key_count * K_PAD *
sizeof(uint16_t));
4667 memset(v_block, 0, (
size_t)D_PAD * key_count *
sizeof(uint16_t));
4668 for (
int key = 0; key < key_count; ++key) {
4669 for (
int d = 0; d < head_dim; ++d) {
4670 k_block[(size_t)key * K_PAD + d] =
4671 float_to_bf16(kh[(
size_t)(n + key) * aligned_head_dim + d]);
4672 v_block[(size_t)d * key_count + key] =
4673 float_to_bf16(vh[(
size_t)(n + key) * aligned_head_dim + d]);
4677 for (
int m = 0; m < num_tokens; m += Q_BLOCK) {
4678 const int query_count = num_tokens - m < Q_BLOCK ? num_tokens - m : Q_BLOCK;
4679 memset(q_block, 0, (
size_t)query_count * K_PAD *
sizeof(uint16_t));
4680 memset(destination, 0, (
size_t)query_count * D_PAD *
sizeof(
float));
4681 for (
int row = 0; row < query_count; ++row) {
4682 for (
int d = 0; d < head_dim; ++d) {
4683 q_block[(size_t)row * K_PAD + d] =
4684 float_to_bf16(qh[(
size_t)(m + row) * aligned_head_dim + d]);
4686 row_max[row] = -INFINITY;
4687 row_sum[row] = 0.0f;
4689 for (
int n = 0; n < num_tokens; n += KV_BLOCK) {
4690 const int key_count = num_tokens - n < KV_BLOCK ? num_tokens - n : KV_BLOCK;
4691 const uint16_t *k_block = k_packed + (size_t)n * K_PAD;
4692 const uint16_t *v_block = v_packed + (size_t)n * D_PAD;
4694 q_block, k_block, scores,
4695 query_count, key_count, K_PAD, 0))
goto fail;
4696 for (
int row = 0; row < query_count; ++row) {
4697 float *score_row = scores + (size_t)row * key_count;
4698 uint16_t *prob_row = probabilities + (size_t)row * key_count;
4699 const float block_max = ck_bf16_sdpa_scale_max_avx512(
4700 score_row, key_count, scale);
4701 const float merged_max = row_max[row] > block_max
4702 ? row_max[row] : block_max;
4703 const float old_scale = isfinite(row_max[row])
4704 ? expf(row_max[row] - merged_max) : 0.0f;
4705 const float block_sum = ck_bf16_sdpa_exp_sum_avx512(
4706 score_row, prob_row, key_count, merged_max);
4707 row_sum[row] = block_sum + old_scale * row_sum[row];
4708 row_max[row] = merged_max;
4710 __m512 scale_v = _mm512_set1_ps(old_scale);
4712 for (; d + 16 <= D_PAD; d += 16) {
4713 float *dst = destination + (size_t)row * D_PAD + d;
4714 _mm512_storeu_ps(dst, _mm512_mul_ps(_mm512_loadu_ps(dst), scale_v));
4719 probabilities, v_block, destination,
4720 query_count, D_PAD, key_count, n > 0))
goto fail;
4722 for (
int row = 0; row < query_count; ++row) {
4723 const float reciprocal = row_sum[row] == 0.0f ? 1.0f : 1.0f / row_sum[row];
4724 float *out_row = output + (
4726 ? ((size_t)(m + row) * (size_t)num_heads + (
size_t)h)
4727 * (
size_t)aligned_head_dim
4728 : ((size_t)h * (
size_t)num_tokens + (size_t)(m + row))
4729 * (
size_t)aligned_head_dim);
4730 for (
int d = 0; d < head_dim; ++d) {
4732 float_to_bf16(destination[(
size_t)row * D_PAD + d] * reciprocal));
4737 free(q_block); free(k_packed); free(probabilities); free(v_packed);
4738 free(scores); free(destination); free(row_max); free(row_sum);
4741 free(q_block); free(k_packed); free(probabilities); free(v_packed);
4742 free(scores); free(destination); free(row_max); free(row_sum);
4745 (void)q; (void)k; (void)v; (void)output; (void)num_heads;
4746 (void)num_kv_heads; (void)num_tokens; (void)head_dim;
4747 (void)aligned_head_dim; (void)kv_stride_tokens; (void)head_begin; (void)head_step;
4748 (void)output_token_major;
4754 const float *q,
const float *k,
const float *v,
float *output,
4755 int num_heads,
int num_kv_heads,
int num_tokens,
4756 int head_dim,
int aligned_head_dim,
int kv_stride_tokens,
4757 int head_begin,
int head_step)
4759 if (!q || !k || !v || !output || num_heads <= 0 || num_kv_heads <= 0 ||
4760 head_dim <= 0 || num_tokens <= 0 || aligned_head_dim < head_dim ||
4761 kv_stride_tokens < num_tokens || num_heads % num_kv_heads != 0)
return 0;
4762 if ((
size_t)num_tokens > SIZE_MAX / (
size_t)head_dim)
return 0;
4763 const size_t v_col_count = (size_t)head_dim * (
size_t)num_tokens;
4764 if (v_col_count > SIZE_MAX /
sizeof(
float))
return 0;
4765 if ((
size_t)num_tokens > SIZE_MAX / (size_t)aligned_head_dim)
return 0;
4766 if ((
size_t)kv_stride_tokens > SIZE_MAX / (size_t)aligned_head_dim)
return 0;
4768 const size_t q_head_stride = (size_t)num_tokens * (
size_t)aligned_head_dim;
4769 const size_t kv_head_stride = (size_t)kv_stride_tokens * (
size_t)aligned_head_dim;
4770 if ((
size_t)num_heads > SIZE_MAX / q_head_stride)
return 0;
4771 if ((
size_t)num_kv_heads > SIZE_MAX / kv_head_stride)
return 0;
4774 float *v_cols = (
float *)malloc(v_col_count *
sizeof(
float));
4775 if (!v_cols)
return 0;
4776 for (
int h = head_begin; h < num_heads; h += head_step) {
4777 const int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
4778 const float *qh = q + (size_t)h * q_head_stride;
4779 const float *kh = k + (size_t)kv_head * kv_head_stride;
4780 const float *vh = v + (size_t)kv_head * kv_head_stride;
4781 float *oh = output + (size_t)h * q_head_stride;
4782 for (
int d = 0; d < head_dim; ++d) {
4783 float *col = v_cols + (size_t)d * (
size_t)num_tokens;
4784 for (
int t = 0; t < num_tokens; ++t) {
4785 col[t] = vh[(size_t)t * (
size_t)aligned_head_dim + (size_t)d];
4788 for (
int row = 0; row < num_tokens; ++row) {
4789 const float *qrow = qh + (size_t)row * (
size_t)aligned_head_dim;
4790 float *dst = oh + (size_t)row * (
size_t)aligned_head_dim;
4791 for (
int d = 0; d < head_dim; ++d) dst[d] = 0.0f;
4792 float running_max = -INFINITY;
4793 float running_sum = 0.0f;
4794 for (
int n = 0; n < num_tokens; n += 512) {
4795 const int block = num_tokens - n < 512 ? num_tokens - n : 512;
4796 float block_max = -INFINITY;
4797 for (
int j = 0; j < block; ++j) {
4800 kh + (
size_t)(n + j) * (
size_t)aligned_head_dim,
4802 if (scores[j] > block_max) block_max = scores[j];
4804 const float merged_max = running_max > block_max ? running_max : block_max;
4805 const float old_scale = isfinite(running_max) ? expf(running_max - merged_max) : 0.0f;
4806 float block_sum = 0.0f;
4807 for (
int j = 0; j < block; ++j) {
4808 const float p = expf(scores[j] - merged_max);
4812 for (
int d = 0; d < head_dim; ++d) {
4815 v_cols + (
size_t)d * (
size_t)num_tokens + (
size_t)n,
4817 dst[d] = dst[d] * old_scale + partial;
4819 running_sum = running_sum * old_scale + block_sum;
4820 running_max = merged_max;
4822 const float inv = running_sum > 0.0f ? 1.0f / running_sum : 0.0f;
4823 for (
int d = 0; d < head_dim; ++d) dst[d] *= inv;
4824 for (
int d = head_dim; d < aligned_head_dim; ++d) dst[d] = 0.0f;
4840 int aligned_head_dim;
4841 int kv_stride_tokens;
4842 int output_token_major;
4844} ck_attention_bf16_sdpa_args_t;
4848 ck_attention_bf16_sdpa_args_t *args = (ck_attention_bf16_sdpa_args_t *)opaque;
4850 args->q, args->k, args->v, args->output,
4851 args->num_heads, args->num_kv_heads, args->num_tokens,
4852 args->head_dim, args->aligned_head_dim, args->kv_stride_tokens,
4854 __atomic_store_n(&args->failed, 1, __ATOMIC_RELAXED);
4860 ck_attention_bf16_sdpa_args_t *args = (ck_attention_bf16_sdpa_args_t *)opaque;
4862 args->q, args->k, args->v, args->output,
4863 args->num_heads, args->num_kv_heads, args->num_tokens,
4864 args->head_dim, args->aligned_head_dim, args->kv_stride_tokens,
4865 ith, nth, args->output_token_major)) {
4866 __atomic_store_n(&args->failed, 1, __ATOMIC_RELAXED);
4871 const float *q,
const float *k,
const float *v,
float *output,
4872 int num_heads,
int num_kv_heads,
int num_tokens,
4873 int head_dim,
int aligned_head_dim,
int kv_stride_tokens,
4874 int output_token_major)
4876 ck_attention_bf16_sdpa_args_t args = {
4877 .q=q, .k=k, .v=v, .output=output,
4878 .num_heads=num_heads, .num_kv_heads=num_kv_heads,
4879 .num_tokens=num_tokens, .head_dim=head_dim,
4880 .aligned_head_dim=aligned_head_dim, .kv_stride_tokens=kv_stride_tokens,
4881 .output_token_major=output_token_major,
4886 if (active > num_heads) active = num_heads;
4887 if (pool && active > 1) {
4893 return __atomic_load_n(&args.failed, __ATOMIC_RELAXED) == 0;
4897 const float *q,
const float *k,
const float *v,
float *output,
4898 int num_heads,
int num_kv_heads,
int num_tokens,
4899 int head_dim,
int aligned_head_dim,
int kv_stride_tokens)
4901 ck_attention_bf16_sdpa_args_t args = {
4902 .q=q, .k=k, .v=v, .output=output,
4903 .num_heads=num_heads, .num_kv_heads=num_kv_heads,
4904 .num_tokens=num_tokens, .head_dim=head_dim,
4905 .aligned_head_dim=aligned_head_dim, .kv_stride_tokens=kv_stride_tokens,
4906 .output_token_major=0,
4911 if (active > num_heads) active = num_heads;
4912 if (pool && active > 1) {
4917 return __atomic_load_n(&args.failed, __ATOMIC_RELAXED) == 0;
4929 int aligned_head_dim,
4930 int kv_stride_tokens)
4934 num_heads, num_kv_heads, num_tokens, head_dim,
4935 aligned_head_dim, kv_stride_tokens,
4939 1.0f / sqrtf((
float)head_dim)
4941 const size_t count = (size_t)num_heads * (
size_t)num_tokens
4942 * (size_t)aligned_head_dim;
4943 for (
size_t i = 0; i < count; ++i) {
4957 int aligned_head_dim,
4958 int kv_stride_tokens)
4961 q, k, v, output, num_heads, num_kv_heads, num_tokens,
4962 head_dim, aligned_head_dim, kv_stride_tokens)) {
4963 const size_t count = (size_t)num_heads * (
size_t)num_tokens
4964 * (size_t)aligned_head_dim;
4965 for (
size_t i = 0; i < count; ++i) {
4970 fprintf(stderr,
"CK numerical contract failure: BF16 tiled SDPA received invalid dimensions or could not allocate scratch\n");
4982 int aligned_head_dim,
4983 int kv_stride_tokens)
4986 q, k, v, output, num_heads, num_kv_heads, num_tokens,
4987 head_dim, aligned_head_dim, kv_stride_tokens,
4992 "HARD KERNEL CONTRACT FAULT: PyTorch CPU-flash BF16 attention "
4993 "requires AMX-BF16, AVX-512, D=72/A=72 and a token multiple of 16; "
4994 "no numerically different fallback is permitted\n");
5007 int aligned_head_dim,
5008 int kv_stride_tokens)
5011 q, k, v, output, num_heads, num_kv_heads, num_tokens,
5012 head_dim, aligned_head_dim, kv_stride_tokens,
5017 "HARD KERNEL CONTRACT FAULT: PyTorch CPU-flash BF16 token-output "
5018 "attention requires AMX-BF16, AVX-512, D=72/A=72 and a token "
5019 "multiple of 16; no numerically different fallback is permitted\n");
5032 int aligned_head_dim,
5033 int kv_stride_tokens)
5037 num_heads, num_kv_heads,
5038 num_tokens, head_dim,
5056 int aligned_head_dim,
5057 int kv_stride_tokens)
5060 num_heads, num_kv_heads,
5061 num_tokens, head_dim,
5075 int aligned_head_dim,
5076 int kv_stride_tokens)
5079 q, q, q, output, num_heads, num_heads, num_tokens,
5080 head_dim, aligned_head_dim, kv_stride_tokens
5092 int aligned_head_dim,
5093 int kv_stride_tokens)
5097 num_heads, num_kv_heads,
5098 num_tokens, head_dim,
5117 int aligned_head_dim,
5118 int kv_stride_tokens,
5121 int output_token_major)
5123 if (!q || !k || !v || !output) {
5126 if (num_heads <= 0 || num_kv_heads <= 0 || num_tokens <= 0) {
5129 if (kv_stride_tokens < num_tokens || head_dim <= 0 || aligned_head_dim <= 0) {
5132 if (visual_start < 0 || visual_tokens <= 0 || visual_start >= num_tokens) {
5134 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
5135 aligned_head_dim, kv_stride_tokens, 1,
5136 0, output_token_major, 1.0f);
5140 int visual_end = visual_start + visual_tokens;
5141 if (visual_end > num_tokens) {
5142 visual_end = num_tokens;
5144 if (visual_end <= visual_start) {
5146 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
5147 aligned_head_dim, kv_stride_tokens, 1,
5148 0, output_token_major, 1.0f);
5152 const int T = num_tokens;
5153 const size_t kv_head_stride = (size_t)kv_stride_tokens * (
size_t)aligned_head_dim;
5154 const float scale = 1.0f;
5160 for (
int h = 0; h < num_heads; ++h) {
5161 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
5162 const float *k_head = k + (size_t)kv_head * kv_head_stride;
5163 const float *v_head = v + (size_t)kv_head * kv_head_stride;
5165 for (
int i = 0; i < T; ++i) {
5166 const float *q_vec = q +
qkv_index(h, i, 0, T, aligned_head_dim);
5168 h, i, num_heads, T, aligned_head_dim, output_token_major);
5169 const int in_visual = (i >= visual_start && i < visual_end);
5170 const int kv_tokens = in_visual ? visual_end : (i + 1);
5173 head_dim, aligned_head_dim,
5177 head_dim, aligned_head_dim,
5179 debug_layer_id, h, i);
5185#if defined(__AVX512F__)
5186 #define FLASH_QUERY_IMPL attention_flash_query_causal_avx512
5187#elif defined(__AVX2__)
5188 #define FLASH_QUERY_IMPL attention_flash_query_causal_avx2
5189#elif defined(__AVX__)
5190 #define FLASH_QUERY_IMPL attention_flash_query_causal_avx
5192 #define FLASH_QUERY_IMPL attention_flash_query_causal
5195 for (
int h = 0; h < num_heads; ++h) {
5196 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
5197 const float *k_head = k + (size_t)kv_head * kv_head_stride;
5198 const float *v_head = v + (size_t)kv_head * kv_head_stride;
5200 for (
int i = 0; i < T; ++i) {
5201 const float *q_vec = q +
qkv_index(h, i, 0, T, aligned_head_dim);
5203 h, i, num_heads, T, aligned_head_dim, output_token_major);
5204 const int in_visual = (i >= visual_start && i < visual_end);
5205 const int kv_tokens = in_visual ? visual_end : (i + 1);
5208 head_dim, aligned_head_dim,
5213#undef FLASH_QUERY_IMPL
5217 const float *q,
const float *k,
const float *v,
float *output,
5218 int num_heads,
int num_kv_heads,
int num_tokens,
int head_dim,
5219 int aligned_head_dim,
int kv_stride_tokens,
int visual_start,
5223 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
5224 aligned_head_dim, kv_stride_tokens, visual_start, visual_tokens,
5229 const float *q,
const float *k,
const float *v,
float *output,
5230 int num_heads,
int num_kv_heads,
int num_tokens,
int head_dim,
5231 int aligned_head_dim,
int kv_stride_tokens,
int visual_start,
5235 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
5236 aligned_head_dim, kv_stride_tokens, visual_start, visual_tokens,
5249 int aligned_head_dim;
5250 int kv_stride_tokens;
5251 int inputs_prerounded;
5252} ck_attention_causal_f16kv_args_t;
5256 const ck_attention_causal_f16kv_args_t *args =
5257 (
const ck_attention_causal_f16kv_args_t *)opaque;
5258 const float scale = 1.0f / sqrtf((
float)args->head_dim);
5259 const int T = args->num_tokens;
5260 const size_t kv_head_stride =
5261 (size_t)args->kv_stride_tokens * (
size_t)args->aligned_head_dim;
5263 for (
int h = ith; h < args->num_heads; h += nth) {
5264 const int kv_head = (int)((
long long)h * (
long long)args->num_kv_heads /
5265 (
long long)args->num_heads);
5266 const float *k_head = args->k + (size_t)kv_head * kv_head_stride;
5267 const float *v_head = args->v + (size_t)kv_head * kv_head_stride;
5269 for (
int i = 0; i < T; ++i) {
5270 const float *q_vec = args->q +
5271 qkv_index(h, i, 0, T, args->aligned_head_dim);
5272 float *out_vec = args->output +
5273 qkv_index(h, i, 0, T, args->aligned_head_dim);
5274 if (args->inputs_prerounded) {
5276 q_vec, k_head, v_head, i + 1,
5277 args->head_dim, args->aligned_head_dim, scale, out_vec);
5280 q_vec, k_head, v_head, i + 1,
5281 args->head_dim, args->aligned_head_dim, scale, out_vec);
5288 const float *q,
const float *k,
const float *v,
float *output,
5289 int num_heads,
int num_kv_heads,
int num_tokens,
int head_dim,
5290 int aligned_head_dim,
int kv_stride_tokens)
5292 if (!q || !k || !v || !output || num_heads <= 0 || num_kv_heads <= 0 ||
5293 num_tokens <= 0 || kv_stride_tokens < num_tokens) {
5296 ck_attention_causal_f16kv_args_t args = {
5297 q, k, v, output, num_heads, num_kv_heads, num_tokens,
5298 head_dim, aligned_head_dim, kv_stride_tokens, 0,
5304 const float *q,
const float *k,
const float *v,
float *output,
5305 int num_heads,
int num_kv_heads,
int num_tokens,
int head_dim,
5306 int aligned_head_dim,
int kv_stride_tokens,
5307 float *rounded_kv,
size_t rounded_kv_bytes)
5309 if (!q || !k || !v || !output || num_heads <= 0 || num_kv_heads <= 0 ||
5310 num_tokens <= 0 || kv_stride_tokens < num_tokens) {
5313 size_t elements = 0;
5314 if ((
size_t)num_kv_heads <= SIZE_MAX / (
size_t)kv_stride_tokens) {
5315 const size_t rows = (size_t)num_kv_heads * (
size_t)kv_stride_tokens;
5316 if (rows <= SIZE_MAX / (
size_t)aligned_head_dim) {
5317 elements = rows * (size_t)aligned_head_dim;
5320 if (elements == 0 || elements > SIZE_MAX / (2 *
sizeof(
float)) ||
5321 !rounded_kv || rounded_kv_bytes < 2 * elements *
sizeof(
float)) {
5323 "HARD KERNEL CONTRACT FAULT: FP16-KV attention workspace is too small\n");
5328 ck_attention_causal_f16kv_args_t args = {
5329 q, rounded_kv, rounded_kv + elements, output,
5330 num_heads, num_kv_heads, num_tokens,
5331 head_dim, aligned_head_dim, kv_stride_tokens, 1,
5335 const int active = workers < num_heads ? workers : num_heads;
5344 const float *q,
const float *k,
const float *v,
float *output,
5345 int num_heads,
int num_kv_heads,
int num_tokens,
int head_dim,
5346 int aligned_head_dim,
int kv_stride_tokens)
5348 size_t elements = 0;
5349 if (num_kv_heads > 0 && kv_stride_tokens > 0 && aligned_head_dim > 0 &&
5350 (
size_t)num_kv_heads <= SIZE_MAX / (
size_t)kv_stride_tokens) {
5351 const size_t rows = (size_t)num_kv_heads * (
size_t)kv_stride_tokens;
5352 if (rows <= SIZE_MAX / (
size_t)aligned_head_dim) {
5353 elements = rows * (size_t)aligned_head_dim;
5356 float *workspace = elements > 0 && elements <= SIZE_MAX / (2 *
sizeof(float))
5357 ? (
float *)malloc(2 * elements *
sizeof(
float))
5361 q, k, v, output, num_heads, num_kv_heads, num_tokens,
5362 head_dim, aligned_head_dim, kv_stride_tokens);
5366 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
5367 aligned_head_dim, kv_stride_tokens, workspace,
5368 2 * elements *
sizeof(
float));
5380 int aligned_head_dim,
5381 int kv_stride_tokens)
5383 if (!q || !k || !v || !output) {
5386 if (num_heads <= 0 || num_kv_heads <= 0 || num_tokens <= 0) {
5389 if (kv_stride_tokens < num_tokens) {
5395 : 1.0f / sqrtf((
float) head_dim);
5396 const int T = num_tokens;
5397 const size_t kv_head_stride = (size_t) kv_stride_tokens * (
size_t) aligned_head_dim;
5399 float *score_row = (
float *) alloca((
size_t) T *
sizeof(float));
5400 float *v_cols = (
float *) alloca((
size_t) head_dim * (size_t) T *
sizeof(
float));
5401 for (
int h = 0; h < num_heads; ++h) {
5402 const int kv_head = (int) ((
long long) h * (
long long) num_kv_heads / (
long long) num_heads);
5403 const float *k_head = k + (size_t) kv_head * kv_head_stride;
5404 const float *v_head = v + (size_t) kv_head * kv_head_stride;
5406#if CK_ENABLE_LLAMA_CPP_PARITY
5407 float *out_head = output + (size_t) h * (
size_t) T * (size_t) aligned_head_dim;
5410 q + (
size_t) h * (
size_t) T * (
size_t) aligned_head_dim,
5423 for (
int d = 0; d < head_dim; ++d) {
5424 float *dst_col = v_cols + (size_t) d * (
size_t) T;
5425 for (
int j = 0; j < T; ++j) {
5426 dst_col[j] = v_head[(size_t) j * (
size_t) aligned_head_dim + (size_t) d];
5430 for (
int i = 0; i < T; ++i) {
5431 const float *q_vec = q +
qkv_index(h, i, 0, T, aligned_head_dim);
5432 float *out_vec = output +
qkv_index(h, i, 0, T, aligned_head_dim);
5458 int aligned_head_dim,
5459 int kv_stride_tokens,
5461 size_t score_rows_bytes,
5463 size_t v_columns_bytes,
5464 float *probability_row,
5465 size_t probability_row_bytes)
5467 if (!q || !k || !v || !output) {
5470 if (num_heads <= 0 || num_kv_heads <= 0 || num_tokens <= 0) {
5473 if (kv_stride_tokens < num_tokens) {
5477 const size_t T = (size_t) num_tokens;
5478 if ((
size_t) num_heads > SIZE_MAX / T ||
5479 (size_t) head_dim > SIZE_MAX / T) {
5482 const size_t score_elements = (size_t) num_heads * T;
5483 const size_t columns_per_head = (size_t) head_dim * T;
5484 if ((
size_t) num_heads > SIZE_MAX / columns_per_head ||
5485 score_elements > SIZE_MAX /
sizeof(float) ||
5486 columns_per_head * (
size_t) num_heads > SIZE_MAX /
sizeof(float) ||
5487 T > SIZE_MAX /
sizeof(
float)) {
5490 const size_t column_elements = columns_per_head * (size_t) num_heads;
5491 if (!score_rows || score_rows_bytes < score_elements *
sizeof(
float) ||
5492 !v_columns || v_columns_bytes < column_elements *
sizeof(float) ||
5493 !probability_row || probability_row_bytes < T *
sizeof(
float)) {
5498 const float scale = strict
5500 : 1.0f / sqrtf((
float) head_dim);
5501 const int token_count = num_tokens;
5502 const size_t kv_head_stride = (size_t) kv_stride_tokens * (
size_t) aligned_head_dim;
5504#if CK_ENABLE_LLAMA_CPP_PARITY
5505 ck_ggml_vec_dot_f32_fn dot_fn = NULL;
5506 ck_ggml_vec_soft_max_f32_fn softmax_fn = NULL;
5507 ck_ggml_compute_forward_mul_mat_fn mul_mat_fn = NULL;
5508 ck_ggml_compute_forward_soft_max_fn softmax_compute_fn = NULL;
5523 dot_fn = ck_resolve_ggml_vec_dot_f32();
5524 softmax_fn = ck_resolve_ggml_vec_soft_max_f32();
5525 mul_mat_fn = ck_resolve_ggml_compute_forward_mul_mat();
5526 softmax_compute_fn = ck_resolve_ggml_compute_forward_soft_max();
5530 float *score_row = score_rows;
5531 float *v_cols = v_columns;
5532#if CK_ENABLE_LLAMA_CPP_PARITY
5533 float *prob_row = probability_row;
5536 for (
int h = 0; h < num_heads; ++h) {
5537 const int kv_head = (int) ((
long long) h * (
long long) num_kv_heads / (
long long) num_heads);
5538 const float *k_head = k + (size_t) kv_head * kv_head_stride;
5539 const float *v_head = v + (size_t) kv_head * kv_head_stride;
5541#if CK_ENABLE_LLAMA_CPP_PARITY
5542 float *out_head = output + (size_t) h * (
size_t) T * (size_t) aligned_head_dim;
5544 q + (
size_t) h * (size_t) T * (
size_t) aligned_head_dim,
5556 for (
int d = 0; d < head_dim; ++d) {
5557 float *dst_col = v_cols + (size_t) d * (
size_t) token_count;
5558 for (
int j = 0; j < token_count; ++j) {
5559 dst_col[j] = v_head[(size_t) j * (
size_t) aligned_head_dim + (size_t) d];
5563#if CK_ENABLE_LLAMA_CPP_PARITY
5565 if (attention_head_full_dyn_ggml_regular_graph_out(
5566 q + (
size_t) h * (size_t) T * (
size_t) aligned_head_dim,
5580 if (token_count > 0) {
5589 for (
int i = 0; i < token_count; ++i) {
5590 const float *q_vec = q +
qkv_index(h, i, 0, token_count, aligned_head_dim);
5591 float *out_vec = output +
qkv_index(h, i, 0, token_count, aligned_head_dim);
5592#if CK_ENABLE_LLAMA_CPP_PARITY
5593 if (dot_fn && softmax_fn) {
5598 attention_query_full_dyn_ggml_regular(q_vec,
5613 }
else if (dot_fn && mul_mat_fn && softmax_compute_fn) {
5617 attention_query_full_ggml_compute_regular(q_vec,
5629 softmax_compute_fn);
5654#pragma omp parallel for schedule(static) if(num_heads > 1)
5655 for (
int h = 0; h < num_heads; ++h) {
5656 float *score_row = score_rows + (size_t) h * (
size_t) token_count;
5657 float *v_cols = v_columns + (size_t) h * (
size_t) head_dim * (size_t) token_count;
5658 const int kv_head = (int) ((
long long) h * (
long long) num_kv_heads / (
long long) num_heads);
5659 const float *k_head = k + (size_t) kv_head * kv_head_stride;
5660 const float *v_head = v + (size_t) kv_head * kv_head_stride;
5663 for (
int d = 0; d < head_dim; ++d) {
5664 float *dst_col = v_cols + (size_t) d * (
size_t) token_count;
5665 for (
int j = 0; j < token_count; ++j) {
5666 dst_col[j] = v_head[(size_t) j * (
size_t) aligned_head_dim + (size_t) d];
5671 for (
int i = 0; i < token_count; ++i) {
5672 const float *q_vec = q +
qkv_index(h, i, 0, token_count, aligned_head_dim);
5673 float *out_vec = output +
qkv_index(h, i, 0, token_count, aligned_head_dim);
5698 int aligned_head_dim,
5699 int kv_stride_tokens)
5701 if (num_heads <= 0 || num_tokens <= 0 || head_dim <= 0 ||
5702 (
size_t) num_heads > SIZE_MAX / (
size_t) num_tokens ||
5703 (
size_t) head_dim > SIZE_MAX / (
size_t) num_tokens) {
5706 const size_t score_elements = (size_t) num_heads * (
size_t) num_tokens;
5707 const size_t columns_per_head = (size_t) head_dim * (
size_t) num_tokens;
5708 if ((
size_t) num_heads > SIZE_MAX / columns_per_head)
return;
5709 const size_t column_elements = (size_t) num_heads * columns_per_head;
5710 if (score_elements > SIZE_MAX - column_elements ||
5711 score_elements + column_elements > SIZE_MAX - (
size_t) num_tokens)
return;
5712 const size_t total_elements = score_elements + column_elements + (size_t) num_tokens;
5713 if (total_elements > SIZE_MAX /
sizeof(
float))
return;
5714 float *workspace = (
float *) malloc(total_elements *
sizeof(
float));
5715 if (!workspace)
return;
5716 float *score_rows = workspace;
5717 float *v_columns = score_rows + score_elements;
5718 float *probability_row = v_columns + column_elements;
5720 q, k, v, output, num_heads, num_kv_heads, num_tokens, head_dim,
5721 aligned_head_dim, kv_stride_tokens,
5722 score_rows, score_elements *
sizeof(
float),
5723 v_columns, column_elements *
sizeof(
float),
5724 probability_row, (
size_t) num_tokens *
sizeof(
float));
5730 if (live_tokens <= 0 || capacity < live_tokens)
return 0;
5731 int padded = live_tokens < 256 ? 256 : ((live_tokens + 255) / 256) * 256;
5732 return padded < capacity ? padded : capacity;
5735#if defined(__AVX512F__)
5736static inline __m512 ck_llama_regular_round_f16x16(__m512 value)
5738 return _mm512_cvtph_ps(_mm512_cvtps_ph(value, _MM_FROUND_TO_NEAREST_INT));
5745#if defined(__AVX512F__)
5747 _mm512_setzero_ps(), _mm512_setzero_ps(),
5748 _mm512_setzero_ps(), _mm512_setzero_ps()
5750 for (; i + 64 <= count; i += 64) {
5751 for (
int lane = 0; lane < 4; ++lane) {
5752 acc[lane] = _mm512_fmadd_ps(
5753 ck_llama_regular_round_f16x16(_mm512_loadu_ps(a + i + lane * 16)),
5754 ck_llama_regular_round_f16x16(_mm512_loadu_ps(b + i + lane * 16)),
5758 acc[0] = _mm512_add_ps(acc[0], acc[2]);
5759 acc[1] = _mm512_add_ps(acc[1], acc[3]);
5760 float sum = _mm512_reduce_add_ps(_mm512_add_ps(acc[0], acc[1]));
5761#elif defined(__AVX__)
5763 _mm256_setzero_ps(), _mm256_setzero_ps(),
5764 _mm256_setzero_ps(), _mm256_setzero_ps()
5766 for (; i + 32 <= count; i += 32) {
5767 for (
int lane = 0; lane < 4; ++lane) {
5769 acc[lane] = _mm256_fmadd_ps(
5770 _mm256_cvtph_ps(_mm256_cvtps_ph(
5771 _mm256_loadu_ps(a + i + lane * 8), _MM_FROUND_TO_NEAREST_INT)),
5772 _mm256_cvtph_ps(_mm256_cvtps_ph(
5773 _mm256_loadu_ps(b + i + lane * 8), _MM_FROUND_TO_NEAREST_INT)),
5776 acc[lane] = _mm256_add_ps(acc[lane], _mm256_mul_ps(
5777 _mm256_cvtph_ps(_mm256_cvtps_ph(
5778 _mm256_loadu_ps(a + i + lane * 8), _MM_FROUND_TO_NEAREST_INT)),
5779 _mm256_cvtph_ps(_mm256_cvtps_ph(
5780 _mm256_loadu_ps(b + i + lane * 8), _MM_FROUND_TO_NEAREST_INT))));
5784 acc[0] = _mm256_add_ps(acc[0], acc[2]);
5785 acc[1] = _mm256_add_ps(acc[1], acc[3]);
5786 const __m256 merged = _mm256_add_ps(acc[0], acc[1]);
5787 __m128 halves = _mm_add_ps(
5788 _mm256_extractf128_ps(merged, 1), _mm256_castps256_ps128(merged));
5789 halves = _mm_add_ps(halves, _mm_movehl_ps(halves, halves));
5790 halves = _mm_add_ss(halves, _mm_movehdup_ps(halves));
5791 float sum = _mm_cvtss_f32(halves);
5793 float sums[4] = {0.0f, 0.0f, 0.0f, 0.0f};
5794 for (; i + 4 <= count; i += 4) {
5795 for (
int lane = 0; lane < 4; ++lane) {
5798 sums[lane] = fmaf(av, bv, sums[lane]);
5801 float sum = (sums[0] + sums[2]) + (sums[1] + sums[3]);
5803 for (; i < count; ++i) {
5806 sum = fmaf(av, bv, sum);
5812 const float *probability,
const float *value_column,
int count)
5815#if defined(__AVX512F__)
5816 __m512 acc = _mm512_setzero_ps();
5817 for (; i + 16 <= count; i += 16) {
5818 acc = _mm512_fmadd_ps(
5819 ck_llama_regular_round_f16x16(_mm512_loadu_ps(value_column + i)),
5820 ck_llama_regular_round_f16x16(_mm512_loadu_ps(probability + i)), acc);
5822 float sum = _mm512_reduce_add_ps(acc);
5823#elif defined(__AVX__)
5824 __m256 acc = _mm256_setzero_ps();
5825 for (; i + 8 <= count; i += 8) {
5827 acc = _mm256_fmadd_ps(
5828 _mm256_cvtph_ps(_mm256_cvtps_ph(
5829 _mm256_loadu_ps(value_column + i), _MM_FROUND_TO_NEAREST_INT)),
5830 _mm256_cvtph_ps(_mm256_cvtps_ph(
5831 _mm256_loadu_ps(probability + i), _MM_FROUND_TO_NEAREST_INT)), acc);
5833 acc = _mm256_add_ps(acc, _mm256_mul_ps(
5834 _mm256_cvtph_ps(_mm256_cvtps_ph(
5835 _mm256_loadu_ps(value_column + i), _MM_FROUND_TO_NEAREST_INT)),
5836 _mm256_cvtph_ps(_mm256_cvtps_ph(
5837 _mm256_loadu_ps(probability + i), _MM_FROUND_TO_NEAREST_INT))));
5840 __m128 halves = _mm_add_ps(
5841 _mm256_extractf128_ps(acc, 1), _mm256_castps256_ps128(acc));
5842 halves = _mm_add_ps(halves, _mm_movehl_ps(halves, halves));
5843 halves = _mm_add_ss(halves, _mm_movehdup_ps(halves));
5844 float sum = _mm_cvtss_f32(halves);
5848 for (; i < count; ++i) {
5851 sum = fmaf(value, probability_value, sum);
5857 const float *query,
const float *key_head,
const float *value_columns,
5858 float *output,
float *scores,
float *scaled_scores,
5859 int live_tokens,
int padded_tokens,
int query_position,
5860 int head_dim,
int aligned_head_dim,
int sliding_window,
5861 int batched_prefill)
5863 const int first = sliding_window > 0 && query_position >= sliding_window
5864 ? query_position - sliding_window + 1 : 0;
5865 const int last = query_position < live_tokens ? query_position : live_tokens - 1;
5868 const float *key = key_head + (size_t)
token * (
size_t)aligned_head_dim;
5869 scores[
token] = batched_prefill
5874 memcpy(scaled_scores, scores, (
size_t)padded_tokens *
sizeof(
float));
5875 const float scale = 1.0f / sqrtf((
float)head_dim);
5879 padded_tokens, scores, scaled_scores, maximum);
5882 for (
int dim = 0; dim < head_dim; ++dim) {
5883 const float *column = value_columns + (size_t)dim * (
size_t)padded_tokens;
5884 output[dim] = batched_prefill
5889 memset(output, 0, (
size_t)head_dim *
sizeof(
float));
5891 for (
int dim = head_dim; dim < aligned_head_dim; ++dim) output[dim] = 0.0f;
5895 const float *q,
const float *k,
const float *v,
float *output,
5896 int num_heads,
int num_kv_heads,
int query_tokens,
int live_tokens,
5897 int head_dim,
int aligned_head_dim,
int kv_stride_tokens,
int sliding_window,
5898 float *scores,
size_t scores_bytes,
5899 float *value_columns,
size_t value_columns_bytes,
5900 float *scaled_scores,
size_t scaled_scores_bytes,
5901 int batched_prefill)
5903 if (!q || !k || !v || !output || !scores || !value_columns || !scaled_scores ||
5904 num_heads <= 0 || num_kv_heads <= 0 || query_tokens <= 0 || live_tokens <= 0 ||
5905 head_dim <= 0 || aligned_head_dim < head_dim || kv_stride_tokens < live_tokens)
return;
5906 size_t scratch_capacity = scores_bytes /
sizeof(float);
5907 const size_t scaled_capacity = scaled_scores_bytes /
sizeof(float);
5908 const size_t value_capacity = value_columns_bytes /
5909 ((size_t)head_dim *
sizeof(
float));
5910 if (scaled_capacity < scratch_capacity) scratch_capacity = scaled_capacity;
5911 if (value_capacity < scratch_capacity) scratch_capacity = value_capacity;
5912 if (!batched_prefill && (
size_t)kv_stride_tokens < scratch_capacity) {
5913 scratch_capacity = (size_t)kv_stride_tokens;
5915 const int padded = scratch_capacity > (size_t)INT_MAX ? 0 :
5917 if (padded <= 0 || scores_bytes < (
size_t)padded *
sizeof(
float) ||
5918 scaled_scores_bytes < (
size_t)padded *
sizeof(
float) ||
5919 value_columns_bytes < (
size_t)head_dim * (
size_t)padded *
sizeof(
float))
return;
5921 const size_t kv_head_stride = (size_t)kv_stride_tokens * (
size_t)aligned_head_dim;
5924 int packed_kv_head = -1;
5925 for (
int head = 0; head < num_heads; ++head) {
5926 const int kv_head = (int)((
long long)head * num_kv_heads / num_heads);
5927 const float *key_head = k + (size_t)kv_head * kv_head_stride;
5928 const float *value_head = v + (size_t)kv_head * kv_head_stride;
5929 if (kv_head != packed_kv_head) {
5930 for (
int dim = 0; dim < head_dim; ++dim) {
5931 float *column = value_columns + (size_t)dim * (
size_t)padded;
5934 column[
token] = value_head[(size_t)
token * aligned_head_dim + dim];
5938 packed_kv_head = kv_head;
5940 for (
int query = 0; query < query_tokens; ++query) {
5941 const int position = batched_prefill ? query : live_tokens - 1;
5943 q + ((
size_t)head * query_tokens + query) * aligned_head_dim,
5944 key_head, value_columns,
5945 output + ((
size_t)head * query_tokens + query) * aligned_head_dim,
5946 scores, scaled_scores, live_tokens, padded, position,
5947 head_dim, aligned_head_dim, sliding_window, batched_prefill);
5948 if (debug_layer_id >= 0 &&
5951 scaled_scores, scores,
5952 output + ((
size_t)head * query_tokens + query) * aligned_head_dim,
5953 value_columns, padded, head_dim,
5954 debug_layer_id, head, query);
5961 const float *q,
const float *k,
const float *v,
float *output,
5962 int num_heads,
int num_kv_heads,
int num_tokens,
int head_dim,
5963 int aligned_head_dim,
int kv_stride_tokens,
int sliding_window,
5964 float *scores,
size_t scores_bytes,
5965 float *value_columns,
size_t value_columns_bytes,
5966 float *scaled_scores,
size_t scaled_scores_bytes)
5969 q, k, v, output, num_heads, num_kv_heads, num_tokens, num_tokens,
5970 head_dim, aligned_head_dim, kv_stride_tokens, sliding_window,
5971 scores, scores_bytes, value_columns, value_columns_bytes,
5972 scaled_scores, scaled_scores_bytes, 1);
5976 const float *q,
const float *k,
const float *v,
float *output,
5977 int num_heads,
int num_kv_heads,
int live_tokens,
int kv_stride_tokens,
5978 int head_dim,
int aligned_head_dim,
int sliding_window,
5979 float *scores,
size_t scores_bytes,
5980 float *value_columns,
size_t value_columns_bytes,
5981 float *scaled_scores,
size_t scaled_scores_bytes)
5984 q, k, v, output, num_heads, num_kv_heads, 1, live_tokens,
5985 head_dim, aligned_head_dim, kv_stride_tokens, sliding_window,
5986 scores, scores_bytes, value_columns, value_columns_bytes,
5987 scaled_scores, scaled_scores_bytes, 0);
6003 const float *k_cache,
6004 const float *v_cache,
6011 int aligned_head_dim)
6013 if (!q_token || !k_cache || !v_cache || !out_token) {
6016 if (num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
6019 if (kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
6023 const float scale = 1.0f / sqrtf((
float)head_dim);
6024 const size_t head_stride = (size_t)cache_capacity * (
size_t)aligned_head_dim;
6026 for (
int h = 0; h < num_heads; ++h) {
6027 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
6028 const float *q_head = q_token + (size_t)h * (
size_t)aligned_head_dim;
6029 const float *k_head = k_cache + (size_t)kv_head * head_stride;
6030 const float *v_head = v_cache + (size_t)kv_head * head_stride;
6031 float *out_head = out_token + (size_t)h * (
size_t)aligned_head_dim;
6047 const float *k_cache,
6048 const float *v_cache,
6055 int aligned_head_dim)
6057 if (!q_token || !k_cache || !v_cache || !out_token) {
6060 if (num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
6063 if (kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
6067 const float scale = 1.0f;
6068 const size_t head_stride = (size_t)cache_capacity * (
size_t)aligned_head_dim;
6070 for (
int h = 0; h < num_heads; ++h) {
6071 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
6072 const float *q_head = q_token + (size_t)h * (
size_t)aligned_head_dim;
6073 const float *k_head = k_cache + (size_t)kv_head * head_stride;
6074 const float *v_head = v_cache + (size_t)kv_head * head_stride;
6075 float *out_head = out_token + (size_t)h * (
size_t)aligned_head_dim;
6090 const float *k_cache,
6091 const float *v_cache,
6099 int aligned_head_dim)
6101 if (!q_chunk || !k_cache || !v_cache || !out_chunk) {
6104 if (num_heads <= 0 || num_kv_heads <= 0 || q_tokens <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
6107 if (kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
6111 const float scale = 1.0f;
6112 const size_t cache_head_stride = (size_t)cache_capacity * (
size_t)aligned_head_dim;
6113 const size_t q_head_stride = (size_t)q_tokens * (
size_t)aligned_head_dim;
6115 for (
int h = 0; h < num_heads; ++h) {
6116 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
6117 const float *k_head = k_cache + (size_t)kv_head * cache_head_stride;
6118 const float *v_head = v_cache + (size_t)kv_head * cache_head_stride;
6119 for (
int t = 0; t < q_tokens; ++t) {
6120 const float *q_head = q_chunk + (size_t)h * q_head_stride + (
size_t)t * (size_t)aligned_head_dim;
6121 float *out_head = out_chunk + (size_t)h * q_head_stride + (
size_t)t * (size_t)aligned_head_dim;
6136 const float *k_cache,
6137 const float *v_cache,
6143 int aligned_head_dim)
6146 q_token, k_cache, v_cache, out_token, num_heads, num_heads,
6147 kv_tokens, cache_capacity, head_dim, aligned_head_dim
6152 const float *k_cache,
6153 const float *v_cache,
6160 int aligned_head_dim)
6162 if (!q_token || !k_cache || !v_cache || !out_token) {
6165 if (num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
6168 if (kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
6172 const float scale = 1.0f / sqrtf((
float)head_dim);
6173 const size_t head_stride = (size_t)cache_capacity * (
size_t)aligned_head_dim;
6175 for (
int h = 0; h < num_heads; ++h) {
6176 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
6177 const float *q_head = q_token + (size_t)h * (
size_t)aligned_head_dim;
6178 const float *k_head = k_cache + (size_t)kv_head * head_stride;
6179 const float *v_head = v_cache + (size_t)kv_head * head_stride;
6180 float *out_head = out_token + (size_t)h * (
size_t)aligned_head_dim;
6194 const float *q_token;
6195 const uint16_t *k_cache;
6196 const uint16_t *v_cache;
6203 int aligned_head_dim;
6205 int scheduled_chunks;
6206 int partition_tokens;
6207} ck_attention_f16_split_args_t;
6219#if defined(__AVX512F__)
6222 __m512 sum0 = _mm512_setzero_ps();
6223 __m512 sum1 = _mm512_setzero_ps();
6224 __m512 sum2 = _mm512_setzero_ps();
6225 __m512 sum3 = _mm512_setzero_ps();
6226 const int n64 = n & ~63;
6227 for (; i < n64; i += 64) {
6228 const __m512 x0 = _mm512_cvtph_ps(_mm256_loadu_si256((
const __m256i *) (x + i)));
6229 const __m512 y0 = _mm512_cvtph_ps(_mm256_loadu_si256((
const __m256i *) (y + i)));
6230 const __m512 x1 = _mm512_cvtph_ps(_mm256_loadu_si256((
const __m256i *) (x + i + 16)));
6231 const __m512 y1 = _mm512_cvtph_ps(_mm256_loadu_si256((
const __m256i *) (y + i + 16)));
6232 const __m512 x2 = _mm512_cvtph_ps(_mm256_loadu_si256((
const __m256i *) (x + i + 32)));
6233 const __m512 y2 = _mm512_cvtph_ps(_mm256_loadu_si256((
const __m256i *) (y + i + 32)));
6234 const __m512 x3 = _mm512_cvtph_ps(_mm256_loadu_si256((
const __m256i *) (x + i + 48)));
6235 const __m512 y3 = _mm512_cvtph_ps(_mm256_loadu_si256((
const __m256i *) (y + i + 48)));
6236 sum0 = _mm512_fmadd_ps(x0, y0, sum0);
6237 sum1 = _mm512_fmadd_ps(x1, y1, sum1);
6238 sum2 = _mm512_fmadd_ps(x2, y2, sum2);
6239 sum3 = _mm512_fmadd_ps(x3, y3, sum3);
6241 sum0 = _mm512_add_ps(sum0, sum2);
6242 sum1 = _mm512_add_ps(sum1, sum3);
6243 sum0 = _mm512_add_ps(sum0, sum1);
6244 const float vector_result = _mm512_reduce_add_ps(sum0);
6245#elif defined(__AVX2__) && defined(__F16C__)
6248 __m256 sum0 = _mm256_setzero_ps();
6249 __m256 sum1 = _mm256_setzero_ps();
6250 __m256 sum2 = _mm256_setzero_ps();
6251 __m256 sum3 = _mm256_setzero_ps();
6252 const int n32 = n & ~31;
6253 for (; i < n32; i += 32) {
6254 const __m256 x0 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (x + i)));
6255 const __m256 y0 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (y + i)));
6256 const __m256 x1 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (x + i + 8)));
6257 const __m256 y1 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (y + i + 8)));
6258 const __m256 x2 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (x + i + 16)));
6259 const __m256 y2 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (y + i + 16)));
6260 const __m256 x3 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (x + i + 24)));
6261 const __m256 y3 = _mm256_cvtph_ps(_mm_loadu_si128((
const __m128i *) (y + i + 24)));
6263 sum0 = _mm256_fmadd_ps(x0, y0, sum0);
6264 sum1 = _mm256_fmadd_ps(x1, y1, sum1);
6265 sum2 = _mm256_fmadd_ps(x2, y2, sum2);
6266 sum3 = _mm256_fmadd_ps(x3, y3, sum3);
6268 sum0 = _mm256_add_ps(sum0, _mm256_mul_ps(x0, y0));
6269 sum1 = _mm256_add_ps(sum1, _mm256_mul_ps(x1, y1));
6270 sum2 = _mm256_add_ps(sum2, _mm256_mul_ps(x2, y2));
6271 sum3 = _mm256_add_ps(sum3, _mm256_mul_ps(x3, y3));
6274 sum0 = _mm256_add_ps(sum0, sum2);
6275 sum1 = _mm256_add_ps(sum1, sum3);
6276 sum0 = _mm256_add_ps(sum0, sum1);
6277 const __m128 pair = _mm_add_ps(
6278 _mm256_castps256_ps128(sum0),
6279 _mm256_extractf128_ps(sum0, 1));
6280 const __m128 half = _mm_hadd_ps(pair, pair);
6281 const float vector_result = _mm_cvtss_f32(_mm_hadd_ps(half, half));
6283 const float vector_result = 0.0f;
6289 double result = (double) vector_result;
6290 for (; i < n; ++i) {
6292 result += (double) product;
6294 return (
float) result;
6300#if defined(__AVX512F__)
6301 const __m512 factor = _mm512_set1_ps(scale);
6302 for (; i + 63 < n; i += 64) {
6303 for (
int lane = 0; lane < 4; ++lane) {
6304 const int offset = i + lane * 16;
6305 __m512 value = _mm512_cvtph_ps(
6306 _mm256_loadu_si256((
const __m256i *) (y + offset)));
6307 value = _mm512_mul_ps(value, factor);
6308 _mm256_storeu_si256(
6309 (__m256i *) (y + offset), _mm512_cvtps_ph(value, 0));
6312#elif defined(__AVX2__) && defined(__F16C__)
6313 const __m256 factor = _mm256_set1_ps(scale);
6314 for (; i + 31 < n; i += 32) {
6315 for (
int lane = 0; lane < 4; ++lane) {
6316 const int offset = i + lane * 8;
6317 __m256 value = _mm256_cvtph_ps(
6318 _mm_loadu_si128((
const __m128i *) (y + offset)));
6319 value = _mm256_mul_ps(value, factor);
6321 (__m128i *) (y + offset), _mm256_cvtps_ph(value, 0));
6325 for (; i < n; ++i) {
6337#if defined(__AVX512F__)
6338 const __m512 factor = _mm512_set1_ps(scale);
6339 for (; i + 63 < n; i += 64) {
6340 for (
int lane = 0; lane < 4; ++lane) {
6341 const int offset = i + lane * 16;
6342 const __m512 xv = _mm512_cvtph_ps(
6343 _mm256_loadu_si256((
const __m256i *) (x + offset)));
6344 __m512 yv = _mm512_cvtph_ps(
6345 _mm256_loadu_si256((
const __m256i *) (y + offset)));
6346 yv = _mm512_fmadd_ps(xv, factor, yv);
6347 _mm256_storeu_si256(
6348 (__m256i *) (y + offset), _mm512_cvtps_ph(yv, 0));
6351#elif defined(__AVX2__) && defined(__F16C__)
6352 const __m256 factor = _mm256_set1_ps(scale);
6353 for (; i + 31 < n; i += 32) {
6354 for (
int lane = 0; lane < 4; ++lane) {
6355 const int offset = i + lane * 8;
6356 const __m256 xv = _mm256_cvtph_ps(
6357 _mm_loadu_si128((
const __m128i *) (x + offset)));
6358 __m256 yv = _mm256_cvtph_ps(
6359 _mm_loadu_si128((
const __m128i *) (y + offset)));
6361 yv = _mm256_fmadd_ps(xv, factor, yv);
6363 yv = _mm256_add_ps(yv, _mm256_mul_ps(xv, factor));
6366 (__m128i *) (y + offset), _mm256_cvtps_ph(yv, 0));
6370 for (; i < n; ++i) {
6379 ck_attention_f16_split_args_t *args = (ck_attention_f16_split_args_t *) opaque;
6380 const int partial_stride = args->aligned_head_dim + 2;
6381 const int total_jobs = args->num_heads * args->scheduled_chunks;
6382 const int chunk_size =
6383 (args->partition_tokens + args->split_chunks - 1) / args->split_chunks;
6384 const size_t head_stride = (size_t) args->cache_capacity * (
size_t) args->aligned_head_dim;
6386 uint16_t *q_half = (uint16_t *) alloca((
size_t) args->aligned_head_dim *
sizeof(uint16_t));
6387 uint16_t *acc_half = (uint16_t *) alloca((
size_t) args->aligned_head_dim *
sizeof(uint16_t));
6389 for (
int job = ith; job < total_jobs; job += nth) {
6390 const int h = job / args->scheduled_chunks;
6391 const int chunk = job % args->scheduled_chunks;
6392 const int kv_head = (int) ((
long long) h * (
long long) args->num_kv_heads /
6393 (
long long) args->num_heads);
6394 const int begin = chunk * chunk_size;
6395 const int end = begin < args->kv_tokens
6396 ? (begin + chunk_size < args->kv_tokens ? begin + chunk_size : args->kv_tokens)
6398 const float *q_head = args->q_token + (size_t) h * (
size_t) args->aligned_head_dim;
6399 const uint16_t *k_head = args->k_cache + (size_t) kv_head * head_stride;
6400 const uint16_t *v_head = args->v_cache + (size_t) kv_head * head_stride;
6401 float *partial = args->partials + (size_t) job * (
size_t) partial_stride;
6403 for (
int d = 0; d < args->aligned_head_dim; ++d) {
6409 float max_score = -INFINITY;
6410 for (
int j = begin; j <
end; ++j) {
6411 const uint16_t *k_vec = k_head + (size_t) j * (
size_t) args->aligned_head_dim;
6412 const uint16_t *v_vec = v_head + (size_t) j * (
size_t) args->aligned_head_dim;
6414 const float score = dot * scale;
6415 const float old_max = max_score;
6416 float max_scale = 1.0f;
6417 float value_scale = 1.0f;
6419 if (
score > max_score) {
6421 max_scale = isfinite(old_max)
6430 acc_half, v_vec, value_scale, args->head_dim);
6431#if defined(__INTEL_LLVM_COMPILER)
6432 sum = ck_attention_mul_add_rounded_f32(
6433 sum, max_scale, value_scale);
6435 sum = fmaf(sum, max_scale, value_scale);
6439 partial[0] = max_score;
6441 for (
int d = 0; d < args->head_dim; ++d) {
6444 for (
int d = args->head_dim; d < args->aligned_head_dim; ++d) {
6445 partial[2 + d] = 0.0f;
6451 const float *q_token,
6452 const uint16_t *k_cache,
6453 const uint16_t *v_cache,
6460 int aligned_head_dim,
6462 int partition_tokens)
6464 if (!q_token || !k_cache || !v_cache || !out_token ||
6465 num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 ||
6466 cache_capacity <= 0 || kv_tokens > cache_capacity ||
6467 head_dim <= 0 || aligned_head_dim < head_dim ||
6468 partition_tokens < kv_tokens) {
6472 if (split_chunks < 1) {
6475 if (split_chunks > kv_tokens) {
6476 split_chunks = kv_tokens;
6479 const int partial_stride = aligned_head_dim + 2;
6480 const size_t max_partial_bytes = 1024u * 1024u;
6481 while (split_chunks > 1 &&
6482 (
size_t) num_heads * (
size_t) split_chunks * (
size_t) partial_stride *
sizeof(
float) >
6483 max_partial_bytes) {
6484 split_chunks = (split_chunks + 1) / 2;
6487 const int chunk_size = (partition_tokens + split_chunks - 1) / split_chunks;
6488 const int scheduled_chunks = (kv_tokens + chunk_size - 1) / chunk_size;
6489 const size_t resolved_count =
6490 (size_t) num_heads * (
size_t) scheduled_chunks * (size_t) partial_stride;
6491 float *partials = (
float *) alloca(resolved_count *
sizeof(
float));
6492 ck_attention_f16_split_args_t args = {
6496 .partials = partials,
6497 .num_heads = num_heads,
6498 .num_kv_heads = num_kv_heads,
6499 .kv_tokens = kv_tokens,
6500 .cache_capacity = cache_capacity,
6501 .head_dim = head_dim,
6502 .aligned_head_dim = aligned_head_dim,
6503 .split_chunks = split_chunks,
6504 .scheduled_chunks = scheduled_chunks,
6505 .partition_tokens = partition_tokens,
6510 const int total_jobs = num_heads * scheduled_chunks;
6511 if (active_threads > total_jobs) {
6512 active_threads = total_jobs;
6514 if (pool && active_threads > 1) {
6520 for (
int h = 0; h < num_heads; ++h) {
6521 float *out_head = out_token + (size_t) h * (
size_t) aligned_head_dim;
6522 float final_max = -INFINITY;
6523 float final_sum = 0.0f;
6524 for (
int d = 0; d < aligned_head_dim; ++d) {
6528 for (
int chunk = 0; chunk < scheduled_chunks; ++chunk) {
6529 const float *partial = partials +
6530 ((size_t) h * (
size_t) scheduled_chunks + (size_t) chunk) * (size_t) partial_stride;
6531 const float chunk_max = partial[0];
6532 const float chunk_sum = partial[1];
6533 if (chunk_sum == 0.0f) {
6536 const float new_max = fmaxf(final_max, chunk_max);
6537 const float old_scale = isfinite(final_max)
6540 const float chunk_scale =
6542 for (
int d = 0; d < head_dim; ++d) {
6543 const float chunk_term = partial[2 + d] * chunk_scale;
6544 out_head[d] = fmaf(out_head[d], old_scale, chunk_term);
6546#if defined(__INTEL_LLVM_COMPILER)
6547 const float scaled_chunk_sum = chunk_sum * chunk_scale;
6548 final_sum = fmaf(final_sum, old_scale, scaled_chunk_sum);
6551 final_sum, old_scale, chunk_sum * chunk_scale);
6553 final_max = new_max;
6556 if (final_sum > 0.0f) {
6557 const float inv_sum = 1.0f / final_sum;
6558 for (
int d = 0; d < head_dim; ++d) {
6559 out_head[d] *= inv_sum;
6566 const uint16_t *k_cache,
6567 const uint16_t *v_cache,
6574 int aligned_head_dim,
6577 const int partition_alignment = 256;
6578 const int partition_tokens =
6579 ((kv_tokens + partition_alignment - 1) / partition_alignment) * partition_alignment;
6581 q_token, k_cache, v_cache, out_token,
6582 num_heads, num_kv_heads, kv_tokens, cache_capacity,
6583 head_dim, aligned_head_dim, split_chunks, partition_tokens);
6587 const float *q_token,
6588 const uint16_t *k_cache,
6589 const uint16_t *v_cache,
6596 int aligned_head_dim,
6599 if (!q_token || !k_cache || !v_cache || !out_token ||
6600 num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 ||
6601 cache_capacity <= 0 || kv_tokens > cache_capacity ||
6602 head_dim <= 0 || aligned_head_dim < head_dim) {
6606 switch (reduction) {
6609 q_token, k_cache, v_cache, out_token,
6610 num_heads, num_kv_heads, kv_tokens, cache_capacity,
6611 head_dim, aligned_head_dim);
6615 const int partition_alignment = 256;
6616 const int partition_tokens =
6617 ((kv_tokens + partition_alignment - 1) / partition_alignment) * partition_alignment;
6620 q_token, k_cache, v_cache, out_token,
6621 num_heads, num_kv_heads, kv_tokens, cache_capacity,
6622 head_dim, aligned_head_dim, split_chunks);
6628 q_token, k_cache, v_cache, out_token,
6629 num_heads, num_kv_heads, kv_tokens, cache_capacity,
6630 head_dim, aligned_head_dim, 1);
6640 const uint16_t *k_cache;
6641 const uint16_t *v_cache;
6649 int aligned_head_dim;
6652 size_t q_head_stride;
6653 size_t output_head_stride;
6654} ck_attention_f16_prefill_qtile64_args_t;
6657 _Alignas(64) int arrived;
6658 _Alignas(64)
int phase;
6660} ck_attention_gqa_team_barrier_t;
6663 ck_attention_f16_prefill_qtile64_args_t base;
6664 float *shared_k_tiles;
6665 float *shared_v_tiles;
6666 ck_attention_gqa_team_barrier_t *barriers;
6667 unsigned char *worker_workspace;
6668 size_t worker_workspace_stride;
6669 int query_tile_size;
6670 int concurrent_query_tiles;
6671} ck_attention_f16_prefill_gqa_reuse_args_t;
6675 return (value + 63u) & ~(size_t) 63u;
6683 int query_tile_size,
6684 int concurrent_query_tiles)
6686 if (num_heads <= 0 || num_kv_heads <= 0 ||
6687 num_heads % num_kv_heads != 0 || workers < num_kv_heads ||
6688 workers % num_kv_heads != 0 || head_dim <= 0 ||
6689 query_tile_size <= 0 || concurrent_query_tiles <= 0) {
6692 const int lanes = workers / num_kv_heads;
6693 const int group_jobs =
6694 (num_heads / num_kv_heads) * concurrent_query_tiles;
6695 const size_t local_capacity =
6696 (size_t) (group_jobs + lanes - 1) / (size_t) lanes;
6699 3u * local_capacity *
sizeof(int);
6701 local_capacity * (size_t) query_tile_size * (
size_t) head_dim *
6707 local_capacity * (size_t) query_tile_size * (
size_t) head_dim *
6710 local_capacity * (size_t) query_tile_size *
sizeof(
float);
6712 local_capacity * (size_t) query_tile_size *
sizeof(
float);
6721 int query_tile_size,
6722 int concurrent_query_tiles)
6724 const size_t worker_bytes =
6726 num_heads, num_kv_heads, head_dim, workers,
6727 query_tile_size, concurrent_query_tiles);
6728 if (worker_bytes == 0)
return 0;
6737 (size_t) num_kv_heads *
sizeof(ck_attention_gqa_team_barrier_t);
6739 (size_t) workers * worker_bytes;
6744 ck_attention_gqa_team_barrier_t *barrier)
6746 const int phase = __atomic_load_n(&barrier->phase, __ATOMIC_RELAXED);
6747 if (__atomic_fetch_add(&barrier->arrived, 1, __ATOMIC_ACQ_REL) ==
6748 barrier->lanes - 1) {
6749 __atomic_store_n(&barrier->arrived, 0, __ATOMIC_RELAXED);
6750 __atomic_store_n(&barrier->phase, phase + 1, __ATOMIC_RELEASE);
6753 while (__atomic_load_n(&barrier->phase, __ATOMIC_ACQUIRE) == phase) {
6754#if defined(__i386__) || defined(__x86_64__)
6767 const ck_attention_f16_prefill_qtile64_args_t *args =
6768 (
const ck_attention_f16_prefill_qtile64_args_t *) opaque;
6769 const int query_tiles =
6771 const int total_jobs = args->num_heads * query_tiles;
6776 nth >= args->num_kv_heads) {
6777 const int kv_group = (ith * args->num_kv_heads) / nth;
6778 const int worker_begin =
6779 (kv_group * nth + args->num_kv_heads - 1) / args->num_kv_heads;
6780 const int worker_end =
6781 ((kv_group + 1) * nth + args->num_kv_heads - 1) /
6783 const int lane = ith - worker_begin;
6784 const int lanes = worker_end - worker_begin;
6785 const int head_begin =
6786 (kv_group * args->num_heads + args->num_kv_heads - 1) /
6788 const int head_end =
6789 ((kv_group + 1) * args->num_heads + args->num_kv_heads - 1) /
6791 const int group_jobs = (head_end - head_begin) * query_tiles;
6792 job_begin = head_begin * query_tiles + (group_jobs * lane) / lanes;
6793 job_end = head_begin * query_tiles + (group_jobs * (lane + 1)) / lanes;
6795 job_begin = (total_jobs * ith) / nth;
6796 job_end = (total_jobs * (ith + 1)) / nth;
6798 const int head_begin = (args->num_heads * ith) / nth;
6799 const int head_end = (args->num_heads * (ith + 1)) / nth;
6800 job_begin = head_begin * query_tiles;
6801 job_end = head_end * query_tiles;
6803 if (job_begin >= job_end)
return;
6805 const int kv_tokens = args->past_tokens + args->q_tokens;
6807 const size_t kv_head_stride =
6808 (size_t) args->cache_capacity * (
size_t) args->aligned_head_dim;
6810 float *q_tile = (
float *) alloca(
6812 float *k_tile = (
float *) alloca(
6814 float *v_tile = (
float *) alloca(
6816 float *kq = (
float *) alloca(
6818 float *vkq = (
float *) alloca(
6821 for (
int job = job_begin; job < job_end; ++job) {
6822 const int h = job / query_tiles;
6825 (int) ((
long long) h * (
long long) args->num_kv_heads /
6826 (
long long) args->num_heads);
6827 const uint16_t *k_head = args->k_cache + (size_t) kv_head * kv_head_stride;
6828 const uint16_t *v_head = args->v_cache + (size_t) kv_head * kv_head_stride;
6830 const int tile_rows =
6832 ? (args->q_tokens - iq)
6839 max_row[tq] = -INFINITY;
6846 for (
int tq = 0; tq < tile_rows; ++tq) {
6847 const float *q_vec = args->q +
6848 (size_t) h * args->q_head_stride +
6849 (
size_t) (iq + tq) * (
size_t) args->aligned_head_dim;
6850 memcpy(q_tile + (
size_t) tq * (
size_t) args->head_dim,
6852 (
size_t) args->head_dim *
sizeof(
float));
6867 for (
int tk = 0; tk < kv_tile; ++tk) {
6868 const uint16_t *k_vec = k_head +
6869 (size_t) (ik + tk) * (size_t) args->aligned_head_dim;
6870 const uint16_t *v_vec = v_head +
6871 (size_t) (ik + tk) * (size_t) args->aligned_head_dim;
6872 for (
int d = 0; d < args->head_dim; ++d) {
6875 v_tile[(size_t) tk * (
size_t) args->head_dim + (size_t) d] =
6887 float *kq_row = kq +
6889 const int last_valid_key = args->past_tokens + iq + tq;
6891 const int key = ik + tk;
6892 if (tk >= kv_tile || tq >= tile_rows || key > last_valid_key) {
6893 kq_row[tk] = -INFINITY;
6897 const float tile_max =
6899 if (tile_max == -INFINITY) {
6905 const float old_max = max_row[tq];
6906 const float new_max = old_max > tile_max ? old_max : tile_max;
6907 if (new_max > old_max) {
6910 vkq + (
size_t) tq * (
size_t) args->head_dim,
6911 args->head_dim, ms);
6914 max_row[tq] = new_max;
6915 sum_row[tq] = (float) (
6916 (
double) sum_row[tq] +
6926 for (
int tq = 0; tq < tile_rows; ++tq) {
6927 float *out_vec = args->output +
6928 (size_t) h * args->output_head_stride +
6929 (
size_t) (iq + tq) * (
size_t) args->aligned_head_dim;
6930 const float inv_sum =
6931 sum_row[tq] == 0.0f ? 0.0f : 1.0f / sum_row[tq];
6932 for (
int d = 0; d < args->head_dim; ++d) {
6934 vkq[(size_t) tq * (
size_t) args->head_dim + (size_t) d] * inv_sum;
6936 for (
int d = args->head_dim; d < args->aligned_head_dim; ++d) {
6945 const ck_attention_f16_prefill_gqa_reuse_args_t *args =
6946 (
const ck_attention_f16_prefill_gqa_reuse_args_t *) opaque;
6947 const ck_attention_f16_prefill_qtile64_args_t *base = &args->base;
6948 const int lanes = nth / base->num_kv_heads;
6949 const int kv_group = ith / lanes;
6950 const int lane = ith % lanes;
6951 const int heads_per_group = base->num_heads / base->num_kv_heads;
6952 const int head_begin = kv_group * heads_per_group;
6953 const int query_tiles =
6954 (base->q_tokens + args->query_tile_size - 1) / args->query_tile_size;
6955 const int kv_tokens = base->past_tokens + base->q_tokens;
6957 const size_t kv_head_stride =
6958 (size_t) base->cache_capacity * (
size_t) base->aligned_head_dim;
6959 const uint16_t *k_head =
6960 base->k_cache + (size_t) kv_group * kv_head_stride;
6961 const uint16_t *v_head =
6962 base->v_cache + (size_t) kv_group * kv_head_stride;
6963 float *shared_k = args->shared_k_tiles +
6965 float *shared_v = args->shared_v_tiles +
6967 ck_attention_gqa_team_barrier_t *barrier = &args->barriers[kv_group];
6968 const int max_group_jobs =
6969 heads_per_group * args->concurrent_query_tiles;
6970 const int local_capacity = (max_group_jobs + lanes - 1) / lanes;
6971 unsigned char *worker = args->worker_workspace +
6972 (size_t) ith * args->worker_workspace_stride;
6975 int *local_heads = (
int *) (worker + cursor);
6976 cursor += (size_t) local_capacity *
sizeof(
int);
6977 int *local_iq = (
int *) (worker + cursor);
6978 cursor += (size_t) local_capacity *
sizeof(
int);
6979 int *local_rows = (
int *) (worker + cursor);
6980 cursor += (size_t) local_capacity *
sizeof(
int);
6982 float *q_tiles = (
float *) (worker + cursor);
6983 cursor += (size_t) local_capacity * (
size_t) args->query_tile_size *
6984 (size_t) base->head_dim *
sizeof(
float);
6986 float *kq_tiles = (
float *) (worker + cursor);
6987 cursor += (size_t) local_capacity * (
size_t) args->query_tile_size *
6990 float *vkq_tiles = (
float *) (worker + cursor);
6991 cursor += (size_t) local_capacity * (
size_t) args->query_tile_size *
6992 (size_t) base->head_dim *
sizeof(
float);
6994 float *sum_rows = (
float *) (worker + cursor);
6995 cursor += (size_t) local_capacity * (
size_t) args->query_tile_size *
6998 float *max_rows = (
float *) (worker + cursor);
7000 for (
int query_tile_begin = 0; query_tile_begin < query_tiles;
7001 query_tile_begin += args->concurrent_query_tiles) {
7002 int batch_tiles = query_tiles - query_tile_begin;
7003 if (batch_tiles > args->concurrent_query_tiles) {
7004 batch_tiles = args->concurrent_query_tiles;
7006 const int group_jobs = heads_per_group * batch_tiles;
7009 for (
int group_job = lane; group_job < group_jobs; group_job += lanes) {
7010 const int local = local_jobs++;
7011 const int group_head = group_job / batch_tiles;
7012 const int batch_tile = group_job % batch_tiles;
7013 const int h = head_begin + group_head;
7015 (query_tile_begin + batch_tile) * args->query_tile_size;
7016 int tile_rows = base->q_tokens - iq;
7017 if (tile_rows > args->query_tile_size) {
7018 tile_rows = args->query_tile_size;
7020 local_heads[local] = h;
7021 local_iq[local] = iq;
7022 local_rows[local] = tile_rows;
7024 float *q_tile = q_tiles +
7025 (size_t) local * (
size_t) args->query_tile_size *
7026 (size_t) base->head_dim;
7027 float *vkq = vkq_tiles +
7028 (size_t) local * (
size_t) args->query_tile_size *
7029 (size_t) base->head_dim;
7030 float *sum_row = sum_rows +
7031 (size_t) local * (
size_t) args->query_tile_size;
7032 float *max_row = max_rows +
7033 (size_t) local * (
size_t) args->query_tile_size;
7035 (
size_t) args->query_tile_size * (
size_t) base->head_dim *
7038 (
size_t) args->query_tile_size * (
size_t) base->head_dim *
7040 for (
int tq = 0; tq < args->query_tile_size; ++tq) {
7042 max_row[tq] = -INFINITY;
7044 for (
int tq = 0; tq < tile_rows; ++tq) {
7045 const float *q_vec = base->q +
7046 (size_t) h * base->q_head_stride +
7047 (
size_t) (iq + tq) * (
size_t) base->aligned_head_dim;
7048 memcpy(q_tile + (
size_t) tq * (
size_t) base->head_dim,
7049 q_vec, (
size_t) base->head_dim *
sizeof(
float));
7053 int kv_limit = base->past_tokens +
7054 (query_tile_begin + batch_tiles) * args->query_tile_size;
7055 if (kv_limit > kv_tokens) kv_limit = kv_tokens;
7058 int kv_tile = kv_limit - ik;
7061 for (
int flat = lane; flat < packed_elems; flat += lanes) {
7062 const int tk = flat / base->head_dim;
7063 const int d = flat % base->head_dim;
7064 float k_value = 0.0f;
7065 float v_value = 0.0f;
7067 const uint16_t *k_vec = k_head +
7068 (size_t) (ik + tk) * (size_t) base->aligned_head_dim;
7069 const uint16_t *v_vec = v_head +
7070 (size_t) (ik + tk) * (size_t) base->aligned_head_dim;
7072 k_vec[d], base->cache_is_bf16);
7074 v_vec[d], base->cache_is_bf16);
7078 shared_v[(size_t) tk * (
size_t) base->head_dim + (size_t) d] =
7083 for (
int local = 0; local < local_jobs; ++local) {
7084 const int iq = local_iq[local];
7085 const int tile_rows = local_rows[local];
7086 float *q_tile = q_tiles +
7087 (size_t) local * (
size_t) args->query_tile_size *
7088 (size_t) base->head_dim;
7089 float *kq = kq_tiles +
7090 (size_t) local * (
size_t) args->query_tile_size *
7092 float *vkq = vkq_tiles +
7093 (size_t) local * (
size_t) args->query_tile_size *
7094 (size_t) base->head_dim;
7095 float *sum_row = sum_rows +
7096 (size_t) local * (
size_t) args->query_tile_size;
7097 float *max_row = max_rows +
7098 (size_t) local * (
size_t) args->query_tile_size;
7103 kq, q_tile, shared_k, args->query_tile_size,
7108 for (
int tq = 0; tq < args->query_tile_size; ++tq) {
7110 const int last_valid_key = base->past_tokens + iq + tq;
7112 const int key = ik + tk;
7113 if (tk >= kv_tile || tq >= tile_rows || key > last_valid_key) {
7114 kq_row[tk] = -INFINITY;
7117 const float tile_max =
7119 if (tile_max == -INFINITY) {
7124 const float old_max = max_row[tq];
7125 const float new_max = old_max > tile_max ? old_max : tile_max;
7126 if (new_max > old_max) {
7130 vkq + (
size_t) tq * (
size_t) base->head_dim,
7131 base->head_dim, ms);
7134 max_row[tq] = new_max;
7135 sum_row[tq] = (float) (
7136 (
double) sum_row[tq] +
7141 vkq, kq, shared_v, args->query_tile_size,
7147 for (
int local = 0; local < local_jobs; ++local) {
7148 const int h = local_heads[local];
7149 const int iq = local_iq[local];
7150 const int tile_rows = local_rows[local];
7151 float *vkq = vkq_tiles +
7152 (size_t) local * (
size_t) args->query_tile_size *
7153 (size_t) base->head_dim;
7154 float *sum_row = sum_rows +
7155 (size_t) local * (
size_t) args->query_tile_size;
7156 for (
int tq = 0; tq < tile_rows; ++tq) {
7157 float *out_vec = base->output +
7158 (size_t) h * base->output_head_stride +
7159 (
size_t) (iq + tq) * (
size_t) base->aligned_head_dim;
7160 const float inv_sum =
7161 sum_row[tq] == 0.0f ? 0.0f : 1.0f / sum_row[tq];
7162 for (
int d = 0; d < base->head_dim; ++d) {
7164 (size_t) tq * (
size_t) base->head_dim + (size_t) d] *
7167 for (
int d = base->head_dim; d < base->aligned_head_dim; ++d) {
7177 const uint16_t *k_cache,
7178 const uint16_t *v_cache,
7186 int aligned_head_dim,
7188 size_t q_head_stride,
7189 size_t output_head_stride,
7196 ck_attention_f16_prefill_qtile64_args_t args = {
7201 .num_heads = num_heads,
7202 .num_kv_heads = num_kv_heads,
7203 .q_tokens = q_tokens,
7204 .past_tokens = past_tokens,
7205 .cache_capacity = cache_capacity,
7206 .head_dim = head_dim,
7207 .aligned_head_dim = aligned_head_dim,
7208 .cache_is_bf16 = cache_is_bf16,
7209 .schedule = schedule,
7210 .q_head_stride = q_head_stride,
7211 .output_head_stride = output_head_stride,
7215 const int query_tiles =
7217 int available_jobs = num_heads;
7219 available_jobs = num_kv_heads;
7222 available_jobs = num_heads * query_tiles;
7224 if (active > available_jobs) active = available_jobs;
7236 const uint16_t *k_cache,
7237 const uint16_t *v_cache,
7245 int aligned_head_dim,
7246 int query_tile_size,
7247 int concurrent_query_tiles,
7249 size_t workspace_bytes)
7251 if (!q || !k_cache || !v_cache || !output || !workspace || num_heads <= 0 ||
7252 num_kv_heads <= 0 || num_heads % num_kv_heads != 0 ||
7253 query_tile_size <= 0 || q_tokens < query_tile_size || past_tokens < 0 ||
7254 past_tokens + q_tokens > cache_capacity || head_dim <= 0 ||
7255 aligned_head_dim < head_dim || query_tile_size < 16 ||
7256 query_tile_size > 128 || query_tile_size % 16 != 0 ||
7257 concurrent_query_tiles <= 0 || concurrent_query_tiles > 4) {
7263 if (!pool || active < num_kv_heads || active % num_kv_heads != 0 ||
7267 const size_t required_workspace =
7269 num_heads, num_kv_heads, head_dim, active,
7270 query_tile_size, concurrent_query_tiles);
7271 if (required_workspace == 0 || workspace_bytes < required_workspace) {
7274 const int lanes = active / num_kv_heads;
7275 const size_t tile_elems =
7277 uintptr_t workspace_address = (uintptr_t) workspace;
7278 workspace_address = (workspace_address + 63u) & ~(uintptr_t) 63u;
7279 unsigned char *workspace_base = (
unsigned char *) workspace_address;
7281 float *shared_k_tiles = (
float *) (workspace_base + cursor);
7282 cursor += tile_elems *
sizeof(float);
7284 float *shared_v_tiles = (
float *) (workspace_base + cursor);
7285 cursor += tile_elems *
sizeof(float);
7287 ck_attention_gqa_team_barrier_t *barriers =
7288 (ck_attention_gqa_team_barrier_t *) (workspace_base + cursor);
7289 cursor += (size_t) num_kv_heads *
sizeof(*barriers);
7291 unsigned char *worker_workspace = workspace_base + cursor;
7292 const size_t worker_workspace_stride =
7294 num_heads, num_kv_heads, head_dim, active,
7295 query_tile_size, concurrent_query_tiles);
7296 for (
int group = 0; group < num_kv_heads; ++group) {
7297 __atomic_store_n(&barriers[group].arrived, 0, __ATOMIC_RELAXED);
7298 __atomic_store_n(&barriers[group].phase, 0, __ATOMIC_RELAXED);
7299 barriers[group].lanes = lanes;
7302 ck_attention_f16_prefill_gqa_reuse_args_t args = {
7308 .num_heads = num_heads,
7309 .num_kv_heads = num_kv_heads,
7310 .q_tokens = q_tokens,
7311 .past_tokens = past_tokens,
7312 .cache_capacity = cache_capacity,
7313 .head_dim = head_dim,
7314 .aligned_head_dim = aligned_head_dim,
7318 (size_t) q_tokens * (
size_t) aligned_head_dim,
7319 .output_head_stride =
7320 (size_t) q_tokens * (
size_t) aligned_head_dim,
7322 .shared_k_tiles = shared_k_tiles,
7323 .shared_v_tiles = shared_v_tiles,
7324 .barriers = barriers,
7325 .worker_workspace = worker_workspace,
7326 .worker_workspace_stride = worker_workspace_stride,
7327 .query_tile_size = query_tile_size,
7328 .concurrent_query_tiles = concurrent_query_tiles,
7337 const uint16_t *k_cache,
7338 const uint16_t *v_cache,
7346 int aligned_head_dim,
7348 float *token_workspace,
7349 size_t token_workspace_bytes,
7350 void *gqa_workspace,
7351 size_t gqa_workspace_bytes,
7352 int route_num_heads,
7353 int route_num_kv_heads,
7355 int route_query_tokens,
7356 int route_min_kv_tokens,
7358 int route_query_tile_size,
7359 int route_concurrent_query_tiles)
7361 if (route_num_heads <= 0 || route_num_kv_heads <= 0 ||
7362 route_num_heads % route_num_kv_heads != 0 || route_head_dim <= 0 ||
7363 route_query_tokens <= 0 || route_min_kv_tokens < route_query_tokens ||
7364 route_workers < route_num_kv_heads ||
7365 route_workers % route_num_kv_heads != 0 ||
7366 route_query_tile_size < 16 || route_query_tile_size > 128 ||
7367 route_query_tile_size % 16 != 0 ||
7368 route_concurrent_query_tiles <= 0 ||
7369 route_concurrent_query_tiles > 4) {
7374 const int kv_tokens = past_tokens + q_tokens;
7376 num_heads == route_num_heads && num_kv_heads == route_num_kv_heads &&
7377 head_dim == route_head_dim && aligned_head_dim == route_head_dim &&
7378 q_tokens == route_query_tokens && kv_tokens >= route_min_kv_tokens &&
7379 active == route_workers) {
7381 q, k_cache, v_cache, output, num_heads, num_kv_heads,
7382 q_tokens, past_tokens, cache_capacity, head_dim, aligned_head_dim,
7383 route_query_tile_size, route_concurrent_query_tiles,
7384 gqa_workspace, gqa_workspace_bytes);
7387 q, k_cache, v_cache, output, num_heads, num_kv_heads,
7388 q_tokens, past_tokens, cache_capacity, head_dim, aligned_head_dim,
7389 reduction, token_workspace, token_workspace_bytes);
7394 const uint16_t *k_cache,
7395 const uint16_t *v_cache,
7403 int aligned_head_dim,
7406 if (!q || !k_cache || !v_cache || !output || num_heads <= 0 ||
7408 past_tokens + q_tokens > cache_capacity || head_dim <= 0 ||
7409 aligned_head_dim < head_dim) {
7413 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
7414 past_tokens, cache_capacity, head_dim, aligned_head_dim, 0,
7415 (
size_t) q_tokens * (
size_t) aligned_head_dim,
7416 (
size_t) q_tokens * (
size_t) aligned_head_dim, schedule);
7421 const uint16_t *k_cache,
7422 const uint16_t *v_cache,
7430 int aligned_head_dim,
7432 float *token_workspace,
7433 size_t token_workspace_bytes)
7435 if (!q || !k_cache || !v_cache || !output ||
7436 num_heads <= 0 || num_kv_heads <= 0 || q_tokens <= 0 ||
7437 past_tokens < 0 || past_tokens + q_tokens > cache_capacity ||
7438 head_dim <= 0 || aligned_head_dim < head_dim) {
7449 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
7450 past_tokens, cache_capacity, head_dim, aligned_head_dim, 0,
7451 (
size_t) q_tokens * (
size_t) aligned_head_dim,
7452 (
size_t) q_tokens * (
size_t) aligned_head_dim,
7462 const size_t token_elems = (size_t) num_heads * (
size_t) aligned_head_dim;
7463 if (token_elems > SIZE_MAX / (2 *
sizeof(
float))) {
7466 const size_t required_bytes = 2 * token_elems *
sizeof(float);
7467 if (!token_workspace || token_workspace_bytes < required_bytes) {
7470 float *q_token = token_workspace;
7471 float *out_token = token_workspace + token_elems;
7474 for (
int t = 0; t < q_tokens; ++t) {
7475 for (
int h = 0; h < num_heads; ++h) {
7476 const float *src = q +
7477 ((size_t) h * (
size_t) q_tokens + (size_t) t) * (size_t) aligned_head_dim;
7478 memcpy(q_token + (
size_t) h * (
size_t) aligned_head_dim,
7480 (
size_t) aligned_head_dim *
sizeof(
float));
7484 q_token, k_cache, v_cache, out_token,
7485 num_heads, num_kv_heads, past_tokens + t + 1, cache_capacity,
7486 head_dim, aligned_head_dim, reduction);
7491 for (
int h = 0; h < num_heads; ++h) {
7492 float *dst = output +
7493 ((size_t) h * (
size_t) q_tokens + (size_t) t) * (size_t) aligned_head_dim;
7495 out_token + (
size_t) h * (
size_t) aligned_head_dim,
7496 (
size_t) aligned_head_dim *
sizeof(
float));
7505 const uint16_t *k_cache,
7506 const uint16_t *v_cache,
7514 int aligned_head_dim,
7516 float *token_workspace,
7517 size_t token_workspace_bytes,
7518 const int *segment_lengths,
7522 if (!q || !k_cache || !v_cache || !output || !segment_lengths ||
7523 num_segments <= 0 || num_heads <= 0 || num_kv_heads <= 0 ||
7524 q_tokens <= 0 || past_tokens < 0 || past_tokens + q_tokens > cache_capacity ||
7525 head_dim <= 0 || aligned_head_dim < head_dim) {
7528 int planned_rows = 0;
7529 for (
int s = 0; s < num_segments; ++s) {
7530 if (segment_lengths[s] < 0 || segment_lengths[s] > q_tokens - planned_rows) {
7533 planned_rows += segment_lengths[s];
7537 const size_t head_stride = (size_t) q_tokens * (
size_t) aligned_head_dim;
7538 const size_t token_elems = (size_t) num_heads * (
size_t) aligned_head_dim;
7539 if (!token_workspace || token_workspace_bytes < 2 * token_elems *
sizeof(
float)) {
7544 for (
int s = 0; s < num_segments; ++s) {
7545 const int rows = segment_lengths[s];
7546 if (rows == 0)
continue;
7549 ck_attention_f16_prefill_qtile64_args_t args = {
7550 .q = q + (size_t) row_offset * (
size_t) aligned_head_dim,
7553 .output = output + (size_t) row_offset * (
size_t) aligned_head_dim,
7554 .num_heads = num_heads,
7555 .num_kv_heads = num_kv_heads,
7557 .past_tokens = past_tokens + row_offset,
7558 .cache_capacity = cache_capacity,
7559 .head_dim = head_dim,
7560 .aligned_head_dim = aligned_head_dim,
7562 .schedule = schedule,
7563 .q_head_stride = head_stride,
7564 .output_head_stride = head_stride,
7568 const int query_tiles =
7570 const int available_jobs =
7573 : num_heads * query_tiles;
7574 if (active > available_jobs) active = available_jobs;
7582 float *q_token = token_workspace;
7583 float *out_token = token_workspace + token_elems;
7588 for (
int t = 0; t < rows; ++t) {
7589 for (
int h = 0; h < num_heads; ++h) {
7591 q_token + (
size_t) h * (
size_t) aligned_head_dim,
7592 q + (
size_t) h * head_stride +
7593 (
size_t) (row_offset + t) * (
size_t) aligned_head_dim,
7594 (
size_t) aligned_head_dim *
sizeof(
float));
7598 q_token, k_cache, v_cache, out_token,
7599 num_heads, num_kv_heads, past_tokens + row_offset + t + 1,
7600 cache_capacity, head_dim, aligned_head_dim, selected);
7602 for (
int h = 0; h < num_heads; ++h) {
7604 output + (
size_t) h * head_stride +
7605 (
size_t) (row_offset + t) * (
size_t) aligned_head_dim,
7606 out_token + (
size_t) h * (
size_t) aligned_head_dim,
7607 (
size_t) aligned_head_dim *
sizeof(
float));
7618 const uint16_t *k_cache,
7619 const uint16_t *v_cache,
7627 int aligned_head_dim,
7629 float *token_workspace,
7630 size_t token_workspace_bytes,
7631 const int *segment_lengths,
7635 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
7636 past_tokens, cache_capacity, head_dim, aligned_head_dim, reduction,
7637 token_workspace, token_workspace_bytes, segment_lengths, num_segments,
7643 const uint16_t *k_cache,
7644 const uint16_t *v_cache,
7652 int aligned_head_dim,
7658 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
7659 past_tokens, cache_capacity, head_dim, aligned_head_dim, reduction,
7663 if (num_heads <= 0 || aligned_head_dim <= 0 ||
7664 (
size_t) num_heads > SIZE_MAX / (
size_t) aligned_head_dim) {
7667 const size_t token_elements = (size_t) num_heads * (
size_t) aligned_head_dim;
7668 if (token_elements > SIZE_MAX / (2 *
sizeof(
float))) {
7671 const size_t workspace_bytes = 2 * token_elements *
sizeof(float);
7672 float *workspace = (
float *) malloc(workspace_bytes);
7678 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
7679 past_tokens, cache_capacity, head_dim, aligned_head_dim, reduction,
7680 workspace, workspace_bytes);
7685#if defined(__AVX512F__)
7686typedef void (*ck_mkl_gemm_bf16_fn)(
7687 const char *,
const char *,
const int *,
const int *,
const int *,
7688 const float *,
const uint16_t *,
const int *,
const uint16_t *,
const int *,
7689 const float *,
float *,
const int *);
7690typedef void (*ck_mkl_cblas_sgemm_fn)(
7691 int, int, int, int, int, int, float,
7692 const float *, int,
const float *, int, float,
float *, int);
7693typedef void (*ck_mkl_cblas_sgemm_batch_fn)(
7694 int,
const int *,
const int *,
const int *,
const int *,
const int *,
7695 const float *,
const float **,
const int *,
const float **,
const int *,
7696 const float *,
float **,
const int *, int,
const int *);
7697typedef __m512 (*ck_sleef_expf16_fn)(__m512);
7699static ck_mkl_gemm_bf16_fn ck_pytorch_bf16_gemm = NULL;
7700static ck_mkl_cblas_sgemm_fn ck_pytorch_sgemm = NULL;
7701static ck_mkl_cblas_sgemm_batch_fn ck_pytorch_sgemm_batch = NULL;
7702static ck_sleef_expf16_fn ck_pytorch_attention_expf16 = NULL;
7703static void *ck_pytorch_mkl_handle = NULL;
7704static void *ck_pytorch_attention_sleef_handle = NULL;
7705static pthread_once_t ck_pytorch_attention_once = PTHREAD_ONCE_INIT;
7707static void ck_bind_pytorch_attention_primitives(
void)
7709 const char *mkl_library = getenv(
"CK_MKL_LIBRARY");
7710 if (mkl_library && *mkl_library) {
7711 ck_pytorch_mkl_handle = dlopen(mkl_library, RTLD_NOW | RTLD_LOCAL);
7712 if (ck_pytorch_mkl_handle) {
7713 ck_pytorch_bf16_gemm = (ck_mkl_gemm_bf16_fn)dlsym(
7714 ck_pytorch_mkl_handle,
"gemm_bf16bf16f32");
7715 ck_pytorch_sgemm = (ck_mkl_cblas_sgemm_fn)dlsym(
7716 ck_pytorch_mkl_handle,
"cblas_sgemm");
7717 ck_pytorch_sgemm_batch = (ck_mkl_cblas_sgemm_batch_fn)dlsym(
7718 ck_pytorch_mkl_handle,
"cblas_sgemm_batch");
7721 ck_pytorch_bf16_gemm =
7722 (ck_mkl_gemm_bf16_fn)dlsym(
RTLD_DEFAULT,
"gemm_bf16bf16f32");
7724 (ck_mkl_cblas_sgemm_fn)dlsym(
RTLD_DEFAULT,
"cblas_sgemm");
7725 ck_pytorch_sgemm_batch =
7726 (ck_mkl_cblas_sgemm_batch_fn)dlsym(
RTLD_DEFAULT,
"cblas_sgemm_batch");
7727 if (!ck_pytorch_bf16_gemm || !ck_pytorch_sgemm ||
7728 !ck_pytorch_sgemm_batch) {
7729 mkl_library =
"libmkl_rt.so.2";
7730 ck_pytorch_mkl_handle = dlopen(mkl_library, RTLD_NOW | RTLD_LOCAL);
7731 if (ck_pytorch_mkl_handle) {
7732 ck_pytorch_bf16_gemm = (ck_mkl_gemm_bf16_fn)dlsym(
7733 ck_pytorch_mkl_handle,
"gemm_bf16bf16f32");
7734 ck_pytorch_sgemm = (ck_mkl_cblas_sgemm_fn)dlsym(
7735 ck_pytorch_mkl_handle,
"cblas_sgemm");
7736 ck_pytorch_sgemm_batch = (ck_mkl_cblas_sgemm_batch_fn)dlsym(
7737 ck_pytorch_mkl_handle,
"cblas_sgemm_batch");
7742 const char *sleef_library = getenv(
"CK_SLEEF_LIBRARY");
7743 if (sleef_library && *sleef_library) {
7744 ck_pytorch_attention_sleef_handle =
7745 dlopen(sleef_library, RTLD_NOW | RTLD_LOCAL);
7746 if (ck_pytorch_attention_sleef_handle) {
7747 ck_pytorch_attention_expf16 = (ck_sleef_expf16_fn)dlsym(
7748 ck_pytorch_attention_sleef_handle,
"Sleef_expf16_u10");
7751 ck_pytorch_attention_expf16 =
7752 (ck_sleef_expf16_fn)dlsym(
RTLD_DEFAULT,
"Sleef_expf16_u10");
7756static float ck_pytorch_scale_max_f32(
float *scores,
int count,
float scale)
7758 const __m512 scale_v = _mm512_set1_ps(scale);
7759 __m512 maximum_v = _mm512_set1_ps(-INFINITY);
7761 for (; i + 16 <= count; i += 16) {
7762 __m512 values = _mm512_mul_ps(_mm512_loadu_ps(scores + i), scale_v);
7763 maximum_v = _mm512_max_ps(maximum_v, values);
7764 _mm512_storeu_ps(scores + i, values);
7766 float maximum = _mm512_reduce_max_ps(maximum_v);
7767 for (; i < count; ++i) {
7769 maximum = fmaxf(maximum, scores[i]);
7774static float ck_pytorch_reduce_add_f32x16(__m512 values)
7776 __m512 shuffled = _mm512_shuffle_f32x4(values, values, 0x4e);
7777 values = _mm512_add_ps(values, shuffled);
7778 shuffled = _mm512_shuffle_f32x4(values, values, 0xb1);
7779 values = _mm512_add_ps(values, shuffled);
7780 shuffled = _mm512_shuffle_ps(values, values, 0x4e);
7781 values = _mm512_add_ps(values, shuffled);
7782 shuffled = _mm512_shuffle_ps(values, values, 0xb1);
7783 values = _mm512_add_ps(values, shuffled);
7784 return _mm512_cvtss_f32(values);
7787static inline __m512 ck_pytorch_flash_fexp_u20_f32x16(__m512 values)
7789 const __m512 c0 = _mm512_set1_ps(0.00010703434948458272f);
7790 const __m512 c1 = _mm512_set1_ps(0.30354260500649682f);
7791 const __m512 c2 = _mm512_set1_ps(-0.22433836478672356f);
7792 const __m512 c3 = _mm512_set1_ps(-0.079204240219773236f);
7793 const __m512 log2e = _mm512_castsi512_ps(_mm512_set1_epi32(0x3fb8aa3b));
7794 const __m512 exponent_scale = _mm512_set1_ps(8388608.0f);
7795 const __m512 exponent_bias = _mm512_set1_ps(8388608.0f * 127.0f);
7796 const __m512 min_input =
7797 _mm512_castsi512_ps(_mm512_set1_epi32(0xc2aeac50));
7798 const __m512 max_input =
7799 _mm512_castsi512_ps(_mm512_set1_epi32(0x42b17218));
7801 const __mmask16 below_min =
7802 _mm512_cmp_ps_mask(values, min_input, _CMP_LT_OS);
7803 const __mmask16 above_max =
7804 _mm512_cmp_ps_mask(values, max_input, _CMP_GT_OS);
7805 __m512 base2 = _mm512_mul_ps(values, log2e);
7806 const __m512 fractional = _mm512_sub_ps(base2, _mm512_floor_ps(base2));
7807 __m512 correction = _mm512_fmadd_ps(fractional, c3, c2);
7808 correction = _mm512_fmadd_ps(fractional, correction, c1);
7809 correction = _mm512_fmadd_ps(fractional, correction, c0);
7810 base2 = _mm512_sub_ps(base2, correction);
7811 const __m512 encoded =
7812 _mm512_fmadd_ps(exponent_scale, base2, exponent_bias);
7813 __m512i result = _mm512_cvttps_epi32(encoded);
7814 result = _mm512_mask_mov_epi32(result, below_min, _mm512_setzero_epi32());
7815 result = _mm512_mask_mov_epi32(
7816 result, above_max, _mm512_set1_epi32(0x7f800000));
7817 return _mm512_castsi512_ps(result);
7820static float ck_pytorch_exp_sum_bf16(
7821 float *scores, uint16_t *probabilities,
int count,
float maximum)
7823 const __m512 maximum_v = _mm512_set1_ps(maximum);
7824 __m512 sum_lo_v = _mm512_setzero_ps();
7825 __m512 sum_hi_v = _mm512_setzero_ps();
7826 __m512 sum_tail_v = _mm512_setzero_ps();
7828 for (; i + 32 <= count; i += 32) {
7829 __m512 values_lo = _mm512_sub_ps(
7830 _mm512_loadu_ps(scores + i), maximum_v);
7831 __m512 values_hi = _mm512_sub_ps(
7832 _mm512_loadu_ps(scores + i + 16), maximum_v);
7833 values_lo = ck_pytorch_flash_fexp_u20_f32x16(values_lo);
7834 values_hi = ck_pytorch_flash_fexp_u20_f32x16(values_hi);
7835 sum_lo_v = _mm512_add_ps(sum_lo_v, values_lo);
7836 sum_hi_v = _mm512_add_ps(sum_hi_v, values_hi);
7838 _mm512_store_ps(lanes, values_lo);
7839 for (
int lane = 0; lane < 16; ++lane) {
7842 _mm512_store_ps(lanes, values_hi);
7843 for (
int lane = 0; lane < 16; ++lane) {
7847 for (; i + 16 <= count; i += 16) {
7848 __m512 values = _mm512_sub_ps(_mm512_loadu_ps(scores + i), maximum_v);
7849 values = ck_pytorch_flash_fexp_u20_f32x16(values);
7850 sum_tail_v = _mm512_add_ps(sum_tail_v, values);
7852 _mm512_store_ps(lanes, values);
7853 for (
int lane = 0; lane < 16; ++lane) {
7857 sum_lo_v = _mm512_add_ps(sum_lo_v, sum_tail_v);
7858 float sum = ck_pytorch_reduce_add_f32x16(
7859 _mm512_add_ps(sum_lo_v, sum_hi_v));
7860 for (; i < count; ++i) {
7861 const float value = expf(scores[i] - maximum);
7868static inline float ck_pytorch_reduce_max_f32x16(__m512 value)
7870 __m512 shuffled = _mm512_shuffle_f32x4(value, value, 0x4e);
7871 value = _mm512_max_ps(value, shuffled);
7872 shuffled = _mm512_shuffle_f32x4(value, value, 0xb1);
7873 value = _mm512_max_ps(value, shuffled);
7874 shuffled = _mm512_shuffle_ps(value, value, 0x4e);
7875 value = _mm512_max_ps(value, shuffled);
7876 shuffled = _mm512_shuffle_ps(value, value, 0xb1);
7877 value = _mm512_max_ps(value, shuffled);
7878 return _mm512_cvtss_f32(value);
7881static inline float ck_pytorch_reduce_sum_f32x16(__m512 value)
7883 __m512 shuffled = _mm512_shuffle_f32x4(value, value, 0x4e);
7884 value = _mm512_add_ps(value, shuffled);
7885 shuffled = _mm512_shuffle_f32x4(value, value, 0xb1);
7886 value = _mm512_add_ps(value, shuffled);
7887 shuffled = _mm512_shuffle_ps(value, value, 0x4e);
7888 value = _mm512_add_ps(value, shuffled);
7889 shuffled = _mm512_shuffle_ps(value, value, 0xb1);
7890 value = _mm512_add_ps(value, shuffled);
7891 return _mm512_cvtss_f32(value);
7894static float ck_pytorch_softmax_f32(
float *scores,
int count)
7900 float maximum = scores[0];
7901 for (
int i = 1; i < count; ++i) {
7902 maximum = fmaxf(maximum, scores[i]);
7905 for (
int i = 0; i < count; ++i) {
7906 scores[i] = expf(scores[i] - maximum);
7909 const float reciprocal = 1.0f / sum;
7910 for (
int i = 0; i < count; ++i) {
7911 scores[i] *= reciprocal;
7916 __m512 maximum_v = _mm512_set1_ps(-INFINITY);
7918 for (; i + 16 <= count; i += 16) {
7919 maximum_v = _mm512_max_ps(maximum_v, _mm512_loadu_ps(scores + i));
7922 const __mmask16 tail_mask = (__mmask16)((1u << (count - i)) - 1u);
7923 maximum_v = _mm512_max_ps(
7925 _mm512_mask_loadu_ps(_mm512_set1_ps(-INFINITY), tail_mask, scores + i));
7927 const float maximum = ck_pytorch_reduce_max_f32x16(maximum_v);
7929 const __m512 maximum_broadcast = _mm512_set1_ps(maximum);
7930 __m512 sum_v = _mm512_setzero_ps();
7932 for (; i + 16 <= count; i += 16) {
7933 __m512 values = _mm512_sub_ps(_mm512_loadu_ps(scores + i), maximum_broadcast);
7934 values = ck_pytorch_attention_expf16(values);
7935 _mm512_storeu_ps(scores + i, values);
7936 sum_v = _mm512_add_ps(sum_v, values);
7939 const __mmask16 tail_mask = (__mmask16)((1u << (count - i)) - 1u);
7940 __m512 values = _mm512_mask_loadu_ps(
7941 _mm512_set1_ps(-INFINITY), tail_mask, scores + i);
7942 values = ck_pytorch_attention_expf16(
7943 _mm512_sub_ps(values, maximum_broadcast));
7944 values = _mm512_maskz_mov_ps(tail_mask, values);
7945 _mm512_mask_storeu_ps(scores + i, tail_mask, values);
7946 sum_v = _mm512_add_ps(sum_v, values);
7948 const float sum = ck_pytorch_reduce_sum_f32x16(sum_v);
7950 const float reciprocal = 1.0f / sum;
7951 const __m512 reciprocal_broadcast = _mm512_set1_ps(reciprocal);
7953 for (; i + 16 <= count; i += 16) {
7957 _mm512_loadu_ps(scores + i), reciprocal_broadcast));
7960 const __mmask16 tail_mask = (__mmask16)((1u << (count - i)) - 1u);
7961 const __m512 values = _mm512_maskz_loadu_ps(tail_mask, scores + i);
7962 _mm512_mask_storeu_ps(
7963 scores + i, tail_mask,
7964 _mm512_mul_ps(values, reciprocal_broadcast));
7970 const float *q_token,
7971 const uint16_t *k_cache,
7972 const uint16_t *v_cache,
7979 int aligned_head_dim)
7981 enum { CBLAS_ROW_MAJOR = 101, CBLAS_NO_TRANS = 111, CBLAS_TRANS = 112 };
7982 if (!ck_pytorch_sgemm_batch || !ck_pytorch_attention_expf16) {
7984 "CK BF16 PyTorch GQA math provider requires MKL cblas_sgemm_batch "
7985 "and SLEEF Sleef_expf16_u10\n");
7989 const size_t matrix_count =
7990 (size_t)num_heads * (
size_t)kv_tokens * (size_t)head_dim;
7991 float *k_scaled = (
float *)malloc(matrix_count *
sizeof(
float));
7992 float *v_f32 = (
float *)malloc(matrix_count *
sizeof(
float));
7993 float *scores = (
float *)malloc(
7994 (
size_t)num_heads * (size_t)kv_tokens *
sizeof(
float));
7995 float *q_scaled = (
float *)malloc(
7996 (
size_t)num_heads * (size_t)head_dim *
sizeof(
float));
7997 float *destination = (
float *)malloc(
7998 (
size_t)num_heads * (size_t)head_dim *
sizeof(
float));
7999 const float **q_batch = (
const float **)malloc(
8000 (
size_t)num_heads *
sizeof(*q_batch));
8001 const float **k_batch = (
const float **)malloc(
8002 (
size_t)num_heads *
sizeof(*k_batch));
8003 float **score_batch = (
float **)malloc(
8004 (
size_t)num_heads *
sizeof(*score_batch));
8005 const float **probability_batch = (
const float **)malloc(
8006 (
size_t)num_heads *
sizeof(*probability_batch));
8007 const float **v_batch = (
const float **)malloc(
8008 (
size_t)num_heads *
sizeof(*v_batch));
8009 float **destination_batch = (
float **)malloc(
8010 (
size_t)num_heads *
sizeof(*destination_batch));
8011 if (!k_scaled || !v_f32 || !scores || !q_scaled || !destination ||
8012 !q_batch || !k_batch || !score_batch || !probability_batch ||
8013 !v_batch || !destination_batch) {
8014 free(destination_batch);
8016 free(probability_batch);
8031 const float split_scale = (float)sqrt(sqrt(1.0 / (
double)head_dim));
8032 const size_t cache_head_stride =
8033 (size_t)cache_capacity * (
size_t)aligned_head_dim;
8034 const int heads_per_kv = num_heads / num_kv_heads;
8036 for (
int h = 0; h < num_heads; ++h) {
8037 const int kv_head = h / heads_per_kv;
8038 const uint16_t *k_head = k_cache + (size_t)kv_head * cache_head_stride;
8039 const uint16_t *v_head = v_cache + (size_t)kv_head * cache_head_stride;
8040 float *k_repeated = k_scaled +
8041 (size_t)h * (
size_t)kv_tokens * (size_t)head_dim;
8042 float *v_repeated = v_f32 +
8043 (size_t)h * (
size_t)kv_tokens * (size_t)head_dim;
8045 for (
int d = 0; d < head_dim; ++d) {
8046 const size_t compact = (size_t)
token * (
size_t)head_dim + (size_t)d;
8047 const size_t cached =
8048 (size_t)
token * (
size_t)aligned_head_dim + (size_t)d;
8049 k_repeated[compact] =
bf16_to_float(k_head[cached]) * split_scale;
8054 const float *q_head = q_token + (size_t)h * (
size_t)aligned_head_dim;
8055 float *q_row = q_scaled + (size_t)h * (
size_t)head_dim;
8056 for (
int d = 0; d < head_dim; ++d) {
8060 k_batch[h] = k_repeated;
8061 score_batch[h] = scores + (size_t)h * (
size_t)kv_tokens;
8062 probability_batch[h] = score_batch[h];
8063 v_batch[h] = v_repeated;
8064 destination_batch[h] = destination + (size_t)h * (
size_t)head_dim;
8067 const int group_count = 1;
8068 const int group_size = num_heads;
8069 const float alpha = 1.0f;
8070 const float beta = 0.0f;
8071 int transpose_a = CBLAS_NO_TRANS;
8072 int transpose_b = CBLAS_TRANS;
8078 int ldc = kv_tokens;
8079 ck_pytorch_sgemm_batch(
8080 CBLAS_ROW_MAJOR, &transpose_a, &transpose_b, &m, &n, &k,
8081 &alpha, q_batch, &lda, k_batch, &ldb, &beta, score_batch, &ldc,
8082 group_count, &group_size);
8084 for (
int h = 0; h < num_heads; ++h) {
8085 (void)ck_pytorch_softmax_f32(score_batch[h], kv_tokens);
8088 transpose_b = CBLAS_NO_TRANS;
8094 ck_pytorch_sgemm_batch(
8095 CBLAS_ROW_MAJOR, &transpose_a, &transpose_b, &m, &n, &k,
8096 &alpha, probability_batch, &lda, v_batch, &ldb,
8097 &beta, destination_batch, &ldc, group_count, &group_size);
8099 for (
int h = 0; h < num_heads; ++h) {
8100 float *out_head = out_token + (size_t)h * (
size_t)aligned_head_dim;
8101 const float *source = destination + (size_t)h * (
size_t)head_dim;
8102 for (
int d = 0; d < head_dim; ++d) {
8105 for (
int d = head_dim; d < aligned_head_dim; ++d) out_head[d] = 0.0f;
8108 free(destination_batch);
8110 free(probability_batch);
8124 const uint16_t *k_cache,
8125 const uint16_t *v_cache,
8133 int aligned_head_dim)
8135 enum { CBLAS_ROW_MAJOR = 101, CBLAS_NO_TRANS = 111, CBLAS_TRANS = 112 };
8136 if (!ck_pytorch_sgemm_batch || !ck_pytorch_attention_expf16) {
8138 "CK BF16 PyTorch full-matrix provider requires MKL "
8139 "cblas_sgemm_batch and SLEEF Sleef_expf16_u10\n");
8143 const int kv_tokens = past_tokens + q_tokens;
8144 const size_t q_matrix_count =
8145 (size_t)num_heads * (
size_t)q_tokens * (size_t)head_dim;
8146 const size_t kv_matrix_count =
8147 (size_t)num_heads * (
size_t)kv_tokens * (size_t)head_dim;
8148 const size_t score_count =
8149 (size_t)num_heads * (
size_t)q_tokens * (size_t)kv_tokens;
8150 float *q_scaled = (
float *)malloc(q_matrix_count *
sizeof(
float));
8151 float *k_scaled = (
float *)malloc(kv_matrix_count *
sizeof(
float));
8152 float *v_f32 = (
float *)malloc(kv_matrix_count *
sizeof(
float));
8153 float *scores = (
float *)malloc(score_count *
sizeof(
float));
8154 float *destination = (
float *)malloc(q_matrix_count *
sizeof(
float));
8155 const float **q_batch =
8156 (
const float **)malloc((
size_t)num_heads *
sizeof(*q_batch));
8157 const float **k_batch =
8158 (
const float **)malloc((
size_t)num_heads *
sizeof(*k_batch));
8159 float **score_batch =
8160 (
float **)malloc((
size_t)num_heads *
sizeof(*score_batch));
8161 const float **probability_batch =
8162 (
const float **)malloc((
size_t)num_heads *
sizeof(*probability_batch));
8163 const float **v_batch =
8164 (
const float **)malloc((
size_t)num_heads *
sizeof(*v_batch));
8165 float **destination_batch =
8166 (
float **)malloc((
size_t)num_heads *
sizeof(*destination_batch));
8167 if (!q_scaled || !k_scaled || !v_f32 || !scores || !destination ||
8168 !q_batch || !k_batch || !score_batch || !probability_batch ||
8169 !v_batch || !destination_batch) {
8170 free(destination_batch);
8172 free(probability_batch);
8184 const float split_scale = (float)sqrt(sqrt(1.0 / (
double)head_dim));
8185 const size_t cache_head_stride =
8186 (size_t)cache_capacity * (
size_t)aligned_head_dim;
8187 const int heads_per_kv = num_heads / num_kv_heads;
8188 for (
int h = 0; h < num_heads; ++h) {
8189 const int kv_head = h / heads_per_kv;
8190 const uint16_t *k_head =
8191 k_cache + (size_t)kv_head * cache_head_stride;
8192 const uint16_t *v_head =
8193 v_cache + (size_t)kv_head * cache_head_stride;
8195 q_scaled + (size_t)h * (
size_t)q_tokens * (size_t)head_dim;
8197 k_scaled + (size_t)h * (
size_t)kv_tokens * (size_t)head_dim;
8199 v_f32 + (size_t)h * (
size_t)kv_tokens * (size_t)head_dim;
8201 const float *q_row = q +
8202 ((size_t)h * (
size_t)q_tokens + (size_t)
token) *
8203 (size_t)aligned_head_dim;
8205 q_head + (size_t)
token * (
size_t)head_dim;
8206 for (
int d = 0; d < head_dim; ++d) {
8212 const uint16_t *k_row =
8213 k_head + (size_t)
token * (
size_t)aligned_head_dim;
8214 const uint16_t *v_row =
8215 v_head + (size_t)
token * (
size_t)aligned_head_dim;
8217 k_head_f32 + (size_t)
token * (
size_t)head_dim;
8219 v_head_f32 + (size_t)
token * (
size_t)head_dim;
8220 for (
int d = 0; d < head_dim; ++d) {
8225 q_batch[h] = q_head;
8226 k_batch[h] = k_head_f32;
8228 scores + (size_t)h * (
size_t)q_tokens * (size_t)kv_tokens;
8229 probability_batch[h] = score_batch[h];
8230 v_batch[h] = v_head_f32;
8231 destination_batch[h] =
8232 destination + (size_t)h * (
size_t)q_tokens * (size_t)head_dim;
8235 const int group_count = 1;
8236 const int group_size = num_heads;
8237 const float alpha = 1.0f;
8238 const float beta = 0.0f;
8239 int transpose_a = CBLAS_NO_TRANS;
8240 int transpose_b = CBLAS_TRANS;
8246 int ldc = kv_tokens;
8247 ck_pytorch_sgemm_batch(
8248 CBLAS_ROW_MAJOR, &transpose_a, &transpose_b, &m, &n, &k,
8249 &alpha, q_batch, &lda, k_batch, &ldb, &beta, score_batch, &ldc,
8250 group_count, &group_size);
8255 for (
int h = 0; h < num_heads; ++h) {
8256 float *score_head = score_batch[h];
8259 score_head + (size_t)
token * (
size_t)kv_tokens;
8260 const int valid = past_tokens +
token + 1;
8261 for (
int key_token = valid; key_token < kv_tokens; ++key_token) {
8262 score_row[key_token] = -INFINITY;
8264 (void)ck_pytorch_softmax_f32(score_row, kv_tokens);
8268 transpose_b = CBLAS_NO_TRANS;
8274 ck_pytorch_sgemm_batch(
8275 CBLAS_ROW_MAJOR, &transpose_a, &transpose_b, &m, &n, &k,
8276 &alpha, probability_batch, &lda, v_batch, &ldb,
8277 &beta, destination_batch, &ldc, group_count, &group_size);
8279 for (
int h = 0; h < num_heads; ++h) {
8280 const float *source =
8281 destination + (size_t)h * (
size_t)q_tokens * (size_t)head_dim;
8283 float *out_row = output +
8284 ((size_t)h * (
size_t)q_tokens + (size_t)
token) *
8285 (size_t)aligned_head_dim;
8286 const float *source_row =
8287 source + (size_t)
token * (
size_t)head_dim;
8288 for (
int d = 0; d < head_dim; ++d) {
8292 for (
int d = head_dim; d < aligned_head_dim; ++d) {
8298 free(destination_batch);
8300 free(probability_batch);
8313 const float *q_token,
8314 const uint16_t *k_cache,
8315 const uint16_t *v_cache,
8317 const float *selected_indices,
8318 int selection_width,
8324 int aligned_head_dim)
8326 enum { CK_PYTORCH_KV_SPLIT = 512, CK_PYTORCH_MAX_HEAD_DIM = 512 };
8327 if (head_dim > CK_PYTORCH_MAX_HEAD_DIM || aligned_head_dim > CK_PYTORCH_MAX_HEAD_DIM) {
8330 pthread_once(&ck_pytorch_attention_once, ck_bind_pytorch_attention_primitives);
8331 if (!ck_pytorch_bf16_gemm || !ck_pytorch_attention_expf16) {
8333 "CK BF16 PyTorch SDPA provider requires MKL gemm_bf16bf16f32 "
8334 "and SLEEF Sleef_expf16_u10; set CK_MKL_LIBRARY and "
8335 "CK_SLEEF_LIBRARY\n");
8339 const float scale = 1.0f / sqrtf((
float)head_dim);
8340 const size_t head_stride = (size_t)cache_capacity * (
size_t)aligned_head_dim;
8341 for (
int h = 0; h < num_heads; ++h) {
8342 const int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
8343 const float *q_head = q_token + (size_t)h * (
size_t)aligned_head_dim;
8344 const uint16_t *k_head = k_cache + (size_t)kv_head * head_stride;
8345 const uint16_t *v_head = v_cache + (size_t)kv_head * head_stride;
8346 float *out_head = out_token + (size_t)h * (
size_t)aligned_head_dim;
8347 uint16_t q_bf16[CK_PYTORCH_MAX_HEAD_DIM]
__attribute__((aligned(64)));
8348 uint16_t probabilities[CK_PYTORCH_KV_SPLIT]
__attribute__((aligned(64)));
8349 float scores[CK_PYTORCH_KV_SPLIT]
__attribute__((aligned(64)));
8350 float destination[CK_PYTORCH_MAX_HEAD_DIM]
__attribute__((aligned(64)));
8351 for (
int d = 0; d < head_dim; ++d) q_bf16[d] =
float_to_bf16(q_head[d]);
8353 float running_max = -INFINITY;
8354 float running_sum = 0.0f;
8355 int has_destination = 0;
8356 for (
int start = 0;
start < kv_tokens;
start += CK_PYTORCH_KV_SPLIT) {
8357 const int block = kv_tokens -
start < CK_PYTORCH_KV_SPLIT
8358 ? kv_tokens -
start : CK_PYTORCH_KV_SPLIT;
8359 const char transpose =
'T';
8360 const char no_transpose =
'N';
8362 const float one_f = 1.0f;
8363 const float zero_f = 0.0f;
8364 ck_pytorch_bf16_gemm(
8365 &transpose, &no_transpose, &block, &one, &head_dim,
8366 &one_f, k_head + (
size_t)
start * (
size_t)aligned_head_dim,
8367 &aligned_head_dim, q_bf16, &aligned_head_dim,
8368 &zero_f, scores, &block);
8370 if (selected_indices) {
8373 while (cursor < selection_width &&
8374 (
int)selected_indices[cursor] <
start) {
8379 while (cursor < selection_width &&
8380 selected_indices[cursor] >= 0.0f &&
8381 (
int)selected_indices[cursor] < absolute_token) {
8384 if (cursor < selection_width &&
8385 (
int)selected_indices[cursor] == absolute_token) {
8389 scores[
token] = -INFINITY;
8392 if (selected == 0 && !has_destination)
continue;
8395 const float block_max = ck_pytorch_scale_max_f32(scores, block, scale);
8396 const float maximum = running_max > block_max ? running_max : block_max;
8397 const float block_sum = ck_pytorch_exp_sum_bf16(
8398 scores, probabilities, block, maximum);
8399 const float previous_scale = expf(running_max - maximum);
8400 running_sum = block_sum + previous_scale * running_sum;
8401 if (has_destination) {
8402 const __m512 previous_scale_v = _mm512_set1_ps(previous_scale);
8404 for (; d + 16 <= head_dim; d += 16) {
8407 _mm512_mul_ps(_mm512_loadu_ps(destination + d), previous_scale_v));
8409 for (; d < head_dim; ++d) destination[d] *= previous_scale;
8411 const float beta = has_destination ? 1.0f : 0.0f;
8412 ck_pytorch_bf16_gemm(
8413 &no_transpose, &no_transpose, &head_dim, &one, &block,
8414 &one_f, v_head + (
size_t)
start * (
size_t)aligned_head_dim,
8415 &aligned_head_dim, probabilities, &block,
8416 &beta, destination, &head_dim);
8417 running_max = maximum;
8418 has_destination = 1;
8421 if (!has_destination) {
8424 const float reciprocal = running_sum != 0.0f ? 1.0f / running_sum : 1.0f;
8425 for (
int d = 0; d < head_dim; ++d) {
8428 for (
int d = head_dim; d < aligned_head_dim; ++d) out_head[d] = 0.0f;
8434 const float *q_token,
8435 const uint16_t *k_cache,
8436 const uint16_t *v_cache,
8443 int aligned_head_dim)
8445 return ck_attention_decode_bf16_pytorch_cpu_flash_masked(
8446 q_token, k_cache, v_cache, out_token, NULL, 0,
8447 num_heads, num_kv_heads, kv_tokens, cache_capacity,
8448 head_dim, aligned_head_dim);
8454 const uint16_t *key_cache,
8455 const uint16_t *value_cache,
8456 const float *selected_indices,
8458 float *score_scratch,
8463 int selection_width,
8467 (void)score_scratch;
8468 if (!query || !key_cache || !value_cache || !selected_indices || !output ||
8469 rows <= 0 || query_heads <= 0 || kv_heads <= 0 || head_dim <= 0 ||
8470 selection_width <= 0 || context_length <= 0 || position < 0 ||
8471 position + rows > context_length || query_heads % kv_heads != 0) {
8472 fprintf(stderr,
"CK sparse BF16 CPU-flash attention: invalid contract\n");
8476#if defined(__AVX512F__)
8477 for (
int row = 0; row < rows; ++row) {
8478 const int visible_tokens = position + row + 1;
8480 ck_attention_decode_bf16_pytorch_cpu_flash_masked(
8481 query + (
size_t)row * (
size_t)query_heads * (
size_t)head_dim,
8482 key_cache, value_cache,
8483 output + (
size_t)row * (
size_t)query_heads * (
size_t)head_dim,
8484 selected_indices + (
size_t)row * (
size_t)selection_width,
8485 selection_width, query_heads, kv_heads, visible_tokens,
8486 context_length, head_dim, head_dim);
8489 "CK sparse BF16 CPU-flash attention unavailable (status=%d)\n",
8496 "CK sparse BF16 CPU-flash attention requires AVX-512F; "
8497 "no numerically different fallback is permitted\n");
8504#if defined(__AVX512F__)
8513#if defined(__AVX512F__)
8514 pthread_once(&ck_pytorch_attention_once, ck_bind_pytorch_attention_primitives);
8515 return ck_pytorch_sgemm_batch != NULL &&
8516 ck_pytorch_attention_expf16 != NULL;
8523 const float *q_token,
8524 const uint16_t *k_cache,
8525 const uint16_t *v_cache,
8532 int aligned_head_dim,
8535 if (!q_token || !k_cache || !v_cache || !out_token ||
8536 num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 ||
8537 cache_capacity <= 0 || kv_tokens > cache_capacity ||
8538 head_dim <= 0 || aligned_head_dim < head_dim ||
8539 num_heads % num_kv_heads != 0) {
8546#if defined(__AVX512F__)
8547 pthread_once(&ck_pytorch_attention_once, ck_bind_pytorch_attention_primitives);
8548 return ck_attention_decode_bf16_pytorch_math_gqa(
8549 q_token, k_cache, v_cache, out_token, num_heads, num_kv_heads,
8550 kv_tokens, cache_capacity, head_dim, aligned_head_dim);
8552 const float scale = 1.0f / sqrtf((
float)head_dim);
8553 const size_t head_stride = (size_t)cache_capacity * (
size_t)aligned_head_dim;
8554 for (
int h = 0; h < num_heads; ++h) {
8555 const int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
8556 const float *q_head = q_token + (size_t)h * (
size_t)aligned_head_dim;
8557 const uint16_t *k_head = k_cache + (size_t)kv_head * head_stride;
8558 const uint16_t *v_head = v_cache + (size_t)kv_head * head_stride;
8559 float *out_head = out_token + (size_t)h * (
size_t)aligned_head_dim;
8561 float maximum = -INFINITY;
8563 const uint16_t *k_row = k_head + (size_t)
token * (
size_t)aligned_head_dim;
8565 for (
int d = 0; d < head_dim; ++d) {
8568 const float score = dot * scale;
8572 for (
int d = 0; d < aligned_head_dim; ++d) out_head[d] = 0.0f;
8573 float denominator = 0.0f;
8575 const uint16_t *k_row = k_head + (size_t)
token * (
size_t)aligned_head_dim;
8576 const uint16_t *v_row = v_head + (size_t)
token * (
size_t)aligned_head_dim;
8578 for (
int d = 0; d < head_dim; ++d) {
8581 const float probability = expf(dot * scale - maximum);
8582 denominator += probability;
8583 for (
int d = 0; d < head_dim; ++d) {
8584 out_head[d] = fmaf(probability,
bf16_to_float(v_row[d]), out_head[d]);
8587 const float inverse = denominator > 0.0f ? 1.0f / denominator : 0.0f;
8588 for (
int d = 0; d < head_dim; ++d) {
8598 const uint16_t *k_cache,
8599 const uint16_t *v_cache,
8607 int aligned_head_dim,
8609 float *token_workspace,
8610 size_t token_workspace_bytes)
8612 if (!q || !k_cache || !v_cache || !output ||
8613 num_heads <= 0 || num_kv_heads <= 0 || q_tokens <= 0 ||
8614 past_tokens < 0 || past_tokens + q_tokens > cache_capacity ||
8615 head_dim <= 0 || aligned_head_dim < head_dim) {
8623 ck_attention_f16_prefill_qtile64_args_t args = {
8624 .q = q, .k_cache = k_cache, .v_cache = v_cache, .output = output,
8625 .num_heads = num_heads, .num_kv_heads = num_kv_heads,
8626 .q_tokens = q_tokens, .past_tokens = past_tokens,
8627 .cache_capacity = cache_capacity, .head_dim = head_dim,
8628 .aligned_head_dim = aligned_head_dim, .cache_is_bf16 = 1,
8632 if (active > num_kv_heads) active = num_kv_heads;
8638 const size_t count = (size_t)num_heads * (
size_t)q_tokens * (size_t)aligned_head_dim;
8639 for (
size_t i = 0; i < count; ++i) {
8645 const size_t token_elems = (size_t)num_heads * (
size_t)aligned_head_dim;
8646 if (token_elems > SIZE_MAX / (2 *
sizeof(
float)) ||
8647 !token_workspace || token_workspace_bytes < 2 * token_elems *
sizeof(float)) {
8650 float *q_token = token_workspace;
8651 float *out_token = token_workspace + token_elems;
8653 for (
int t = 0; t < q_tokens; ++t) {
8654 for (
int h = 0; h < num_heads; ++h) {
8655 memcpy(q_token + (
size_t)h * (
size_t)aligned_head_dim,
8656 q + ((
size_t)h * (
size_t)q_tokens + (
size_t)t) * (
size_t)aligned_head_dim,
8657 (
size_t)aligned_head_dim *
sizeof(
float));
8660 q_token, k_cache, v_cache, out_token,
8661 num_heads, num_kv_heads, past_tokens + t + 1, cache_capacity,
8662 head_dim, aligned_head_dim, reduction);
8664 for (
int h = 0; h < num_heads; ++h) {
8665 memcpy(output + ((
size_t)h * (
size_t)q_tokens + (
size_t)t) * (
size_t)aligned_head_dim,
8666 out_token + (
size_t)h * (
size_t)aligned_head_dim,
8667 (
size_t)aligned_head_dim *
sizeof(
float));
8675 const uint16_t *k_cache,
8676 const uint16_t *v_cache,
8684 int aligned_head_dim,
8689 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
8690 past_tokens, cache_capacity, head_dim, aligned_head_dim, reduction,
8693 if (num_heads <= 0 || aligned_head_dim <= 0 ||
8694 (
size_t) num_heads > SIZE_MAX / (
size_t) aligned_head_dim) {
8697 const size_t token_elements = (size_t) num_heads * (
size_t) aligned_head_dim;
8698 if (token_elements > SIZE_MAX / (2 *
sizeof(
float))) {
8701 const size_t workspace_bytes = 2 * token_elements *
sizeof(float);
8702 float *workspace = (
float *) malloc(workspace_bytes);
8706 q, k_cache, v_cache, output, num_heads, num_kv_heads, q_tokens,
8707 past_tokens, cache_capacity, head_dim, aligned_head_dim, reduction,
8708 workspace, workspace_bytes);
8715 const uint16_t *k_cache,
8716 const uint16_t *v_cache,
8724 int aligned_head_dim,
8727 if (!q || !k_cache || !v_cache || !output ||
8728 num_heads <= 0 || num_kv_heads <= 0 ||
8729 num_heads % num_kv_heads != 0 ||
8730 q_tokens <= 0 || past_tokens < 0 ||
8731 past_tokens + q_tokens > cache_capacity ||
8732 head_dim <= 0 || aligned_head_dim < head_dim) {
8739#if defined(__AVX512F__)
8740 pthread_once(&ck_pytorch_attention_once, ck_bind_pytorch_attention_primitives);
8741 return ck_attention_prefill_bf16_pytorch_math_gqa_full(
8742 q, k_cache, v_cache, output,
8743 num_heads, num_kv_heads, q_tokens, past_tokens, cache_capacity,
8744 head_dim, aligned_head_dim);
8751 const uint16_t *k_cache,
8752 const uint16_t *v_cache,
8759 int aligned_head_dim)
8761 if (!q_token || !k_cache || !v_cache || !out_token) {
8764 if (num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
8767 if (kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
8771 const float scale = 1.0f / sqrtf((
float)head_dim);
8772 const size_t head_stride = (size_t)cache_capacity * (
size_t)aligned_head_dim;
8773 const size_t scratch_elems = (size_t)kv_tokens * (
size_t)aligned_head_dim;
8774 const size_t scratch_bytes = scratch_elems *
sizeof(float);
8775 const size_t max_stack_bytes = 1024u * 1024u;
8777 if (scratch_bytes * 2u > max_stack_bytes) {
8778 for (
int h = 0; h < num_heads; ++h) {
8779 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
8780 const float *q_head = q_token + (size_t)h * (
size_t)aligned_head_dim;
8781 const uint16_t *k_head = k_cache + (size_t)kv_head * head_stride;
8782 const uint16_t *v_head = v_cache + (size_t)kv_head * head_stride;
8783 float *out_head = out_token + (size_t)h * (
size_t)aligned_head_dim;
8785 for (
int d = 0; d < aligned_head_dim; ++d) {
8789 float max_score = -INFINITY;
8790 for (
int j = 0; j < kv_tokens; ++j) {
8791 const uint16_t *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
8793 for (
int d = 0; d < head_dim; ++d) {
8796 const float score = dot * scale;
8797 if (
score > max_score) {
8803 for (
int j = 0; j < kv_tokens; ++j) {
8804 const uint16_t *k_vec = k_head + (size_t)j * (
size_t)aligned_head_dim;
8805 const uint16_t *v_vec = v_head + (size_t)j * (
size_t)aligned_head_dim;
8807 for (
int d = 0; d < head_dim; ++d) {
8810 const float w = expf(dot * scale - max_score);
8812 for (
int d = 0; d < head_dim; ++d) {
8818 const float inv_sum = 1.0f / sum;
8819 for (
int d = 0; d < head_dim; ++d) {
8820 out_head[d] *= inv_sum;
8823 for (
int d = head_dim; d < aligned_head_dim; ++d) {
8830 float *k_head_fp32 = (
float *)alloca(scratch_bytes);
8831 float *v_head_fp32 = (
float *)alloca(scratch_bytes);
8833 for (
int kv_head = 0; kv_head < num_kv_heads; ++kv_head) {
8834 const uint16_t *k_head = k_cache + (size_t)kv_head * head_stride;
8835 const uint16_t *v_head = v_cache + (size_t)kv_head * head_stride;
8836 const int q_begin = (int)((
long long)kv_head * (
long long)num_heads / (
long long)num_kv_heads);
8837 const int q_end = (int)((
long long)(kv_head + 1) * (
long long)num_heads / (
long long)num_kv_heads);
8842 for (
int h = q_begin; h < q_end; ++h) {
8843 const float *q_head = q_token + (size_t)h * (
size_t)aligned_head_dim;
8844 float *out_head = out_token + (size_t)h * (
size_t)aligned_head_dim;
8874 const float *k_cache,
8875 const float *v_cache,
8882 int aligned_head_dim)
8884 if (!q_token || !k_cache || !v_cache || !out_token) {
8887 if (num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
8890 if (kv_tokens > cache_capacity) {
8895 const float scale = strict
8897 : 1.0f / sqrtf((
float) head_dim);
8898 const size_t head_stride = (size_t)cache_capacity * (
size_t)aligned_head_dim;
8901#if defined(__AVX512F__)
8902 #define FLASH_QUERY_IMPL_DECODE attention_flash_query_causal_avx512
8903#elif defined(__AVX2__)
8904 #define FLASH_QUERY_IMPL_DECODE attention_flash_query_causal_avx2
8905#elif defined(__AVX__)
8906 #define FLASH_QUERY_IMPL_DECODE attention_flash_query_causal_avx
8908 #define FLASH_QUERY_IMPL_DECODE attention_flash_query_causal
8911#pragma omp parallel for schedule(static) if(num_heads > 1)
8912 for (
int h = 0; h < num_heads; ++h) {
8913 int kv_head = (int)((
long long)h * (
long long)num_kv_heads / (
long long)num_heads);
8914 const float *q_vec = q_token + (size_t)h * (
size_t)aligned_head_dim;
8915 const float *k_head = k_cache + (size_t)kv_head * head_stride;
8916 const float *v_head = v_cache + (size_t)kv_head * head_stride;
8917 float *out_vec = out_token + (size_t)h * (
size_t)aligned_head_dim;
8932 kv_tokens, head_dim, aligned_head_dim,
8936#undef FLASH_QUERY_IMPL_DECODE
8984 const uint16_t *d_output,
8989 const float *attn_weights,
8998 int aligned_head_dim,
8999 int aligned_context_window,
9000 float *scratch_d_output,
9006 const size_t head_elems = (size_t)num_heads * (
size_t)num_tokens * (size_t)aligned_head_dim;
9007 const size_t kv_elems = (size_t)num_kv_heads * (
size_t)num_tokens * (size_t)aligned_head_dim;
9009 if (!scratch_d_output || !scratch_q || !scratch_k || !scratch_v)
return;
9018 d_q, d_k, d_v, d_scores,
9019 num_heads, num_kv_heads,
9020 num_tokens, head_dim,
9021 aligned_head_dim, aligned_context_window);
9037 const float *d_output,
9041 const float *attn_weights,
9050 int aligned_head_dim,
9051 int aligned_context_window)
9053 const float scale = 1.0f / sqrtf((
float)head_dim);
9056 int H_kv = num_kv_heads;
9058 int ad = aligned_head_dim;
9059 int aw = aligned_context_window;
9061 const size_t d_q_elems = (size_t)H * (
size_t)T * (size_t)ad;
9062 const size_t kv_elems = (size_t)H_kv * (
size_t)T * (size_t)ad;
9064 for (
size_t idx = 0; idx < d_q_elems; ++idx) {
9067 for (
size_t idx = 0; idx < kv_elems; ++idx) {
9073 for (
int h = 0; h < H; ++h) {
9075 int kv_h = (int)((
long long)h * (
long long)H_kv / (
long long)H);
9083 for (
int i = 0; i < T; ++i) {
9084 size_t d_out_base =
qkv_index(h, i, 0, T, ad);
9086 for (
int j = 0; j <= i; ++j) {
9087 size_t v_base =
qkv_index(kv_h, j, 0, T, ad);
9089 float w = attn_weights[w_idx];
9093 for (
int dd = 0; dd < hd; ++dd) {
9094 dot += d_output[d_out_base + dd] * v[v_base + dd];
9096 d_scores[w_idx] = dot;
9099 for (
int dd = 0; dd < hd; ++dd) {
9100 d_v[v_base + dd] += w * d_output[d_out_base + dd];
9105 for (
int j = i + 1; j < T; ++j) {
9109 for (
int j = T; j < aw; ++j) {
9120 for (
int i = 0; i < T; ++i) {
9121 int base = h * aw * aw + i * aw;
9124 float dot_product = 0.0f;
9125 for (
int j = 0; j <= i; ++j) {
9126 float wt = attn_weights[base + j];
9127 float dw = d_scores[base + j];
9128 dot_product += wt * dw;
9132 for (
int j = 0; j <= i; ++j) {
9133 float wt = attn_weights[base + j];
9134 float dw = d_scores[base + j];
9135 d_scores[base + j] = wt * (dw - dot_product);
9144 for (
int i = 0; i < T; ++i) {
9145 size_t d_q_base =
qkv_index(h, i, 0, T, ad);
9146 size_t q_base =
qkv_index(h, i, 0, T, ad);
9150 for (
int j = 0; j <= i; ++j) {
9151 size_t k_base =
qkv_index(kv_h, j, 0, T, ad);
9152 size_t d_k_base =
qkv_index(kv_h, j, 0, T, ad);
9153 float ds = d_scores[
score_index(h, i, j, aw)] * scale;
9155 for (
int dd = 0; dd < hd; ++dd) {
9156 d_q[d_q_base + dd] += ds * k[k_base + dd];
9157 d_k[d_k_base + dd] += ds * q[q_base + dd];
9176 const float *d_output,
9180 const float *attn_weights,
9188 int aligned_head_dim,
9189 int aligned_context_window)
9192 d_output, q, k, v, attn_weights,
9193 d_q, d_k, d_v, d_scores,
9194 num_heads, num_heads,
9195 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)
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)
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
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)
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 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)
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)
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)
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_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)
static int ck_attention_reverse_out_dot_enabled(void)
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)
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)
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)
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, size_t q_head_stride, size_t output_head_stride, ck_attention_prefill_schedule_t schedule)
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
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)
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)
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)
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
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 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 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.
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_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)