Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
331d727
perf(cuda): levers3, Qwen3.5's alpha/beta pair folded into the conv-s…
marcospaulo Sep 30, 2026
e74ed87
perf(glm5next): the KDA output gate's low-rank pair goes into the gra…
marcospaulo Sep 30, 2026
7536ed7
perf(cuda): glm5next's KDA output gate written by the recurrence's ke…
marcospaulo Sep 30, 2026
b850d70
perf(cuda): take out the KDA gated norm in the recurrence's kernel (7…
marcospaulo Sep 30, 2026
4135a7e
docs(torad): rows for the Qwen levers (331d72782), the KDA output gat…
marcospaulo Sep 30, 2026
bbe5370
perf(cuda): the routed down projection lists its experts and streams …
marcospaulo Sep 30, 2026
ff9a73c
docs(torad): row for the routed down's pre-wait tiles (bbe53707b) and…
marcospaulo Sep 30, 2026
3a68863
perf(cuda): the routed experts' weighted sum in one launch, bit for b…
marcospaulo Sep 30, 2026
cb7d859
docs(torad): row for the routed experts' weighted sum in one launch (…
marcospaulo Sep 30, 2026
90d1b98
perf(cuda): the hyper-connection front writes its normed mix's q8_1 c…
marcospaulo Sep 30, 2026
c38e7a8
docs(torad): row for the hyper-connection front's own q8_1 copy (90d1…
marcospaulo Sep 30, 2026
4bce940
perf(cuda): the hyper-connection front's comb beside the stream, off …
marcospaulo Sep 30, 2026
e815919
docs(torad): row for the hyper-connection front's comb beside the str…
marcospaulo Sep 30, 2026
6588e1d
test: a backend's outputs are read as soon as its evaluation returns,…
marcospaulo Sep 30, 2026
c6b4ecf
fix(cuda): the hyper-connection front's comb beside the stream only i…
marcospaulo Sep 30, 2026
09c216b
docs(torad): rows for the harness compare order (6588e1d6a) and the c…
marcospaulo Sep 30, 2026
5c03ed9
perf(cuda): the fused MoE top-k at 2-4 rows, its weights and ids free…
marcospaulo Sep 30, 2026
b3fc826
perf(cuda): the paced L2 issuer stops as a routed-expert ring starts
marcospaulo Sep 30, 2026
3dbefa8
perf(cuda): a routed-expert ring of several tokens decodes an IQ3_XXS…
marcospaulo Sep 30, 2026
c33735a
docs(cuda): the routed-expert ring's one write before its dependency …
marcospaulo Sep 30, 2026
2e699cc
docs(torad): rows for the fused top-k at 2-4 rows (5c03ed96f), the L2…
marcospaulo Sep 30, 2026
04dde5d
perf(cuda): the routed-expert ring takes its pairs' offsets from host…
marcospaulo Sep 30, 2026
2606ae5
docs(torad): row for the ring's pair offsets from host tables and fas…
marcospaulo Sep 30, 2026
18fa139
perf(cuda): a float mat-mul that mmf would run on fewer blocks than S…
marcospaulo Sep 30, 2026
c47f13e
docs(torad): row for float mat-muls mmf would underfill taking the ve…
marcospaulo Sep 30, 2026
2c5fb99
perf(cuda): the routed-expert ring decodes once for an expert's pairs…
marcospaulo Sep 30, 2026
a993de2
docs(torad): row for the ring decoding once for an expert's pairs onl…
marcospaulo Sep 30, 2026
98a6656
perf(cuda): the hyper-connection comb beside the stream becomes opt-i…
marcospaulo Sep 30, 2026
5b9b8e5
docs(torad): row for the hyper-connection comb beside the stream beco…
marcospaulo Sep 30, 2026
304cc84
perf(cuda): the hyper-connection comb beside the stream is removed
marcospaulo Sep 30, 2026
0b7316a
perf(kpool): the pooled-indexer inputs follow the cells that changed,…
marcospaulo Sep 30, 2026
0b0e97b
perf(cuda): sparse flash attention reads only the cells a DSA layer s…
marcospaulo Sep 30, 2026
c986f0c
docs(torad): rows for the comb beside the stream removed (304cc84cc),…
marcospaulo Sep 30, 2026
4a88ac9
fix(kpool): the rows of a scatter are unique: the sparse mask's fille…
marcospaulo Sep 30, 2026
69b9332
fix(meta): a node with no sources is mirrored
marcospaulo Sep 30, 2026
9c506a4
fix(cuda): every warp of the MMA flash-attention combine reaches one …
marcospaulo Oct 1, 2026
f8352b6
perf(cuda): the sparse mask scan reads 32768 columns a round, 1024 th…
marcospaulo Oct 1, 2026
252f29c
feat(cuda): the lightning indexer reads pooled keys in place, and sco…
marcospaulo Oct 1, 2026
c40b9d5
perf(cuda): the routed-expert ring quantizes its own down-projection …
marcospaulo Oct 1, 2026
6fbde0b
perf(cuda): the hyper-connection front runs in one launch, bit for bit
marcospaulo Oct 1, 2026
d769cb1
docs(torad): rows for the meta sourceless fix, the MMA combine barrie…
marcospaulo Oct 1, 2026
e1c1ca7
perf(cuda): the one-launch hyper-connection front becomes opt-in — it…
marcospaulo Oct 1, 2026
12ef697
docs(torad): row for the scatter's unique rows (4a88ac993): no value …
marcospaulo Oct 1, 2026
e11e67c
perf(kpool): the sparse mask's filler slots come from dump pools in t…
marcospaulo Oct 1, 2026
1e20fd5
docs(torad): row for the dump-pool fold (e11e67c29): its filler slots…
marcospaulo Oct 1, 2026
22d5415
quantize: a tensor already in its target type needs no imatrix
marcospaulo Oct 1, 2026
25be8c4
test-backend-ops: glm5next's non-expert shapes at the 4-bit candidates
marcospaulo Oct 1, 2026
a61c58f
perplexity: score from a chosen position, and report dKLD by position
marcospaulo Oct 1, 2026
c95678d
cuda: GGML_CUDA_TIME_LAUNCH=1, cudaGraphLaunch's host cost without a …
marcospaulo Oct 1, 2026
acfa019
llama: LLAMA_TIME_DECODE=1, where a decode token's host time actually…
marcospaulo Oct 1, 2026
2cde319
perplexity: same top by position beside the binned dKLD
marcospaulo Oct 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions TORAD.md

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions ggml/include/ggml.h
Original file line number Diff line number Diff line change
Expand Up @@ -2467,6 +2467,15 @@ extern "C" {
GGML_API bool ggml_flash_attn_ext_get_mask_prefix(
const struct ggml_tensor * a);

// Use finite mask entries as a sparse K/V set. Set 0 to disable.
// n_kv_max must bound the number of finite entries in every mask row.
GGML_API void ggml_flash_attn_ext_set_n_kv_max(
struct ggml_tensor * a,
int32_t n_kv_max);

GGML_API int32_t ggml_flash_attn_ext_get_n_kv_max(
const struct ggml_tensor * a);

// TODO: needs to be adapted to ggml_flash_attn_ext
GGML_API struct ggml_tensor * ggml_flash_attn_back(
struct ggml_context * ctx,
Expand Down Expand Up @@ -2666,6 +2675,19 @@ extern "C" {
struct ggml_tensor * weights,
struct ggml_tensor * mask);

// the same with key i of stream s at row k_rows[i, s] of k (a view into a cache, no gathered copy), and the
// scores in f32 whatever k's type (as over the f32 rows ggml_get_rows would have copied):
// k: [n_embd_idx, 1, n_rows, ne3]
// k_rows: [n_kv, ne3] I32, each in [0, n_rows)
// mask, res: n_kv as above
GGML_API struct ggml_tensor * ggml_lightning_indexer_rows(
struct ggml_context * ctx,
struct ggml_tensor * q,
struct ggml_tensor * k,
struct ggml_tensor * k_rows,
struct ggml_tensor * weights,
struct ggml_tensor * mask);

// DeepSeek V4 hyper-connections (ref. https://arxiv.org/pdf/2512.24880)
// In short these operations are replacements for the original residual connection (x = transformer(x) + x)
// using a richer representation through streams.
Expand Down
5 changes: 4 additions & 1 deletion ggml/src/ggml-backend-meta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,8 @@ static struct ggml_backend_meta_split_state ggml_backend_meta_get_split_state(co
}
}
if (ret.axis == GGML_BACKEND_SPLIT_AXIS_NONE) {
ret = {GGML_BACKEND_SPLIT_AXIS_UNKNOWN, {0}, {1}, 1};
// no sources (ARANGE): every device computes the same values
ret = {GGML_BACKEND_SPLIT_AXIS_MIRRORED, {0}, {1}, 1};
}
if (scalar_only && ret.axis >= 0 && ret.axis < GGML_MAX_DIMS) {
ret = {GGML_BACKEND_SPLIT_AXIS_UNKNOWN, {0}, {1}, 1};
Expand Down Expand Up @@ -851,6 +852,8 @@ static struct ggml_backend_meta_split_state ggml_backend_meta_get_split_state(co
for (size_t i = 0; i < 4; i++) {
GGML_ASSERT(src_ss[i].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED);
}
// ggml_lightning_indexer_rows: every device reads the same keys through the same rows
GGML_ASSERT(tensor->src[4] == nullptr || src_ss[4].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED);
return {GGML_BACKEND_SPLIT_AXIS_MIRRORED, {0}, {1}, 1};
};

Expand Down
5 changes: 3 additions & 2 deletions ggml/src/ggml-backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2386,9 +2386,10 @@ bool ggml_backend_compare_graph_backend(ggml_backend_t backend1, ggml_backend_t

if (num_test_nodes != 0) {
GGML_ASSERT(test_nodes);
// Compute the whole graph and only test the output for specific tensors
ggml_backend_graph_compute(backend1, g1);
// Compute the whole graph and only test the output for specific tensors: backend1's last, so its outputs are
// read as soon as its evaluation returns, and work it leaves running past the return reads as a wrong result
ggml_backend_graph_compute(backend2, g2);
ggml_backend_graph_compute(backend1, g1);

bool verified = false;
for (int i = 0; i < g1->n_nodes; i++) {
Expand Down
8 changes: 6 additions & 2 deletions ggml/src/ggml-cpu/ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12163,11 +12163,13 @@ void ggml_compute_forward_lightning_indexer(
const ggml_tensor * k = dst->src[1];
const ggml_tensor * w = dst->src[2]; // weights
const ggml_tensor * m = dst->src[3]; // mask
const ggml_tensor * r = dst->src[4]; // ggml_lightning_indexer_rows: key i of stream s at k's row r[i, s]

GGML_ASSERT(dst->type == GGML_TYPE_F32);
GGML_ASSERT( q->type == GGML_TYPE_F32);
GGML_ASSERT( w->type == GGML_TYPE_F32);
GGML_ASSERT( m->type == GGML_TYPE_F16);
GGML_ASSERT(r == nullptr || r->type == GGML_TYPE_I32);

GGML_TENSOR_LOCALS(int64_t, neq, q, ne)
GGML_TENSOR_LOCALS(size_t, nbq, q, nb)
Expand All @@ -12190,7 +12192,7 @@ void ggml_compute_forward_lightning_indexer(
const int n_head = q->ne[1];
const int n_tokens = q->ne[2];
const int n_stream = q->ne[3];
const int n_kv = k->ne[2];
const int n_kv = dst->ne[0];

ggml_to_float_t const k_to_float = ggml_get_type_traits(k->type)->to_float;
GGML_ASSERT((k->type == GGML_TYPE_F32 || k_to_float) && "lightning indexer: unsupported K-type");
Expand All @@ -12215,7 +12217,9 @@ void ggml_compute_forward_lightning_indexer(
const ggml_fp16_t * m_row = (ggml_fp16_t *) ((char *) m->data + t*nbm1 + (s%nem3)*nbm3);
float * dst_row = (float *) ((char *) dst->data + t*nb1 + s*nb3 );
for (int ik = ir0; ik < ir1; ++ik) {
char * k_row = (char *) k->data + ik*nbk2 + s*nbk3;
const int64_t i_row = r ? ((const int32_t *) ((const char *) r->data + s*r->nb[1]))[ik] : ik;
GGML_ASSERT(i_row >= 0 && i_row < nek2);
char * k_row = (char *) k->data + i_row*nbk2 + s*nbk3;
if (k_to_float) {
k_to_float(k_row, k_row_f32, n_embd);
} else {
Expand Down
39 changes: 39 additions & 0 deletions ggml/src/ggml-cuda/binbcast.cu
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,45 @@ void ggml_cuda_op_fused_mul(ggml_backend_cuda_context & ctx, ggml_tensor * dst,
}
}

// a thread an element of a token's sum, the slots in their order: each product and each sum rounded on its own, as the
// MUL and the ADDs round them (never contracted into an FMA)
static __global__ void k_moe_weighted_sum(const float * experts, const float * weights, float * dst, const int n_embd,
const int n_used, const int64_t se1, const int64_t se2, const int64_t sw1, const int64_t sw2, const int64_t sd1) {
ggml_cuda_pdl_lc();
const int i = blockIdx.x*blockDim.x + threadIdx.x;
const int64_t t = blockIdx.y;
if (i >= n_embd) {
return;
}
ggml_cuda_pdl_sync();
const float * e = experts + t*se2 + i;
const float * w = weights + t*sw2;
float acc = __fmul_rn(e[0], w[0]);
for (int s = 1; s < n_used; ++s) {
acc = __fadd_rn(acc, __fmul_rn(e[s*se1], w[s*sw1]));
}
dst[t*sd1 + i] = acc;
}

void ggml_cuda_op_moe_weighted_sum(ggml_backend_cuda_context & ctx, const ggml_tensor * experts,
const ggml_tensor * weights, ggml_tensor * dst) {
GGML_ASSERT(experts->type == GGML_TYPE_F32 && weights->type == GGML_TYPE_F32 && dst->type == GGML_TYPE_F32);
GGML_ASSERT(experts->nb[0] == sizeof(float) && dst->nb[0] == sizeof(float));
const int n_embd = (int) experts->ne[0];
const int n_used = (int) experts->ne[1];
const int64_t n_tokens = experts->ne[2];
GGML_ASSERT(weights->ne[0] == 1 && weights->ne[1] == n_used && weights->ne[2] == n_tokens);
GGML_ASSERT(dst->ne[0] == n_embd && dst->ne[1] == n_tokens);

constexpr int block_size = 128; // k_bin_bcast's
const ggml_cuda_kernel_launch_params params = ggml_cuda_kernel_launch_params(
dim3((n_embd + block_size - 1) / block_size, (unsigned) n_tokens, 1), dim3(block_size, 1, 1), 0, ctx.stream());
ggml_cuda_kernel_launch(k_moe_weighted_sum, params, (const float *) experts->data, (const float *) weights->data,
(float *) dst->data, n_embd, n_used, experts->nb[1] / (int64_t) sizeof(float),
experts->nb[2] / (int64_t) sizeof(float), weights->nb[1] / (int64_t) sizeof(float),
weights->nb[2] / (int64_t) sizeof(float), dst->nb[1] / (int64_t) sizeof(float));
}

void ggml_cuda_op_repeat_back(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
const ggml_tensor * src0 = dst->src[0];

Expand Down
7 changes: 7 additions & 0 deletions ggml/src/ggml-cuda/binbcast.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,10 @@ void ggml_cuda_op_repeat_back(ggml_backend_cuda_context & ctx, ggml_tensor * dst

void ggml_cuda_op_fused_add(ggml_backend_cuda_context & ctx, ggml_tensor * dst, int n_fuse);
void ggml_cuda_op_fused_mul(ggml_backend_cuda_context & ctx, ggml_tensor * dst, int n_fuse);

// Routed experts' weighted sum as build_moe_ffn writes it, MUL(experts, weights) then the slots' views added in order
// (ADD(ADD(v0, v1), v2), ...), in one launch: dst[i, t] = ((e[i,0,t]*w[0,t] + e[i,1,t]*w[1,t]) + ...), every product and
// sum rounded as those nodes round them, so bit for bit their result. experts [n_embd, n_used, n_tokens], weights
// [1, n_used, n_tokens], dst [n_embd, n_tokens], all F32 with contiguous rows; dst lies over neither input.
void ggml_cuda_op_moe_weighted_sum(ggml_backend_cuda_context & ctx, const ggml_tensor * experts,
const ggml_tensor * weights, ggml_tensor * dst);
Loading
Loading