Skip to content

Commit dc010d6

Browse files
committed
feat(paged): gate GDN prefill geometry by scan length (patch 0046)
Patch 0022 retuned the gated-DeltaNet (GDN) sequential-recurrence dispatch (case 128) to a (NUM_WARPS=16, COLS_PER_WARP=8) column-fold tile. That is a DECODE win (short scans: small n_tokens, large n_seqs) but an UNCONDITIONAL dense-prefill regression vs stock: on a long sequential scan the launch grid.z collapses from S_v/4=32 to S_v/(16*8)=1, so the SMs starve. Profiling the dense-prefill path attributed the whole regression (~-6%) to gated_delta_net (+54% GPU time) at the (16,8) geometry. Gate the geometry by per-call scan length instead of applying (16,8) unconditionally. Long scans (prefill, n_tokens >= GDN_PREFILL_NTOK, default 256) take stock's high-grid.z (4,1) geometry; short scans (decode) keep the (16,8) retune. This recovers dense prefill +7.2% back to stock parity while preserving the (16,8) decode win. Bit-exact: patch 0022 proved every selectable {NUM_WARPS, COLS_PER_WARP} variant is byte-identical (the sweep cannot change the md5), so this scan-length gate is greedy-md5 bit-exact. GDN_PREFILL_NTOK tunes the crossover; the explicit GDN_NW / GDN_CPW one-build %peak sweep still wins (the gate yields when either is set), so the A/B harness is unchanged. Root cause: patch 0022 applied the (16,8) tile unconditionally. This patch sequences after 0022/0044 (it edits the same gated_delta_net.cu case-128 dispatch) and adds only the scan-length gate. Assisted-by: Claude:opus-4.8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
1 parent 263d181 commit dc010d6

1 file changed

Lines changed: 17 additions & 0 deletions

File tree

ggml/src/ggml-cuda/gated_delta_net.cu

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,23 @@ static void launch_gated_delta_net(
550550
launch_gdn_variant<64, KDA, keep_rs_t, 4, 1, 2>(GDN_LAUNCH_ARGS);
551551
break;
552552
case 128: {
553+
// Dense-prefill regression fix: gate patch 0022's column-fold geometry by per-call scan
554+
// length. The (16,8) tile is a DECODE win (short scans: n_tokens small, n_seqs large) but a
555+
// long-sequential-scan PREFILL loss - grid.z collapses from S_v/4=32 to S_v/(16*8)=1, so the
556+
// SMs starve on the long scan (profiled: gated_delta_net +54% GPU time == the whole dense-
557+
// prefill regression). Long scans (prefill) take stock's high-grid.z (4,1) geometry; short
558+
// scans (decode) keep the (16,8) winner. Every {NW,CPW} variant is byte-identical (patch 0022
559+
// proved md5-invariance across the ladder), so this stays greedy-md5 bit-exact. Default-on;
560+
// GDN_PREFILL_NTOK tunes the crossover; the explicit GDN_NW/GDN_CPW sweep still wins (gate
561+
// yields when either is set) so the one-build %peak A/B harness is unchanged.
562+
static const int64_t gdn_prefill_ntok =
563+
[]{ const char * e = getenv("GDN_PREFILL_NTOK"); return e ? (int64_t) atoll(e) : (int64_t) 256; }();
564+
static const bool gdn_nw_forced = (getenv("GDN_NW") != nullptr);
565+
static const bool gdn_cpw_forced = (getenv("GDN_CPW") != nullptr);
566+
if (n_tokens >= gdn_prefill_ntok && !gdn_nw_forced && !gdn_cpw_forced) {
567+
launch_gdn_variant<128, KDA, keep_rs_t, 4, 1, 2>(GDN_LAUNCH_ARGS);
568+
break;
569+
}
553570
// Bit-exact occupancy/coalescing retune (patch 0022): fold COLS_PER_WARP columns per warp
554571
// to raise per-warp memory-level parallelism on this bandwidth-bound recurrence. Default is
555572
// the measured winner; GDN_NW / GDN_CPW override it for the one-build %peak sweep (every

0 commit comments

Comments
 (0)