← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
gemm_kernels_bf16.c File Reference

Optimized BF16 GEMM Kernels for AVX-512. More...

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bf16_utils.h"
#include "ckernel_engine.h"
#include "ck_threadpool.h"

Go to the source code of this file.

Macros

#define BLK_K   256
 
#define BLK_M   64
 
#define BLK_N   64
 

Functions

 __attribute__ ((unused))
 
static void ck_bf16_convert_work (int ith, int nth, void *opaque)
 
static void ck_bf16_round_work (int ith, int nth, void *opaque)
 
int ck_gemm_bf16_amx_available (void)
 
static void ck_gemm_bf16_amx_work (int ith, int nth, void *opaque)
 
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)
 
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_gemm_nt_bf16_storage_exact_rows (int begin, int end, void *opaque)
 
static void ck_gemv_bf16_rows (int begin, int end, void *opaque)
 
static void ck_gemv_bf16_storage_rows (int begin, int end, void *opaque)
 
static int ck_min_i (int a, int b)
 
static void ck_patch_projection_bf16_native_work (int ith, int nth, void *opaque)
 
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)
 
void gemm_bf16_fp32out (const uint16_t *A, const uint16_t *B, const float *bias, float *C, int M, int N, 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 gemm_nn_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 (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
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 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)
 
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_bf16_storage_parallel_dispatch (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_native_bf16_storage (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)
 
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)
 
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_pytorch_onednn_3_12_brgemm_bf16_storage (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
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 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_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_tn_bf16 (const uint16_t *A, const uint16_t *B, const uint16_t *bias, uint16_t *C, int M, int N, int K)
 
void gemv_bf16 (float *y, const void *W, const float *x, int M, int K)
 
void gemv_bf16_bf16_storage (float *y, const void *W, const float *x, int M, int K)
 
void gemv_bf16_bf16_storage_parallel_dispatch (float *y, const void *W, const float *x, int M, 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 gemv_bf16_parallel_dispatch (float *y, const void *W, const float *x, int M, int K)
 
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 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 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)
 
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)
 

Detailed Description

Optimized BF16 GEMM Kernels for AVX-512.

CK-ENGINE KERNEL RULES:

  1. NO malloc/free - memory via bump allocator, pointers passed in
  2. NO OpenMP - parallelization at orchestrator/codegen layer
  3. API must define: inputs, outputs, workspace, and memory layouts
  4. Pure computation - deterministic, no side effects

After changes: make test && make llamacpp-parity-full

Layout: A: [M x K] row-major (BF16) B: [N x K] row-major, stored as [out x in] (BF16) C: [M x N] row-major (BF16 or FP32)

Key optimizations:

  1. AVX-512 BF16 instructions (VDPBF16PS) when available
  2. Cache blocking for L1/L2 efficiency
  3. Vectorized BF16<->FP32 conversion
  4. CKE thread-pool row parallelization

Definition in file gemm_kernels_bf16.c.

Macro Definition Documentation

◆ BLK_K

#define BLK_K   256

Definition at line 56 of file gemm_kernels_bf16.c.

◆ BLK_M

#define BLK_M   64

Definition at line 54 of file gemm_kernels_bf16.c.

◆ BLK_N

#define BLK_N   64

Definition at line 55 of file gemm_kernels_bf16.c.

Function Documentation

◆ __attribute__()

__attribute__ ( (unused)  )

Definition at line 64 of file gemm_kernels_bf16.c.

70{
71 for (int i = 0; i < M; ++i) {
72 for (int j = 0; j < N; ++j) {
73 float sum = bias ? bf16_to_float(bias[j]) : 0.0f;
74 const size_t a_row = (size_t)i * (size_t)K;
75 const size_t b_row = (size_t)j * (size_t)K;
76 for (int k = 0; k < K; ++k) {
77 sum += bf16_to_float(A[a_row + k]) * bf16_to_float(B[b_row + k]);
78 }
79 C[(size_t)i * (size_t)N + j] = float_to_bf16(sum);
80 }
81 }
82}
static uint16_t float_to_bf16(float f)
Definition bf16_utils.h:90
static float bf16_to_float(uint16_t v)
Definition bf16_utils.h:38
#define C(color)
Definition show_config.c:39

References __attribute__(), bf16_to_float(), C, and float_to_bf16().

◆ ck_bf16_convert_work()

static void ck_bf16_convert_work ( int  ith,
int  nth,
void *  opaque 
)
static

Definition at line 1100 of file gemm_kernels_bf16.c.

1101{
1102 ck_bf16_convert_args_t *args = (ck_bf16_convert_args_t *)opaque;
1103 const size_t begin = args->count * (size_t)ith / (size_t)nth;
1104 const size_t end = args->count * (size_t)(ith + 1) / (size_t)nth;
1105 for (size_t i = begin; i < end; ++i) args->dst[i] = float_to_bf16(args->src[i]);
1106}
uint32_t end
Definition utf8.c:215

References end, and float_to_bf16().

Referenced by gemm_nt_bf16_amx_bf16_storage_workspace().

◆ ck_bf16_round_work()

static void ck_bf16_round_work ( int  ith,
int  nth,
void *  opaque 
)
static

Definition at line 1186 of file gemm_kernels_bf16.c.

1187{
1188 ck_bf16_round_args_t *args = (ck_bf16_round_args_t *)opaque;
1189 const size_t begin = args->count * (size_t)ith / (size_t)nth;
1190 const size_t end = args->count * (size_t)(ith + 1) / (size_t)nth;
1191 for (size_t i = begin; i < end; ++i) {
1192 args->values[i] = bf16_to_float(float_to_bf16(args->values[i]));
1193 }
1194}

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

Referenced by gemm_nt_bf16_amx_bf16_storage_workspace().

◆ ck_gemm_bf16_amx_available()

int ck_gemm_bf16_amx_available ( void  )

Definition at line 1196 of file gemm_kernels_bf16.c.

1197{
1198#if HAVE_AMX_BF16
1199 return ck_amx_request_xtile_data();
1200#else
1201 return 0;
1202#endif
1203}

Referenced by ck_attention_full_bf16_sdpa_amx_range(), gemm_nt_bf16_prefill_shape_safe_bf16_storage(), and gemm_nt_bf16_prefill_shape_safe_bf16_storage_workspace().

◆ ck_gemm_bf16_amx_work()

static void ck_gemm_bf16_amx_work ( int  ith,
int  nth,
void *  opaque 
)
static

Definition at line 1119 of file gemm_kernels_bf16.c.

1120{
1121#if HAVE_AMX_BF16
1122 ck_gemm_bf16_amx_args_t *args = (ck_gemm_bf16_amx_args_t *)opaque;
1123 if (!ck_amx_request_xtile_data()) {
1124 __atomic_store_n(&args->failed, 1, __ATOMIC_RELAXED);
1125 return;
1126 }
1127 ck_amx_config_bf16_16x16x32();
1128 uint16_t b_tile[16 * 32];
1129 const int mb = args->M / 16;
1130 const int nb = args->N / 16;
1131 const int m_groups = (mb + 3) / 4;
1132 const int jobs = m_groups * nb;
1133
1134 for (int job = ith; job < jobs; job += nth) {
1135 const int m_group = job / nb;
1136 const int j = (job % nb) * 16;
1137 const int group_blocks = (mb - m_group * 4 < 4) ? mb - m_group * 4 : 4;
1138 _tile_zero(2);
1139 if (group_blocks > 1) _tile_zero(3);
1140 if (group_blocks > 2) _tile_zero(4);
1141 if (group_blocks > 3) _tile_zero(5);
1142 for (int k = 0; k < args->K; k += 32) {
1143 ck_pack_bf16_ktile_pairs_16x16(b_tile, args->B, args->K, j, k);
1144 _tile_loadd(1, b_tile, 32 * (int)sizeof(uint16_t));
1145 for (int g = 0; g < group_blocks; ++g) {
1146 const int i = (m_group * 4 + g) * 16;
1147 _tile_loadd(0, args->A + (size_t)i * args->K + k,
1148 args->K * (int)sizeof(uint16_t));
1149 switch (g) {
1150 case 0: _tile_dpbf16ps(2, 0, 1); break;
1151 case 1: _tile_dpbf16ps(3, 0, 1); break;
1152 case 2: _tile_dpbf16ps(4, 0, 1); break;
1153 default: _tile_dpbf16ps(5, 0, 1); break;
1154 }
1155 }
1156 }
1157 for (int g = 0; g < group_blocks; ++g) {
1158 const int i = (m_group * 4 + g) * 16;
1159 float *tile_dst = args->C + (size_t)i * args->N + j;
1160 const int tile_stride = args->N * (int)sizeof(float);
1161 switch (g) {
1162 case 0: _tile_stored(2, tile_dst, tile_stride); break;
1163 case 1: _tile_stored(3, tile_dst, tile_stride); break;
1164 case 2: _tile_stored(4, tile_dst, tile_stride); break;
1165 default: _tile_stored(5, tile_dst, tile_stride); break;
1166 }
1167 if (args->bias) {
1168 for (int ii = 0; ii < 16; ++ii) {
1169 float *row = args->C + (size_t)(i + ii) * args->N + j;
1170 for (int jj = 0; jj < 16; ++jj) row[jj] += args->bias[j + jj];
1171 }
1172 }
1173 }
1174 }
1175 _tile_release();
1176#else
1177 (void)ith; (void)nth; (void)opaque;
1178#endif
1179}

Referenced by gemm_nt_bf16_amx_bf16_storage_workspace().

◆ ck_gemm_bf16_fp32out_amx_raw()

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 
)

Definition at line 1205 of file gemm_kernels_bf16.c.

1210{
1211#if HAVE_AMX_BF16
1212 if (!A || !B || !C || M <= 0 || N <= 0 || K <= 0 ||
1213 (M % 16) != 0 || (N % 16) != 0 || (K % 2) != 0 ||
1214 !ck_amx_request_xtile_data()) {
1215 return 0;
1216 }
1217 /* Match oneDNN BRGEMM: largest even divisor of K no greater than 32. */
1218 int k_block = K < 32 ? K : 32;
1219 while (k_block > 2 && K % k_block != 0) k_block -= 2;
1220 ck_amx_config_bf16_16x16_kblock(k_block);
1221 uint16_t b_tile[16 * 32];
1222 for (int i = 0; i < M; i += 16) {
1223 for (int j = 0; j < N; j += 16) {
1224 if (accumulate) {
1225 _tile_loadd(2, C + (size_t)i * (size_t)N + (size_t)j,
1226 N * (int)sizeof(float));
1227 } else {
1228 _tile_zero(2);
1229 }
1230 for (int k = 0; k < K; k += k_block) {
1231 memset(b_tile, 0, sizeof(b_tile));
1232 for (int kp = 0; kp < k_block / 2; ++kp) {
1233 const int k0 = k + kp * 2;
1234 for (int nn = 0; nn < 16; ++nn) {
1235 b_tile[(size_t)kp * 32u + (size_t)nn * 2u] =
1236 B[(size_t)(j + nn) * (size_t)K + (size_t)k0];
1237 b_tile[(size_t)kp * 32u + (size_t)nn * 2u + 1u] =
1238 B[(size_t)(j + nn) * (size_t)K + (size_t)k0 + 1u];
1239 }
1240 }
1241 _tile_loadd(0, A + (size_t)i * (size_t)K + (size_t)k,
1242 K * (int)sizeof(uint16_t));
1243 _tile_loadd(1, b_tile, 32 * (int)sizeof(uint16_t));
1244 _tile_dpbf16ps(2, 0, 1);
1245 }
1246 _tile_stored(2, C + (size_t)i * (size_t)N + (size_t)j,
1247 N * (int)sizeof(float));
1248 }
1249 }
1250 _tile_release();
1251 return 1;
1252#else
1253 (void)A; (void)B; (void)C; (void)M; (void)N; (void)K; (void)accumulate;
1254 return 0;
1255#endif
1256}

References C.

Referenced by ck_attention_full_bf16_sdpa_amx_range().

◆ ck_gemm_bf16_native_work()

static void ck_gemm_bf16_native_work ( int  ith,
int  nth,
void *  opaque 
)
static

Definition at line 969 of file gemm_kernels_bf16.c.

970{
971 ck_gemm_bf16_native_args_t *args = (ck_gemm_bf16_native_args_t *)opaque;
972 const int N = args->N;
973 const int K = args->K;
974 enum { ROW_TILE = 4 };
975 uint16_t *a_bf16 = (uint16_t *)alloca(
976 (size_t)ROW_TILE * (size_t)K * sizeof(uint16_t));
977
978 for (int row0 = ith * ROW_TILE; row0 < args->M; row0 += nth * ROW_TILE) {
979 const int rows = args->M - row0 < ROW_TILE ? args->M - row0 : ROW_TILE;
980 for (int r = 0; r < rows; ++r) {
981 const float *src = args->A + (size_t)(row0 + r) * (size_t)K;
982 uint16_t *ar = a_bf16 + (size_t)r * (size_t)K;
983 for (int k = 0; k < K; ++k) ar[k] = float_to_bf16(src[k]);
984 }
985
986#if HAVE_NATIVE_BF16
987 int j = 0;
988 for (; j + 4 <= N; j += 4) {
989 const uint16_t *b0 = args->B + (size_t)(j + 0) * K;
990 const uint16_t *b1 = args->B + (size_t)(j + 1) * K;
991 const uint16_t *b2 = args->B + (size_t)(j + 2) * K;
992 const uint16_t *b3 = args->B + (size_t)(j + 3) * K;
993 __m512 acc[ROW_TILE][4];
994 for (int r = 0; r < rows; ++r) {
995 for (int lane = 0; lane < 4; ++lane) acc[r][lane] = _mm512_setzero_ps();
996 }
997 int k = 0;
998 for (; k <= K - 32; k += 32) {
999 const __m512bh bv[4] = {
1000 load_bf16x32(b0 + k), load_bf16x32(b1 + k),
1001 load_bf16x32(b2 + k), load_bf16x32(b3 + k)
1002 };
1003 for (int r = 0; r < rows; ++r) {
1004 const __m512bh av =
1005 load_bf16x32(a_bf16 + (size_t)r * (size_t)K + k);
1006 for (int lane = 0; lane < 4; ++lane) {
1007 acc[r][lane] = _mm512_dpbf16_ps(acc[r][lane], av, bv[lane]);
1008 }
1009 }
1010 }
1011 for (int r = 0; r < rows; ++r) {
1012 float sums[4];
1013 for (int lane = 0; lane < 4; ++lane) {
1014 sums[lane] = _mm512_reduce_add_ps(acc[r][lane]);
1015 }
1016 const uint16_t *ar = a_bf16 + (size_t)r * (size_t)K;
1017 for (int tail = k; tail < K; ++tail) {
1018 const float av = bf16_to_float(ar[tail]);
1019 sums[0] += av * bf16_to_float(b0[tail]);
1020 sums[1] += av * bf16_to_float(b1[tail]);
1021 sums[2] += av * bf16_to_float(b2[tail]);
1022 sums[3] += av * bf16_to_float(b3[tail]);
1023 }
1024 float *dst = args->C + (size_t)(row0 + r) * (size_t)N;
1025 for (int lane = 0; lane < 4; ++lane) {
1026 if (args->bias) sums[lane] += args->bias[j + lane];
1027 dst[j + lane] = bf16_to_float(float_to_bf16(sums[lane]));
1028 }
1029 }
1030 }
1031 for (; j < N; ++j) {
1032 const uint16_t *b = args->B + (size_t)j * K;
1033 __m512 acc[ROW_TILE];
1034 for (int r = 0; r < rows; ++r) acc[r] = _mm512_setzero_ps();
1035 int k = 0;
1036 for (; k <= K - 32; k += 32) {
1037 const __m512bh bv = load_bf16x32(b + k);
1038 for (int r = 0; r < rows; ++r) {
1039 acc[r] = _mm512_dpbf16_ps(
1040 acc[r], load_bf16x32(a_bf16 + (size_t)r * (size_t)K + k), bv);
1041 }
1042 }
1043 for (int r = 0; r < rows; ++r) {
1044 const uint16_t *ar = a_bf16 + (size_t)r * (size_t)K;
1045 float sum = _mm512_reduce_add_ps(acc[r]);
1046 for (int tail = k; tail < K; ++tail) {
1047 sum += bf16_to_float(ar[tail]) * bf16_to_float(b[tail]);
1048 }
1049 if (args->bias) sum += args->bias[j];
1050 args->C[(size_t)(row0 + r) * (size_t)N + j] =
1052 }
1053 }
1054#else
1055 for (int r = 0; r < rows; ++r) {
1056 const uint16_t *ar = a_bf16 + (size_t)r * (size_t)K;
1057 float *dst = args->C + (size_t)(row0 + r) * (size_t)N;
1058 for (int j = 0; j < N; ++j) {
1059 const uint16_t *b = args->B + (size_t)j * K;
1060 float sum = args->bias ? args->bias[j] : 0.0f;
1061 for (int k = 0; k < K; ++k) {
1062 sum += bf16_to_float(ar[k]) * bf16_to_float(b[k]);
1063 }
1064 dst[j] = bf16_to_float(float_to_bf16(sum));
1065 }
1066 }
1067#endif
1068 }
1069}

References bf16_to_float(), and float_to_bf16().

Referenced by gemm_nt_bf16_native_bf16_storage().

◆ ck_gemm_nt_bf16_exact_rows()

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

Definition at line 768 of file gemm_kernels_bf16.c.

769{
770 const ck_gemm_nt_bf16_exact_args_t *args =
771 (const ck_gemm_nt_bf16_exact_args_t *)opaque;
773 args->A, args->B, args->bias, args->C,
774 args->M, args->N, args->K, begin, end);
775}
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)

References end, and gemm_nt_bf16_row_range().

Referenced by gemm_nt_bf16_parallel_dispatch().

◆ ck_gemm_nt_bf16_storage_exact_rows()

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

Definition at line 2001 of file gemm_kernels_bf16.c.

2002{
2003 const ck_gemm_nt_bf16_exact_args_t *args =
2004 (const ck_gemm_nt_bf16_exact_args_t *)opaque;
2006 args->A, args->B, args->bias, args->C,
2007 args->M, args->N, args->K, begin, end);
2008}
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)

References end, and gemm_nt_bf16_bf16_storage_row_range().

Referenced by gemm_nt_bf16_bf16_storage_parallel_dispatch().

◆ ck_gemv_bf16_rows()

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

Definition at line 639 of file gemm_kernels_bf16.c.

640{
641 const ck_gemv_bf16_args_t *args = (const ck_gemv_bf16_args_t *)opaque;
643 args->y, args->w, args->x, args->M, args->K, begin, end);
644}
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)

References end, and gemv_bf16_row_range().

Referenced by gemv_bf16_parallel_dispatch().

◆ ck_gemv_bf16_storage_rows()

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

Definition at line 681 of file gemm_kernels_bf16.c.

682{
683 const ck_gemv_bf16_args_t *args = (const ck_gemv_bf16_args_t *)opaque;
685 args->y, args->w, args->x, args->M, args->K, begin, end);
686}
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)

References end, and gemv_bf16_bf16_storage_row_range().

Referenced by gemv_bf16_bf16_storage_parallel_dispatch().

◆ ck_min_i()

static int ck_min_i ( int  a,
int  b 
)
inlinestatic

Definition at line 58 of file gemm_kernels_bf16.c.

58{ return a < b ? a : b; }

◆ ck_patch_projection_bf16_native_work()

static void ck_patch_projection_bf16_native_work ( int  ith,
int  nth,
void *  opaque 
)
static

Definition at line 1853 of file gemm_kernels_bf16.c.

1855{
1856 ck_patch_projection_bf16_native_args_t *args =
1857 (ck_patch_projection_bf16_native_args_t *)opaque;
1858 const int begin = args->batch * ith / nth;
1859 const int end = args->batch * (ith + 1) / nth;
1860 const int patch_area = args->patch_size * args->patch_size;
1861 const int half_k = args->channels * patch_area;
1862 const int tiles_per_row = args->grid_w / args->merge_size;
1863 const int tile_area = args->merge_size * args->merge_size;
1864
1865 for (int tok = begin; tok < end; ++tok) {
1866 const int tile = tok / tile_area;
1867 const int within = tok % tile_area;
1868 const int patch_y =
1869 (tile / tiles_per_row) * args->merge_size + within / args->merge_size;
1870 const int patch_x =
1871 (tile % tiles_per_row) * args->merge_size + within % args->merge_size;
1872 for (int n = 0; n < args->out_channels; ++n) {
1873 float sum = args->bias
1874 ? bf16_to_float(float_to_bf16(args->bias[n]))
1875 : 0.0f;
1876#if defined(__AVX512BF16__) && defined(__AVX512VL__)
1877 if (args->patch_size == 16) {
1878 __m256 acc = _mm256_setzero_ps();
1879 for (int c = 0; c < args->channels; ++c) {
1880 for (int t = 0; t < 2; ++t) {
1881 const uint16_t *weights = t == 0
1882 ? args->weights_t0 : args->weights_t1;
1883 const uint16_t *weight_plane = weights +
1884 (size_t)n * (size_t)half_k +
1885 (size_t)c * (size_t)patch_area;
1886 for (int py = 0; py < 16; ++py) {
1887 const float *src = args->image +
1888 ((size_t)c * (size_t)args->image_h +
1889 (size_t)(patch_y * 16 + py)) *
1890 (size_t)args->image_w +
1891 (size_t)(patch_x * 16);
1892 const __m256bh image_bf16 = _mm256_cvtne2ps_pbh(
1893 _mm256_loadu_ps(src + 8), _mm256_loadu_ps(src));
1894 const __m256bh weight_bf16 = (__m256bh)_mm256_loadu_si256(
1895 (const __m256i *)(weight_plane + (size_t)py * 16u));
1896 acc = _mm256_dpbf16_ps(acc, image_bf16, weight_bf16);
1897 }
1898 }
1899 }
1900 float lanes[8];
1901 _mm256_storeu_ps(lanes, acc);
1902 const float sum01 = lanes[0] + lanes[1];
1903 const float sum23 = lanes[2] + lanes[3];
1904 const float sum45 = lanes[4] + lanes[5];
1905 const float sum67 = lanes[6] + lanes[7];
1906 sum += (sum01 + sum23) + (sum45 + sum67);
1907 } else
1908#endif
1909 {
1910 for (int c = 0; c < args->channels; ++c) {
1911 for (int t = 0; t < 2; ++t) {
1912 const uint16_t *weights = t == 0
1913 ? args->weights_t0 : args->weights_t1;
1914 const uint16_t *weight_plane = weights +
1915 (size_t)n * (size_t)half_k +
1916 (size_t)c * (size_t)patch_area;
1917 for (int py = 0; py < args->patch_size; ++py) {
1918 const float *src = args->image +
1919 ((size_t)c * (size_t)args->image_h +
1920 (size_t)(patch_y * args->patch_size + py)) *
1921 (size_t)args->image_w +
1922 (size_t)(patch_x * args->patch_size);
1923 for (int px = 0; px < args->patch_size; ++px) {
1924 const float value = bf16_to_float(float_to_bf16(src[px]));
1925 const float weight = bf16_to_float(
1926 weight_plane[(size_t)py *
1927 (size_t)args->patch_size + (size_t)px]);
1928 sum += value * weight;
1929 }
1930 }
1931 }
1932 }
1933 }
1934 args->output[(size_t)tok * (size_t)args->out_channels + (size_t)n] =
1936 }
1937 }
1938}

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

Referenced by patch_projection_image_bf16_native_storage().

◆ gemm_backward_bf16_mixed()

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 
)

Definition at line 2043 of file gemm_kernels_bf16.c.

2052{
2053 if (!d_output || !input || !weight || tokens <= 0 || in_dim <= 0 || out_dim <= 0) {
2054 return;
2055 }
2056
2057 if (d_input) {
2058 for (int t = 0; t < tokens; ++t) {
2059 for (int i = 0; i < in_dim; ++i) {
2060 float sum = 0.0f;
2061 for (int o = 0; o < out_dim; ++o) {
2062 const float dy = bf16_to_float(d_output[(size_t)t * (size_t)out_dim + (size_t)o]);
2063 const float w = bf16_to_float(weight[(size_t)o * (size_t)in_dim + (size_t)i]);
2064 sum += dy * w;
2065 }
2066 d_input[(size_t)t * (size_t)in_dim + (size_t)i] = sum;
2067 }
2068 }
2069 }
2070
2071 if (d_weight) {
2072 for (int o = 0; o < out_dim; ++o) {
2073 for (int i = 0; i < in_dim; ++i) {
2074 float sum = 0.0f;
2075 for (int t = 0; t < tokens; ++t) {
2076 const float dy = bf16_to_float(d_output[(size_t)t * (size_t)out_dim + (size_t)o]);
2077 const float x = bf16_to_float(input[(size_t)t * (size_t)in_dim + (size_t)i]);
2078 sum += dy * x;
2079 }
2080 d_weight[(size_t)o * (size_t)in_dim + (size_t)i] = sum;
2081 }
2082 }
2083 }
2084
2085 if (d_bias) {
2086 for (int o = 0; o < out_dim; ++o) {
2087 float sum = 0.0f;
2088 for (int t = 0; t < tokens; ++t) {
2089 sum += bf16_to_float(d_output[(size_t)t * (size_t)out_dim + (size_t)o]);
2090 }
2091 d_bias[o] = sum;
2092 }
2093 }
2094}

References bf16_to_float().

◆ gemm_bf16_fp32out()

void gemm_bf16_fp32out ( const uint16_t *  A,
const uint16_t *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 453 of file gemm_kernels_bf16.c.

458{
459 if (!A || !B || !C || M <= 0 || N <= 0 || K <= 0) {
460 return;
461 }
462
463#if HAVE_NATIVE_BF16
464#if HAVE_AMX_BF16
465 const char *amx_env = getenv("CK_BF16_AMX");
466 if (amx_env && amx_env[0] == '1' &&
467 (M % 16) == 0 && (N % 16) == 0 && (K % 32) == 0 &&
468 M >= 16 && N >= 16 && K >= 32 && ck_amx_request_xtile_data()) {
469 gemm_bf16_fp32out_amx(A, B, bias, C, M, N, K);
470 return;
471 }
472#endif
473
474 #pragma omp parallel for schedule(dynamic)
475 for (int i = 0; i < M; ++i) {
476 const uint16_t *a_row = A + (size_t)i * K;
477 int j = 0;
478
479 for (; j + 4 <= N; j += 4) {
480 const uint16_t *b0 = B + (size_t)(j + 0) * K;
481 const uint16_t *b1 = B + (size_t)(j + 1) * K;
482 const uint16_t *b2 = B + (size_t)(j + 2) * K;
483 const uint16_t *b3 = B + (size_t)(j + 3) * K;
484 __m512 acc0 = _mm512_setzero_ps();
485 __m512 acc1 = _mm512_setzero_ps();
486 __m512 acc2 = _mm512_setzero_ps();
487 __m512 acc3 = _mm512_setzero_ps();
488
489 int k = 0;
490 for (; k <= K - 32; k += 32) {
491 const __m512bh a_vec = load_bf16x32(a_row + k);
492 acc0 = _mm512_dpbf16_ps(acc0, a_vec, load_bf16x32(b0 + k));
493 acc1 = _mm512_dpbf16_ps(acc1, a_vec, load_bf16x32(b1 + k));
494 acc2 = _mm512_dpbf16_ps(acc2, a_vec, load_bf16x32(b2 + k));
495 acc3 = _mm512_dpbf16_ps(acc3, a_vec, load_bf16x32(b3 + k));
496 }
497
498 float s0 = _mm512_reduce_add_ps(acc0);
499 float s1 = _mm512_reduce_add_ps(acc1);
500 float s2 = _mm512_reduce_add_ps(acc2);
501 float s3 = _mm512_reduce_add_ps(acc3);
502 for (; k < K; ++k) {
503 const float a = bf16_to_float(a_row[k]);
504 s0 += a * bf16_to_float(b0[k]);
505 s1 += a * bf16_to_float(b1[k]);
506 s2 += a * bf16_to_float(b2[k]);
507 s3 += a * bf16_to_float(b3[k]);
508 }
509 if (bias) {
510 s0 += bias[j + 0];
511 s1 += bias[j + 1];
512 s2 += bias[j + 2];
513 s3 += bias[j + 3];
514 }
515 C[(size_t)i * N + (j + 0)] = s0;
516 C[(size_t)i * N + (j + 1)] = s1;
517 C[(size_t)i * N + (j + 2)] = s2;
518 C[(size_t)i * N + (j + 3)] = s3;
519 }
520
521 for (; j < N; ++j) {
522 const uint16_t *b_row = B + (size_t)j * K;
523 __m512 sum_vec = _mm512_setzero_ps();
524
525 int k = 0;
526 for (; k <= K - 32; k += 32) {
527 const __m512bh a_vec = load_bf16x32(a_row + k);
528 const __m512bh b_vec = load_bf16x32(b_row + k);
529 sum_vec = _mm512_dpbf16_ps(sum_vec, a_vec, b_vec);
530 }
531
532 float sum = _mm512_reduce_add_ps(sum_vec);
533 for (; k < K; ++k) {
534 sum += bf16_to_float(a_row[k]) * bf16_to_float(b_row[k]);
535 }
536 if (bias) {
537 sum += bias[j];
538 }
539 C[(size_t)i * N + j] = sum;
540 }
541 }
542#elif defined(__AVX512F__)
543 #pragma omp parallel for schedule(dynamic)
544 for (int i = 0; i < M; ++i) {
545 const uint16_t *a_row = A + (size_t)i * K;
546
547 for (int j = 0; j < N; ++j) {
548 const uint16_t *b_row = B + (size_t)j * K;
549
550 __m512 sum_vec = _mm512_setzero_ps();
551
552 int k = 0;
553 for (; k <= K - 16; k += 16) {
554 __m256i a_bf16 = _mm256_loadu_si256((const __m256i *)(a_row + k));
555 __m256i b_bf16 = _mm256_loadu_si256((const __m256i *)(b_row + k));
556 sum_vec = bf16_dot16(a_bf16, b_bf16, sum_vec);
557 }
558
559 float sum = _mm512_reduce_add_ps(sum_vec);
560
561 for (; k < K; ++k) {
562 sum += bf16_to_float(a_row[k]) * bf16_to_float(b_row[k]);
563 }
564
565 if (bias) {
566 sum += bias[j];
567 }
568
569 C[(size_t)i * N + j] = sum;
570 }
571 }
572#else
573 for (int i = 0; i < M; ++i) {
574 for (int j = 0; j < N; ++j) {
575 float sum = bias ? bias[j] : 0.0f;
576 for (int k = 0; k < K; ++k) {
577 sum += bf16_to_float(A[(size_t)i * K + k]) *
578 bf16_to_float(B[(size_t)j * K + k]);
579 }
580 C[(size_t)i * N + j] = sum;
581 }
582 }
583#endif
584}

References bf16_to_float(), and C.

Referenced by mlp_token_parallel_bf16(), and mlp_token_parallel_bf16_fp32act().

◆ gemm_blocked_serial_bf16()

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 
)

Definition at line 424 of file gemm_kernels_bf16.c.

429{
430 if (!A || !B || !C || M <= 0 || N <= 0 || K <= 0) {
431 return;
432 }
433
434#if HAVE_NATIVE_BF16
435 /* Native BF16 instructions available (Ice Lake / Sapphire Rapids+) */
436 gemm_bf16_native(A, B, bias, C, M, N, K);
437#elif defined(__AVX512F__)
438 /* Use AVX-512F with software BF16 conversion */
439 if (M * N > 4096) {
440 gemm_bf16_blocked_avx512(A, B, bias, C, M, N, K);
441 } else {
442 gemm_bf16_avx512(A, B, bias, C, M, N, K);
443 }
444#else
445 /* Scalar fallback */
446 gemm_bf16_scalar(A, B, bias, C, M, N, K);
447#endif
448}

References C.

◆ gemm_nn_bf16()

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 
)

Definition at line 808 of file gemm_kernels_bf16.c.

813{
814 if (!A || !B || !C || M <= 0 || N <= 0 || K <= 0) {
815 return;
816 }
817
818#if defined(__AVX512F__)
819 #pragma omp parallel for
820 for (int i = 0; i < M; ++i) {
821 /* Initialize row with bias */
822 int j = 0;
823 for (; j <= N - 16; j += 16) {
824 __m512 b_vec = bias ? bf16x16_to_fp32(_mm256_loadu_si256((const __m256i *)(bias + j)))
825 : _mm512_setzero_ps();
826 __m256i out = fp32x16_to_bf16(b_vec);
827 _mm256_storeu_si256((__m256i *)(C + (size_t)i * N + j), out);
828 }
829 for (; j < N; ++j) {
830 float b = bias ? bf16_to_float(bias[j]) : 0.0f;
831 C[(size_t)i * N + j] = float_to_bf16(b);
832 }
833
834 /* Accumulate: C[i,:] += A[i,k] * B[k,:] */
835 for (int k = 0; k < K; ++k) {
836 float a_val = bf16_to_float(A[(size_t)i * K + k]);
837 __m512 a_broadcast = _mm512_set1_ps(a_val);
838
839 j = 0;
840 for (; j <= N - 16; j += 16) {
841 __m256i b_bf16 = _mm256_loadu_si256((const __m256i *)(B + (size_t)k * N + j));
842 __m512 b_fp32 = bf16x16_to_fp32(b_bf16);
843
844 __m256i c_bf16 = _mm256_loadu_si256((const __m256i *)(C + (size_t)i * N + j));
845 __m512 c_fp32 = bf16x16_to_fp32(c_bf16);
846
847 c_fp32 = _mm512_fmadd_ps(a_broadcast, b_fp32, c_fp32);
848
849 __m256i c_out = fp32x16_to_bf16(c_fp32);
850 _mm256_storeu_si256((__m256i *)(C + (size_t)i * N + j), c_out);
851 }
852 for (; j < N; ++j) {
853 float c_val = bf16_to_float(C[(size_t)i * N + j]);
854 c_val += a_val * bf16_to_float(B[(size_t)k * N + j]);
855 C[(size_t)i * N + j] = float_to_bf16(c_val);
856 }
857 }
858 }
859#else
860 /* Scalar fallback */
861 for (int i = 0; i < M; ++i) {
862 for (int j = 0; j < N; ++j) {
863 float sum = bias ? bf16_to_float(bias[j]) : 0.0f;
864 for (int k = 0; k < K; ++k) {
865 sum += bf16_to_float(A[(size_t)i * K + k]) *
866 bf16_to_float(B[(size_t)k * N + j]);
867 }
868 C[(size_t)i * N + j] = float_to_bf16(sum);
869 }
870 }
871#endif
872}

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

◆ gemm_nt_bf16()

void gemm_nt_bf16 ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 748 of file gemm_kernels_bf16.c.

753{
754 if (M <= 0) return;
755 gemm_nt_bf16_row_range(A, B, bias, C, M, N, K, 0, M);
756}

References C, and gemm_nt_bf16_row_range().

Referenced by gemm_nt_bf16_parallel_dispatch().

◆ gemm_nt_bf16_amx_bf16_storage()

void gemm_nt_bf16_amx_bf16_storage ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 1311 of file gemm_kernels_bf16.c.

1316{
1317 size_t input_count = 0;
1318 if (M > 0 && K > 0 && (size_t)M <= SIZE_MAX / (size_t)K) {
1319 input_count = (size_t)M * (size_t)K;
1320 }
1321 uint16_t *workspace = input_count > 0 && input_count <= SIZE_MAX / sizeof(uint16_t)
1322 ? (uint16_t *)malloc(input_count * sizeof(uint16_t))
1323 : NULL;
1324 if (!workspace) {
1325 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: AMX BF16 compatibility workspace allocation failed\n");
1326 abort();
1327 }
1329 A, B, bias, C, M, N, K, workspace, input_count * sizeof(uint16_t));
1330 free(workspace);
1331}
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)

References C, and gemm_nt_bf16_amx_bf16_storage_workspace().

Referenced by gemm_nt_bf16_prefill_shape_safe_bf16_storage().

◆ gemm_nt_bf16_amx_bf16_storage_workspace()

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 
)

Definition at line 1258 of file gemm_kernels_bf16.c.

1265{
1266#if HAVE_AMX_BF16
1267 if (!A || !B || !C || M < 16 || N < 16 || K < 32 ||
1268 (M % 16) != 0 || (N % 16) != 0 || (K % 32) != 0) {
1269 fprintf(stderr,
1270 "HARD KERNEL CONTRACT FAULT: AMX BF16 GEMM requires non-null buffers "
1271 "and M%%16=N%%16=K%%32=0 (M=%d N=%d K=%d)\n",
1272 M, N, K);
1273 abort();
1274 }
1275 const size_t input_count = (size_t)M * K;
1276 if (!a_bf16 || input_count > SIZE_MAX / sizeof(uint16_t) ||
1277 a_bf16_bytes < input_count * sizeof(uint16_t)) {
1278 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: AMX BF16 activation workspace is too small\n");
1279 abort();
1280 }
1281 ck_threadpool_t *pool = ck_threadpool_global();
1282 int active = pool ? ck_threadpool_n_threads(pool) : 1;
1283 if (active > 24) active = 24;
1284 ck_bf16_convert_args_t convert = {.src=A, .dst=a_bf16, .count=input_count};
1285 if (pool && active > 1) ck_threadpool_dispatch_n(pool, active, ck_bf16_convert_work, &convert);
1286 else ck_bf16_convert_work(0, 1, &convert);
1287 ck_gemm_bf16_amx_args_t gemm = {
1288 .A=a_bf16, .B=(const uint16_t *)B, .bias=bias, .C=C,
1289 .M=M, .N=N, .K=K, .failed=0
1290 };
1291 if (pool && active > 1) ck_threadpool_dispatch_n(pool, active, ck_gemm_bf16_amx_work, &gemm);
1292 else ck_gemm_bf16_amx_work(0, 1, &gemm);
1293 if (__atomic_load_n(&gemm.failed, __ATOMIC_RELAXED)) {
1294 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: AMX tile permission request failed\n");
1295 abort();
1296 }
1297 ck_bf16_round_args_t round = {.values=C, .count=(size_t)M * N};
1298 if (pool && active > 1) ck_threadpool_dispatch_n(pool, active, ck_bf16_round_work, &round);
1299 else ck_bf16_round_work(0, 1, &round);
1300 return;
1301#else
1302 (void)A; (void)B; (void)bias; (void)C; (void)M; (void)N; (void)K;
1303 (void)a_bf16; (void)a_bf16_bytes;
1304 fprintf(stderr,
1305 "HARD KERNEL CONTRACT FAULT: gemm_nt_bf16_amx_bf16_storage was selected "
1306 "without AMX BF16 support\n");
1307 abort();
1308#endif
1309}
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)
static void ck_bf16_convert_work(int ith, int nth, void *opaque)
static void ck_bf16_round_work(int ith, int nth, void *opaque)
static void ck_gemm_bf16_amx_work(int ith, int nth, void *opaque)

References C, ck_bf16_convert_work(), ck_bf16_round_work(), ck_gemm_bf16_amx_work(), ck_threadpool_dispatch_n(), ck_threadpool_global(), and ck_threadpool_n_threads().

Referenced by gemm_nt_bf16_amx_bf16_storage(), and gemm_nt_bf16_prefill_shape_safe_bf16_storage_workspace().

◆ gemm_nt_bf16_bf16_storage()

void gemm_nt_bf16_bf16_storage ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 2034 of file gemm_kernels_bf16.c.

2039{
2040 gemm_nt_bf16_bf16_storage_parallel_dispatch(A, B, bias, C, M, N, K);
2041}
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)

References C, and gemm_nt_bf16_bf16_storage_parallel_dispatch().

◆ gemm_nt_bf16_bf16_storage_parallel_dispatch()

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 
)

Definition at line 2010 of file gemm_kernels_bf16.c.

2015{
2016 ck_threadpool_t *pool = ck_threadpool_global();
2017 if (!pool || ck_threadpool_n_threads(pool) <= 1 || M < 2 ||
2018 (size_t)M * (size_t)N <= 4096) {
2019 gemm_nt_bf16_bf16_storage_row_range(A, B, bias, C, M, N, K, 0, M);
2020 return;
2021 }
2022
2023 ck_gemm_nt_bf16_exact_args_t args = {
2024 .A = A, .B = B, .bias = bias, .C = C, .M = M, .N = N, .K = K,
2025 };
2026 int active = ck_threadpool_n_threads(pool);
2027 if (active > M) active = M;
2028 int grain = M / (active * 4);
2029 if (grain < 1) grain = 1;
2031 pool, active, 0, M, grain, ck_gemm_nt_bf16_storage_exact_rows, &args);
2032}
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)
static void ck_gemm_nt_bf16_storage_exact_rows(int begin, int end, void *opaque)

References C, ck_gemm_nt_bf16_storage_exact_rows(), ck_threadpool_global(), ck_threadpool_n_threads(), ck_threadpool_parallel_for_n(), and gemm_nt_bf16_bf16_storage_row_range().

Referenced by gemm_nt_bf16_bf16_storage().

◆ gemm_nt_bf16_bf16_storage_row_range()

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 
)

Definition at line 1985 of file gemm_kernels_bf16.c.

1991{
1992 gemm_nt_bf16_row_range(A, B, bias, C, M, N, K, row_begin, row_end);
1993 for (int row = row_begin; row < row_end; ++row) {
1994 float *dst = C + (size_t)row * (size_t)N;
1995 for (int col = 0; col < N; ++col) {
1996 dst[col] = bf16_to_float(float_to_bf16(dst[col]));
1997 }
1998 }
1999}

References bf16_to_float(), C, float_to_bf16(), and gemm_nt_bf16_row_range().

Referenced by ck_gemm_nt_bf16_storage_exact_rows(), and gemm_nt_bf16_bf16_storage_parallel_dispatch().

◆ gemm_nt_bf16_native_bf16_storage()

void gemm_nt_bf16_native_bf16_storage ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 1071 of file gemm_kernels_bf16.c.

1076{
1077 const uint16_t *weights = (const uint16_t *)B;
1078 if (!A || !weights || !C || M <= 0 || N <= 0 || K <= 0) return;
1079
1080 ck_gemm_bf16_native_args_t args = {
1081 .A = A, .B = weights, .bias = bias, .C = C, .M = M, .N = N, .K = K
1082 };
1083 ck_threadpool_t *pool = ck_threadpool_global();
1084 int active = pool ? ck_threadpool_n_threads(pool) : 1;
1085 if (active > M) active = M;
1086 if (active > 24) active = 24;
1087 if (!pool || active <= 1 || (size_t)M * (size_t)N <= 4096) {
1088 ck_gemm_bf16_native_work(0, 1, &args);
1089 return;
1090 }
1092}
static void ck_gemm_bf16_native_work(int ith, int nth, void *opaque)

References C, ck_gemm_bf16_native_work(), ck_threadpool_dispatch_n(), ck_threadpool_global(), and ck_threadpool_n_threads().

Referenced by gemm_nt_bf16_prefill_shape_safe_bf16_storage(), and gemm_nt_bf16_prefill_shape_safe_bf16_storage_workspace().

◆ gemm_nt_bf16_parallel_dispatch()

void gemm_nt_bf16_parallel_dispatch ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 777 of file gemm_kernels_bf16.c.

782{
783 ck_threadpool_t *pool = ck_threadpool_global();
784 const char *disabled = getenv("CK_DISABLE_BF16_GEMM_PARALLEL_PREFILL");
785 if ((disabled && disabled[0] && strcmp(disabled, "0") != 0) ||
786 !pool || ck_threadpool_n_threads(pool) <= 1 || M < 2 ||
787 (size_t)M * (size_t)N <= 4096) {
788 gemm_nt_bf16(A, B, bias, C, M, N, K);
789 return;
790 }
791
792 ck_gemm_nt_bf16_exact_args_t args = {
793 .A = A, .B = B, .bias = bias, .C = C, .M = M, .N = N, .K = K,
794 };
795 int active = ck_threadpool_n_threads(pool);
796 if (active > M) active = M;
797 int grain = M / (active * 4);
798 if (grain < 1) grain = 1;
800 pool, active, 0, M, grain, ck_gemm_nt_bf16_exact_rows, &args);
801}
void gemm_nt_bf16(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
static void ck_gemm_nt_bf16_exact_rows(int begin, int end, void *opaque)

References C, ck_gemm_nt_bf16_exact_rows(), ck_threadpool_global(), ck_threadpool_n_threads(), ck_threadpool_parallel_for_n(), and gemm_nt_bf16().

◆ gemm_nt_bf16_prefill_shape_safe_bf16_storage()

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 
)

Definition at line 1347 of file gemm_kernels_bf16.c.

1352{
1353 const int amx_shape = M >= 16 && N >= 16 && K >= 32 &&
1354 (M % 16) == 0 && (N % 16) == 0 && (K % 32) == 0;
1355 if (amx_shape && ck_gemm_bf16_amx_available()) {
1356 gemm_nt_bf16_amx_bf16_storage(A, B, bias, C, M, N, K);
1357 return;
1358 }
1359 gemm_nt_bf16_native_bf16_storage(A, B, bias, C, M, N, K);
1360}
int ck_gemm_bf16_amx_available(void)
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_amx_bf16_storage(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)

References C, ck_gemm_bf16_amx_available(), gemm_nt_bf16_amx_bf16_storage(), and gemm_nt_bf16_native_bf16_storage().

◆ gemm_nt_bf16_prefill_shape_safe_bf16_storage_workspace()

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 
)

Definition at line 1333 of file gemm_kernels_bf16.c.

1336{
1337 const int amx_shape = M >= 16 && N >= 16 && K >= 32 &&
1338 (M % 16) == 0 && (N % 16) == 0 && (K % 32) == 0;
1339 if (amx_shape && ck_gemm_bf16_amx_available()) {
1341 A, B, bias, C, M, N, K, a_bf16, a_bf16_bytes);
1342 return;
1343 }
1344 gemm_nt_bf16_native_bf16_storage(A, B, bias, C, M, N, K);
1345}

References C, ck_gemm_bf16_amx_available(), gemm_nt_bf16_amx_bf16_storage_workspace(), and gemm_nt_bf16_native_bf16_storage().

◆ gemm_nt_bf16_pytorch_onednn_3_12_brgemm_bf16_storage()

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 
)

Definition at line 1551 of file gemm_kernels_bf16.c.

1554{
1555#ifdef USE_ONEDNN
1556 ck_pytorch_brgemm_require_version(
1557 3, 12, 0, "80afa71049cd69a3df32adcccb623b12cd7baa22",
1558 "gemm_nt_bf16_pytorch_onednn_3_12_brgemm_bf16_storage", M, N, K);
1559#endif
1561 A, B, bias, C, M, N, K);
1562}
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)

References C, and gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage_impl().

◆ gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage()

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 
)

Definition at line 1536 of file gemm_kernels_bf16.c.

1541{
1542#ifdef USE_ONEDNN
1543 ck_pytorch_brgemm_require_version(
1544 3, 7, 1, "8d263e693366ef8db40acc569cc7d8edf644556d",
1545 "gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage", M, N, K);
1546#endif
1548 A, B, bias, C, M, N, K);
1549}

References C, and gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage_impl().

◆ gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage_impl()

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 
)
static

Definition at line 1430 of file gemm_kernels_bf16.c.

1433{
1434#ifdef USE_ONEDNN
1435 if (!A || !B || !C || M <= 0 || N <= 0 || K <= 0) {
1436 ck_pytorch_brgemm_fault("received an invalid tensor contract", M, N, K);
1437 }
1438 if (ck_pytorch_brgemm_init_status != 0) {
1439 ck_pytorch_brgemm_fault("could not initialize oneDNN", M, N, K);
1440 }
1441
1442 const size_t input_count = (size_t)M * (size_t)K;
1443 const size_t output_count = (size_t)M * (size_t)N;
1444 uint16_t *input_bf16 = (uint16_t *)malloc(input_count * sizeof(*input_bf16));
1445 uint16_t *output_bf16 = (uint16_t *)malloc(output_count * sizeof(*output_bf16));
1446 uint16_t *bias_bf16 = bias ? (uint16_t *)malloc((size_t)N * sizeof(*bias_bf16)) : NULL;
1447 if (!input_bf16 || !output_bf16 || (bias && !bias_bf16)) {
1448 free(bias_bf16);
1449 free(output_bf16);
1450 free(input_bf16);
1451 ck_pytorch_brgemm_fault("workspace allocation failed", M, N, K);
1452 }
1453 for (size_t i = 0; i < input_count; ++i) input_bf16[i] = float_to_bf16(A[i]);
1454 if (bias) {
1455 for (int j = 0; j < N; ++j) bias_bf16[j] = float_to_bf16(bias[j]);
1456 for (int i = 0; i < M; ++i) {
1457 memcpy(output_bf16 + (size_t)i * (size_t)N,
1458 bias_bf16, (size_t)N * sizeof(*bias_bf16));
1459 }
1460 }
1461
1462 dnnl_memory_desc_t src_md = NULL, weights_md = NULL, dst_md = NULL;
1463 dnnl_primitive_attr_t attr = NULL;
1464 dnnl_post_ops_t post_ops = NULL;
1465 dnnl_primitive_desc_t primitive_desc = NULL;
1466 dnnl_primitive_t primitive = NULL;
1467 dnnl_memory_t src_mem = NULL, weights_mem = NULL, dst_mem = NULL;
1468 dnnl_dims_t src_dims = {M, K};
1469 dnnl_dims_t weights_dims = {K, N};
1470 dnnl_dims_t dst_dims = {M, N};
1471 dnnl_dims_t src_strides = {K, 1};
1472 dnnl_dims_t weights_strides = {1, K};
1473 dnnl_dims_t dst_strides = {N, 1};
1474 dnnl_status_t status = dnnl_success;
1475
1476#define CK_DNNL(call) do { status = (call); if (status != dnnl_success) goto cleanup; } while (0)
1477 pthread_mutex_lock(&ck_pytorch_brgemm_lock);
1478 CK_DNNL(dnnl_memory_desc_create_with_strides(&src_md, 2, src_dims, dnnl_bf16, src_strides));
1479 CK_DNNL(dnnl_memory_desc_create_with_strides(
1480 &weights_md, 2, weights_dims, dnnl_bf16, weights_strides));
1481 CK_DNNL(dnnl_memory_desc_create_with_strides(&dst_md, 2, dst_dims, dnnl_bf16, dst_strides));
1482 if (bias) {
1483 CK_DNNL(dnnl_primitive_attr_create(&attr));
1484 CK_DNNL(dnnl_post_ops_create(&post_ops));
1485 CK_DNNL(dnnl_post_ops_append_sum(post_ops, 1.0f, 0, dnnl_bf16));
1486 CK_DNNL(dnnl_primitive_attr_set_post_ops(attr, post_ops));
1487 }
1488 CK_DNNL(dnnl_matmul_primitive_desc_create(
1489 &primitive_desc, ck_pytorch_brgemm_engine, src_md, weights_md, NULL, dst_md, attr));
1490 CK_DNNL(dnnl_primitive_create(&primitive, primitive_desc));
1491 CK_DNNL(dnnl_memory_create(&src_mem, src_md, ck_pytorch_brgemm_engine, input_bf16));
1492 CK_DNNL(dnnl_memory_create(
1493 &weights_mem, weights_md, ck_pytorch_brgemm_engine, (void *)B));
1494 CK_DNNL(dnnl_memory_create(&dst_mem, dst_md, ck_pytorch_brgemm_engine, output_bf16));
1495 dnnl_exec_arg_t args[] = {
1496 {DNNL_ARG_SRC, src_mem},
1497 {DNNL_ARG_WEIGHTS, weights_mem},
1498 {DNNL_ARG_DST, dst_mem},
1499 };
1500 CK_DNNL(dnnl_primitive_execute(
1501 primitive, ck_pytorch_brgemm_stream, (int)(sizeof(args) / sizeof(args[0])), args));
1502 CK_DNNL(dnnl_stream_wait(ck_pytorch_brgemm_stream));
1503
1504cleanup:
1505 if (dst_mem) dnnl_memory_destroy(dst_mem);
1506 if (weights_mem) dnnl_memory_destroy(weights_mem);
1507 if (src_mem) dnnl_memory_destroy(src_mem);
1508 if (primitive) dnnl_primitive_destroy(primitive);
1509 if (primitive_desc) dnnl_primitive_desc_destroy(primitive_desc);
1510 if (dst_md) dnnl_memory_desc_destroy(dst_md);
1511 if (weights_md) dnnl_memory_desc_destroy(weights_md);
1512 if (src_md) dnnl_memory_desc_destroy(src_md);
1513 if (post_ops) dnnl_post_ops_destroy(post_ops);
1514 if (attr) dnnl_primitive_attr_destroy(attr);
1515 pthread_mutex_unlock(&ck_pytorch_brgemm_lock);
1516#undef CK_DNNL
1517
1518 if (status != dnnl_success) {
1519 free(bias_bf16);
1520 free(output_bf16);
1521 free(input_bf16);
1522 ck_pytorch_brgemm_fault("execution failed", M, N, K);
1523 }
1524 for (size_t i = 0; i < output_count; ++i) C[i] = bf16_to_float(output_bf16[i]);
1525 free(bias_bf16);
1526 free(output_bf16);
1527 free(input_bf16);
1528#else
1529 (void)A; (void)B; (void)bias; (void)C; (void)M; (void)N; (void)K;
1530 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: PyTorch oneDNN BF16 BRGEMM was "
1531 "selected without USE_ONEDNN=1\n");
1532 abort();
1533#endif
1534}

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

Referenced by gemm_nt_bf16_pytorch_onednn_3_12_brgemm_bf16_storage(), and gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage().

◆ gemm_nt_bf16_row_range()

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 
)

Definition at line 720 of file gemm_kernels_bf16.c.

726{
727 const uint16_t *w = (const uint16_t *)B;
728 if (!A || !w || !C || M <= 0 || N <= 0 || K <= 0 ||
729 row_begin < 0 || row_begin >= row_end || row_end > M) {
730 return;
731 }
732
733 for (int i = row_begin; i < row_end; ++i) {
734 const float *a_row = A + (size_t)i * (size_t)K;
735 float *c_row = C + (size_t)i * (size_t)N;
736 for (int j = 0; j < N; ++j) {
737 const uint16_t *w_row = w + (size_t)j * (size_t)K;
738 float sum = bias ? bias[j] : 0.0f;
739 for (int k = 0; k < K; ++k) {
740 const float ab = bf16_to_float(float_to_bf16(a_row[k]));
741 sum += ab * bf16_to_float(w_row[k]);
742 }
743 c_row[j] = sum;
744 }
745 }
746}

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

Referenced by ck_gemm_nt_bf16_exact_rows(), gemm_nt_bf16(), and gemm_nt_bf16_bf16_storage_row_range().

◆ gemm_tn_bf16()

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 
)

Definition at line 875 of file gemm_kernels_bf16.c.

880{
881 if (!A || !B || !C || M <= 0 || N <= 0 || K <= 0) {
882 return;
883 }
884
885 /* A is [K x M], we want A.T which is [M x K] */
886 /* B is [K x N] */
887 /* C is [M x N] */
888
889#if defined(__AVX512F__)
890 /* Initialize C with bias */
891 #pragma omp parallel for
892 for (int i = 0; i < M; ++i) {
893 for (int j = 0; j < N; ++j) {
894 float b = bias ? bf16_to_float(bias[j]) : 0.0f;
895 C[(size_t)i * N + j] = float_to_bf16(b);
896 }
897 }
898
899 /* Accumulate: C[i,j] += sum_k A[k,i] * B[k,j] */
900 #pragma omp parallel for
901 for (int i = 0; i < M; ++i) {
902 for (int j = 0; j < N; ++j) {
903 __m512 sum_vec = _mm512_setzero_ps();
904
905 int k = 0;
906 for (; k <= K - 16; k += 16) {
907 /* Gather A[k:k+16, i] - strided access */
908 __m512 a_fp32 = _mm512_setzero_ps();
909 for (int kk = 0; kk < 16; ++kk) {
910 float val = bf16_to_float(A[(size_t)(k + kk) * M + i]);
911 a_fp32 = _mm512_mask_mov_ps(a_fp32, 1 << kk, _mm512_set1_ps(val));
912 }
913
914 /* Note: B has stride N, so we need to gather element by element */
915 __m512 b_fp32 = _mm512_setzero_ps();
916 for (int kk = 0; kk < 16; ++kk) {
917 float val = bf16_to_float(B[(size_t)(k + kk) * N + j]);
918 b_fp32 = _mm512_mask_mov_ps(b_fp32, 1 << kk, _mm512_set1_ps(val));
919 }
920
921 sum_vec = _mm512_fmadd_ps(a_fp32, b_fp32, sum_vec);
922 }
923
924 float sum = _mm512_reduce_add_ps(sum_vec);
925
926 for (; k < K; ++k) {
927 sum += bf16_to_float(A[(size_t)k * M + i]) *
928 bf16_to_float(B[(size_t)k * N + j]);
929 }
930
931 float old_val = bf16_to_float(C[(size_t)i * N + j]);
932 C[(size_t)i * N + j] = float_to_bf16(old_val + sum);
933 }
934 }
935#else
936 for (int i = 0; i < M; ++i) {
937 for (int j = 0; j < N; ++j) {
938 float sum = bias ? bf16_to_float(bias[j]) : 0.0f;
939 for (int k = 0; k < K; ++k) {
940 sum += bf16_to_float(A[(size_t)k * M + i]) *
941 bf16_to_float(B[(size_t)k * N + j]);
942 }
943 C[(size_t)i * N + j] = float_to_bf16(sum);
944 }
945 }
946#endif
947}

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

◆ gemv_bf16()

void gemv_bf16 ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Definition at line 622 of file gemm_kernels_bf16.c.

626{
628 y, (const uint16_t *)W, x, M, K, 0, M);
629}

References gemv_bf16_row_range().

Referenced by gemv_bf16_parallel_dispatch().

◆ gemv_bf16_bf16_storage()

void gemv_bf16_bf16_storage ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Definition at line 712 of file gemm_kernels_bf16.c.

716{
718}
void gemv_bf16_bf16_storage_parallel_dispatch(float *y, const void *W, const float *x, int M, int K)

References gemv_bf16_bf16_storage_parallel_dispatch().

◆ gemv_bf16_bf16_storage_parallel_dispatch()

void gemv_bf16_bf16_storage_parallel_dispatch ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Definition at line 688 of file gemm_kernels_bf16.c.

692{
693 ck_threadpool_t *pool = ck_threadpool_global();
694 if (!pool || ck_threadpool_n_threads(pool) <= 1 || M < 2 ||
695 (size_t)M * (size_t)K <= 65536) {
697 y, (const uint16_t *)W, x, M, K, 0, M);
698 return;
699 }
700
701 ck_gemv_bf16_args_t args = {
702 .y = y, .w = (const uint16_t *)W, .x = x, .M = M, .K = K,
703 };
704 int active = ck_threadpool_n_threads(pool);
705 if (active > M) active = M;
706 int grain = M / (active * 4);
707 if (grain < 1) grain = 1;
709 pool, active, 0, M, grain, ck_gemv_bf16_storage_rows, &args);
710}
static void ck_gemv_bf16_storage_rows(int begin, int end, void *opaque)

References ck_gemv_bf16_storage_rows(), ck_threadpool_global(), ck_threadpool_n_threads(), ck_threadpool_parallel_for_n(), and gemv_bf16_bf16_storage_row_range().

Referenced by gemv_bf16_bf16_storage().

◆ gemv_bf16_bf16_storage_row_range()

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 
)
static

Definition at line 669 of file gemm_kernels_bf16.c.

674{
675 gemv_bf16_row_range(y, w, x, M, K, row_begin, row_end);
676 for (int row = row_begin; row < row_end; ++row) {
677 y[row] = bf16_to_float(float_to_bf16(y[row]));
678 }
679}

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

Referenced by ck_gemv_bf16_storage_rows(), and gemv_bf16_bf16_storage_parallel_dispatch().

◆ gemv_bf16_parallel_dispatch()

void gemv_bf16_parallel_dispatch ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Definition at line 646 of file gemm_kernels_bf16.c.

650{
651 ck_threadpool_t *pool = ck_threadpool_global();
652 if (!pool || ck_threadpool_n_threads(pool) <= 1 || M < 2 ||
653 (size_t)M * (size_t)K <= 65536) {
654 gemv_bf16(y, W, x, M, K);
655 return;
656 }
657
658 ck_gemv_bf16_args_t args = {
659 .y = y, .w = (const uint16_t *)W, .x = x, .M = M, .K = K,
660 };
661 int active = ck_threadpool_n_threads(pool);
662 if (active > M) active = M;
663 int grain = M / (active * 4);
664 if (grain < 1) grain = 1;
666 pool, active, 0, M, grain, ck_gemv_bf16_rows, &args);
667}
static void ck_gemv_bf16_rows(int begin, int end, void *opaque)
void gemv_bf16(float *y, const void *W, const float *x, int M, int K)

References ck_gemv_bf16_rows(), ck_threadpool_global(), ck_threadpool_n_threads(), ck_threadpool_parallel_for_n(), and gemv_bf16().

◆ gemv_bf16_row_range()

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 
)
static

Definition at line 600 of file gemm_kernels_bf16.c.

605{
606 if (!y || !w || !x || M <= 0 || K <= 0 ||
607 row_begin < 0 || row_begin >= row_end || row_end > M) {
608 return;
609 }
610
611 for (int i = row_begin; i < row_end; ++i) {
612 const uint16_t *w_row = w + (size_t)i * (size_t)K;
613 float sum = 0.0f;
614 for (int k = 0; k < K; ++k) {
615 const float xb = bf16_to_float(float_to_bf16(x[k]));
616 sum += xb * bf16_to_float(w_row[k]);
617 }
618 y[i] = sum;
619 }
620}

References bf16_to_float(), and float_to_bf16().

Referenced by ck_gemv_bf16_rows(), gemv_bf16(), and gemv_bf16_bf16_storage_row_range().

◆ patch_projection_bf16_pytorch_onednn_conv3d_storage()

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 
)

Definition at line 1564 of file gemm_kernels_bf16.c.

1568{
1569#ifdef USE_ONEDNN
1570 if (!input || !weights || !bias || !output || batch <= 0 ||
1571 out_channels <= 0 || in_channels <= 0 || temporal <= 0 ||
1572 patch_h <= 0 || patch_w <= 0) {
1573 ck_pytorch_brgemm_fault("invalid Conv3D patch contract", batch,
1574 out_channels, in_channels * temporal * patch_h * patch_w);
1575 }
1576 pthread_once(&ck_pytorch_brgemm_once, ck_pytorch_brgemm_init);
1577 if (ck_pytorch_brgemm_init_status != 0) {
1578 ck_pytorch_brgemm_fault("could not initialize oneDNN Conv3D", batch,
1579 out_channels, in_channels * temporal * patch_h * patch_w);
1580 }
1581 ck_pytorch_brgemm_require_version(
1582 3, 7, 1, "8d263e693366ef8db40acc569cc7d8edf644556d",
1583 "patch_projection_bf16_pytorch_onednn_conv3d_storage",
1584 batch, out_channels, in_channels * temporal * patch_h * patch_w);
1585
1586 const size_t input_count = (size_t)batch * (size_t)in_channels *
1587 (size_t)temporal * (size_t)patch_h * (size_t)patch_w;
1588 const size_t output_count = (size_t)batch * (size_t)out_channels;
1589 uint16_t *input_bf16 = (uint16_t *)malloc(input_count * sizeof(*input_bf16));
1590 uint16_t *bias_bf16 = (uint16_t *)malloc((size_t)out_channels * sizeof(*bias_bf16));
1591 uint16_t *output_bf16 = (uint16_t *)malloc(output_count * sizeof(*output_bf16));
1592 if (!input_bf16 || !bias_bf16 || !output_bf16) {
1593 free(output_bf16);
1594 free(bias_bf16);
1595 free(input_bf16);
1596 ck_pytorch_brgemm_fault("Conv3D workspace allocation failed", batch,
1597 out_channels, in_channels * temporal * patch_h * patch_w);
1598 }
1599 for (size_t i = 0; i < input_count; ++i) input_bf16[i] = float_to_bf16(input[i]);
1600 for (int i = 0; i < out_channels; ++i) bias_bf16[i] = float_to_bf16(bias[i]);
1601
1602 dnnl_dims_t src_dims = {batch, in_channels, temporal, patch_h, patch_w};
1603 dnnl_dims_t weight_dims = {
1604 out_channels, in_channels, temporal, patch_h, patch_w};
1605 dnnl_dims_t bias_dims = {out_channels};
1606 dnnl_dims_t dst_dims = {batch, out_channels, 1, 1, 1};
1607 dnnl_dims_t strides = {temporal, patch_h, patch_w};
1608 dnnl_dims_t dilates = {0, 0, 0};
1609 dnnl_dims_t padding = {0, 0, 0};
1610
1611 dnnl_memory_desc_t user_src_md = NULL, user_weight_md = NULL;
1612 dnnl_memory_desc_t bias_md = NULL, user_dst_md = NULL;
1613 dnnl_memory_desc_t any_src_md = NULL, any_weight_md = NULL, any_dst_md = NULL;
1614 dnnl_primitive_desc_t conv_pd = NULL;
1615 dnnl_primitive_t conv = NULL;
1616 dnnl_primitive_desc_t reorder_pd = NULL;
1617 dnnl_primitive_t reorder = NULL;
1618 dnnl_exec_arg_t reorder_args[2];
1619 dnnl_memory_t user_src = NULL, user_weight = NULL, bias_mem = NULL, user_dst = NULL;
1620 dnnl_memory_t conv_src = NULL, conv_weight = NULL, conv_dst = NULL;
1621 dnnl_status_t status = dnnl_success;
1622
1623#define CK_DNNL_CONV(call) do { status = (call); if (status != dnnl_success) goto cleanup_conv; } while (0)
1624 pthread_mutex_lock(&ck_pytorch_brgemm_lock);
1625 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1626 &user_src_md, 5, src_dims, dnnl_bf16, dnnl_ncdhw));
1627 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1628 &user_weight_md, 5, weight_dims, dnnl_bf16, dnnl_oidhw));
1629 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1630 &bias_md, 1, bias_dims, dnnl_bf16, dnnl_x));
1631 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1632 &user_dst_md, 5, dst_dims, dnnl_bf16, dnnl_ncdhw));
1633 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1634 &any_src_md, 5, src_dims, dnnl_bf16, dnnl_format_tag_any));
1635 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1636 &any_weight_md, 5, weight_dims, dnnl_bf16, dnnl_format_tag_any));
1637 CK_DNNL_CONV(dnnl_memory_desc_create_with_tag(
1638 &any_dst_md, 5, dst_dims, dnnl_bf16, dnnl_format_tag_any));
1639 CK_DNNL_CONV(dnnl_convolution_forward_primitive_desc_create(
1640 &conv_pd, ck_pytorch_brgemm_engine, dnnl_forward_training,
1641 dnnl_convolution_direct, any_src_md, any_weight_md, bias_md, any_dst_md,
1642 strides, dilates, padding, padding, NULL));
1643
1644 const_dnnl_memory_desc_t conv_src_md =
1645 dnnl_primitive_desc_query_md(conv_pd, dnnl_query_src_md, 0);
1646 const_dnnl_memory_desc_t conv_weight_md =
1647 dnnl_primitive_desc_query_md(conv_pd, dnnl_query_weights_md, 0);
1648 const_dnnl_memory_desc_t conv_dst_md =
1649 dnnl_primitive_desc_query_md(conv_pd, dnnl_query_dst_md, 0);
1650 CK_DNNL_CONV(dnnl_memory_create(
1651 &user_src, user_src_md, ck_pytorch_brgemm_engine, input_bf16));
1652 CK_DNNL_CONV(dnnl_memory_create(
1653 &user_weight, user_weight_md, ck_pytorch_brgemm_engine, (void *)weights));
1654 CK_DNNL_CONV(dnnl_memory_create(
1655 &bias_mem, bias_md, ck_pytorch_brgemm_engine, bias_bf16));
1656 CK_DNNL_CONV(dnnl_memory_create(
1657 &user_dst, user_dst_md, ck_pytorch_brgemm_engine, output_bf16));
1658 CK_DNNL_CONV(dnnl_memory_create(
1659 &conv_src, conv_src_md, ck_pytorch_brgemm_engine, DNNL_MEMORY_ALLOCATE));
1660 CK_DNNL_CONV(dnnl_memory_create(
1661 &conv_weight, conv_weight_md, ck_pytorch_brgemm_engine, DNNL_MEMORY_ALLOCATE));
1662 CK_DNNL_CONV(dnnl_memory_create(
1663 &conv_dst, conv_dst_md, ck_pytorch_brgemm_engine, DNNL_MEMORY_ALLOCATE));
1664
1665 CK_DNNL_CONV(dnnl_reorder_primitive_desc_create(
1666 &reorder_pd, user_src_md, ck_pytorch_brgemm_engine,
1667 conv_src_md, ck_pytorch_brgemm_engine, NULL));
1668 CK_DNNL_CONV(dnnl_primitive_create(&reorder, reorder_pd));
1669 reorder_args[0] = (dnnl_exec_arg_t){DNNL_ARG_FROM, user_src};
1670 reorder_args[1] = (dnnl_exec_arg_t){DNNL_ARG_TO, conv_src};
1671 CK_DNNL_CONV(dnnl_primitive_execute(
1672 reorder, ck_pytorch_brgemm_stream, 2, reorder_args));
1673 dnnl_primitive_destroy(reorder); reorder = NULL;
1674 dnnl_primitive_desc_destroy(reorder_pd); reorder_pd = NULL;
1675
1676 CK_DNNL_CONV(dnnl_reorder_primitive_desc_create(
1677 &reorder_pd, user_weight_md, ck_pytorch_brgemm_engine,
1678 conv_weight_md, ck_pytorch_brgemm_engine, NULL));
1679 CK_DNNL_CONV(dnnl_primitive_create(&reorder, reorder_pd));
1680 reorder_args[0] = (dnnl_exec_arg_t){DNNL_ARG_FROM, user_weight};
1681 reorder_args[1] = (dnnl_exec_arg_t){DNNL_ARG_TO, conv_weight};
1682 CK_DNNL_CONV(dnnl_primitive_execute(
1683 reorder, ck_pytorch_brgemm_stream, 2, reorder_args));
1684 dnnl_primitive_destroy(reorder); reorder = NULL;
1685 dnnl_primitive_desc_destroy(reorder_pd); reorder_pd = NULL;
1686
1687 CK_DNNL_CONV(dnnl_primitive_create(&conv, conv_pd));
1688 dnnl_exec_arg_t conv_args[] = {
1689 {DNNL_ARG_SRC, conv_src},
1690 {DNNL_ARG_WEIGHTS, conv_weight},
1691 {DNNL_ARG_BIAS, bias_mem},
1692 {DNNL_ARG_DST, conv_dst},
1693 };
1694 CK_DNNL_CONV(dnnl_primitive_execute(
1695 conv, ck_pytorch_brgemm_stream,
1696 (int)(sizeof(conv_args) / sizeof(conv_args[0])), conv_args));
1697
1698 CK_DNNL_CONV(dnnl_reorder_primitive_desc_create(
1699 &reorder_pd, conv_dst_md, ck_pytorch_brgemm_engine,
1700 user_dst_md, ck_pytorch_brgemm_engine, NULL));
1701 CK_DNNL_CONV(dnnl_primitive_create(&reorder, reorder_pd));
1702 reorder_args[0] = (dnnl_exec_arg_t){DNNL_ARG_FROM, conv_dst};
1703 reorder_args[1] = (dnnl_exec_arg_t){DNNL_ARG_TO, user_dst};
1704 CK_DNNL_CONV(dnnl_primitive_execute(
1705 reorder, ck_pytorch_brgemm_stream, 2, reorder_args));
1706 CK_DNNL_CONV(dnnl_stream_wait(ck_pytorch_brgemm_stream));
1707
1708cleanup_conv:
1709 if (reorder) dnnl_primitive_destroy(reorder);
1710 if (reorder_pd) dnnl_primitive_desc_destroy(reorder_pd);
1711 if (conv) dnnl_primitive_destroy(conv);
1712 if (conv_dst) dnnl_memory_destroy(conv_dst);
1713 if (conv_weight) dnnl_memory_destroy(conv_weight);
1714 if (conv_src) dnnl_memory_destroy(conv_src);
1715 if (user_dst) dnnl_memory_destroy(user_dst);
1716 if (bias_mem) dnnl_memory_destroy(bias_mem);
1717 if (user_weight) dnnl_memory_destroy(user_weight);
1718 if (user_src) dnnl_memory_destroy(user_src);
1719 if (conv_pd) dnnl_primitive_desc_destroy(conv_pd);
1720 if (any_dst_md) dnnl_memory_desc_destroy(any_dst_md);
1721 if (any_weight_md) dnnl_memory_desc_destroy(any_weight_md);
1722 if (any_src_md) dnnl_memory_desc_destroy(any_src_md);
1723 if (user_dst_md) dnnl_memory_desc_destroy(user_dst_md);
1724 if (bias_md) dnnl_memory_desc_destroy(bias_md);
1725 if (user_weight_md) dnnl_memory_desc_destroy(user_weight_md);
1726 if (user_src_md) dnnl_memory_desc_destroy(user_src_md);
1727 pthread_mutex_unlock(&ck_pytorch_brgemm_lock);
1728#undef CK_DNNL_CONV
1729
1730 if (status != dnnl_success) {
1731 free(output_bf16);
1732 free(bias_bf16);
1733 free(input_bf16);
1734 ck_pytorch_brgemm_fault("oneDNN Conv3D execution failed", batch,
1735 out_channels, in_channels * temporal * patch_h * patch_w);
1736 }
1737 for (size_t i = 0; i < output_count; ++i) output[i] = bf16_to_float(output_bf16[i]);
1738 free(output_bf16);
1739 free(bias_bf16);
1740 free(input_bf16);
1741#else
1742 (void)input; (void)weights; (void)bias; (void)output; (void)batch;
1743 (void)out_channels; (void)in_channels; (void)temporal; (void)patch_h; (void)patch_w;
1744 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: PyTorch oneDNN BF16 Conv3D "
1745 "was selected without USE_ONEDNN=1\n");
1746 abort();
1747#endif
1748}

References bf16_to_float(), and float_to_bf16().

Referenced by patch_projection_image_bf16_pytorch_onednn_conv3d_storage().

◆ patch_projection_image_bf16_native_storage()

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 
)

Definition at line 1940 of file gemm_kernels_bf16.c.

1944{
1945 if (!image || !weights_t0 || !weights_t1 || !output || channels <= 0 ||
1946 image_h <= 0 || image_w <= 0 || patch_size <= 0 || out_channels <= 0 ||
1947 merge_size <= 0 || image_h % patch_size != 0 ||
1948 image_w % patch_size != 0) {
1949 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: invalid native BF16 image patch projection\n");
1950 abort();
1951 }
1952 const int grid_h = image_h / patch_size;
1953 const int grid_w = image_w / patch_size;
1954 if (grid_h % merge_size != 0 || grid_w % merge_size != 0) {
1955 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: native BF16 patch grid is not merge aligned\n");
1956 abort();
1957 }
1958 ck_patch_projection_bf16_native_args_t args = {
1959 .image = image,
1960 .weights_t0 = (const uint16_t *)weights_t0,
1961 .weights_t1 = (const uint16_t *)weights_t1,
1962 .bias = bias,
1963 .output = output,
1964 .channels = channels,
1965 .image_h = image_h,
1966 .image_w = image_w,
1967 .patch_size = patch_size,
1968 .out_channels = out_channels,
1969 .merge_size = merge_size,
1970 .grid_w = grid_w,
1971 .batch = grid_h * grid_w,
1972 };
1973 ck_threadpool_t *pool = ck_threadpool_global();
1974 int active = pool ? ck_threadpool_n_threads(pool) : 1;
1975 if (active > args.batch) active = args.batch;
1976 if (active > 24) active = 24;
1977 if (pool && active > 1) {
1979 pool, active, ck_patch_projection_bf16_native_work, &args);
1980 } else {
1982 }
1983}
static void ck_patch_projection_bf16_native_work(int ith, int nth, void *opaque)

References ck_patch_projection_bf16_native_work(), ck_threadpool_dispatch_n(), ck_threadpool_global(), and ck_threadpool_n_threads().

◆ patch_projection_image_bf16_pytorch_onednn_conv3d_storage()

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 
)

Definition at line 1750 of file gemm_kernels_bf16.c.

1754{
1755#ifdef USE_ONEDNN
1756 if (!image || !weights_t0 || !weights_t1 || !bias || !output ||
1757 channels <= 0 || image_h <= 0 || image_w <= 0 || patch_size <= 0 ||
1758 out_channels <= 0 || merge_size <= 0 || image_h % patch_size != 0 ||
1759 image_w % patch_size != 0) {
1760 ck_pytorch_brgemm_fault("invalid image patch projection contract",
1761 image_h, image_w, patch_size);
1762 }
1763 const int grid_h = image_h / patch_size;
1764 const int grid_w = image_w / patch_size;
1765 if (grid_h % merge_size != 0 || grid_w % merge_size != 0) {
1766 ck_pytorch_brgemm_fault("patch grid is not merge-tile aligned",
1767 grid_h, grid_w, merge_size);
1768 }
1769 const int batch = grid_h * grid_w;
1770 const int temporal = 2;
1771 const int half_k = channels * patch_size * patch_size;
1772 const int full_k = temporal * half_k;
1773 float *patches = (float *)malloc((size_t)batch * (size_t)full_k * sizeof(*patches));
1774 uint16_t *weights = (uint16_t *)malloc(
1775 (size_t)out_channels * (size_t)full_k * sizeof(*weights));
1776 if (!patches || !weights) {
1777 free(weights);
1778 free(patches);
1779 ck_pytorch_brgemm_fault("image patch projection workspace allocation failed",
1780 batch, out_channels, full_k);
1781 }
1782
1783 for (int tok = 0; tok < batch; ++tok) {
1784 const int tiles_per_row = grid_w / merge_size;
1785 const int tile_area = merge_size * merge_size;
1786 const int tile = tok / tile_area;
1787 const int within = tok % tile_area;
1788 const int patch_y = (tile / tiles_per_row) * merge_size + within / merge_size;
1789 const int patch_x = (tile % tiles_per_row) * merge_size + within % merge_size;
1790 float *dst = patches + (size_t)tok * (size_t)full_k;
1791 for (int c = 0; c < channels; ++c) {
1792 for (int t = 0; t < temporal; ++t) {
1793 for (int py = 0; py < patch_size; ++py) {
1794 const float *src = image +
1795 ((size_t)c * (size_t)image_h +
1796 (size_t)(patch_y * patch_size + py)) * (size_t)image_w +
1797 (size_t)(patch_x * patch_size);
1798 memcpy(dst, src, (size_t)patch_size * sizeof(*dst));
1799 dst += patch_size;
1800 }
1801 }
1802 }
1803 }
1804
1805 const uint16_t *w0 = (const uint16_t *)weights_t0;
1806 const uint16_t *w1 = (const uint16_t *)weights_t1;
1807 for (int n = 0; n < out_channels; ++n) {
1808 uint16_t *dst = weights + (size_t)n * (size_t)full_k;
1809 for (int c = 0; c < channels; ++c) {
1810 const size_t channel_offset =
1811 (size_t)n * (size_t)half_k +
1812 (size_t)c * (size_t)patch_size * (size_t)patch_size;
1813 const size_t plane_bytes =
1814 (size_t)patch_size * (size_t)patch_size * sizeof(*dst);
1815 memcpy(dst, w0 + channel_offset, plane_bytes);
1816 dst += patch_size * patch_size;
1817 memcpy(dst, w1 + channel_offset, plane_bytes);
1818 dst += patch_size * patch_size;
1819 }
1820 }
1821
1823 patches, weights, bias, output, batch, out_channels, channels,
1824 temporal, patch_size, patch_size);
1825 free(weights);
1826 free(patches);
1827#else
1828 (void)image; (void)weights_t0; (void)weights_t1; (void)bias; (void)output;
1829 (void)channels; (void)image_h; (void)image_w; (void)patch_size;
1830 (void)out_channels; (void)merge_size;
1831 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: PyTorch oneDNN BF16 image "
1832 "patch projection was selected without USE_ONEDNN=1\n");
1833 abort();
1834#endif
1835}
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)

References patch_projection_bf16_pytorch_onednn_conv3d_storage().