mirror of
https://github.com/Niko1221/Strata.git
synced 2026-11-07 18:35:04 -10:00
prefill: STRATA_PF_PAD=1 - the S23 prompt GEMM rows padded to stride K + 64, bitwise
A 4 KB-multiple row stride (K 2048 / 4096 / 6144 halves) camps on the memory channels: the gfx1151 WMMA prompt GEMM ran ssm_out (N 2560, K 6144) at 19 TFLOPS against 31-32 for K 2560. Padding the rows by 64 halves (gemm_probe8, M 16384): K 6144 19.1 -> 35.0 TFLOPS (W alone 29.0, X alone 23.7), K 2560 31.7 -> 36.6. With STRATA_PF_GEMM=1 on chunks of STRATA_PF_SWITCH_MIN_T+ tokens: Gemm::native dequantizes the weight into the scratch with stride K + 64 (dequant_f16_ld, non-i-quant types) and runs strata_pf_gemm_f16_ld; the FP16 activations of the two K 6144 projections (gdn_recurrence's y16 for ssm_out, gate_attn's out16 for attn_output) are written with stride 6144 + 64. The same products in the same order: the same bits. c-best3 v2 + STRATA_PF_PAD=1 (Aurora, interleaved, same generated ids): prompt 8K 954.2 / 930.7 -> 983.7 / 940.8, 64K 947.0 / 946.2 -> 974.8 / 1014.4 tok/s.
This commit is contained in:
1 parent
b6b7a87d84
commit
bedb808741
9 files changed
+115
-42
No files matched your search
@@ -21,6 +21,11 @@ void dequant_bf16(int ggml_type, const void* blocks, int64_t row0, int64_t rows,
|
||||
void dequant_f16(int ggml_type, const void* blocks, int64_t row0, int64_t rows, int64_t cols, uint16_t* out,
|
||||
void* stream);
|
||||
|
||||
/// dequant_f16 with output row stride `ld` >= cols (a multiple of 8): S23's padded weight scratch. False (nothing
|
||||
/// launched) for the i-quant formats and unsupported shapes.
|
||||
bool dequant_f16_ld(int ggml_type, const void* blocks, int64_t row0, int64_t rows, int64_t cols, int64_t ld,
|
||||
uint16_t* out, void* stream);
|
||||
|
||||
/// The same into FP32 (tests and small tensors).
|
||||
void dequant_f32(int ggml_type, const void* blocks, int64_t row0, int64_t rows, int64_t cols, float* out, void* stream);
|
||||
|
||||
|
||||
@@ -33,9 +33,10 @@ public:
|
||||
void f16(const uint16_t* X, const uint16_t* W, float* Y, int64_t T, int64_t N, int64_t K, int64_t ldy = 0,
|
||||
float beta = 0.0f);
|
||||
|
||||
/// W given as native GGUF blocks of `ggml_type`, dequantized to FP16 in the scratch, X in FP16.
|
||||
/// W given as native GGUF blocks of `ggml_type`, dequantized to FP16 in the scratch, X in FP16. `ldx` (> K) is
|
||||
/// X's padded row stride, taken only by STRATA_PF_PAD's path (0 = K).
|
||||
void native(const uint16_t* X, int ggml_type, const void* W_blocks, float* Y, int64_t T, int64_t N, int64_t K,
|
||||
int64_t ldy = 0, float beta = 0.0f);
|
||||
int64_t ldy = 0, float beta = 0.0f, int64_t ldx = 0);
|
||||
|
||||
/// Caller-owned buffers only: the scratch and workspace moved (the prompt path laid its buffers out again).
|
||||
void rebind(uint16_t* scratch, int64_t scratch_elems, void* workspace, size_t ws_bytes);
|
||||
|
||||
@@ -50,13 +50,14 @@ void gdn_conv(float* history, const float* qkv, const float* conv_w, float* h, i
|
||||
/// The recurrence over the chunk, block per value head, state in registers; y[t] = rmsnorm(o) * gamma * sigmoid(z)
|
||||
/// (FP32 and FP16 bits: the out projection is quantized).
|
||||
void gdn_recurrence(float* state, const float* h, const float* gate, const float* beta, const float* z,
|
||||
const float* gamma, float eps, float* y, uint16_t* y16, int64_t T, void* stream);
|
||||
const float* gamma, float eps, float* y, uint16_t* y16, int64_t T, void* stream,
|
||||
int64_t ld16 = 0); // ld16: y16's row stride (0 = 6144; S23 STRATA_PF_PAD pads it)
|
||||
/// The kernels behind gdn_recurrence, for the parity test: 0 = the column-split kernels + the norm kernel (or the
|
||||
/// one-block-per-head kernel under STRATA_GDN_REC_HEADS), 1 = four lanes per column (no barrier per token) + the grid-stride norm, 2 = the
|
||||
/// one-block-per-head kernel (its fused norm rounds differently). 0 and 1 give the same bits.
|
||||
void gdn_recurrence_variant(int variant, float* state, const float* h, const float* gate, const float* beta,
|
||||
const float* z, const float* gamma, float eps, float* y, uint16_t* y16, int64_t T,
|
||||
void* stream);
|
||||
void* stream, int64_t ld16 = 0);
|
||||
|
||||
// ---- MoE
|
||||
/// softmax over 512, top-10 (ties to the lower id), weights renormalised over the ten (the native router).
|
||||
@@ -86,7 +87,7 @@ void rope(float* x, int64_t T, int64_t heads, int64_t dim, int64_t ld, int64_t p
|
||||
/// q_full [T, 24, 512] (q | gate per head) -> q [T, 24, 256]
|
||||
void split_q(const float* q_full, float* q, int64_t T, void* stream);
|
||||
/// attn[t, h, d] *= sigmoid(q_full[t, h, 256 + d]) -> out16 (fp16 bits: the o-projection is quantized)
|
||||
void gate_attn(const float* attn, const float* q_full, uint16_t* out16, int64_t T, void* stream);
|
||||
void gate_attn(const float* attn, const float* q_full, uint16_t* out16, int64_t T, void* stream, int64_t ld16 = 0);
|
||||
|
||||
/// K and V of T consecutive cells (positions pos0..pos0+T-1; K normed and rotated) into the paged pools: FP16
|
||||
/// (`k_pool`/`v_pool`) or INT8 codes + FP16 scale per 64 (`k_q`...), the decode append's arithmetic.
|
||||
|
||||
@@ -167,11 +167,11 @@ __device__ __forceinline__ void group32(const uint8_t* row_blocks, int gi_in_row
|
||||
|
||||
template <int TYPE, typename T>
|
||||
__global__ void dequant_kernel(const uint8_t* __restrict__ blocks, int64_t row_bytes, int64_t row0, int64_t rows,
|
||||
int64_t groups_per_row, T* __restrict__ out) {
|
||||
int64_t groups_per_row, int64_t ld, T* __restrict__ out) {
|
||||
const int64_t g = (int64_t) blockIdx.x * blockDim.x + threadIdx.x;
|
||||
if (g >= rows * groups_per_row) return;
|
||||
const int64_t r = g / groups_per_row, gi = g % groups_per_row;
|
||||
group32<TYPE>(blocks + (row0 + r) * row_bytes, (int) gi, out + r * groups_per_row * 32 + gi * 32);
|
||||
group32<TYPE>(blocks + (row0 + r) * row_bytes, (int) gi, out + r * ld + gi * 32);
|
||||
}
|
||||
|
||||
bool geometry(int type, int& block_elems, int& block_bytes) {
|
||||
@@ -192,7 +192,8 @@ bool geometry(int type, int& block_elems, int& block_bytes) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void launch(int type, const void* blocks, int64_t row0, int64_t rows, int64_t cols, T* out, void* stream) {
|
||||
void launch(int type, const void* blocks, int64_t row0, int64_t rows, int64_t cols, T* out, void* stream,
|
||||
int64_t ld = 0) {
|
||||
int be = 0, bb = 0;
|
||||
if (!geometry(type, be, bb) || cols % be != 0 || rows <= 0) {
|
||||
std::fprintf(stderr, "dequant: unsupported type %d or shape %lld x %lld\n", type, (long long) rows,
|
||||
@@ -200,10 +201,11 @@ void launch(int type, const void* blocks, int64_t row0, int64_t rows, int64_t co
|
||||
std::exit(1);
|
||||
}
|
||||
const int64_t row_bytes = cols / be * bb, gpr = cols / 32, total = rows * gpr;
|
||||
if (ld <= 0) ld = cols;
|
||||
const unsigned grid = (unsigned) ((total + 255) / 256);
|
||||
const uint8_t* p = (const uint8_t*) blocks;
|
||||
cudaStream_t st = (cudaStream_t) stream;
|
||||
#define STRATA_DQ(TY) dequant_kernel<TY, T><<<grid, 256, 0, st>>>(p, row_bytes, row0, rows, gpr, out); break
|
||||
#define STRATA_DQ(TY) dequant_kernel<TY, T><<<grid, 256, 0, st>>>(p, row_bytes, row0, rows, gpr, ld, out); break
|
||||
switch (type) {
|
||||
case 2: STRATA_DQ(2);
|
||||
case 6: STRATA_DQ(6);
|
||||
@@ -249,6 +251,15 @@ void dequant_f16(int ggml_type, const void* blocks, int64_t row0, int64_t rows,
|
||||
launch<H16>(ggml_type, blocks, row0, rows, cols, reinterpret_cast<H16*>(out), stream);
|
||||
}
|
||||
|
||||
bool dequant_f16_ld(int ggml_type, const void* blocks, int64_t row0, int64_t rows, int64_t cols, int64_t ld,
|
||||
uint16_t* out, void* stream) {
|
||||
int be = 0, bb = 0;
|
||||
if (iq_only(ggml_type) || !geometry(ggml_type, be, bb) || cols % be != 0 || rows <= 0 || ld < cols || ld % 8 != 0)
|
||||
return false;
|
||||
launch<H16>(ggml_type, blocks, row0, rows, cols, reinterpret_cast<H16*>(out), stream, ld);
|
||||
return true;
|
||||
}
|
||||
|
||||
void dequant_f32(int ggml_type, const void* blocks, int64_t row0, int64_t rows, int64_t cols, float* out, void* stream) {
|
||||
if (iq_only(ggml_type)) {
|
||||
iq_dequant_f32(ggml_type, (const uint8_t*) blocks + (size_t) row0 * iq_row_bytes(ggml_type, cols), rows * cols,
|
||||
|
||||
+21
-1
@@ -437,7 +437,27 @@ void Gemm::f16(const uint16_t* X, const uint16_t* W, float* Y, int64_t T, int64_
|
||||
}
|
||||
|
||||
void Gemm::native(const uint16_t* X, int ggml_type, const void* W_blocks, float* Y, int64_t T, int64_t N, int64_t K,
|
||||
int64_t ldy, float beta) {
|
||||
int64_t ldy, float beta, int64_t ldx) {
|
||||
#ifdef STRATA_USE_HIP
|
||||
// S23 (opt-in STRATA_PF_PAD=1, with STRATA_PF_GEMM=1 on chunks of STRATA_PF_SWITCH_MIN_T+ tokens): the weight
|
||||
// dequantized into the scratch with row stride K + 64 halves, so no 4 KB-multiple stride camps on the memory
|
||||
// channels (gemm_probe8: K 6144 19 -> 29 TFLOPS from W alone, 35 with X padded too). Bitwise the same products.
|
||||
static const bool pad_on = [] { const char* v = std::getenv("STRATA_PF_PAD"); return v && v[0] == '1'; }();
|
||||
static const bool pf_on = [] { const char* v = std::getenv("STRATA_PF_GEMM"); return v && v[0] == '1'; }();
|
||||
static const int64_t pf_min_t = [] { const char* v = std::getenv("STRATA_PF_SWITCH_MIN_T"); return v ? (int64_t) std::atoll(v) : (int64_t) 0; }();
|
||||
if (pad_on && pf_on && T >= pf_min_t && T >= 64 && N >= 512 && K % 32 == 0 && N * (K + 64) <= scratch_elems_) {
|
||||
const int64_t ldw = K + 64;
|
||||
if (strata::kernels::dequant_f16_ld(ggml_type, W_blocks, 0, N, K, ldw, scratch_, stream_) &&
|
||||
strata_pf_gemm_f16_ld(X, ldx > 0 ? ldx : K, scratch_, ldw, Y, T, N, K, ldy, beta, stream_)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (ldx > 0 && ldx != K) {
|
||||
std::fprintf(stderr, "prefill gemm: a padded X (ldx %lld, K %lld) needs STRATA_PF_PAD's path\n",
|
||||
(long long) ldx, (long long) K);
|
||||
std::exit(1);
|
||||
}
|
||||
if (N * K > scratch_elems_) {
|
||||
// Too large for the scratch at once: in row slices.
|
||||
const int64_t rows = scratch_elems_ / K;
|
||||
|
||||
+21
-17
@@ -280,7 +280,8 @@ __global__ void __launch_bounds__(S * RG) gdn_rec_kernel(float* __restrict__ sta
|
||||
const float* __restrict__ gate,
|
||||
const float* __restrict__ beta, const float* __restrict__ z,
|
||||
const float* __restrict__ gamma, float eps,
|
||||
float* __restrict__ y, uint16_t* __restrict__ y16, int64_t T) {
|
||||
float* __restrict__ y, uint16_t* __restrict__ y16, int64_t T,
|
||||
int64_t ld16) {
|
||||
__shared__ float sk[S], sq[S], red[RG][S], wsum[16];
|
||||
const int head = blockIdx.x, col = threadIdx.x, rg = threadIdx.y, tid = rg * S + col;
|
||||
const int qh = head % HK;
|
||||
@@ -324,7 +325,7 @@ __global__ void __launch_bounds__(S * RG) gdn_rec_kernel(float* __restrict__ sta
|
||||
const float ss = wsum[0] + wsum[1] + wsum[2] + wsum[3];
|
||||
const float v = oc * rsqrtf(ss / (float) S + eps) * g_col * sigm(z[t * HV * S + head * S + col]);
|
||||
y[t * HV * S + head * S + col] = v;
|
||||
y16[t * HV * S + head * S + col] = hf(v);
|
||||
y16[t * ld16 + head * S + col] = hf(v);
|
||||
}
|
||||
}
|
||||
#pragma unroll
|
||||
@@ -557,7 +558,7 @@ __global__ void __launch_bounds__(QTH) gdn_rec_quad_kernel(float* __restrict__ s
|
||||
// per row with four values per lane rounded differently in its first xor step).
|
||||
__global__ void __launch_bounds__(S) gdn_out_norm_loop_kernel(const float* __restrict__ z, const float* __restrict__ gamma,
|
||||
float eps, float* __restrict__ y, uint16_t* __restrict__ y16,
|
||||
int64_t rows) {
|
||||
int64_t rows, int64_t ld16) {
|
||||
__shared__ float wsum[4];
|
||||
const int col = threadIdx.x;
|
||||
for (int64_t row = blockIdx.x; row < rows; row += gridDim.x) {
|
||||
@@ -570,11 +571,12 @@ __global__ void __launch_bounds__(S) gdn_out_norm_loop_kernel(const float* __res
|
||||
const float ss = wsum[0] + wsum[1] + wsum[2] + wsum[3];
|
||||
const float v = oc * rsqrtf(ss / (float) S + eps) * gamma[col] * sigm(z[at]);
|
||||
y[at] = v;
|
||||
y16[at] = hf(v);
|
||||
y16[(size_t) (row / HV) * ld16 + (size_t) (row % HV) * S + col] = hf(v);
|
||||
}
|
||||
}
|
||||
__global__ void __launch_bounds__(S) gdn_out_norm_kernel(const float* __restrict__ z, const float* __restrict__ gamma,
|
||||
float eps, float* __restrict__ y, uint16_t* __restrict__ y16) {
|
||||
float eps, float* __restrict__ y, uint16_t* __restrict__ y16,
|
||||
int64_t ld16) {
|
||||
__shared__ float wsum[4];
|
||||
const int64_t t = blockIdx.x;
|
||||
const int head = blockIdx.y, col = threadIdx.x;
|
||||
@@ -586,7 +588,7 @@ __global__ void __launch_bounds__(S) gdn_out_norm_kernel(const float* __restrict
|
||||
const float ss = wsum[0] + wsum[1] + wsum[2] + wsum[3];
|
||||
const float v = oc * rsqrtf(ss / (float) S + eps) * gamma[col] * sigm(z[t * HV * S + head * S + col]);
|
||||
y[at] = v;
|
||||
y16[at] = hf(v);
|
||||
y16[(size_t) t * ld16 + (size_t) head * S + col] = hf(v);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- MoE
|
||||
@@ -730,11 +732,11 @@ __global__ void split_q_kernel(const float* __restrict__ qf, float* __restrict__
|
||||
q[i] = qf[t * 24 * 512 + h * 512 + d];
|
||||
}
|
||||
__global__ void gate_attn_kernel(const float* __restrict__ a, const float* __restrict__ qf, uint16_t* __restrict__ o16,
|
||||
int64_t T) {
|
||||
int64_t T, int64_t ld16) {
|
||||
const int64_t i = (int64_t) blockIdx.x * blockDim.x + threadIdx.x;
|
||||
if (i >= T * 24 * 256) return;
|
||||
const int64_t t = i / (24 * 256), h = (i / 256) % 24, d = i % 256;
|
||||
o16[i] = hf(a[i] * (1.0f / (1.0f + expf(-qf[t * 24 * 512 + h * 512 + 256 + d]))));
|
||||
o16[t * ld16 + h * 256 + d] = hf(a[i] * (1.0f / (1.0f + expf(-qf[t * 24 * 512 + h * 512 + 256 + d]))));
|
||||
}
|
||||
|
||||
// one block per (token, kv head, 64-value group); 64 threads. KV streaming: the pool page only if the block is
|
||||
@@ -974,11 +976,12 @@ void gdn_conv(float* history, const float* qkv, const float* conv_w, float* h, i
|
||||
}
|
||||
void gdn_recurrence_variant(int variant, float* state, const float* h, const float* gate, const float* beta,
|
||||
const float* z, const float* gamma, float eps, float* y, uint16_t* y16, int64_t T,
|
||||
void* stream) {
|
||||
void* stream, int64_t ld16) {
|
||||
if (ld16 <= 0) ld16 = (int64_t) HV * S;
|
||||
if (variant == 3) { // diagnostics: the quad recurrence + the old norm kernel
|
||||
if (T > 0) {
|
||||
gdn_rec_quad_kernel<<<HV * (S / QCB), QTH, 0, (cudaStream_t) stream>>>(state, h, gate, beta, y, T);
|
||||
gdn_out_norm_kernel<<<dim3((unsigned) T, HV), S, 0, (cudaStream_t) stream>>>(z, gamma, eps, y, y16);
|
||||
gdn_out_norm_kernel<<<dim3((unsigned) T, HV), S, 0, (cudaStream_t) stream>>>(z, gamma, eps, y, y16, ld16);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -986,31 +989,31 @@ void gdn_recurrence_variant(int variant, float* state, const float* h, const flo
|
||||
if (T > 0) {
|
||||
gdn_rec_quad_kernel<<<HV * (S / QCB), QTH, 0, (cudaStream_t) stream>>>(state, h, gate, beta, y, T);
|
||||
gdn_out_norm_loop_kernel<<<(unsigned) std::min<int64_t>(T * HV, 4096), S, 0, (cudaStream_t) stream>>>(
|
||||
z, gamma, eps, y, y16, T * HV);
|
||||
z, gamma, eps, y, y16, T * HV, ld16);
|
||||
}
|
||||
check("gdn_recurrence (quad)");
|
||||
return;
|
||||
}
|
||||
static const bool serial = std::getenv("STRATA_GDN_REC_HEADS") != nullptr; // the one-block-per-head kernel (A/B)
|
||||
if (serial || T <= 0 || variant == 2) {
|
||||
gdn_rec_kernel<<<HV, dim3(S, RG), 0, (cudaStream_t) stream>>>(state, h, gate, beta, z, gamma, eps, y, y16, T);
|
||||
gdn_rec_kernel<<<HV, dim3(S, RG), 0, (cudaStream_t) stream>>>(state, h, gate, beta, z, gamma, eps, y, y16, T, ld16);
|
||||
} else {
|
||||
static const bool pipe = [] { const char* v = std::getenv("STRATA_GDN_PIPELINE"); return v == nullptr || std::atoi(v) != 0; }();
|
||||
if (pipe) // the software-pipelined loads (same bits)
|
||||
gdn_rec_cols_pipe_kernel<<<HV * NCB, dim3(CB, RG), 0, (cudaStream_t) stream>>>(state, h, gate, beta, y, T);
|
||||
else
|
||||
gdn_rec_cols_kernel<<<HV * NCB, dim3(CB, RG), 0, (cudaStream_t) stream>>>(state, h, gate, beta, y, T);
|
||||
gdn_out_norm_kernel<<<dim3((unsigned) T, HV), S, 0, (cudaStream_t) stream>>>(z, gamma, eps, y, y16);
|
||||
gdn_out_norm_kernel<<<dim3((unsigned) T, HV), S, 0, (cudaStream_t) stream>>>(z, gamma, eps, y, y16, ld16);
|
||||
}
|
||||
check("gdn_recurrence");
|
||||
}
|
||||
void gdn_recurrence(float* state, const float* h, const float* gate, const float* beta, const float* z,
|
||||
const float* gamma, float eps, float* y, uint16_t* y16, int64_t T, void* stream) {
|
||||
const float* gamma, float eps, float* y, uint16_t* y16, int64_t T, void* stream, int64_t ld16) {
|
||||
// Aurora (S23): four lanes per column + the grid-stride norm, the same bits (tests/hip/gdn_rec_head.cpp);
|
||||
// STRATA_GDN_HEAD=0 (or STRATA_GDN_REC_HEADS) keeps the earlier kernels
|
||||
static const bool head = [] { const char* v = std::getenv("STRATA_GDN_HEAD"); return v == nullptr || std::atoi(v) != 0; }();
|
||||
static const bool serial = std::getenv("STRATA_GDN_REC_HEADS") != nullptr;
|
||||
gdn_recurrence_variant(head && !serial ? 1 : 0, state, h, gate, beta, z, gamma, eps, y, y16, T, stream);
|
||||
gdn_recurrence_variant(head && !serial ? 1 : 0, state, h, gate, beta, z, gamma, eps, y, y16, T, stream, ld16);
|
||||
}
|
||||
void route(const float* logits, int32_t* ids, float* weights, int64_t T, int64_t n_expert, void* stream) {
|
||||
if (n_expert == 512)
|
||||
@@ -1090,8 +1093,9 @@ void split_q(const float* q_full, float* q, int64_t T, void* stream) {
|
||||
split_q_kernel<<<blocks_for(T * 24 * 256), 256, 0, (cudaStream_t) stream>>>(q_full, q, T);
|
||||
check("split_q");
|
||||
}
|
||||
void gate_attn(const float* attn, const float* q_full, uint16_t* out16, int64_t T, void* stream) {
|
||||
gate_attn_kernel<<<blocks_for(T * 24 * 256), 256, 0, (cudaStream_t) stream>>>(attn, q_full, out16, T);
|
||||
void gate_attn(const float* attn, const float* q_full, uint16_t* out16, int64_t T, void* stream, int64_t ld16) {
|
||||
gate_attn_kernel<<<blocks_for(T * 24 * 256), 256, 0, (cudaStream_t) stream>>>(attn, q_full, out16, T,
|
||||
ld16 > 0 ? ld16 : 24 * 256);
|
||||
check("gate_attn");
|
||||
}
|
||||
|
||||
|
||||
+26
-10
@@ -180,6 +180,17 @@ inline bool hc_upmix() {
|
||||
return v;
|
||||
}
|
||||
inline bool bf16x2_hc() { return bf16x2_mode() == 1; }
|
||||
// S23 (opt-in STRATA_PF_PAD=1 with STRATA_PF_GEMM=1): the FP16 activations of the two K 6144 projections (ssm_out's
|
||||
// y_h, attn_output's attn_h) with row stride 6144 + 64, so the GEMM's rows do not camp on the memory channels (the
|
||||
// 4 KB-multiple stride; Gemm::native pads the weight the same way). Same bits.
|
||||
inline bool pf_pad() {
|
||||
static const bool v = [] {
|
||||
const char* p = std::getenv("STRATA_PF_PAD"); const char* g = std::getenv("STRATA_PF_GEMM");
|
||||
return p && p[0] == '1' && g && g[0] == '1';
|
||||
}();
|
||||
return v;
|
||||
}
|
||||
constexpr int64_t ZV_PAD = 64;
|
||||
|
||||
// F-1: STRATA_GR_UNFUSED=1 keeps the FP32 copy of the normalized rows (gr_norm + gr_mix), the A/B arm
|
||||
inline bool gr_unfused() {
|
||||
@@ -507,14 +518,16 @@ constexpr size_t GEMM_WS = 32u << 20; // cuBLAS workspace
|
||||
uint64_t gdn_set_bytes(size_t T) {
|
||||
Alloc a; a.count_only = true; bool ok = true;
|
||||
a.take<float>(T * C, ok); a.take<float>(T * ZV, ok); a.take<float>(T * 2 * HV, ok); a.take<float>(T * HV, ok);
|
||||
a.take<float>(T * HV, ok); a.take<float>(T * C, ok); a.take<float>(T * ZV, ok); a.take<uint16_t>(T * ZV, ok);
|
||||
a.take<float>(T * HV, ok); a.take<float>(T * C, ok); a.take<float>(T * ZV, ok);
|
||||
a.take<uint16_t>(T * (ZV + (pf_pad() ? ZV_PAD : 0)), ok);
|
||||
return a.used;
|
||||
}
|
||||
uint64_t qsa_set_bytes(size_t T, int64_t cap, int64_t max_blocks, int64_t sel_batch, int64_t attn_batch,
|
||||
const strata::kernels::QsaShapes& s) {
|
||||
Alloc a; a.count_only = true; bool ok = true;
|
||||
a.take<float>(T * 512, ok); a.take<float>(T * 512, ok); a.take<float>(T * 12288, ok); a.take<float>(T * ZV, ok);
|
||||
a.take<float>(T * 128, ok); a.take<float>(T * 512, ok); a.take<float>(T * ZV, ok); a.take<uint16_t>(T * ZV, ok);
|
||||
a.take<float>(T * 128, ok); a.take<float>(T * 512, ok); a.take<float>(T * ZV, ok);
|
||||
a.take<uint16_t>(T * (ZV + (pf_pad() ? ZV_PAD : 0)), ok);
|
||||
a.take<int32_t>(T * (size_t) cap, ok);
|
||||
a.take<float>((size_t) sel_batch * (size_t) max_blocks, ok);
|
||||
a.take<float>((size_t) attn_batch * strata::kernels::qsa_decode_attn_scratch_floats(cap, s), ok);
|
||||
@@ -744,12 +757,12 @@ bool Prefill::carve(size_t T, void* alloc) {
|
||||
a.base = base; a.cap = region; a.owned = &m.owned;
|
||||
m.qkv = a.take<float>(T * C, ok); m.z = a.take<float>(T * ZV, ok); m.ab = a.take<float>(T * 2 * HV, ok);
|
||||
m.gate = a.take<float>(T * HV, ok); m.beta = a.take<float>(T * HV, ok); m.hbuf = a.take<float>(T * C, ok);
|
||||
m.y = a.take<float>(T * ZV, ok); m.y_h = a.take<uint16_t>(T * ZV, ok);
|
||||
m.y = a.take<float>(T * ZV, ok); m.y_h = a.take<uint16_t>(T * (ZV + (pf_pad() ? ZV_PAD : 0)), ok);
|
||||
Alloc b;
|
||||
b.base = base; b.cap = region; b.owned = &m.owned;
|
||||
m.Kc = b.take<float>(T * 512, ok); m.Vc = b.take<float>(T * 512, ok); m.Qf = b.take<float>(T * 12288, ok);
|
||||
m.q = b.take<float>(T * ZV, ok); m.idx_raw = b.take<float>(T * 128, ok); m.q_idx = b.take<float>(T * 512, ok);
|
||||
m.attn = b.take<float>(T * ZV, ok); m.attn_h = b.take<uint16_t>(T * ZV, ok);
|
||||
m.attn = b.take<float>(T * ZV, ok); m.attn_h = b.take<uint16_t>(T * (ZV + (pf_pad() ? ZV_PAD : 0)), ok);
|
||||
m.sel_ids = b.take<int32_t>(T * (size_t) m.cap, ok);
|
||||
m.sel_scores = b.take<float>((size_t) m.sel_batch * (size_t) m.max_blocks, ok);
|
||||
m.attn_scratch = b.take<float>((size_t) m.attn_batch * strata::kernels::qsa_decode_attn_scratch_floats(m.cap, s), ok);
|
||||
@@ -1020,9 +1033,9 @@ const core::WeightRef* need(const core::LayerView& v, const char* suffix, std::s
|
||||
return r;
|
||||
}
|
||||
bool native_proj(Gemm& gm, const core::WeightRef* w, const uint16_t* X, float* Y, int64_t T, const std::string& name,
|
||||
std::string& err, int64_t ldy = 0) {
|
||||
std::string& err, int64_t ldy = 0, int64_t ldx = 0) {
|
||||
if (!w->native_data) { err = "prefill: " + name + " has no native GGUF blocks (run with --native)"; return false; }
|
||||
gm.native(X, w->native_type, w->native_data, Y, T, w->ne1, w->ne0, ldy);
|
||||
gm.native(X, w->native_type, w->native_data, Y, T, w->ne1, w->ne0, ldy, 0.0f, ldx);
|
||||
return true;
|
||||
}
|
||||
bool bf16_proj(Gemm& gm, const core::WeightRef* w, const uint16_t* X, float* Y, int64_t T, const std::string& name,
|
||||
@@ -1480,9 +1493,11 @@ bool Prefill::run(const int64_t* tokens, int64_t n, int64_t pos0, std::string& e
|
||||
gdn_gates(m.ab, (const float*) wdt->data, (const float*) wsa->data, m.gate, m.beta, T, m.cs);
|
||||
gdn_conv(conv, m.qkv, (const float*) wc->data, m.hbuf, T, EPS, m.cs);
|
||||
pt.mark(kPfGdnRec, cs);
|
||||
gdn_recurrence(state, m.hbuf, m.gate, m.beta, m.z, (const float*) wnm->data, EPS, m.y, m.y_h, T, m.cs);
|
||||
const int64_t ld_y = pf_pad() && T >= std::max<int64_t>(pf_switch_min_t(), 64) ? ZV + ZV_PAD : 0;
|
||||
gdn_recurrence(state, m.hbuf, m.gate, m.beta, m.z, (const float*) wnm->data, EPS, m.y, m.y_h, T, m.cs,
|
||||
ld_y);
|
||||
pt.mark(kPfGdnOut, cs);
|
||||
if (!native_proj(m.gemm, wo, m.y_h, m.bo, T, v.name("ssm_out.weight"), err)) return false;
|
||||
if (!native_proj(m.gemm, wo, m.y_h, m.bo, T, v.name("ssm_out.weight"), err, 0, ld_y)) return false;
|
||||
++gdn_index;
|
||||
} else if (half == 0) {
|
||||
// ======================= QSA =======================
|
||||
@@ -1679,8 +1694,9 @@ bool Prefill::run(const int64_t* tokens, int64_t n, int64_t pos0, std::string& e
|
||||
}
|
||||
if (st.kv_rot || st.kv_hybrid) strata::kernels::fwht256_inplace_cuda(m.attn, T * 24, m.cs);
|
||||
pt.mark(kPfQsa, cs);
|
||||
gate_attn(m.attn, m.Qf, m.attn_h, T, m.cs);
|
||||
if (!native_proj(m.gemm, wo, m.attn_h, m.bo, T, v.name("attn_output.weight"), err)) return false;
|
||||
const int64_t ld_a = pf_pad() && T >= std::max<int64_t>(pf_switch_min_t(), 64) ? ZV + ZV_PAD : 0;
|
||||
gate_attn(m.attn, m.Qf, m.attn_h, T, m.cs, ld_a);
|
||||
if (!native_proj(m.gemm, wo, m.attn_h, m.bo, T, v.name("attn_output.weight"), err, 0, ld_a)) return false;
|
||||
++qsa_index;
|
||||
} else {
|
||||
// ======================= MoE =======================
|
||||
|
||||
@@ -300,7 +300,8 @@ __device__ __forceinline__ h16 frag(const _Float16* p) {
|
||||
}
|
||||
template <int BN, int WN>
|
||||
__global__ void __launch_bounds__(256) kernel(const _Float16* __restrict__ X, const _Float16* __restrict__ W,
|
||||
float* __restrict__ Y, int M, int N, int K, int ldy, int accumulate) {
|
||||
float* __restrict__ Y, int M, int N, int K, int ldy, int accumulate,
|
||||
int ldx, int ldw) {
|
||||
#if defined(__gfx1100__) || defined(__gfx1101__) || defined(__gfx1102__) || defined(__gfx1150__) || defined(__gfx1151__)
|
||||
constexpr int TN = WN / 16, NB = BN / 64;
|
||||
__shared__ __align__(16) _Float16 sA[2][BM][LDK];
|
||||
@@ -312,10 +313,10 @@ __global__ void __launch_bounds__(256) kernel(const _Float16* __restrict__ X, co
|
||||
const int m0 = (first_m + (b % (GM * num_n)) % gsize) * BM, n0 = ((b % (GM * num_n)) / gsize) * BN;
|
||||
const int sr = tid >> 2, sq = tid & 3;
|
||||
auto ldA = [&](int k0, int r) -> uint4 {
|
||||
return *reinterpret_cast<const uint4*>(X + (size_t) min(m0 + r, M - 1) * K + k0 + 8 * sq);
|
||||
return *reinterpret_cast<const uint4*>(X + (size_t) min(m0 + r, M - 1) * ldx + k0 + 8 * sq);
|
||||
};
|
||||
auto ldB = [&](int k0, int r) -> uint4 {
|
||||
return *reinterpret_cast<const uint4*>(W + (size_t) min(n0 + r, N - 1) * K + k0 + 8 * sq);
|
||||
return *reinterpret_cast<const uint4*>(W + (size_t) min(n0 + r, N - 1) * ldw + k0 + 8 * sq);
|
||||
};
|
||||
f8 acc[4][TN];
|
||||
for (int i = 0; i < 4; ++i) for (int j = 0; j < TN; ++j) acc[i][j] = f8{0, 0, 0, 0, 0, 0, 0, 0};
|
||||
@@ -374,9 +375,15 @@ __global__ void __launch_bounds__(256) kernel(const _Float16* __restrict__ X, co
|
||||
|
||||
bool strata_pf_gemm_f16(const uint16_t* X, const uint16_t* W, float* Y, int64_t T, int64_t N, int64_t K, int64_t ldy,
|
||||
float beta, void* stream) {
|
||||
return strata_pf_gemm_f16_ld(X, K, W, K, Y, T, N, K, ldy, beta, stream);
|
||||
}
|
||||
|
||||
bool strata_pf_gemm_f16_ld(const uint16_t* X, int64_t ldx, const uint16_t* W, int64_t ldw, float* Y, int64_t T,
|
||||
int64_t N, int64_t K, int64_t ldy, float beta, void* stream) {
|
||||
if (!X || !W || !Y || T < 64 || N < 512 || K % pfg::BK != 0 || K < pfg::BK) return false;
|
||||
if (beta != 0.0f && beta != 1.0f) return false;
|
||||
if (ldy <= 0) ldy = N;
|
||||
if (ldx < K || ldw < K || ldx % 8 != 0 || ldw % 8 != 0 || ldx > (1LL << 30) || ldw > (1LL << 30)) return false;
|
||||
if (ldy < N || T > (1LL << 30) || N > (1LL << 30) || K > (1LL << 30)) return false;
|
||||
static const bool gfx11 = [] {
|
||||
int dev = 0;
|
||||
@@ -391,11 +398,11 @@ bool strata_pf_gemm_f16(const uint16_t* X, const uint16_t* W, float* Y, int64_t
|
||||
if (N >= 1024) {
|
||||
const unsigned grid = (unsigned) (mt * ((N + 255) / 256));
|
||||
pfg::kernel<256, 64><<<grid, 256, 0, s>>>((const _Float16*) X, (const _Float16*) W, Y, (int) T, (int) N, (int) K,
|
||||
(int) ldy, acc);
|
||||
(int) ldy, acc, (int) ldx, (int) ldw);
|
||||
} else {
|
||||
const unsigned grid = (unsigned) (mt * ((N + 127) / 128));
|
||||
pfg::kernel<128, 32><<<grid, 256, 0, s>>>((const _Float16*) X, (const _Float16*) W, Y, (int) T, (int) N, (int) K,
|
||||
(int) ldy, acc);
|
||||
(int) ldy, acc, (int) ldx, (int) ldw);
|
||||
}
|
||||
return hipGetLastError() == hipSuccess;
|
||||
}
|
||||
@@ -405,6 +412,10 @@ bool strata_pf_gemm_f16(const uint16_t* X, const uint16_t* W, float* Y, int64_t
|
||||
bool strata_pf_gemm_f16(const uint16_t*, const uint16_t*, float*, int64_t, int64_t, int64_t, int64_t, float, void*) {
|
||||
return false;
|
||||
}
|
||||
bool strata_pf_gemm_f16_ld(const uint16_t*, int64_t, const uint16_t*, int64_t, float*, int64_t, int64_t, int64_t,
|
||||
int64_t, float, void*) {
|
||||
return false;
|
||||
}
|
||||
bool strata_wmma_gemm_f16(const uint16_t*, const uint16_t*, float*,
|
||||
int64_t, int64_t, int64_t, int64_t, float,
|
||||
void*) {
|
||||
|
||||
@@ -21,6 +21,10 @@ bool strata_wmma_gemm_f16(const uint16_t* X, const uint16_t* W, float* Y,
|
||||
/// T >= 64, N >= 512; the 128 x 256 / 128 x 128 grouped-order WMMA kernel. False (nothing launched) otherwise / off gfx11.
|
||||
bool strata_pf_gemm_f16(const uint16_t* X, const uint16_t* W, float* Y, int64_t T, int64_t N, int64_t K, int64_t ldy,
|
||||
float beta, void* stream = nullptr);
|
||||
/// The same with row strides ldx >= K and ldw >= K (multiples of 8): a 4 KB-multiple row stride (K 2048 / 4096 /
|
||||
/// 6144) camps on the memory channels, K + 64 does not (S23 gemm_probe7/8: K 6144 19 -> 35 TFLOPS).
|
||||
bool strata_pf_gemm_f16_ld(const uint16_t* X, int64_t ldx, const uint16_t* W, int64_t ldw, float* Y, int64_t T,
|
||||
int64_t N, int64_t K, int64_t ldy, float beta, void* stream = nullptr);
|
||||
|
||||
bool strata_wmma_gemm_bf16(const uint16_t* X, const uint16_t* W, float* Y,
|
||||
int64_t T, int64_t N, int64_t K, int64_t ldy, float beta,
|
||||
|
||||
Reference in new issue
Block a user