← 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_accurate_storage_rows (int begin, int end, 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)
 
static void ck_pytorch_brgemm_fault (const char *message, int M, int N, int K)
 
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)
 
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_accurate_storage (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
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)
 
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_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_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 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 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_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 63 of file gemm_kernels_bf16.c.

◆ BLK_M

#define BLK_M   64

Definition at line 61 of file gemm_kernels_bf16.c.

◆ BLK_N

#define BLK_N   64

Definition at line 62 of file gemm_kernels_bf16.c.

Function Documentation

◆ __attribute__()

__attribute__ ( (unused)  )

Definition at line 71 of file gemm_kernels_bf16.c.

77{
78 for (int i = 0; i < M; ++i) {
79 for (int j = 0; j < N; ++j) {
80 float sum = bias ? bf16_to_float(bias[j]) : 0.0f;
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) {
84 sum += bf16_to_float(A[a_row + k]) * bf16_to_float(B[b_row + k]);
85 }
86 C[(size_t)i * (size_t)N + j] = float_to_bf16(sum);
87 }
88 }
89}
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 1107 of file gemm_kernels_bf16.c.

1108{
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]);
1113}
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 1193 of file gemm_kernels_bf16.c.

1194{
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) {
1199 args->values[i] = bf16_to_float(float_to_bf16(args->values[i]));
1200 }
1201}

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 1203 of file gemm_kernels_bf16.c.

1204{
1205#if HAVE_AMX_BF16
1206 return ck_amx_request_xtile_data();
1207#else
1208 return 0;
1209#endif
1210}

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 1126 of file gemm_kernels_bf16.c.

1127{
1128#if HAVE_AMX_BF16
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);
1132 return;
1133 }
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;
1140
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;
1145 _tile_zero(2);
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));
1156 switch (g) {
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;
1161 }
1162 }
1163 }
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);
1168 switch (g) {
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;
1173 }
1174 if (args->bias) {
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];
1178 }
1179 }
1180 }
1181 }
1182 _tile_release();
1183#else
1184 (void)ith; (void)nth; (void)opaque;
1185#endif
1186}

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 1212 of file gemm_kernels_bf16.c.

1217{
1218#if HAVE_AMX_BF16
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()) {
1222 return 0;
1223 }
1224 /* Match oneDNN BRGEMM: largest even divisor of K no greater than 32. */
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) {
1231 if (accumulate) {
1232 _tile_loadd(2, C + (size_t)i * (size_t)N + (size_t)j,
1233 N * (int)sizeof(float));
1234 } else {
1235 _tile_zero(2);
1236 }
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];
1246 }
1247 }
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);
1252 }
1253 _tile_stored(2, C + (size_t)i * (size_t)N + (size_t)j,
1254 N * (int)sizeof(float));
1255 }
1256 }
1257 _tile_release();
1258 return 1;
1259#else
1260 (void)A; (void)B; (void)C; (void)M; (void)N; (void)K; (void)accumulate;
1261 return 0;
1262#endif
1263}

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 976 of file gemm_kernels_bf16.c.

977{
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));
984
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;
990 for (int k = 0; k < K; ++k) ar[k] = float_to_bf16(src[k]);
991 }
992
993#if HAVE_NATIVE_BF16
994 int j = 0;
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();
1003 }
1004 int k = 0;
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)
1009 };
1010 for (int r = 0; r < rows; ++r) {
1011 const __m512bh av =
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]);
1015 }
1016 }
1017 }
1018 for (int r = 0; r < rows; ++r) {
1019 float sums[4];
1020 for (int lane = 0; lane < 4; ++lane) {
1021 sums[lane] = _mm512_reduce_add_ps(acc[r][lane]);
1022 }
1023 const uint16_t *ar = a_bf16 + (size_t)r * (size_t)K;
1024 for (int tail = k; tail < K; ++tail) {
1025 const float av = bf16_to_float(ar[tail]);
1026 sums[0] += av * bf16_to_float(b0[tail]);
1027 sums[1] += av * bf16_to_float(b1[tail]);
1028 sums[2] += av * bf16_to_float(b2[tail]);
1029 sums[3] += av * bf16_to_float(b3[tail]);
1030 }
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];
1034 dst[j + lane] = bf16_to_float(float_to_bf16(sums[lane]));
1035 }
1036 }
1037 }
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();
1042 int k = 0;
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);
1048 }
1049 }
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) {
1054 sum += bf16_to_float(ar[tail]) * bf16_to_float(b[tail]);
1055 }
1056 if (args->bias) sum += args->bias[j];
1057 args->C[(size_t)(row0 + r) * (size_t)N + j] =
1059 }
1060 }
1061#else
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) {
1069 sum += bf16_to_float(ar[k]) * bf16_to_float(b[k]);
1070 }
1071 dst[j] = bf16_to_float(float_to_bf16(sum));
1072 }
1073 }
1074#endif
1075 }
1076}

References bf16_to_float(), and float_to_bf16().

Referenced by gemm_nt_bf16_native_bf16_storage().

◆ ck_gemm_nt_bf16_accurate_storage_rows()

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

Definition at line 2119 of file gemm_kernels_bf16.c.

2120{
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);
2126}
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)

References end, and gemm_nt_bf16_accurate_storage_row_range().

Referenced by gemm_nt_bf16_accurate_storage_parallel_dispatch().

◆ ck_gemm_nt_bf16_exact_rows()

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

Definition at line 775 of file gemm_kernels_bf16.c.

776{
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);
782}
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 2110 of file gemm_kernels_bf16.c.

2111{
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);
2117}
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 646 of file gemm_kernels_bf16.c.

647{
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);
651}
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 688 of file gemm_kernels_bf16.c.

689{
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);
693}
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 65 of file gemm_kernels_bf16.c.

65{ 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 1922 of file gemm_kernels_bf16.c.

1924{
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;
1933
1934 for (int tok = begin; tok < end; ++tok) {
1935 const int tile = tok / tile_area;
1936 const int within = tok % tile_area;
1937 const int patch_y =
1938 (tile / tiles_per_row) * args->merge_size + within / args->merge_size;
1939 const int patch_x =
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
1943 ? bf16_to_float(float_to_bf16(args->bias[n]))
1944 : 0.0f;
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);
1966 }
1967 }
1968 }
1969 float lanes[8];
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);
1976 } else
1977#endif
1978 {
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) {
1993 const float value = bf16_to_float(float_to_bf16(src[px]));
1994 const float weight = bf16_to_float(
1995 weight_plane[(size_t)py *
1996 (size_t)args->patch_size + (size_t)px]);
1997 sum += value * weight;
1998 }
1999 }
2000 }
2001 }
2002 }
2003 args->output[(size_t)tok * (size_t)args->out_channels + (size_t)n] =
2005 }
2006 }
2007}

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

Referenced by patch_projection_image_bf16_native_storage().

◆ ck_pytorch_brgemm_fault()

static void ck_pytorch_brgemm_fault ( const char *  message,
int  M,
int  N,
int  K 
)
static

Definition at line 31 of file gemm_kernels_bf16.c.

32{
33 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: PyTorch oneDNN BF16 BRGEMM %s "
34 "(M=%d N=%d K=%d)\n", message, M, N, K);
35 abort();
36}

Referenced by ck_pytorch_brgemm_workspace_sizes(), gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage_impl(), gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage_workspace_impl(), patch_projection_bf16_pytorch_onednn_conv3d_storage(), and patch_projection_image_bf16_pytorch_onednn_conv3d_storage().

◆ ck_pytorch_brgemm_workspace_sizes()

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

Definition at line 1430 of file gemm_kernels_bf16.c.

1433{
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) {
1437 ck_pytorch_brgemm_fault("workspace size overflow", M, N, K);
1438 }
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)) {
1444 ck_pytorch_brgemm_fault("workspace byte size overflow", M, N, K);
1445 }
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);
1449}
static void ck_pytorch_brgemm_fault(const char *message, int M, int N, int K)

References ck_pytorch_brgemm_fault().

Referenced by gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage_impl(), and gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage_workspace_impl().

◆ 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 2194 of file gemm_kernels_bf16.c.

2203{
2204 if (!d_output || !input || !weight || tokens <= 0 || in_dim <= 0 || out_dim <= 0) {
2205 return;
2206 }
2207
2208 if (d_input) {
2209 for (int t = 0; t < tokens; ++t) {
2210 for (int i = 0; i < in_dim; ++i) {
2211 float sum = 0.0f;
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]);
2215 sum += dy * w;
2216 }
2217 d_input[(size_t)t * (size_t)in_dim + (size_t)i] = sum;
2218 }
2219 }
2220 }
2221
2222 if (d_weight) {
2223 for (int o = 0; o < out_dim; ++o) {
2224 for (int i = 0; i < in_dim; ++i) {
2225 float sum = 0.0f;
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]);
2229 sum += dy * x;
2230 }
2231 d_weight[(size_t)o * (size_t)in_dim + (size_t)i] = sum;
2232 }
2233 }
2234 }
2235
2236 if (d_bias) {
2237 for (int o = 0; o < out_dim; ++o) {
2238 float sum = 0.0f;
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]);
2241 }
2242 d_bias[o] = sum;
2243 }
2244 }
2245}

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 460 of file gemm_kernels_bf16.c.

465{
466 if (!A || !B || !C || M <= 0 || N <= 0 || K <= 0) {
467 return;
468 }
469
470#if HAVE_NATIVE_BF16
471#if HAVE_AMX_BF16
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);
477 return;
478 }
479#endif
480
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;
484 int j = 0;
485
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();
495
496 int k = 0;
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));
503 }
504
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);
509 for (; k < K; ++k) {
510 const float a = bf16_to_float(a_row[k]);
511 s0 += a * bf16_to_float(b0[k]);
512 s1 += a * bf16_to_float(b1[k]);
513 s2 += a * bf16_to_float(b2[k]);
514 s3 += a * bf16_to_float(b3[k]);
515 }
516 if (bias) {
517 s0 += bias[j + 0];
518 s1 += bias[j + 1];
519 s2 += bias[j + 2];
520 s3 += bias[j + 3];
521 }
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;
526 }
527
528 for (; j < N; ++j) {
529 const uint16_t *b_row = B + (size_t)j * K;
530 __m512 sum_vec = _mm512_setzero_ps();
531
532 int k = 0;
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);
537 }
538
539 float sum = _mm512_reduce_add_ps(sum_vec);
540 for (; k < K; ++k) {
541 sum += bf16_to_float(a_row[k]) * bf16_to_float(b_row[k]);
542 }
543 if (bias) {
544 sum += bias[j];
545 }
546 C[(size_t)i * N + j] = sum;
547 }
548 }
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;
553
554 for (int j = 0; j < N; ++j) {
555 const uint16_t *b_row = B + (size_t)j * K;
556
557 __m512 sum_vec = _mm512_setzero_ps();
558
559 int k = 0;
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);
564 }
565
566 float sum = _mm512_reduce_add_ps(sum_vec);
567
568 for (; k < K; ++k) {
569 sum += bf16_to_float(a_row[k]) * bf16_to_float(b_row[k]);
570 }
571
572 if (bias) {
573 sum += bias[j];
574 }
575
576 C[(size_t)i * N + j] = sum;
577 }
578 }
579#else
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) {
584 sum += bf16_to_float(A[(size_t)i * K + k]) *
585 bf16_to_float(B[(size_t)j * K + k]);
586 }
587 C[(size_t)i * N + j] = sum;
588 }
589 }
590#endif
591}

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 431 of file gemm_kernels_bf16.c.

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

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 815 of file gemm_kernels_bf16.c.

820{
821 if (!A || !B || !C || M <= 0 || N <= 0 || K <= 0) {
822 return;
823 }
824
825#if defined(__AVX512F__)
826 #pragma omp parallel for
827 for (int i = 0; i < M; ++i) {
828 /* Initialize row with bias */
829 int j = 0;
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);
835 }
836 for (; j < N; ++j) {
837 float b = bias ? bf16_to_float(bias[j]) : 0.0f;
838 C[(size_t)i * N + j] = float_to_bf16(b);
839 }
840
841 /* Accumulate: C[i,:] += A[i,k] * B[k,:] */
842 for (int k = 0; k < K; ++k) {
843 float a_val = bf16_to_float(A[(size_t)i * K + k]);
844 __m512 a_broadcast = _mm512_set1_ps(a_val);
845
846 j = 0;
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);
850
851 __m256i c_bf16 = _mm256_loadu_si256((const __m256i *)(C + (size_t)i * N + j));
852 __m512 c_fp32 = bf16x16_to_fp32(c_bf16);
853
854 c_fp32 = _mm512_fmadd_ps(a_broadcast, b_fp32, c_fp32);
855
856 __m256i c_out = fp32x16_to_bf16(c_fp32);
857 _mm256_storeu_si256((__m256i *)(C + (size_t)i * N + j), c_out);
858 }
859 for (; j < N; ++j) {
860 float c_val = bf16_to_float(C[(size_t)i * N + j]);
861 c_val += a_val * bf16_to_float(B[(size_t)k * N + j]);
862 C[(size_t)i * N + j] = float_to_bf16(c_val);
863 }
864 }
865 }
866#else
867 /* Scalar fallback */
868 for (int i = 0; i < M; ++i) {
869 for (int j = 0; j < N; ++j) {
870 float sum = bias ? bf16_to_float(bias[j]) : 0.0f;
871 for (int k = 0; k < K; ++k) {
872 sum += bf16_to_float(A[(size_t)i * K + k]) *
873 bf16_to_float(B[(size_t)k * N + j]);
874 }
875 C[(size_t)i * N + j] = float_to_bf16(sum);
876 }
877 }
878#endif
879}

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 755 of file gemm_kernels_bf16.c.

760{
761 if (M <= 0) return;
762 gemm_nt_bf16_row_range(A, B, bias, C, M, N, K, 0, M);
763}

References C, and gemm_nt_bf16_row_range().

Referenced by gemm_nt_bf16_parallel_dispatch().

◆ gemm_nt_bf16_accurate_storage()

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

Definition at line 2185 of file gemm_kernels_bf16.c.

2190{
2192}
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)

References C, and gemm_nt_bf16_accurate_storage_parallel_dispatch().

◆ gemm_nt_bf16_accurate_storage_parallel_dispatch()

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 
)

Definition at line 2161 of file gemm_kernels_bf16.c.

2166{
2167 ck_threadpool_t *pool = ck_threadpool_global();
2168 if (!pool || ck_threadpool_n_threads(pool) <= 1 || M < 2 ||
2169 (size_t)M * (size_t)N <= 4096) {
2170 gemm_nt_bf16_accurate_storage_row_range(A, B, bias, C, M, N, K, 0, M);
2171 return;
2172 }
2173
2174 ck_gemm_nt_bf16_exact_args_t args = {
2175 .A = A, .B = B, .bias = bias, .C = C, .M = M, .N = N, .K = K,
2176 };
2177 int active = ck_threadpool_n_threads(pool);
2178 if (active > M) active = M;
2179 int grain = M / (active * 4);
2180 if (grain < 1) grain = 1;
2182 pool, active, 0, M, grain, ck_gemm_nt_bf16_accurate_storage_rows, &args);
2183}
void ck_threadpool_parallel_for_n(ck_threadpool_t *pool, int active_threads, int begin, int end, int grain_size, ck_range_fn_t fn, void *args)
ck_threadpool_t * ck_threadpool_global(void)
int ck_threadpool_n_threads(const ck_threadpool_t *pool)
static void ck_gemm_nt_bf16_accurate_storage_rows(int begin, int end, void *opaque)

References C, ck_gemm_nt_bf16_accurate_storage_rows(), ck_threadpool_global(), ck_threadpool_n_threads(), ck_threadpool_parallel_for_n(), and gemm_nt_bf16_accurate_storage_row_range().

Referenced by gemm_nt_bf16_accurate_storage().

◆ gemm_nt_bf16_accurate_storage_row_range()

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 
)

Definition at line 2070 of file gemm_kernels_bf16.c.

2076{
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) {
2080 return;
2081 }
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;
2087 /* BF16 products are exact in double. A single FP32 accumulator can
2088 * round a long dot across a BF16 midpoint before output storage;
2089 * that changes downstream routing. Keep the accumulation accurate
2090 * until the declared FP32 bias/output conversion boundary. */
2091 double even = 0.0;
2092 double odd = 0.0;
2093 int k = 0;
2094 for (; k + 1 < K; k += 2) {
2095 even += (double)bf16_to_float(float_to_bf16(a_row[k])) *
2096 (double)bf16_to_float(w_row[k]);
2097 odd += (double)bf16_to_float(float_to_bf16(a_row[k + 1])) *
2098 (double)bf16_to_float(w_row[k + 1]);
2099 }
2100 if (k < K) {
2101 even += (double)bf16_to_float(float_to_bf16(a_row[k])) *
2102 (double)bf16_to_float(w_row[k]);
2103 }
2104 const float sum = (float)((even + odd) + (bias ? bias[col] : 0.0f));
2105 dst[col] = bf16_to_float(float_to_bf16(sum));
2106 }
2107 }
2108}

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

Referenced by ck_gemm_nt_bf16_accurate_storage_rows(), and gemm_nt_bf16_accurate_storage_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 1318 of file gemm_kernels_bf16.c.

1323{
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;
1327 }
1328 uint16_t *workspace = input_count > 0 && input_count <= SIZE_MAX / sizeof(uint16_t)
1329 ? (uint16_t *)malloc(input_count * sizeof(uint16_t))
1330 : NULL;
1331 if (!workspace) {
1332 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: AMX BF16 compatibility workspace allocation failed\n");
1333 abort();
1334 }
1336 A, B, bias, C, M, N, K, workspace, input_count * sizeof(uint16_t));
1337 free(workspace);
1338}
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 1265 of file gemm_kernels_bf16.c.

1272{
1273#if HAVE_AMX_BF16
1274 if (!A || !B || !C || M < 16 || N < 16 || K < 32 ||
1275 (M % 16) != 0 || (N % 16) != 0 || (K % 32) != 0) {
1276 fprintf(stderr,
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",
1279 M, N, K);
1280 abort();
1281 }
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");
1286 abort();
1287 }
1288 ck_threadpool_t *pool = ck_threadpool_global();
1289 int active = pool ? ck_threadpool_n_threads(pool) : 1;
1290 if (active > 24) active = 24;
1291 ck_bf16_convert_args_t convert = {.src=A, .dst=a_bf16, .count=input_count};
1292 if (pool && active > 1) ck_threadpool_dispatch_n(pool, active, ck_bf16_convert_work, &convert);
1293 else ck_bf16_convert_work(0, 1, &convert);
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
1297 };
1298 if (pool && active > 1) ck_threadpool_dispatch_n(pool, active, ck_gemm_bf16_amx_work, &gemm);
1299 else ck_gemm_bf16_amx_work(0, 1, &gemm);
1300 if (__atomic_load_n(&gemm.failed, __ATOMIC_RELAXED)) {
1301 fprintf(stderr, "HARD KERNEL CONTRACT FAULT: AMX tile permission request failed\n");
1302 abort();
1303 }
1304 ck_bf16_round_args_t round = {.values=C, .count=(size_t)M * N};
1305 if (pool && active > 1) ck_threadpool_dispatch_n(pool, active, ck_bf16_round_work, &round);
1306 else ck_bf16_round_work(0, 1, &round);
1307 return;
1308#else
1309 (void)A; (void)B; (void)bias; (void)C; (void)M; (void)N; (void)K;
1310 (void)a_bf16; (void)a_bf16_bytes;
1311 fprintf(stderr,
1312 "HARD KERNEL CONTRACT FAULT: gemm_nt_bf16_amx_bf16_storage was selected "
1313 "without AMX BF16 support\n");
1314 abort();
1315#endif
1316}
void ck_threadpool_dispatch_n(ck_threadpool_t *pool, int active_threads, ck_work_fn_t fn, void *args)
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 2152 of file gemm_kernels_bf16.c.

2157{
2158 gemm_nt_bf16_bf16_storage_parallel_dispatch(A, B, bias, C, M, N, K);
2159}
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 2128 of file gemm_kernels_bf16.c.

2133{
2134 ck_threadpool_t *pool = ck_threadpool_global();
2135 if (!pool || ck_threadpool_n_threads(pool) <= 1 || M < 2 ||
2136 (size_t)M * (size_t)N <= 4096) {
2137 gemm_nt_bf16_bf16_storage_row_range(A, B, bias, C, M, N, K, 0, M);
2138 return;
2139 }
2140
2141 ck_gemm_nt_bf16_exact_args_t args = {
2142 .A = A, .B = B, .bias = bias, .C = C, .M = M, .N = N, .K = K,
2143 };
2144 int active = ck_threadpool_n_threads(pool);
2145 if (active > M) active = M;
2146 int grain = M / (active * 4);
2147 if (grain < 1) grain = 1;
2149 pool, active, 0, M, grain, ck_gemm_nt_bf16_storage_exact_rows, &args);
2150}
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 2054 of file gemm_kernels_bf16.c.

2060{
2061 gemm_nt_bf16_row_range(A, B, bias, C, M, N, K, row_begin, 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) {
2065 dst[col] = bf16_to_float(float_to_bf16(dst[col]));
2066 }
2067 }
2068}

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 1078 of file gemm_kernels_bf16.c.

1083{
1084 const uint16_t *weights = (const uint16_t *)B;
1085 if (!A || !weights || !C || M <= 0 || N <= 0 || K <= 0) return;
1086
1087 ck_gemm_bf16_native_args_t args = {
1088 .A = A, .B = weights, .bias = bias, .C = C, .M = M, .N = N, .K = K
1089 };
1090 ck_threadpool_t *pool = ck_threadpool_global();
1091 int active = pool ? ck_threadpool_n_threads(pool) : 1;
1092 if (active > M) active = M;
1093 if (active > 24) active = 24;
1094 if (!pool || active <= 1 || (size_t)M * (size_t)N <= 4096) {
1095 ck_gemm_bf16_native_work(0, 1, &args);
1096 return;
1097 }
1099}
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 784 of file gemm_kernels_bf16.c.

789{
790 ck_threadpool_t *pool = ck_threadpool_global();
791 const char *disabled = getenv("CK_DISABLE_BF16_GEMM_PARALLEL_PREFILL");
792 if ((disabled && disabled[0] && strcmp(disabled, "0") != 0) ||
793 !pool || ck_threadpool_n_threads(pool) <= 1 || M < 2 ||
794 (size_t)M * (size_t)N <= 4096) {
795 gemm_nt_bf16(A, B, bias, C, M, N, K);
796 return;
797 }
798
799 ck_gemm_nt_bf16_exact_args_t args = {
800 .A = A, .B = B, .bias = bias, .C = C, .M = M, .N = N, .K = K,
801 };
802 int active = ck_threadpool_n_threads(pool);
803 if (active > M) active = M;
804 int grain = M / (active * 4);
805 if (grain < 1) grain = 1;
807 pool, active, 0, M, grain, ck_gemm_nt_bf16_exact_rows, &args);
808}
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 1354 of file gemm_kernels_bf16.c.

1359{
1360 const int amx_shape = M >= 16 && N >= 16 && K >= 32 &&
1361 (M % 16) == 0 && (N % 16) == 0 && (K % 32) == 0;
1362 if (amx_shape && ck_gemm_bf16_amx_available()) {
1363 gemm_nt_bf16_amx_bf16_storage(A, B, bias, C, M, N, K);
1364 return;
1365 }
1366 gemm_nt_bf16_native_bf16_storage(A, B, bias, C, M, N, K);
1367}
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 1340 of file gemm_kernels_bf16.c.

1343{
1344 const int amx_shape = M >= 16 && N >= 16 && K >= 32 &&
1345 (M % 16) == 0 && (N % 16) == 0 && (K % 32) == 0;
1346 if (amx_shape && ck_gemm_bf16_amx_available()) {
1348 A, B, bias, C, M, N, K, a_bf16, a_bf16_bytes);
1349 return;
1350 }
1351 gemm_nt_bf16_native_bf16_storage(A, B, bias, C, M, N, K);
1352}

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 1601 of file gemm_kernels_bf16.c.

1604{
1605#ifdef USE_ONEDNN
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);
1609#endif
1611 A, B, bias, C, M, N, K);
1612}
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_3_12_brgemm_bf16_storage_workspace()

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 
)

Definition at line 1614 of file gemm_kernels_bf16.c.

1620{
1621#ifdef USE_ONEDNN
1622 ck_pytorch_brgemm_require_version(
1623 3, 12, 0, "80afa71049cd69a3df32adcccb623b12cd7baa22",
1624 "gemm_nt_bf16_pytorch_onednn_3_12_brgemm_bf16_storage_workspace",
1625 M, N, K);
1626#endif
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);
1631}
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)

References C, and gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage_workspace_impl().

Referenced by ck_attention_muse_eager_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 1586 of file gemm_kernels_bf16.c.

1591{
1592#ifdef USE_ONEDNN
1593 ck_pytorch_brgemm_require_version(
1594 3, 7, 1, "8d263e693366ef8db40acc569cc7d8edf644556d",
1595 "gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage", M, N, K);
1596#endif
1598 A, B, bias, C, M, N, K);
1599}

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 1559 of file gemm_kernels_bf16.c.

1562{
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)) {
1572 free(bias_bf16);
1573 free(output_bf16);
1574 free(input_bf16);
1575 ck_pytorch_brgemm_fault("workspace allocation failed", M, N, K);
1576 }
1578 A, B, bias, C, M, N, K,
1579 input_bf16, input_bytes, output_bf16, output_bytes,
1580 bias_bf16, bias_bytes);
1581 free(bias_bf16);
1582 free(output_bf16);
1583 free(input_bf16);
1584}
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)

References C, ck_pytorch_brgemm_fault(), ck_pytorch_brgemm_workspace_sizes(), and gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage_workspace_impl().

Referenced by gemm_nt_bf16_pytorch_onednn_3_12_brgemm_bf16_storage(), and gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage().

◆ gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage_workspace_impl()

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

Definition at line 1451 of file gemm_kernels_bf16.c.

1457{
1458#ifdef USE_ONEDNN
1459 if (!A || !B || !C || M <= 0 || N <= 0 || K <= 0) {
1460 ck_pytorch_brgemm_fault("received an invalid tensor contract", M, N, K);
1461 }
1462 if (ck_pytorch_brgemm_init_status != 0) {
1463 ck_pytorch_brgemm_fault("could not initialize oneDNN", M, N, K);
1464 }
1465
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))) {
1477 ck_pytorch_brgemm_fault("received an undersized workspace", M, N, K);
1478 }
1479 for (size_t i = 0; i < input_count; ++i) input_bf16[i] = float_to_bf16(A[i]);
1480 if (bias) {
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));
1485 }
1486 }
1487
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;
1501
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));
1508 if (bias) {
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));
1513 }
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},
1525 };
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));
1529
1530cleanup:
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);
1542#undef CK_DNNL
1543
1544 if (status != dnnl_success) {
1545 ck_pytorch_brgemm_fault("execution failed", M, N, K);
1546 }
1547 for (size_t i = 0; i < output_count; ++i) C[i] = bf16_to_float(output_bf16[i]);
1548#else
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");
1555 abort();
1556#endif
1557}

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

Referenced by gemm_nt_bf16_pytorch_onednn_3_12_brgemm_bf16_storage_workspace(), and gemm_nt_bf16_pytorch_onednn_brgemm_bf16_storage_impl().

◆ 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 727 of file gemm_kernels_bf16.c.

733{
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) {
737 return;
738 }
739
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) {
747 const float ab = bf16_to_float(float_to_bf16(a_row[k]));
748 sum += ab * bf16_to_float(w_row[k]);
749 }
750 c_row[j] = sum;
751 }
752 }
753}

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 882 of file gemm_kernels_bf16.c.

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

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 629 of file gemm_kernels_bf16.c.

633{
635 y, (const uint16_t *)W, x, M, K, 0, M);
636}

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 719 of file gemm_kernels_bf16.c.

723{
725}
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 695 of file gemm_kernels_bf16.c.

699{
700 ck_threadpool_t *pool = ck_threadpool_global();
701 if (!pool || ck_threadpool_n_threads(pool) <= 1 || M < 2 ||
702 (size_t)M * (size_t)K <= 65536) {
704 y, (const uint16_t *)W, x, M, K, 0, M);
705 return;
706 }
707
708 ck_gemv_bf16_args_t args = {
709 .y = y, .w = (const uint16_t *)W, .x = x, .M = M, .K = K,
710 };
711 int active = ck_threadpool_n_threads(pool);
712 if (active > M) active = M;
713 int grain = M / (active * 4);
714 if (grain < 1) grain = 1;
716 pool, active, 0, M, grain, ck_gemv_bf16_storage_rows, &args);
717}
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 676 of file gemm_kernels_bf16.c.

681{
682 gemv_bf16_row_range(y, w, x, M, K, row_begin, row_end);
683 for (int row = row_begin; row < row_end; ++row) {
684 y[row] = bf16_to_float(float_to_bf16(y[row]));
685 }
686}

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 653 of file gemm_kernels_bf16.c.

657{
658 ck_threadpool_t *pool = ck_threadpool_global();
659 if (!pool || ck_threadpool_n_threads(pool) <= 1 || M < 2 ||
660 (size_t)M * (size_t)K <= 65536) {
661 gemv_bf16(y, W, x, M, K);
662 return;
663 }
664
665 ck_gemv_bf16_args_t args = {
666 .y = y, .w = (const uint16_t *)W, .x = x, .M = M, .K = K,
667 };
668 int active = ck_threadpool_n_threads(pool);
669 if (active > M) active = M;
670 int grain = M / (active * 4);
671 if (grain < 1) grain = 1;
673 pool, active, 0, M, grain, ck_gemv_bf16_rows, &args);
674}
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 607 of file gemm_kernels_bf16.c.

612{
613 if (!y || !w || !x || M <= 0 || K <= 0 ||
614 row_begin < 0 || row_begin >= row_end || row_end > M) {
615 return;
616 }
617
618 for (int i = row_begin; i < row_end; ++i) {
619 const uint16_t *w_row = w + (size_t)i * (size_t)K;
620 float sum = 0.0f;
621 for (int k = 0; k < K; ++k) {
622 const float xb = bf16_to_float(float_to_bf16(x[k]));
623 sum += xb * bf16_to_float(w_row[k]);
624 }
625 y[i] = sum;
626 }
627}

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 1633 of file gemm_kernels_bf16.c.

1637{
1638#ifdef USE_ONEDNN
1639 if (!input || !weights || !bias || !output || batch <= 0 ||
1640 out_channels <= 0 || in_channels <= 0 || temporal <= 0 ||
1641 patch_h <= 0 || patch_w <= 0) {
1642 ck_pytorch_brgemm_fault("invalid Conv3D patch contract", batch,
1643 out_channels, in_channels * temporal * patch_h * patch_w);
1644 }
1645 pthread_once(&ck_pytorch_brgemm_once, ck_pytorch_brgemm_init);
1646 if (ck_pytorch_brgemm_init_status != 0) {
1647 ck_pytorch_brgemm_fault("could not initialize oneDNN Conv3D", batch,
1648 out_channels, in_channels * temporal * patch_h * patch_w);
1649 }
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);
1654
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) {
1662 free(output_bf16);
1663 free(bias_bf16);
1664 free(input_bf16);
1665 ck_pytorch_brgemm_fault("Conv3D workspace allocation failed", batch,
1666 out_channels, in_channels * temporal * patch_h * patch_w);
1667 }
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]);
1670
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};
1679
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;
1691
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));
1712
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));
1733
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;
1744
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;
1755
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},
1762 };
1763 CK_DNNL_CONV(dnnl_primitive_execute(
1764 conv, ck_pytorch_brgemm_stream,
1765 (int)(sizeof(conv_args) / sizeof(conv_args[0])), conv_args));
1766
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));
1776
1777cleanup_conv:
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);
1797#undef CK_DNNL_CONV
1798
1799 if (status != dnnl_success) {
1800 free(output_bf16);
1801 free(bias_bf16);
1802 free(input_bf16);
1803 ck_pytorch_brgemm_fault("oneDNN Conv3D execution failed", batch,
1804 out_channels, in_channels * temporal * patch_h * patch_w);
1805 }
1806 for (size_t i = 0; i < output_count; ++i) output[i] = bf16_to_float(output_bf16[i]);
1807 free(output_bf16);
1808 free(bias_bf16);
1809 free(input_bf16);
1810#else
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");
1815 abort();
1816#endif
1817}

References bf16_to_float(), ck_pytorch_brgemm_fault(), 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 2009 of file gemm_kernels_bf16.c.

2013{
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");
2019 abort();
2020 }
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");
2025 abort();
2026 }
2027 ck_patch_projection_bf16_native_args_t args = {
2028 .image = image,
2029 .weights_t0 = (const uint16_t *)weights_t0,
2030 .weights_t1 = (const uint16_t *)weights_t1,
2031 .bias = bias,
2032 .output = output,
2033 .channels = channels,
2034 .image_h = image_h,
2035 .image_w = image_w,
2036 .patch_size = patch_size,
2037 .out_channels = out_channels,
2038 .merge_size = merge_size,
2039 .grid_w = grid_w,
2040 .batch = grid_h * grid_w,
2041 };
2042 ck_threadpool_t *pool = ck_threadpool_global();
2043 int active = pool ? ck_threadpool_n_threads(pool) : 1;
2044 if (active > args.batch) active = args.batch;
2045 if (active > 24) active = 24;
2046 if (pool && active > 1) {
2048 pool, active, ck_patch_projection_bf16_native_work, &args);
2049 } else {
2051 }
2052}
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 1819 of file gemm_kernels_bf16.c.

1823{
1824#ifdef USE_ONEDNN
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) {
1829 ck_pytorch_brgemm_fault("invalid image patch projection contract",
1830 image_h, image_w, patch_size);
1831 }
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) {
1835 ck_pytorch_brgemm_fault("patch grid is not merge-tile aligned",
1836 grid_h, grid_w, merge_size);
1837 }
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) {
1846 free(weights);
1847 free(patches);
1848 ck_pytorch_brgemm_fault("image patch projection workspace allocation failed",
1849 batch, out_channels, full_k);
1850 }
1851
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));
1868 dst += patch_size;
1869 }
1870 }
1871 }
1872 }
1873
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;
1888 }
1889 }
1890
1892 patches, weights, bias, output, batch, out_channels, channels,
1893 temporal, patch_size, patch_size);
1894 free(weights);
1895 free(patches);
1896#else
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");
1902 abort();
1903#endif
1904}
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 ck_pytorch_brgemm_fault(), and patch_projection_bf16_pytorch_onednn_conv3d_storage().