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:
Niko1221 committed 2026-10-04 03:00:48 +02:00
1 parent b6b7a87d84
commit bedb808741
9 files changed
+115 -42

No files matched your search

+5
View File
@@ -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);
+3 -2
View File
@@ -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);
+4 -3
View File
@@ -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.
+15 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 =======================
+16 -5
View File
@@ -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*) {
+4
View File
@@ -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,