33 fprintf(stderr,
"HARD KERNEL CONTRACT FAULT: PyTorch oneDNN BF16 BRGEMM %s "
34 "(M=%d N=%d K=%d)\n", message, M, N, K);
43#if defined(__AVX512F__)
47#if defined(__linux__) && defined(__AMX_TILE__)
48#include <sys/syscall.h>
65static inline int ck_min_i(
int a,
int b) {
return a < b ? a : b; }
72static void gemm_bf16_scalar(
const uint16_t *A,
78 for (
int i = 0; i < M; ++i) {
79 for (
int j = 0; j < N; ++j) {
81 const size_t a_row = (size_t)i * (
size_t)K;
82 const size_t b_row = (size_t)j * (
size_t)K;
83 for (
int k = 0; k < K; ++k) {
90#if defined(__AVX512F__)
101static inline __m512 bf16_dot16(__m256i a_bf16, __m256i b_bf16, __m512 acc)
103 __m512 a_fp32 = bf16x16_to_fp32(a_bf16);
104 __m512 b_fp32 = bf16x16_to_fp32(b_bf16);
105 return _mm512_fmadd_ps(a_fp32, b_fp32, acc);
112static void gemm_bf16_avx512(
const uint16_t *A,
114 const uint16_t *bias,
118 #pragma omp parallel for schedule(dynamic)
119 for (
int i = 0; i < M; ++i) {
120 const uint16_t *a_row = A + (size_t)i * K;
122 for (
int j = 0; j < N; ++j) {
123 const uint16_t *b_row = B + (size_t)j * K;
126 __m512 sum_vec = _mm512_setzero_ps();
130 for (; k <= K - 16; k += 16) {
131 __m256i a_bf16 = _mm256_loadu_si256((
const __m256i *)(a_row + k));
132 __m256i b_bf16 = _mm256_loadu_si256((
const __m256i *)(b_row + k));
133 sum_vec = bf16_dot16(a_bf16, b_bf16, sum_vec);
137 float sum = _mm512_reduce_add_ps(sum_vec);
158static void gemm_bf16_blocked_avx512(
const uint16_t *A,
160 const uint16_t *bias,
165 #pragma omp parallel for
166 for (
int i = 0; i < M; ++i) {
167 for (
int j = 0; j < N; ++j) {
174 #pragma omp parallel for collapse(2) schedule(dynamic)
175 for (
int ii = 0; ii < M; ii +=
BLK_M) {
176 for (
int jj = 0; jj < N; jj +=
BLK_N) {
182 for (
int i = 0; i <
BLK_M; ++i) {
183 for (
int j = 0; j <
BLK_N; ++j) {
189 for (
int kk = 0; kk < K; kk +=
BLK_K) {
192 for (
int i = ii; i < i_end; ++i) {
193 const uint16_t *a_row = A + (size_t)i * K;
194 int local_i = i - ii;
196 for (
int j = jj; j < j_end; ++j) {
197 const uint16_t *b_row = B + (size_t)j * K;
198 int local_j = j - jj;
200 __m512 sum_vec = _mm512_setzero_ps();
203 for (; k <= k_end - 16; k += 16) {
204 __m256i a_bf16 = _mm256_loadu_si256((
const __m256i *)(a_row + k));
205 __m256i b_bf16 = _mm256_loadu_si256((
const __m256i *)(b_row + k));
206 sum_vec = bf16_dot16(a_bf16, b_bf16, sum_vec);
209 float partial = _mm512_reduce_add_ps(sum_vec);
210 for (; k < k_end; ++k) {
214 acc[local_i][local_j] += partial;
220 for (
int i = ii; i < i_end; ++i) {
221 for (
int j = jj; j < j_end; ++j) {
223 float new_val = old_val + acc[i - ii][j - jj];
236#if defined(__AVX512BF16__) && defined(__AVX512VL__)
239static inline __m512bh load_bf16x32(
const uint16_t *ptr)
241 return (__m512bh)_mm512_loadu_si512((
const __m512i *)ptr);
244#if defined(__AMX_TILE__) && defined(__AMX_BF16__)
246#ifndef ARCH_REQ_XCOMP_PERM
247#define ARCH_REQ_XCOMP_PERM 0x1023
249#ifndef XFEATURE_XTILE_DATA
250#define XFEATURE_XTILE_DATA 18
253typedef struct ck_amx_tile_config {
256 uint8_t reserved_0[14];
261_Static_assert(
sizeof(ck_amx_tile_config) == 64,
262 "AMX tile configuration must occupy exactly 64 bytes");
264static int ck_amx_request_xtile_data(
void)
266#if defined(__linux__)
267 static int state = 0;
274 long rc = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_PERM, XFEATURE_XTILE_DATA);
275 state = (rc == 0) ? 1 : -1;
282static void ck_amx_config_bf16_16x16x32(
void)
284 ck_amx_tile_config cfg;
285 memset(&cfg, 0,
sizeof(cfg));
294 for (
int tile = 3; tile <= 5; ++tile) {
296 cfg.colsb[tile] = 64;
299 _tile_loadconfig(&cfg);
302static void ck_amx_config_bf16_16x16_kblock(
int k_block)
304 ck_amx_tile_config cfg;
305 memset(&cfg, 0,
sizeof(cfg));
308 cfg.colsb[0] = (uint16_t)(k_block * (
int)
sizeof(uint16_t));
309 cfg.rows[1] = (uint8_t)(k_block / 2);
315 for (
int tile = 3; tile <= 5; ++tile) {
317 cfg.colsb[tile] = 64;
321 __asm__
volatile(
"" : :
"m"(cfg) :
"memory");
322 _tile_loadconfig(&cfg);
325static void ck_pack_bf16_ktile_pairs_16x16(uint16_t *dst,
331 for (
int kp = 0; kp < 16; ++kp) {
332 const int k0 = k + kp * 2;
333 for (
int nn = 0; nn < 16; ++nn) {
334 dst[(size_t)kp * 32u + (
size_t)nn * 2u + 0u] =
335 B[(size_t)(j + nn) * (size_t)K + (
size_t)k0];
336 dst[(size_t)kp * 32u + (
size_t)nn * 2u + 1u] =
337 B[(size_t)(j + nn) * (size_t)K + (
size_t)(k0 + 1)];
342static void gemm_bf16_fp32out_amx(
const uint16_t *A,
348 ck_amx_config_bf16_16x16x32();
350 uint16_t b_tile[16 * 32];
352 for (
int i = 0; i < M; i += 16) {
353 for (
int j = 0; j < N; j += 16) {
356 for (
int k = 0; k < K; k += 32) {
357 ck_pack_bf16_ktile_pairs_16x16(b_tile, B, K, j, k);
358 _tile_loadd(0, A + (
size_t)i * (
size_t)K + (
size_t)k, K * (
int)
sizeof(uint16_t));
359 _tile_loadd(1, b_tile, 32 * (
int)
sizeof(uint16_t));
360 _tile_dpbf16ps(2, 0, 1);
363 _tile_stored(2,
C + (
size_t)i * (
size_t)N + (
size_t)j, N * (
int)
sizeof(
float));
366 for (
int ii = 0; ii < 16; ++ii) {
367 float *c_row =
C + (size_t)(i + ii) * (size_t)N + (
size_t)j;
368 for (
int jj = 0; jj < 16; ++jj) {
369 c_row[jj] += bias[j + jj];
379#define HAVE_AMX_BF16 1
381#define HAVE_AMX_BF16 0
384static void gemm_bf16_native(
const uint16_t *A,
386 const uint16_t *bias,
390 #pragma omp parallel for schedule(dynamic)
391 for (
int i = 0; i < M; ++i) {
392 for (
int j = 0; j < N; ++j) {
394 __m512 sum_vec = _mm512_setzero_ps();
398 for (; k <= K - 32; k += 32) {
399 __m512bh a_vec = load_bf16x32(A + (
size_t)i * K + k);
400 __m512bh b_vec = load_bf16x32(B + (
size_t)j * K + k);
401 sum_vec = _mm512_dpbf16_ps(sum_vec, a_vec, b_vec);
404 float sum = _mm512_reduce_add_ps(sum_vec);
421#define HAVE_NATIVE_BF16 1
423#define HAVE_NATIVE_BF16 0
433 const uint16_t *bias,
437 if (!A || !B || !
C || M <= 0 || N <= 0 || K <= 0) {
443 gemm_bf16_native(A, B, bias,
C, M, N, K);
444#elif defined(__AVX512F__)
447 gemm_bf16_blocked_avx512(A, B, bias,
C, M, N, K);
449 gemm_bf16_avx512(A, B, bias,
C, M, N, K);
453 gemm_bf16_scalar(A, B, bias,
C, M, N, K);
466 if (!A || !B || !
C || M <= 0 || N <= 0 || K <= 0) {
472 const char *amx_env = getenv(
"CK_BF16_AMX");
473 if (amx_env && amx_env[0] ==
'1' &&
474 (M % 16) == 0 && (N % 16) == 0 && (K % 32) == 0 &&
475 M >= 16 && N >= 16 && K >= 32 && ck_amx_request_xtile_data()) {
476 gemm_bf16_fp32out_amx(A, B, bias,
C, M, N, K);
481 #pragma omp parallel for schedule(dynamic)
482 for (
int i = 0; i < M; ++i) {
483 const uint16_t *a_row = A + (size_t)i * K;
486 for (; j + 4 <= N; j += 4) {
487 const uint16_t *b0 = B + (size_t)(j + 0) * K;
488 const uint16_t *b1 = B + (size_t)(j + 1) * K;
489 const uint16_t *b2 = B + (size_t)(j + 2) * K;
490 const uint16_t *b3 = B + (size_t)(j + 3) * K;
491 __m512 acc0 = _mm512_setzero_ps();
492 __m512 acc1 = _mm512_setzero_ps();
493 __m512 acc2 = _mm512_setzero_ps();
494 __m512 acc3 = _mm512_setzero_ps();
497 for (; k <= K - 32; k += 32) {
498 const __m512bh a_vec = load_bf16x32(a_row + k);
499 acc0 = _mm512_dpbf16_ps(acc0, a_vec, load_bf16x32(b0 + k));
500 acc1 = _mm512_dpbf16_ps(acc1, a_vec, load_bf16x32(b1 + k));
501 acc2 = _mm512_dpbf16_ps(acc2, a_vec, load_bf16x32(b2 + k));
502 acc3 = _mm512_dpbf16_ps(acc3, a_vec, load_bf16x32(b3 + k));
505 float s0 = _mm512_reduce_add_ps(acc0);
506 float s1 = _mm512_reduce_add_ps(acc1);
507 float s2 = _mm512_reduce_add_ps(acc2);
508 float s3 = _mm512_reduce_add_ps(acc3);
522 C[(size_t)i * N + (j + 0)] = s0;
523 C[(size_t)i * N + (j + 1)] = s1;
524 C[(size_t)i * N + (j + 2)] = s2;
525 C[(size_t)i * N + (j + 3)] = s3;
529 const uint16_t *b_row = B + (size_t)j * K;
530 __m512 sum_vec = _mm512_setzero_ps();
533 for (; k <= K - 32; k += 32) {
534 const __m512bh a_vec = load_bf16x32(a_row + k);
535 const __m512bh b_vec = load_bf16x32(b_row + k);
536 sum_vec = _mm512_dpbf16_ps(sum_vec, a_vec, b_vec);
539 float sum = _mm512_reduce_add_ps(sum_vec);
546 C[(size_t)i * N + j] = sum;
549#elif defined(__AVX512F__)
550 #pragma omp parallel for schedule(dynamic)
551 for (
int i = 0; i < M; ++i) {
552 const uint16_t *a_row = A + (size_t)i * K;
554 for (
int j = 0; j < N; ++j) {
555 const uint16_t *b_row = B + (size_t)j * K;
557 __m512 sum_vec = _mm512_setzero_ps();
560 for (; k <= K - 16; k += 16) {
561 __m256i a_bf16 = _mm256_loadu_si256((
const __m256i *)(a_row + k));
562 __m256i b_bf16 = _mm256_loadu_si256((
const __m256i *)(b_row + k));
563 sum_vec = bf16_dot16(a_bf16, b_bf16, sum_vec);
566 float sum = _mm512_reduce_add_ps(sum_vec);
576 C[(size_t)i * N + j] = sum;
580 for (
int i = 0; i < M; ++i) {
581 for (
int j = 0; j < N; ++j) {
582 float sum = bias ? bias[j] : 0.0f;
583 for (
int k = 0; k < K; ++k) {
587 C[(size_t)i * N + j] = sum;
611 int row_begin,
int row_end)
613 if (!y || !w || !x || M <= 0 || K <= 0 ||
614 row_begin < 0 || row_begin >= row_end || row_end > M) {
618 for (
int i = row_begin; i < row_end; ++i) {
619 const uint16_t *w_row = w + (size_t)i * (
size_t)K;
621 for (
int k = 0; k < K; ++k) {
635 y, (
const uint16_t *)W, x, M, K, 0, M);
644} ck_gemv_bf16_args_t;
648 const ck_gemv_bf16_args_t *args = (
const ck_gemv_bf16_args_t *)opaque;
650 args->y, args->w, args->x, args->M, args->K, begin,
end);
660 (
size_t)M * (
size_t)K <= 65536) {
665 ck_gemv_bf16_args_t args = {
666 .y = y, .w = (
const uint16_t *)W, .x = x, .M = M, .K = K,
669 if (active > M) active = M;
670 int grain = M / (active * 4);
671 if (grain < 1) grain = 1;
680 int row_begin,
int row_end)
683 for (
int row = row_begin; row < row_end; ++row) {
690 const ck_gemv_bf16_args_t *args = (
const ck_gemv_bf16_args_t *)opaque;
692 args->y, args->w, args->x, args->M, args->K, begin,
end);
702 (
size_t)M * (
size_t)K <= 65536) {
704 y, (
const uint16_t *)W, x, M, K, 0, M);
708 ck_gemv_bf16_args_t args = {
709 .y = y, .w = (
const uint16_t *)W, .x = x, .M = M, .K = K,
712 if (active > M) active = M;
713 int grain = M / (active * 4);
714 if (grain < 1) grain = 1;
732 int row_begin,
int row_end)
734 const uint16_t *w = (
const uint16_t *)B;
735 if (!A || !w || !
C || M <= 0 || N <= 0 || K <= 0 ||
736 row_begin < 0 || row_begin >= row_end || row_end > M) {
740 for (
int i = row_begin; i < row_end; ++i) {
741 const float *a_row = A + (size_t)i * (
size_t)K;
742 float *c_row =
C + (size_t)i * (
size_t)N;
743 for (
int j = 0; j < N; ++j) {
744 const uint16_t *w_row = w + (size_t)j * (
size_t)K;
745 float sum = bias ? bias[j] : 0.0f;
746 for (
int k = 0; k < K; ++k) {
773} ck_gemm_nt_bf16_exact_args_t;
777 const ck_gemm_nt_bf16_exact_args_t *args =
778 (
const ck_gemm_nt_bf16_exact_args_t *)opaque;
780 args->A, args->B, args->bias, args->C,
781 args->M, args->N, args->K, begin,
end);
791 const char *disabled = getenv(
"CK_DISABLE_BF16_GEMM_PARALLEL_PREFILL");
792 if ((disabled && disabled[0] && strcmp(disabled,
"0") != 0) ||
794 (
size_t)M * (
size_t)N <= 4096) {
799 ck_gemm_nt_bf16_exact_args_t args = {
800 .A = A, .B = B, .bias = bias, .C =
C, .M = M, .N = N, .K = K,
803 if (active > M) active = M;
804 int grain = M / (active * 4);
805 if (grain < 1) grain = 1;
817 const uint16_t *bias,
821 if (!A || !B || !
C || M <= 0 || N <= 0 || K <= 0) {
825#if defined(__AVX512F__)
826 #pragma omp parallel for
827 for (
int i = 0; i < M; ++i) {
830 for (; j <= N - 16; j += 16) {
831 __m512 b_vec = bias ? bf16x16_to_fp32(_mm256_loadu_si256((
const __m256i *)(bias + j)))
832 : _mm512_setzero_ps();
833 __m256i out = fp32x16_to_bf16(b_vec);
834 _mm256_storeu_si256((__m256i *)(
C + (
size_t)i * N + j), out);
842 for (
int k = 0; k < K; ++k) {
844 __m512 a_broadcast = _mm512_set1_ps(a_val);
847 for (; j <= N - 16; j += 16) {
848 __m256i b_bf16 = _mm256_loadu_si256((
const __m256i *)(B + (
size_t)k * N + j));
849 __m512 b_fp32 = bf16x16_to_fp32(b_bf16);
851 __m256i c_bf16 = _mm256_loadu_si256((
const __m256i *)(
C + (
size_t)i * N + j));
852 __m512 c_fp32 = bf16x16_to_fp32(c_bf16);
854 c_fp32 = _mm512_fmadd_ps(a_broadcast, b_fp32, c_fp32);
856 __m256i c_out = fp32x16_to_bf16(c_fp32);
857 _mm256_storeu_si256((__m256i *)(
C + (
size_t)i * N + j), c_out);
868 for (
int i = 0; i < M; ++i) {
869 for (
int j = 0; j < N; ++j) {
871 for (
int k = 0; k < K; ++k) {
884 const uint16_t *bias,
888 if (!A || !B || !
C || M <= 0 || N <= 0 || K <= 0) {
896#if defined(__AVX512F__)
898 #pragma omp parallel for
899 for (
int i = 0; i < M; ++i) {
900 for (
int j = 0; j < N; ++j) {
907 #pragma omp parallel for
908 for (
int i = 0; i < M; ++i) {
909 for (
int j = 0; j < N; ++j) {
910 __m512 sum_vec = _mm512_setzero_ps();
913 for (; k <= K - 16; k += 16) {
915 __m512 a_fp32 = _mm512_setzero_ps();
916 for (
int kk = 0; kk < 16; ++kk) {
918 a_fp32 = _mm512_mask_mov_ps(a_fp32, 1 << kk, _mm512_set1_ps(val));
922 __m512 b_fp32 = _mm512_setzero_ps();
923 for (
int kk = 0; kk < 16; ++kk) {
925 b_fp32 = _mm512_mask_mov_ps(b_fp32, 1 << kk, _mm512_set1_ps(val));
928 sum_vec = _mm512_fmadd_ps(a_fp32, b_fp32, sum_vec);
931 float sum = _mm512_reduce_add_ps(sum_vec);
943 for (
int i = 0; i < M; ++i) {
944 for (
int j = 0; j < N; ++j) {
946 for (
int k = 0; k < K; ++k) {
974} ck_gemm_bf16_native_args_t;
978 ck_gemm_bf16_native_args_t *args = (ck_gemm_bf16_native_args_t *)opaque;
979 const int N = args->N;
980 const int K = args->K;
981 enum { ROW_TILE = 4 };
982 uint16_t *a_bf16 = (uint16_t *)alloca(
983 (
size_t)ROW_TILE * (size_t)K *
sizeof(uint16_t));
985 for (
int row0 = ith * ROW_TILE; row0 < args->M; row0 += nth * ROW_TILE) {
986 const int rows = args->M - row0 < ROW_TILE ? args->M - row0 : ROW_TILE;
987 for (
int r = 0; r < rows; ++r) {
988 const float *src = args->A + (size_t)(row0 + r) * (size_t)K;
989 uint16_t *ar = a_bf16 + (size_t)r * (
size_t)K;
995 for (; j + 4 <= N; j += 4) {
996 const uint16_t *b0 = args->B + (size_t)(j + 0) * K;
997 const uint16_t *b1 = args->B + (size_t)(j + 1) * K;
998 const uint16_t *b2 = args->B + (size_t)(j + 2) * K;
999 const uint16_t *b3 = args->B + (size_t)(j + 3) * K;
1000 __m512 acc[ROW_TILE][4];
1001 for (
int r = 0; r < rows; ++r) {
1002 for (
int lane = 0; lane < 4; ++lane) acc[r][lane] = _mm512_setzero_ps();
1005 for (; k <= K - 32; k += 32) {
1006 const __m512bh bv[4] = {
1007 load_bf16x32(b0 + k), load_bf16x32(b1 + k),
1008 load_bf16x32(b2 + k), load_bf16x32(b3 + k)
1010 for (
int r = 0; r < rows; ++r) {
1012 load_bf16x32(a_bf16 + (
size_t)r * (
size_t)K + k);
1013 for (
int lane = 0; lane < 4; ++lane) {
1014 acc[r][lane] = _mm512_dpbf16_ps(acc[r][lane], av, bv[lane]);
1018 for (
int r = 0; r < rows; ++r) {
1020 for (
int lane = 0; lane < 4; ++lane) {
1021 sums[lane] = _mm512_reduce_add_ps(acc[r][lane]);
1023 const uint16_t *ar = a_bf16 + (size_t)r * (
size_t)K;
1024 for (
int tail = k; tail < K; ++tail) {
1031 float *dst = args->C + (size_t)(row0 + r) * (size_t)N;
1032 for (
int lane = 0; lane < 4; ++lane) {
1033 if (args->bias) sums[lane] += args->bias[j + lane];
1038 for (; j < N; ++j) {
1039 const uint16_t *b = args->B + (size_t)j * K;
1040 __m512 acc[ROW_TILE];
1041 for (
int r = 0; r < rows; ++r) acc[r] = _mm512_setzero_ps();
1043 for (; k <= K - 32; k += 32) {
1044 const __m512bh bv = load_bf16x32(b + k);
1045 for (
int r = 0; r < rows; ++r) {
1046 acc[r] = _mm512_dpbf16_ps(
1047 acc[r], load_bf16x32(a_bf16 + (
size_t)r * (
size_t)K + k), bv);
1050 for (
int r = 0; r < rows; ++r) {
1051 const uint16_t *ar = a_bf16 + (size_t)r * (
size_t)K;
1052 float sum = _mm512_reduce_add_ps(acc[r]);
1053 for (
int tail = k; tail < K; ++tail) {
1056 if (args->bias) sum += args->bias[j];
1057 args->C[(size_t)(row0 + r) * (size_t)N + j] =
1062 for (
int r = 0; r < rows; ++r) {
1063 const uint16_t *ar = a_bf16 + (size_t)r * (
size_t)K;
1064 float *dst = args->C + (size_t)(row0 + r) * (size_t)N;
1065 for (
int j = 0; j < N; ++j) {
1066 const uint16_t *b = args->B + (size_t)j * K;
1067 float sum = args->bias ? args->bias[j] : 0.0f;
1068 for (
int k = 0; k < K; ++k) {
1082 int M,
int N,
int K)
1084 const uint16_t *weights = (
const uint16_t *)B;
1085 if (!A || !weights || !
C || M <= 0 || N <= 0 || K <= 0)
return;
1087 ck_gemm_bf16_native_args_t args = {
1088 .A = A, .B = weights, .bias = bias, .C =
C, .M = M, .N = N, .K = K
1092 if (active > M) active = M;
1093 if (active > 24) active = 24;
1094 if (!pool || active <= 1 || (
size_t)M * (
size_t)N <= 4096) {
1105} ck_bf16_convert_args_t;
1109 ck_bf16_convert_args_t *args = (ck_bf16_convert_args_t *)opaque;
1110 const size_t begin = args->count * (size_t)ith / (
size_t)nth;
1111 const size_t end = args->count * (size_t)(ith + 1) / (size_t)nth;
1112 for (
size_t i = begin; i <
end; ++i) args->dst[i] =
float_to_bf16(args->src[i]);
1124} ck_gemm_bf16_amx_args_t;
1129 ck_gemm_bf16_amx_args_t *args = (ck_gemm_bf16_amx_args_t *)opaque;
1130 if (!ck_amx_request_xtile_data()) {
1131 __atomic_store_n(&args->failed, 1, __ATOMIC_RELAXED);
1134 ck_amx_config_bf16_16x16x32();
1135 uint16_t b_tile[16 * 32];
1136 const int mb = args->M / 16;
1137 const int nb = args->N / 16;
1138 const int m_groups = (mb + 3) / 4;
1139 const int jobs = m_groups * nb;
1141 for (
int job = ith; job < jobs; job += nth) {
1142 const int m_group = job / nb;
1143 const int j = (job % nb) * 16;
1144 const int group_blocks = (mb - m_group * 4 < 4) ? mb - m_group * 4 : 4;
1146 if (group_blocks > 1) _tile_zero(3);
1147 if (group_blocks > 2) _tile_zero(4);
1148 if (group_blocks > 3) _tile_zero(5);
1149 for (
int k = 0; k < args->K; k += 32) {
1150 ck_pack_bf16_ktile_pairs_16x16(b_tile, args->B, args->K, j, k);
1151 _tile_loadd(1, b_tile, 32 * (
int)
sizeof(uint16_t));
1152 for (
int g = 0; g < group_blocks; ++g) {
1153 const int i = (m_group * 4 + g) * 16;
1154 _tile_loadd(0, args->A + (
size_t)i * args->K + k,
1155 args->K * (
int)
sizeof(uint16_t));
1157 case 0: _tile_dpbf16ps(2, 0, 1);
break;
1158 case 1: _tile_dpbf16ps(3, 0, 1);
break;
1159 case 2: _tile_dpbf16ps(4, 0, 1);
break;
1160 default: _tile_dpbf16ps(5, 0, 1);
break;
1164 for (
int g = 0; g < group_blocks; ++g) {
1165 const int i = (m_group * 4 + g) * 16;
1166 float *tile_dst = args->C + (size_t)i * args->N + j;
1167 const int tile_stride = args->N * (int)
sizeof(
float);
1169 case 0: _tile_stored(2, tile_dst, tile_stride);
break;
1170 case 1: _tile_stored(3, tile_dst, tile_stride);
break;
1171 case 2: _tile_stored(4, tile_dst, tile_stride);
break;
1172 default: _tile_stored(5, tile_dst, tile_stride);
break;
1175 for (
int ii = 0; ii < 16; ++ii) {
1176 float *row = args->C + (size_t)(i + ii) * args->N + j;
1177 for (
int jj = 0; jj < 16; ++jj) row[jj] += args->bias[j + jj];
1184 (void)ith; (void)nth; (void)opaque;
1191} ck_bf16_round_args_t;
1195 ck_bf16_round_args_t *args = (ck_bf16_round_args_t *)opaque;
1196 const size_t begin = args->count * (size_t)ith / (
size_t)nth;
1197 const size_t end = args->count * (size_t)(ith + 1) / (size_t)nth;
1198 for (
size_t i = begin; i <
end; ++i) {
1206 return ck_amx_request_xtile_data();
1215 int M,
int N,
int K,
1219 if (!A || !B || !
C || M <= 0 || N <= 0 || K <= 0 ||
1220 (M % 16) != 0 || (N % 16) != 0 || (K % 2) != 0 ||
1221 !ck_amx_request_xtile_data()) {
1225 int k_block = K < 32 ? K : 32;
1226 while (k_block > 2 && K % k_block != 0) k_block -= 2;
1227 ck_amx_config_bf16_16x16_kblock(k_block);
1228 uint16_t b_tile[16 * 32];
1229 for (
int i = 0; i < M; i += 16) {
1230 for (
int j = 0; j < N; j += 16) {
1232 _tile_loadd(2,
C + (
size_t)i * (
size_t)N + (
size_t)j,
1233 N * (
int)
sizeof(
float));
1237 for (
int k = 0; k < K; k += k_block) {
1238 memset(b_tile, 0,
sizeof(b_tile));
1239 for (
int kp = 0; kp < k_block / 2; ++kp) {
1240 const int k0 = k + kp * 2;
1241 for (
int nn = 0; nn < 16; ++nn) {
1242 b_tile[(size_t)kp * 32u + (
size_t)nn * 2u] =
1243 B[(size_t)(j + nn) * (size_t)K + (
size_t)k0];
1244 b_tile[(size_t)kp * 32u + (
size_t)nn * 2u + 1u] =
1245 B[(size_t)(j + nn) * (size_t)K + (
size_t)k0 + 1u];
1248 _tile_loadd(0, A + (
size_t)i * (
size_t)K + (
size_t)k,
1249 K * (
int)
sizeof(uint16_t));
1250 _tile_loadd(1, b_tile, 32 * (
int)
sizeof(uint16_t));
1251 _tile_dpbf16ps(2, 0, 1);
1253 _tile_stored(2,
C + (
size_t)i * (
size_t)N + (
size_t)j,
1254 N * (
int)
sizeof(
float));
1260 (void)A; (void)B; (void)
C; (void)M; (void)N; (void)K; (void)accumulate;
1269 int M,
int N,
int K,
1271 size_t a_bf16_bytes)
1274 if (!A || !B || !
C || M < 16 || N < 16 || K < 32 ||
1275 (M % 16) != 0 || (N % 16) != 0 || (K % 32) != 0) {
1277 "HARD KERNEL CONTRACT FAULT: AMX BF16 GEMM requires non-null buffers "
1278 "and M%%16=N%%16=K%%32=0 (M=%d N=%d K=%d)\n",
1282 const size_t input_count = (size_t)M * K;
1283 if (!a_bf16 || input_count > SIZE_MAX /
sizeof(uint16_t) ||
1284 a_bf16_bytes < input_count *
sizeof(uint16_t)) {
1285 fprintf(stderr,
"HARD KERNEL CONTRACT FAULT: AMX BF16 activation workspace is too small\n");
1290 if (active > 24) active = 24;
1291 ck_bf16_convert_args_t convert = {.src=A, .dst=a_bf16, .count=input_count};
1294 ck_gemm_bf16_amx_args_t gemm = {
1295 .A=a_bf16, .B=(
const uint16_t *)B, .bias=bias, .
C=
C,
1296 .M=M, .N=N, .K=K, .failed=0
1300 if (__atomic_load_n(&gemm.failed, __ATOMIC_RELAXED)) {
1301 fprintf(stderr,
"HARD KERNEL CONTRACT FAULT: AMX tile permission request failed\n");
1304 ck_bf16_round_args_t round = {.values=
C, .count=(size_t)M * N};
1309 (void)A; (void)B; (void)bias; (void)
C; (void)M; (void)N; (void)K;
1310 (void)a_bf16; (void)a_bf16_bytes;
1312 "HARD KERNEL CONTRACT FAULT: gemm_nt_bf16_amx_bf16_storage was selected "
1313 "without AMX BF16 support\n");
1322 int M,
int N,
int K)
1324 size_t input_count = 0;
1325 if (M > 0 && K > 0 && (
size_t)M <= SIZE_MAX / (
size_t)K) {
1326 input_count = (size_t)M * (
size_t)K;
1328 uint16_t *workspace = input_count > 0 && input_count <= SIZE_MAX /
sizeof(uint16_t)
1329 ? (uint16_t *)malloc(input_count *
sizeof(uint16_t))
1332 fprintf(stderr,
"HARD KERNEL CONTRACT FAULT: AMX BF16 compatibility workspace allocation failed\n");
1336 A, B, bias,
C, M, N, K, workspace, input_count *
sizeof(uint16_t));
1341 const float *A,
const void *B,
const float *bias,
float *
C,
1342 int M,
int N,
int K, uint16_t *a_bf16,
size_t a_bf16_bytes)
1344 const int amx_shape = M >= 16 && N >= 16 && K >= 32 &&
1345 (M % 16) == 0 && (N % 16) == 0 && (K % 32) == 0;
1348 A, B, bias,
C, M, N, K, a_bf16, a_bf16_bytes);
1358 int M,
int N,
int K)
1360 const int amx_shape = M >= 16 && N >= 16 && K >= 32 &&
1361 (M % 16) == 0 && (N % 16) == 0 && (K % 32) == 0;
1370static dnnl_engine_t ck_pytorch_brgemm_engine;
1371static dnnl_stream_t ck_pytorch_brgemm_stream;
1372static int ck_pytorch_brgemm_init_status = -1;
1373static pthread_once_t ck_pytorch_brgemm_once = PTHREAD_ONCE_INIT;
1374static pthread_mutex_t ck_pytorch_brgemm_lock = PTHREAD_MUTEX_INITIALIZER;
1375static const dnnl_version_t *ck_pytorch_brgemm_version;
1377static void ck_pytorch_brgemm_init(
void)
1379 const dnnl_version_t *version = dnnl_version();
1380 if (!version || version->cpu_runtime != DNNL_RUNTIME_OMP || !version->hash) {
1382 "HARD KERNEL CONTRACT FAULT: PyTorch oneDNN BF16 BRGEMM requires "
1383 "an identity-bearing OpenMP oneDNN runtime "
1384 "(found %d.%d.%d runtime=%u hash=%s)\n",
1385 version ? version->major : -1,
1386 version ? version->minor : -1,
1387 version ? version->patch : -1,
1388 version ? version->cpu_runtime : 0,
1389 version && version->hash ? version->hash :
"<missing>");
1392 ck_pytorch_brgemm_version = version;
1393 if (dnnl_engine_create(&ck_pytorch_brgemm_engine, dnnl_cpu, 0) != dnnl_success)
return;
1394 if (dnnl_stream_create(&ck_pytorch_brgemm_stream, ck_pytorch_brgemm_engine,
1395 dnnl_stream_default_flags) != dnnl_success) {
1396 dnnl_engine_destroy(ck_pytorch_brgemm_engine);
1397 ck_pytorch_brgemm_engine = NULL;
1400 ck_pytorch_brgemm_init_status = 0;
1403static void ck_pytorch_brgemm_require_version(
int major,
int minor,
int patch,
1404 const char *source_hash,
1405 const char *provider,
1406 int M,
int N,
int K)
1408 pthread_once(&ck_pytorch_brgemm_once, ck_pytorch_brgemm_init);
1409 if (ck_pytorch_brgemm_init_status != 0 || !ck_pytorch_brgemm_version) {
1412 if (ck_pytorch_brgemm_version->major != major ||
1413 ck_pytorch_brgemm_version->minor != minor ||
1414 ck_pytorch_brgemm_version->patch != patch ||
1415 strcmp(ck_pytorch_brgemm_version->hash, source_hash) != 0) {
1417 "HARD KERNEL CONTRACT FAULT: %s requires oneDNN %d.%d.%d "
1418 "OpenMP at %s (found %d.%d.%d runtime=%u hash=%s)\n",
1419 provider, major, minor, patch, source_hash,
1420 ck_pytorch_brgemm_version->major,
1421 ck_pytorch_brgemm_version->minor,
1422 ck_pytorch_brgemm_version->patch,
1423 ck_pytorch_brgemm_version->cpu_runtime,
1424 ck_pytorch_brgemm_version->hash);
1431 int M,
int N,
int K,
1432 size_t *input_bytes,
size_t *output_bytes,
size_t *bias_bytes)
1434 if (M <= 0 || N <= 0 || K <= 0 ||
1435 (
size_t)M > SIZE_MAX / (
size_t)K ||
1436 (
size_t)M > SIZE_MAX / (
size_t)N) {
1439 const size_t input_count = (size_t)M * (
size_t)K;
1440 const size_t output_count = (size_t)M * (
size_t)N;
1441 if (input_count > SIZE_MAX /
sizeof(uint16_t) ||
1442 output_count > SIZE_MAX /
sizeof(uint16_t) ||
1443 (
size_t)N > SIZE_MAX /
sizeof(uint16_t)) {
1446 *input_bytes = input_count *
sizeof(uint16_t);
1447 *output_bytes = output_count *
sizeof(uint16_t);
1448 *bias_bytes = (size_t)N *
sizeof(uint16_t);
1452 const float *A,
const void *B,
const float *bias,
float *
C,
1453 int M,
int N,
int K,
1454 uint16_t *input_bf16,
size_t input_bf16_bytes,
1455 uint16_t *output_bf16,
size_t output_bf16_bytes,
1456 uint16_t *bias_bf16,
size_t bias_bf16_bytes)
1459 if (!A || !B || !
C || M <= 0 || N <= 0 || K <= 0) {
1462 if (ck_pytorch_brgemm_init_status != 0) {
1466 size_t required_input_bytes = 0;
1467 size_t required_output_bytes = 0;
1468 size_t required_bias_bytes = 0;
1470 M, N, K, &required_input_bytes, &required_output_bytes,
1471 &required_bias_bytes);
1472 const size_t input_count = required_input_bytes /
sizeof(*input_bf16);
1473 const size_t output_count = required_output_bytes /
sizeof(*output_bf16);
1474 if (!input_bf16 || input_bf16_bytes < required_input_bytes ||
1475 !output_bf16 || output_bf16_bytes < required_output_bytes ||
1476 (bias && (!bias_bf16 || bias_bf16_bytes < required_bias_bytes))) {
1479 for (
size_t i = 0; i < input_count; ++i) input_bf16[i] =
float_to_bf16(A[i]);
1481 for (
int j = 0; j < N; ++j) bias_bf16[j] =
float_to_bf16(bias[j]);
1482 for (
int i = 0; i < M; ++i) {
1483 memcpy(output_bf16 + (
size_t)i * (
size_t)N,
1484 bias_bf16, (
size_t)N *
sizeof(*bias_bf16));
1488 dnnl_memory_desc_t src_md = NULL, weights_md = NULL, dst_md = NULL;
1489 dnnl_primitive_attr_t attr = NULL;
1490 dnnl_post_ops_t post_ops = NULL;
1491 dnnl_primitive_desc_t primitive_desc = NULL;
1492 dnnl_primitive_t primitive = NULL;
1493 dnnl_memory_t src_mem = NULL, weights_mem = NULL, dst_mem = NULL;
1494 dnnl_dims_t src_dims = {M, K};
1495 dnnl_dims_t weights_dims = {K, N};
1496 dnnl_dims_t dst_dims = {M, N};
1497 dnnl_dims_t src_strides = {K, 1};
1498 dnnl_dims_t weights_strides = {1, K};
1499 dnnl_dims_t dst_strides = {N, 1};
1500 dnnl_status_t status = dnnl_success;
1502#define CK_DNNL(call) do { status = (call); if (status != dnnl_success) goto cleanup; } while (0)
1503 pthread_mutex_lock(&ck_pytorch_brgemm_lock);
1504 CK_DNNL(dnnl_memory_desc_create_with_strides(&src_md, 2, src_dims, dnnl_bf16, src_strides));
1505 CK_DNNL(dnnl_memory_desc_create_with_strides(
1506 &weights_md, 2, weights_dims, dnnl_bf16, weights_strides));
1507 CK_DNNL(dnnl_memory_desc_create_with_strides(&dst_md, 2, dst_dims, dnnl_bf16, dst_strides));
1509 CK_DNNL(dnnl_primitive_attr_create(&attr));
1510 CK_DNNL(dnnl_post_ops_create(&post_ops));
1511 CK_DNNL(dnnl_post_ops_append_sum(post_ops, 1.0f, 0, dnnl_bf16));
1512 CK_DNNL(dnnl_primitive_attr_set_post_ops(attr, post_ops));
1514 CK_DNNL(dnnl_matmul_primitive_desc_create(
1515 &primitive_desc, ck_pytorch_brgemm_engine, src_md, weights_md, NULL, dst_md, attr));
1516 CK_DNNL(dnnl_primitive_create(&primitive, primitive_desc));
1517 CK_DNNL(dnnl_memory_create(&src_mem, src_md, ck_pytorch_brgemm_engine, input_bf16));
1518 CK_DNNL(dnnl_memory_create(
1519 &weights_mem, weights_md, ck_pytorch_brgemm_engine, (
void *)B));
1520 CK_DNNL(dnnl_memory_create(&dst_mem, dst_md, ck_pytorch_brgemm_engine, output_bf16));
1521 dnnl_exec_arg_t args[] = {
1522 {DNNL_ARG_SRC, src_mem},
1523 {DNNL_ARG_WEIGHTS, weights_mem},
1524 {DNNL_ARG_DST, dst_mem},
1526 CK_DNNL(dnnl_primitive_execute(
1527 primitive, ck_pytorch_brgemm_stream, (
int)(
sizeof(args) /
sizeof(args[0])), args));
1528 CK_DNNL(dnnl_stream_wait(ck_pytorch_brgemm_stream));
1531 if (dst_mem) dnnl_memory_destroy(dst_mem);
1532 if (weights_mem) dnnl_memory_destroy(weights_mem);
1533 if (src_mem) dnnl_memory_destroy(src_mem);
1534 if (primitive) dnnl_primitive_destroy(primitive);
1535 if (primitive_desc) dnnl_primitive_desc_destroy(primitive_desc);
1536 if (dst_md) dnnl_memory_desc_destroy(dst_md);
1537 if (weights_md) dnnl_memory_desc_destroy(weights_md);
1538 if (src_md) dnnl_memory_desc_destroy(src_md);
1539 if (post_ops) dnnl_post_ops_destroy(post_ops);
1540 if (attr) dnnl_primitive_attr_destroy(attr);
1541 pthread_mutex_unlock(&ck_pytorch_brgemm_lock);
1544 if (status != dnnl_success) {
1547 for (
size_t i = 0; i < output_count; ++i)
C[i] =
bf16_to_float(output_bf16[i]);
1549 (void)A; (void)B; (void)bias; (void)
C; (void)M; (void)N; (void)K;
1550 (void)input_bf16; (void)input_bf16_bytes;
1551 (void)output_bf16; (void)output_bf16_bytes;
1552 (void)bias_bf16; (void)bias_bf16_bytes;
1553 fprintf(stderr,
"HARD KERNEL CONTRACT FAULT: PyTorch oneDNN BF16 BRGEMM was "
1554 "selected without USE_ONEDNN=1\n");
1560 const float *A,
const void *B,
const float *bias,
float *
C,
1561 int M,
int N,
int K)
1563 size_t input_bytes = 0;
1564 size_t output_bytes = 0;
1565 size_t bias_bytes = 0;
1567 M, N, K, &input_bytes, &output_bytes, &bias_bytes);
1568 uint16_t *input_bf16 = (uint16_t *)malloc(input_bytes);
1569 uint16_t *output_bf16 = (uint16_t *)malloc(output_bytes);
1570 uint16_t *bias_bf16 = bias ? (uint16_t *)malloc(bias_bytes) : NULL;
1571 if (!input_bf16 || !output_bf16 || (bias && !bias_bf16)) {
1578 A, B, bias,
C, M, N, K,
1579 input_bf16, input_bytes, output_bf16, output_bytes,
1580 bias_bf16, bias_bytes);
1590 int M,
int N,
int K)
1593 ck_pytorch_brgemm_require_version(
1594 3, 7, 1,
"8d263e693366ef8db40acc569cc7d8edf644556d",
1595 "gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage", M, N, K);
1598 A, B, bias,
C, M, N, K);
1602 const float *A,
const void *B,
const float *bias,
float *
C,
1603 int M,
int N,
int K)
1606 ck_pytorch_brgemm_require_version(
1607 3, 12, 0,
"80afa71049cd69a3df32adcccb623b12cd7baa22",
1608 "gemm_nt_bf16_pytorch_onednn_3_12_brgemm_bf16_storage", M, N, K);
1611 A, B, bias,
C, M, N, K);
1615 const float *A,
const void *B,
const float *bias,
float *
C,
1616 int M,
int N,
int K,
1617 uint16_t *input_bf16,
size_t input_bf16_bytes,
1618 uint16_t *output_bf16,
size_t output_bf16_bytes,
1619 uint16_t *bias_bf16,
size_t bias_bf16_bytes)
1622 ck_pytorch_brgemm_require_version(
1623 3, 12, 0,
"80afa71049cd69a3df32adcccb623b12cd7baa22",
1624 "gemm_nt_bf16_pytorch_onednn_3_12_brgemm_bf16_storage_workspace",
1628 A, B, bias,
C, M, N, K,
1629 input_bf16, input_bf16_bytes, output_bf16, output_bf16_bytes,
1630 bias_bf16, bias_bf16_bytes);
1634 const float *input,
const void *weights,
const float *bias,
float *output,
1635 int batch,
int out_channels,
int in_channels,
int temporal,
1636 int patch_h,
int patch_w)
1639 if (!input || !weights || !bias || !output || batch <= 0 ||
1640 out_channels <= 0 || in_channels <= 0 || temporal <= 0 ||
1641 patch_h <= 0 || patch_w <= 0) {
1643 out_channels, in_channels * temporal * patch_h * patch_w);
1645 pthread_once(&ck_pytorch_brgemm_once, ck_pytorch_brgemm_init);
1646 if (ck_pytorch_brgemm_init_status != 0) {
1648 out_channels, in_channels * temporal * patch_h * patch_w);
1650 ck_pytorch_brgemm_require_version(
1651 3, 7, 1,
"8d263e693366ef8db40acc569cc7d8edf644556d",
1652 "patch_projection_bf16_pytorch_onednn_conv3d_storage",
1653 batch, out_channels, in_channels * temporal * patch_h * patch_w);
1655 const size_t input_count = (size_t)batch * (
size_t)in_channels *
1656 (size_t)temporal * (
size_t)patch_h * (size_t)patch_w;
1657 const size_t output_count = (size_t)batch * (
size_t)out_channels;
1658 uint16_t *input_bf16 = (uint16_t *)malloc(input_count *
sizeof(*input_bf16));
1659 uint16_t *bias_bf16 = (uint16_t *)malloc((
size_t)out_channels *
sizeof(*bias_bf16));
1660 uint16_t *output_bf16 = (uint16_t *)malloc(output_count *
sizeof(*output_bf16));
1661 if (!input_bf16 || !bias_bf16 || !output_bf16) {
1666 out_channels, in_channels * temporal * patch_h * patch_w);
1668 for (
size_t i = 0; i < input_count; ++i) input_bf16[i] =
float_to_bf16(input[i]);
1669 for (
int i = 0; i < out_channels; ++i) bias_bf16[i] =
float_to_bf16(bias[i]);
1671 dnnl_dims_t src_dims = {batch, in_channels, temporal, patch_h, patch_w};
1672 dnnl_dims_t weight_dims = {
1673 out_channels, in_channels, temporal, patch_h, patch_w};
1674 dnnl_dims_t bias_dims = {out_channels};
1675 dnnl_dims_t dst_dims = {batch, out_channels, 1, 1, 1};
1676 dnnl_dims_t strides = {temporal, patch_h, patch_w};
1677 dnnl_dims_t dilates = {0, 0, 0};
1678 dnnl_dims_t padding = {0, 0, 0};
1680 dnnl_memory_desc_t user_src_md = NULL, user_weight_md = NULL;
1681 dnnl_memory_desc_t bias_md = NULL, user_dst_md = NULL;
1682 dnnl_memory_desc_t any_src_md = NULL, any_weight_md = NULL, any_dst_md = NULL;
1683 dnnl_primitive_desc_t conv_pd = NULL;
1684 dnnl_primitive_t conv = NULL;
1685 dnnl_primitive_desc_t reorder_pd = NULL;
1686 dnnl_primitive_t reorder = NULL;
1687 dnnl_exec_arg_t reorder_args[2];
1688 dnnl_memory_t user_src = NULL, user_weight = NULL, bias_mem = NULL, user_dst = NULL;
1689 dnnl_memory_t conv_src = NULL, conv_weight = NULL, conv_dst = NULL;
1690 dnnl_status_t status = dnnl_success;
1692#define CK_DNNL_CONV(call) do { status = (call); if (status != dnnl_success) goto cleanup_conv; } while (0)
1693 pthread_mutex_lock(&ck_pytorch_brgemm_lock);
1694 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1695 &user_src_md, 5, src_dims, dnnl_bf16, dnnl_ncdhw));
1696 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1697 &user_weight_md, 5, weight_dims, dnnl_bf16, dnnl_oidhw));
1698 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1699 &bias_md, 1, bias_dims, dnnl_bf16, dnnl_x));
1700 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1701 &user_dst_md, 5, dst_dims, dnnl_bf16, dnnl_ncdhw));
1702 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1703 &any_src_md, 5, src_dims, dnnl_bf16, dnnl_format_tag_any));
1704 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1705 &any_weight_md, 5, weight_dims, dnnl_bf16, dnnl_format_tag_any));
1706 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1707 &any_dst_md, 5, dst_dims, dnnl_bf16, dnnl_format_tag_any));
1708 CK_DNNL_CONV(dnnl_convolution_forward_primitive_desc_create(
1709 &conv_pd, ck_pytorch_brgemm_engine, dnnl_forward_training,
1710 dnnl_convolution_direct, any_src_md, any_weight_md, bias_md, any_dst_md,
1711 strides, dilates, padding, padding, NULL));
1713 const_dnnl_memory_desc_t conv_src_md =
1714 dnnl_primitive_desc_query_md(conv_pd, dnnl_query_src_md, 0);
1715 const_dnnl_memory_desc_t conv_weight_md =
1716 dnnl_primitive_desc_query_md(conv_pd, dnnl_query_weights_md, 0);
1717 const_dnnl_memory_desc_t conv_dst_md =
1718 dnnl_primitive_desc_query_md(conv_pd, dnnl_query_dst_md, 0);
1719 CK_DNNL_CONV(dnnl_memory_create(
1720 &user_src, user_src_md, ck_pytorch_brgemm_engine, input_bf16));
1721 CK_DNNL_CONV(dnnl_memory_create(
1722 &user_weight, user_weight_md, ck_pytorch_brgemm_engine, (
void *)weights));
1723 CK_DNNL_CONV(dnnl_memory_create(
1724 &bias_mem, bias_md, ck_pytorch_brgemm_engine, bias_bf16));
1725 CK_DNNL_CONV(dnnl_memory_create(
1726 &user_dst, user_dst_md, ck_pytorch_brgemm_engine, output_bf16));
1727 CK_DNNL_CONV(dnnl_memory_create(
1728 &conv_src, conv_src_md, ck_pytorch_brgemm_engine, DNNL_MEMORY_ALLOCATE));
1729 CK_DNNL_CONV(dnnl_memory_create(
1730 &conv_weight, conv_weight_md, ck_pytorch_brgemm_engine, DNNL_MEMORY_ALLOCATE));
1731 CK_DNNL_CONV(dnnl_memory_create(
1732 &conv_dst, conv_dst_md, ck_pytorch_brgemm_engine, DNNL_MEMORY_ALLOCATE));
1734 CK_DNNL_CONV(dnnl_reorder_primitive_desc_create(
1735 &reorder_pd, user_src_md, ck_pytorch_brgemm_engine,
1736 conv_src_md, ck_pytorch_brgemm_engine, NULL));
1737 CK_DNNL_CONV(dnnl_primitive_create(&reorder, reorder_pd));
1738 reorder_args[0] = (dnnl_exec_arg_t){DNNL_ARG_FROM, user_src};
1739 reorder_args[1] = (dnnl_exec_arg_t){DNNL_ARG_TO, conv_src};
1740 CK_DNNL_CONV(dnnl_primitive_execute(
1741 reorder, ck_pytorch_brgemm_stream, 2, reorder_args));
1742 dnnl_primitive_destroy(reorder); reorder = NULL;
1743 dnnl_primitive_desc_destroy(reorder_pd); reorder_pd = NULL;
1745 CK_DNNL_CONV(dnnl_reorder_primitive_desc_create(
1746 &reorder_pd, user_weight_md, ck_pytorch_brgemm_engine,
1747 conv_weight_md, ck_pytorch_brgemm_engine, NULL));
1748 CK_DNNL_CONV(dnnl_primitive_create(&reorder, reorder_pd));
1749 reorder_args[0] = (dnnl_exec_arg_t){DNNL_ARG_FROM, user_weight};
1750 reorder_args[1] = (dnnl_exec_arg_t){DNNL_ARG_TO, conv_weight};
1751 CK_DNNL_CONV(dnnl_primitive_execute(
1752 reorder, ck_pytorch_brgemm_stream, 2, reorder_args));
1753 dnnl_primitive_destroy(reorder); reorder = NULL;
1754 dnnl_primitive_desc_destroy(reorder_pd); reorder_pd = NULL;
1756 CK_DNNL_CONV(dnnl_primitive_create(&conv, conv_pd));
1757 dnnl_exec_arg_t conv_args[] = {
1758 {DNNL_ARG_SRC, conv_src},
1759 {DNNL_ARG_WEIGHTS, conv_weight},
1760 {DNNL_ARG_BIAS, bias_mem},
1761 {DNNL_ARG_DST, conv_dst},
1763 CK_DNNL_CONV(dnnl_primitive_execute(
1764 conv, ck_pytorch_brgemm_stream,
1765 (
int)(
sizeof(conv_args) /
sizeof(conv_args[0])), conv_args));
1767 CK_DNNL_CONV(dnnl_reorder_primitive_desc_create(
1768 &reorder_pd, conv_dst_md, ck_pytorch_brgemm_engine,
1769 user_dst_md, ck_pytorch_brgemm_engine, NULL));
1770 CK_DNNL_CONV(dnnl_primitive_create(&reorder, reorder_pd));
1771 reorder_args[0] = (dnnl_exec_arg_t){DNNL_ARG_FROM, conv_dst};
1772 reorder_args[1] = (dnnl_exec_arg_t){DNNL_ARG_TO, user_dst};
1773 CK_DNNL_CONV(dnnl_primitive_execute(
1774 reorder, ck_pytorch_brgemm_stream, 2, reorder_args));
1775 CK_DNNL_CONV(dnnl_stream_wait(ck_pytorch_brgemm_stream));
1778 if (reorder) dnnl_primitive_destroy(reorder);
1779 if (reorder_pd) dnnl_primitive_desc_destroy(reorder_pd);
1780 if (conv) dnnl_primitive_destroy(conv);
1781 if (conv_dst) dnnl_memory_destroy(conv_dst);
1782 if (conv_weight) dnnl_memory_destroy(conv_weight);
1783 if (conv_src) dnnl_memory_destroy(conv_src);
1784 if (user_dst) dnnl_memory_destroy(user_dst);
1785 if (bias_mem) dnnl_memory_destroy(bias_mem);
1786 if (user_weight) dnnl_memory_destroy(user_weight);
1787 if (user_src) dnnl_memory_destroy(user_src);
1788 if (conv_pd) dnnl_primitive_desc_destroy(conv_pd);
1789 if (any_dst_md) dnnl_memory_desc_destroy(any_dst_md);
1790 if (any_weight_md) dnnl_memory_desc_destroy(any_weight_md);
1791 if (any_src_md) dnnl_memory_desc_destroy(any_src_md);
1792 if (user_dst_md) dnnl_memory_desc_destroy(user_dst_md);
1793 if (bias_md) dnnl_memory_desc_destroy(bias_md);
1794 if (user_weight_md) dnnl_memory_desc_destroy(user_weight_md);
1795 if (user_src_md) dnnl_memory_desc_destroy(user_src_md);
1796 pthread_mutex_unlock(&ck_pytorch_brgemm_lock);
1799 if (status != dnnl_success) {
1804 out_channels, in_channels * temporal * patch_h * patch_w);
1806 for (
size_t i = 0; i < output_count; ++i) output[i] =
bf16_to_float(output_bf16[i]);
1811 (void)input; (void)weights; (void)bias; (void)output; (void)batch;
1812 (void)out_channels; (void)in_channels; (void)temporal; (void)patch_h; (void)patch_w;
1813 fprintf(stderr,
"HARD KERNEL CONTRACT FAULT: PyTorch oneDNN BF16 Conv3D "
1814 "was selected without USE_ONEDNN=1\n");
1820 const float *image,
const void *weights_t0,
const void *weights_t1,
1821 const float *bias,
float *output,
int channels,
int image_h,
int image_w,
1822 int patch_size,
int out_channels,
int merge_size)
1825 if (!image || !weights_t0 || !weights_t1 || !bias || !output ||
1826 channels <= 0 || image_h <= 0 || image_w <= 0 || patch_size <= 0 ||
1827 out_channels <= 0 || merge_size <= 0 || image_h % patch_size != 0 ||
1828 image_w % patch_size != 0) {
1830 image_h, image_w, patch_size);
1832 const int grid_h = image_h / patch_size;
1833 const int grid_w = image_w / patch_size;
1834 if (grid_h % merge_size != 0 || grid_w % merge_size != 0) {
1836 grid_h, grid_w, merge_size);
1838 const int batch = grid_h * grid_w;
1839 const int temporal = 2;
1840 const int half_k = channels * patch_size * patch_size;
1841 const int full_k = temporal * half_k;
1842 float *patches = (
float *)malloc((
size_t)batch * (size_t)full_k *
sizeof(*patches));
1843 uint16_t *weights = (uint16_t *)malloc(
1844 (
size_t)out_channels * (size_t)full_k *
sizeof(*weights));
1845 if (!patches || !weights) {
1849 batch, out_channels, full_k);
1852 for (
int tok = 0; tok < batch; ++tok) {
1853 const int tiles_per_row = grid_w / merge_size;
1854 const int tile_area = merge_size * merge_size;
1855 const int tile = tok / tile_area;
1856 const int within = tok % tile_area;
1857 const int patch_y = (tile / tiles_per_row) * merge_size + within / merge_size;
1858 const int patch_x = (tile % tiles_per_row) * merge_size + within % merge_size;
1859 float *dst = patches + (size_t)tok * (
size_t)full_k;
1860 for (
int c = 0; c < channels; ++c) {
1861 for (
int t = 0; t < temporal; ++t) {
1862 for (
int py = 0; py < patch_size; ++py) {
1863 const float *src = image +
1864 ((size_t)c * (
size_t)image_h +
1865 (size_t)(patch_y * patch_size + py)) * (
size_t)image_w +
1866 (size_t)(patch_x * patch_size);
1867 memcpy(dst, src, (
size_t)patch_size *
sizeof(*dst));
1874 const uint16_t *w0 = (
const uint16_t *)weights_t0;
1875 const uint16_t *w1 = (
const uint16_t *)weights_t1;
1876 for (
int n = 0; n < out_channels; ++n) {
1877 uint16_t *dst = weights + (size_t)n * (
size_t)full_k;
1878 for (
int c = 0; c < channels; ++c) {
1879 const size_t channel_offset =
1880 (size_t)n * (
size_t)half_k +
1881 (size_t)c * (
size_t)patch_size * (size_t)patch_size;
1882 const size_t plane_bytes =
1883 (size_t)patch_size * (
size_t)patch_size *
sizeof(*dst);
1884 memcpy(dst, w0 + channel_offset, plane_bytes);
1885 dst += patch_size * patch_size;
1886 memcpy(dst, w1 + channel_offset, plane_bytes);
1887 dst += patch_size * patch_size;
1892 patches, weights, bias, output, batch, out_channels, channels,
1893 temporal, patch_size, patch_size);
1897 (void)image; (void)weights_t0; (void)weights_t1; (void)bias; (void)output;
1898 (void)channels; (void)image_h; (void)image_w; (void)patch_size;
1899 (void)out_channels; (void)merge_size;
1900 fprintf(stderr,
"HARD KERNEL CONTRACT FAULT: PyTorch oneDNN BF16 image "
1901 "patch projection was selected without USE_ONEDNN=1\n");
1908 const uint16_t *weights_t0;
1909 const uint16_t *weights_t1;
1920} ck_patch_projection_bf16_native_args_t;
1923 int ith,
int nth,
void *opaque)
1925 ck_patch_projection_bf16_native_args_t *args =
1926 (ck_patch_projection_bf16_native_args_t *)opaque;
1927 const int begin = args->batch * ith / nth;
1928 const int end = args->batch * (ith + 1) / nth;
1929 const int patch_area = args->patch_size * args->patch_size;
1930 const int half_k = args->channels * patch_area;
1931 const int tiles_per_row = args->grid_w / args->merge_size;
1932 const int tile_area = args->merge_size * args->merge_size;
1934 for (
int tok = begin; tok <
end; ++tok) {
1935 const int tile = tok / tile_area;
1936 const int within = tok % tile_area;
1938 (tile / tiles_per_row) * args->merge_size + within / args->merge_size;
1940 (tile % tiles_per_row) * args->merge_size + within % args->merge_size;
1941 for (
int n = 0; n < args->out_channels; ++n) {
1942 float sum = args->bias
1945#if defined(__AVX512BF16__) && defined(__AVX512VL__)
1946 if (args->patch_size == 16) {
1947 __m256 acc = _mm256_setzero_ps();
1948 for (
int c = 0; c < args->channels; ++c) {
1949 for (
int t = 0; t < 2; ++t) {
1950 const uint16_t *weights = t == 0
1951 ? args->weights_t0 : args->weights_t1;
1952 const uint16_t *weight_plane = weights +
1953 (size_t)n * (
size_t)half_k +
1954 (size_t)c * (
size_t)patch_area;
1955 for (
int py = 0; py < 16; ++py) {
1956 const float *src = args->image +
1957 ((size_t)c * (
size_t)args->image_h +
1958 (size_t)(patch_y * 16 + py)) *
1959 (
size_t)args->image_w +
1960 (size_t)(patch_x * 16);
1961 const __m256bh image_bf16 = _mm256_cvtne2ps_pbh(
1962 _mm256_loadu_ps(src + 8), _mm256_loadu_ps(src));
1963 const __m256bh weight_bf16 = (__m256bh)_mm256_loadu_si256(
1964 (
const __m256i *)(weight_plane + (size_t)py * 16u));
1965 acc = _mm256_dpbf16_ps(acc, image_bf16, weight_bf16);
1970 _mm256_storeu_ps(lanes, acc);
1971 const float sum01 = lanes[0] + lanes[1];
1972 const float sum23 = lanes[2] + lanes[3];
1973 const float sum45 = lanes[4] + lanes[5];
1974 const float sum67 = lanes[6] + lanes[7];
1975 sum += (sum01 + sum23) + (sum45 + sum67);
1979 for (
int c = 0; c < args->channels; ++c) {
1980 for (
int t = 0; t < 2; ++t) {
1981 const uint16_t *weights = t == 0
1982 ? args->weights_t0 : args->weights_t1;
1983 const uint16_t *weight_plane = weights +
1984 (size_t)n * (
size_t)half_k +
1985 (size_t)c * (
size_t)patch_area;
1986 for (
int py = 0; py < args->patch_size; ++py) {
1987 const float *src = args->image +
1988 ((size_t)c * (
size_t)args->image_h +
1989 (size_t)(patch_y * args->patch_size + py)) *
1990 (
size_t)args->image_w +
1991 (size_t)(patch_x * args->patch_size);
1992 for (
int px = 0; px < args->patch_size; ++px) {
1995 weight_plane[(
size_t)py *
1996 (
size_t)args->patch_size + (
size_t)px]);
1997 sum += value * weight;
2003 args->output[(size_t)tok * (
size_t)args->out_channels + (size_t)n] =
2010 const float *image,
const void *weights_t0,
const void *weights_t1,
2011 const float *bias,
float *output,
int channels,
int image_h,
int image_w,
2012 int patch_size,
int out_channels,
int merge_size)
2014 if (!image || !weights_t0 || !weights_t1 || !output || channels <= 0 ||
2015 image_h <= 0 || image_w <= 0 || patch_size <= 0 || out_channels <= 0 ||
2016 merge_size <= 0 || image_h % patch_size != 0 ||
2017 image_w % patch_size != 0) {
2018 fprintf(stderr,
"HARD KERNEL CONTRACT FAULT: invalid native BF16 image patch projection\n");
2021 const int grid_h = image_h / patch_size;
2022 const int grid_w = image_w / patch_size;
2023 if (grid_h % merge_size != 0 || grid_w % merge_size != 0) {
2024 fprintf(stderr,
"HARD KERNEL CONTRACT FAULT: native BF16 patch grid is not merge aligned\n");
2027 ck_patch_projection_bf16_native_args_t args = {
2029 .weights_t0 = (
const uint16_t *)weights_t0,
2030 .weights_t1 = (
const uint16_t *)weights_t1,
2033 .channels = channels,
2036 .patch_size = patch_size,
2037 .out_channels = out_channels,
2038 .merge_size = merge_size,
2040 .batch = grid_h * grid_w,
2044 if (active > args.batch) active = args.batch;
2045 if (active > 24) active = 24;
2046 if (pool && active > 1) {
2058 int M,
int N,
int K,
2059 int row_begin,
int row_end)
2062 for (
int row = row_begin; row < row_end; ++row) {
2063 float *dst =
C + (size_t)row * (
size_t)N;
2064 for (
int col = 0; col < N; ++col) {
2074 int M,
int N,
int K,
2075 int row_begin,
int row_end)
2077 const uint16_t *w = (
const uint16_t *)B;
2078 if (!A || !w || !
C || M <= 0 || N <= 0 || K <= 0 ||
2079 row_begin < 0 || row_begin >= row_end || row_end > M) {
2082 for (
int row = row_begin; row < row_end; ++row) {
2083 const float *a_row = A + (size_t)row * (
size_t)K;
2084 float *dst =
C + (size_t)row * (
size_t)N;
2085 for (
int col = 0; col < N; ++col) {
2086 const uint16_t *w_row = w + (size_t)col * (
size_t)K;
2094 for (; k + 1 < K; k += 2) {
2104 const float sum = (float)((even + odd) + (bias ? bias[col] : 0.0f));
2112 const ck_gemm_nt_bf16_exact_args_t *args =
2113 (
const ck_gemm_nt_bf16_exact_args_t *)opaque;
2115 args->A, args->B, args->bias, args->C,
2116 args->M, args->N, args->K, begin,
end);
2121 const ck_gemm_nt_bf16_exact_args_t *args =
2122 (
const ck_gemm_nt_bf16_exact_args_t *)opaque;
2124 args->A, args->B, args->bias, args->C,
2125 args->M, args->N, args->K, begin,
end);
2132 int M,
int N,
int K)
2136 (
size_t)M * (
size_t)N <= 4096) {
2141 ck_gemm_nt_bf16_exact_args_t args = {
2142 .A = A, .B = B, .bias = bias, .C =
C, .M = M, .N = N, .K = K,
2145 if (active > M) active = M;
2146 int grain = M / (active * 4);
2147 if (grain < 1) grain = 1;
2156 int M,
int N,
int K)
2165 int M,
int N,
int K)
2169 (
size_t)M * (
size_t)N <= 4096) {
2174 ck_gemm_nt_bf16_exact_args_t args = {
2175 .A = A, .B = B, .bias = bias, .C =
C, .M = M, .N = N, .K = K,
2178 if (active > M) active = M;
2179 int grain = M / (active * 4);
2180 if (grain < 1) grain = 1;
2189 int M,
int N,
int K)
2195 const uint16_t *input,
2196 const uint16_t *weight,
2204 if (!d_output || !input || !weight || tokens <= 0 || in_dim <= 0 || out_dim <= 0) {
2209 for (
int t = 0; t < tokens; ++t) {
2210 for (
int i = 0; i < in_dim; ++i) {
2212 for (
int o = 0; o < out_dim; ++o) {
2213 const float dy =
bf16_to_float(d_output[(
size_t)t * (
size_t)out_dim + (
size_t)o]);
2214 const float w =
bf16_to_float(weight[(
size_t)o * (
size_t)in_dim + (
size_t)i]);
2217 d_input[(size_t)t * (
size_t)in_dim + (size_t)i] = sum;
2223 for (
int o = 0; o < out_dim; ++o) {
2224 for (
int i = 0; i < in_dim; ++i) {
2226 for (
int t = 0; t < tokens; ++t) {
2227 const float dy =
bf16_to_float(d_output[(
size_t)t * (
size_t)out_dim + (
size_t)o]);
2228 const float x =
bf16_to_float(input[(
size_t)t * (
size_t)in_dim + (
size_t)i]);
2231 d_weight[(size_t)o * (
size_t)in_dim + (size_t)i] = sum;
2237 for (
int o = 0; o < out_dim; ++o) {
2239 for (
int t = 0; t < tokens; ++t) {
2240 sum +=
bf16_to_float(d_output[(
size_t)t * (
size_t)out_dim + (
size_t)o]);
static uint16_t float_to_bf16(float f)
static float bf16_to_float(uint16_t v)
Persistent pthread thread pool for CK-Engine inference.
void ck_threadpool_parallel_for_n(ck_threadpool_t *pool, int active_threads, int begin, int end, int grain_size, ck_range_fn_t fn, void *args)
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_n_threads(const ck_threadpool_t *pool)
void gemm_nt_bf16_pytorch_onednn_3_12_brgemm_bf16_storage(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
static void gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage_workspace_impl(const float *A, const void *B, const float *bias, float *C, int M, int N, int K, uint16_t *input_bf16, size_t input_bf16_bytes, uint16_t *output_bf16, size_t output_bf16_bytes, uint16_t *bias_bf16, size_t bias_bf16_bytes)
void gemm_tn_bf16(const uint16_t *A, const uint16_t *B, const uint16_t *bias, uint16_t *C, int M, int N, int K)
void gemm_nt_bf16_accurate_storage_row_range(const float *A, const void *B, const float *bias, float *C, int M, int N, int K, int row_begin, int row_end)
void gemm_nt_bf16_pytorch_onednn_3_12_brgemm_bf16_storage_workspace(const float *A, const void *B, const float *bias, float *C, int M, int N, int K, uint16_t *input_bf16, size_t input_bf16_bytes, uint16_t *output_bf16, size_t output_bf16_bytes, uint16_t *bias_bf16, size_t bias_bf16_bytes)
void gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
static void ck_gemv_bf16_rows(int begin, int end, void *opaque)
void gemv_bf16_bf16_storage(float *y, const void *W, const float *x, int M, int K)
int ck_gemm_bf16_amx_available(void)
void gemm_nt_bf16_bf16_storage_parallel_dispatch(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
static void ck_gemm_nt_bf16_accurate_storage_rows(int begin, int end, void *opaque)
void gemm_nt_bf16_native_bf16_storage(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
void gemm_nt_bf16_accurate_storage(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
void gemm_nt_bf16_bf16_storage_row_range(const float *A, const void *B, const float *bias, float *C, int M, int N, int K, int row_begin, int row_end)
void gemm_nt_bf16_amx_bf16_storage(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
void patch_projection_bf16_pytorch_onednn_conv3d_storage(const float *input, const void *weights, const float *bias, float *output, int batch, int out_channels, int in_channels, int temporal, int patch_h, int patch_w)
void gemm_bf16_fp32out(const uint16_t *A, const uint16_t *B, const float *bias, float *C, int M, int N, int K)
void gemv_bf16_bf16_storage_parallel_dispatch(float *y, const void *W, const float *x, int M, int K)
void gemm_blocked_serial_bf16(const uint16_t *A, const uint16_t *B, const uint16_t *bias, uint16_t *C, int M, int N, int K)
void patch_projection_image_bf16_native_storage(const float *image, const void *weights_t0, const void *weights_t1, const float *bias, float *output, int channels, int image_h, int image_w, int patch_size, int out_channels, int merge_size)
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)
void gemm_nt_bf16(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
void gemm_nt_bf16_parallel_dispatch(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
static void ck_bf16_convert_work(int ith, int nth, void *opaque)
static int ck_min_i(int a, int b)
void gemv_bf16(float *y, const void *W, const float *x, int M, int K)
void gemm_nn_bf16(const uint16_t *A, const uint16_t *B, const uint16_t *bias, uint16_t *C, int M, int N, int K)
static void ck_gemm_bf16_native_work(int ith, int nth, void *opaque)
static void ck_gemm_nt_bf16_exact_rows(int begin, int end, void *opaque)
static void ck_bf16_round_work(int ith, int nth, void *opaque)
void gemm_nt_bf16_accurate_storage_parallel_dispatch(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
static void gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage_impl(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
void gemm_backward_bf16_mixed(const uint16_t *d_output, const uint16_t *input, const uint16_t *weight, float *d_input, float *d_weight, float *d_bias, int tokens, int in_dim, int out_dim)
static void gemv_bf16_row_range(float *y, const uint16_t *w, const float *x, int M, int K, int row_begin, int row_end)
void gemv_bf16_parallel_dispatch(float *y, const void *W, const float *x, int M, int K)
static void ck_gemm_nt_bf16_storage_exact_rows(int begin, int end, void *opaque)
static void ck_pytorch_brgemm_fault(const char *message, int M, int N, int K)
static void ck_patch_projection_bf16_native_work(int ith, int nth, void *opaque)
static void ck_gemm_bf16_amx_work(int ith, int nth, void *opaque)
void patch_projection_image_bf16_pytorch_onednn_conv3d_storage(const float *image, const void *weights_t0, const void *weights_t1, const float *bias, float *output, int channels, int image_h, int image_w, int patch_size, int out_channels, int merge_size)
void gemm_nt_bf16_bf16_storage(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
void gemm_nt_bf16_prefill_shape_safe_bf16_storage(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
static void gemv_bf16_bf16_storage_row_range(float *y, const uint16_t *w, const float *x, int M, int K, int row_begin, int row_end)
void gemm_nt_bf16_prefill_shape_safe_bf16_storage_workspace(const float *A, const void *B, const float *bias, float *C, int M, int N, int K, uint16_t *a_bf16, size_t a_bf16_bytes)
void gemm_nt_bf16_row_range(const float *A, const void *B, const float *bias, float *C, int M, int N, int K, int row_begin, int row_end)
void gemm_nt_bf16_amx_bf16_storage_workspace(const float *A, const void *B, const float *bias, float *C, int M, int N, int K, uint16_t *a_bf16, size_t a_bf16_bytes)
static void ck_pytorch_brgemm_workspace_sizes(int M, int N, int K, size_t *input_bytes, size_t *output_bytes, size_t *bias_bytes)
static void ck_gemv_bf16_storage_rows(int begin, int end, void *opaque)
__attribute__((visibility("default"))) CKTokenizer *ck_tokenizer_create(CKTokenizerType type)
const uint8_t size_t count