sov-kernel-monster / rtx /src /cuda_gemm_dispatch.c
SNAPKITTYWEST's picture
chore: push full sov-kernel-monster content from local build
9425aed verified
Raw
History Blame Contribute Delete
6.1 kB
#include "cuda_driver_loader.h"
#include "rowm_cuda_validation.h"
extern const unsigned char gemm_ptx[];
extern const unsigned int gemm_ptx_len;
enum {
SOV_GEMM_ERR_INVALID_ARGUMENT = -1,
SOV_GEMM_ERR_MODULE_LOAD = -2,
SOV_GEMM_ERR_TENSOR_LOOKUP = -3,
SOV_GEMM_ERR_SCALAR_LOOKUP = -4,
SOV_GEMM_ERR_LAUNCH = -5,
SOV_GEMM_ERR_GRID_TOO_LARGE = -6
};
static CUmodule g_gemm_module;
static CUfunction g_gemm_tensor_kernel;
static CUfunction g_gemm_scalar_kernel;
static uint64_t g_gemm_context_generation;
static int checked_mul_u64(uint64_t left, uint64_t right, uint64_t* product) {
if (!product) return -1;
if (left != 0 && right > UINT64_MAX / left) return -1;
*product = left * right;
return 0;
}
#define UINT64_MAX ((uint64_t)0xFFFFFFFFFFFFFFFFu)
static int matrix_end(CUdeviceptr base, uint64_t rows, uint64_t cols,
uint64_t ld, CUdeviceptr* end) {
uint64_t last_row, elements, bytes;
if (!base || !rows || !cols || !end) return -1;
if (checked_mul_u64(rows - 1u, ld, &last_row) != 0
|| last_row > UINT64_MAX - cols) return -1;
elements = last_row + cols;
if (checked_mul_u64(elements, 2u, &bytes) != 0
|| base > UINT64_MAX - bytes) return -1;
*end = base + bytes;
return 0;
}
static int ranges_overlap(CUdeviceptr lb, CUdeviceptr le,
CUdeviceptr rb, CUdeviceptr re) {
return lb < re && rb < le;
}
int sov_cuda_gemm_init(void) {
CUresult result;
uint64_t ctx_gen;
if (gemm_ptx_len == 0u || gemm_ptx[gemm_ptx_len - 1u] != 0u)
return SOV_GEMM_ERR_MODULE_LOAD;
if (!sov_cuda_is_initialized() && sov_cuda_init() != 0)
return SOV_GEMM_ERR_MODULE_LOAD;
ctx_gen = sov_cuda_context_generation();
if (ctx_gen == 0u) return SOV_GEMM_ERR_MODULE_LOAD;
if (g_gemm_tensor_kernel && g_gemm_scalar_kernel
&& g_gemm_context_generation == ctx_gen) return 0;
if (g_gemm_context_generation != ctx_gen) {
g_gemm_module = 0;
g_gemm_tensor_kernel = 0;
g_gemm_scalar_kernel = 0;
g_gemm_context_generation = 0;
}
result = sov_cuda_module_load_data(&g_gemm_module, (const void*)gemm_ptx);
if (result != CUDA_SUCCESS) { g_gemm_module = 0; return SOV_GEMM_ERR_MODULE_LOAD; }
result = sov_cuda_module_get_function(&g_gemm_tensor_kernel, g_gemm_module,
"gemm_f16_f32_accum");
if (result != CUDA_SUCCESS) {
sov_cuda_module_unload(g_gemm_module);
g_gemm_module = 0; g_gemm_tensor_kernel = 0;
return SOV_GEMM_ERR_TENSOR_LOOKUP;
}
result = sov_cuda_module_get_function(&g_gemm_scalar_kernel, g_gemm_module,
"gemm_f16_f32_accum_scalar");
if (result != CUDA_SUCCESS) {
sov_cuda_module_unload(g_gemm_module);
g_gemm_module = 0; g_gemm_tensor_kernel = 0; g_gemm_scalar_kernel = 0;
return SOV_GEMM_ERR_SCALAR_LOOKUP;
}
g_gemm_context_generation = ctx_gen;
return 0;
}
int sov_cuda_gemm_ex(CUdeviceptr A, CUdeviceptr B, CUdeviceptr C,
int M, int N, int K,
int lda, int ldb, int ldc) {
CUfunction kernel;
CUresult result;
unsigned int grid_x, grid_y, block_x, block_y;
int power_state, use_tensor, prepare;
CUdeviceptr a_end, b_end, c_end;
void* args[10];
if (!A || !B || !C
|| M < 0 || N < 0 || K < 0
|| lda < K || ldb < N || ldc < N
|| lda < 0 || ldb < 0 || ldc < 0)
return SOV_GEMM_ERR_INVALID_ARGUMENT;
if (M == 0 || N == 0) return 0;
if (matrix_end(C, (uint64_t)M, (uint64_t)N, (uint64_t)ldc, &c_end) != 0)
return SOV_GEMM_ERR_INVALID_ARGUMENT;
if (K > 0) {
if (matrix_end(A, (uint64_t)M, (uint64_t)K, (uint64_t)lda, &a_end) != 0
|| matrix_end(B, (uint64_t)K, (uint64_t)N, (uint64_t)ldb, &b_end) != 0
|| ranges_overlap(A, a_end, C, c_end)
|| ranges_overlap(B, b_end, C, c_end))
return SOV_GEMM_ERR_INVALID_ARGUMENT;
}
use_tensor = (M & 15) == 0 && (N & 7) == 0 && (K & 15) == 0;
if (use_tensor) {
grid_x = (unsigned int)M / 16u;
grid_y = (unsigned int)N / 8u;
block_x = 32u; block_y = 1u;
} else {
grid_x = ((unsigned int)N + 15u) / 16u;
grid_y = ((unsigned int)M + 15u) / 16u;
block_x = 16u; block_y = 16u;
}
if (grid_y > 65535u) return SOV_GEMM_ERR_GRID_TOO_LARGE;
prepare = sov_cuda_gemm_init();
if (prepare != 0) return prepare;
prepare = sov_cuda_validation_require_authorized(sov_cuda_context_generation());
if (prepare != SOV_CUDA_ROWM_OK) return prepare;
kernel = use_tensor ? g_gemm_tensor_kernel : g_gemm_scalar_kernel;
power_state = 0; /* sov_get_power_state() wired by caller after link */
args[0] = &A; args[1] = &B; args[2] = &C;
args[3] = &M; args[4] = &N; args[5] = &K;
args[6] = &lda; args[7] = &ldb; args[8] = &ldc;
args[9] = &power_state;
result = sov_cuda_launch_kernel(kernel,
grid_x, grid_y, 1u,
block_x, block_y, 1u,
0u, (CUstream)0, args, 0);
return result == CUDA_SUCCESS ? 0 : SOV_GEMM_ERR_LAUNCH;
}
int sov_cuda_gemm(CUdeviceptr A, CUdeviceptr B, CUdeviceptr C,
int M, int N, int K) {
return sov_cuda_gemm_ex(A, B, C, M, N, K, K, N, N);
}
void sov_cuda_gemm_shutdown(void) {
if (g_gemm_module
&& sov_cuda_is_initialized()
&& g_gemm_context_generation == sov_cuda_context_generation())
sov_cuda_module_unload(g_gemm_module);
g_gemm_module = 0;
g_gemm_tensor_kernel = 0;
g_gemm_scalar_kernel = 0;
g_gemm_context_generation = 0;
}