Repository navigation
prefill: STRATA_GDN_CHUNKED=1 on gfx11 WMMA (opt-in; gfx1151: recurrence 1.6x, a warm 4K-128K prompt 1.1-2.5%) - #2299
libratechw wants to merge 1 commit into
Conversation
…nce in 16-token chunks on the matrix cores (opt-in) The switch exists for CUDA (Niko1221#1372) and is compiled out on HIP. On gfx11 it now runs the WY form of the gated delta rule in chunks of 16 tokens, every product one 16x16x16 WMMA (FP16 operands, FP32 accumulation, the state in the accumulators), with the output norm and the z gate fused: a prep kernel for T and P of every chunk, then a scan with a block per value head. It rounds differently from the FP32 recurrence, so it is opt-in; the default path is unchanged. A gfx1100, gfx1101, gfx1102, gfx1103, gfx1150 or gfx1151 part, 64 tokens and more, an output row stride divisible by 8 and no STRATA_GDN_REC_HEADS take it; anything else runs the existing kernels. tests/hip/gdn_chunked.cpp: bounds on the FP16 output and the carried state against the existing recurrence over 0-16,385 tokens (chunk and stride edges, a split request), a double-precision CPU check, and bit-identical output with the switch off or unset. tests/hip/gdn_rec_head.cpp unsets the switch, as its variants 0 and 1 are the references there. hip_gdn_chunked --bench and --bench-default time this path and gfx1151's default kernels, one per process (the switch is read once). gfx1151 (Ryzen AI Max+ 395, UD-IQ4_XS): a layer's recurrence + norm takes 1.6x less time than the default kernels at 16K and 32K tokens; a whole prompt 1.1-2.5% less at 4K-128K after a warm-up prompt (11 pairs each: 1.9-2.5% with the docs/STRIX_HALO.md section-5 switches, 1.1-1.2% without them, 10 or 11 of 11 faster); first-token KL against the default 0.006-0.007 on average, the same top token in 12 of 12 prompts. Run on gfx1151 only; kernels.cu compiles for gfx1030, 1100, 1103, 1151, 1152 and 1201 (docs/AMD_HIP.md). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
0a475ae to
35d321a
Compare
|
Ported (two comment/CMake conflicts resolved, your authorship kept as co-author), opt-in only. We cannot run gfx11 matrix cores here; on an R9700 the switch is inert (the new tests report exact equality with the old recurrence, the identity gate is unchanged), and the file builds for gfx1100/1103/1150/1151/1201. Your numbers (+1.4-2.1% for a whole prompt, KL 0.004-0.007) are modest and change bits, so it stays opt-in. |
…o1221#2020 The 32K prompt A/B and layer timings of Niko1221#2018, the GDN ctest of Niko1221#2299, and the KL and task-check runs of Niko1221#2020, on the maintainer's main. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Thanks for porting this as opt-in. Since you can't run the gfx11 matrix cores, I ran the GDN tests on the merged build (477ac13, gfx1151): The test log: https://github.com/libratechw/Strata/blob/09df26f072914f96cfa4fcae3e835e462358808e/main477/gdn-ctest.log |
|
Thanks for porting this and for the review. I confirmed the change is in main, and there is nothing further I need from this PR, so I'm closing it. |
Title
Issue: none (follows #1372, which added
STRATA_GDN_CHUNKED=1for CUDA; related: #1296, the gfx1100 WY arm)Summary
STRATA_GDN_CHUNKED=1exists for CUDA (#1372) and is compiled out on HIP. On gfx1151 the prompt's recurrence isgdn_rec_quad2c_kernelplus a norm kernel: token by token, FP32, on the vector ALUs. This PR makes the same switch take a gfx11path: the WY form of the gated delta rule in chunks of 16 tokens, every product one 16x16x16 WMMA (FP16 operands, FP32
accumulation, the state in the waves' accumulators), with the output norm and the z gate fused into the scan.
It is off by default; the default path is unchanged. It rounds differently from the FP32 recurrence (FP16 operands), which is why
it is opt-in; the KL numbers are below.
What changed
src/prefill/kernels.cu, HIP only, behind theSTRATA_GDN_CHUNKEDswitch ingdn_recurrence_variant(variants 0 and 1, theones
gdn_recurrenceuses;STRATA_GDN_REC_HEADSis read once at the top of the function now, one declaration moved up):gdn_wmma_prep_kernel: T = (I + A)^-1 and P of every chunk at once (they do not depend on the state); a block per(key head, chunk), a wave per value head.
gdn_wmma_scan_kernel: a block per value head, a wave per 16 value columns; walks the chunks and loads the next chunk's k/q/vwhile this one computes. Its barriers wait for LDS only (
__syncthreads()also waits for every global load in flight, whichwould put the prefetch in front of every barrier), and the prefetched rows are
ext_vector_typevalues (HIP'sfloat4copiesgo through a stack object, which also waits for the load); both are in the code comments.
gdn_rec_wmma: the launch. It returns false, and the existing kernels run, for a part outsidegfx_arch_is_gfx11_wmma(gfx1100-1103, gfx1150, gfx1151), fewerthan 64 tokens and an output row stride not divisible by 8; the caller skips it under
STRATA_GDN_REC_HEADS. The part isjudged per call from the current device of the calling thread. The gfx11-only instructions sit inside the gfx11 device passes.
tests/hip/gdn_chunked.cppand CMake:hip_gdn_chunked,hip_gdn_chunked_off,hip_gdn_chunked_default, andhip_gdn_chunked --bench/--bench-default(one layer's time on this path / on gfx1151's default kernels).tests/hip/gdn_rec_head.cppunsetsSTRATA_GDN_CHUNKED(its variants 0 and 1 are the references there).include/strata/prefill/kernels.hpp(the variant comment),docs/AMD_HIP.md(conditions, numbers, how to run the checks),docs/DETAILS.md(the CUDA entry now says what HIP does).Not touched: the CUDA kernels (the
#if !defined(__HIPCC__)block), the SYCL port, any default. On HIPSTRATA_GDN_CHUNKED=2isthe same as 1 (the docs say so).
Checks
Ryzen AI Max+ 395 (gfx1151), ROCm 7.14.1, Linux 7.0, UD-IQ4_XS unless stated, all on this commit. "Section 5" is the nine variables of
docs/STRIX_HALO.mdsection 5 (withSTRATA_PF_SWITCH_MIN_T=2048where the doc has 4096); "defaults" is the engine without them(section 4's gfx1151 defaults stay).
The default path is unchanged. With the switch unset or 0, for a chunk of fewer than 64 tokens and for a row stride the path
does not take, the output and the carried state are bit-identical to the existing recurrence (
hip_gdn_chunked_off,hip_gdn_chunked_default; both setSTRATA_GDN_HEAD=1andSTRATA_GDN_PP=2, gfx1151's defaults).Numerics (
hip_gdn_chunked). 0-16,385 tokens, the 64-token edge, 16-token remainders, row strides 6144 / 6152 / 6145, weakdecay, beta = 0, and a request split at 129 + 128 tokens with the state carried. Bounds: relative RMS of the FP16 output and of the
final state <= 0.003; max |diff| <= 2% of the reference's max + 1e-5; all finite; guard values around the output unchanged. Two
short cases are also compared with a double-precision CPU recurrence of three value heads.
First-token KL against the same run without the switch (
STRATA_DUMP_FIRST_LOGITS; 12 natural-text prompts of 1.5K-24K tokens,nats, full vocabulary):
Section 5's own switches against the defaults are 0.0076 (IQ4_XS) and 0.0065 (Q4_K_XL); that is a different change, given for scale
and not as a limit for this one. #1372 reports 0.002-0.009 for the CUDA path. The mean is carried by a few prompts (one at 0.054;
the medians are 0.001-0.004). Only the first generated token is compared, and across the 12 prompts it takes only two distinct values,
so top-1 agreement is a weak check: a long generation, coding / agent use and perplexity have not been measured, which is the
reason for opt-in.
Speed, one layer (
hip_gdn_chunked --benchagainst--bench-default, which runs gfx1151's default kernels withSTRATA_GDN_PP=2andSTRATA_GDN_NOY=1; the switch is read once per process, so the two are separate runs, alternated threetimes; each run reports the GPU-event median of 7 runs after 2 warmups with the same nonzero start state; recurrence + norm;
medians of the three):
Speed, whole prompt. The same binary on both sides, only
STRATA_GDN_CHUNKEDdiffering, a fresh engine per side, residentbudget 55 GiB, int8 KV, 11 pairs in alternating order after a discarded one, 256-token answers, the engine's
prompt_ms. Everyprompt has its own nonce at the front and was read in full (0 reused tokens in every request). Each engine reads a discarded 4K
prompt first: on those first prompts the same pairs gave 95% intervals of [1.015, 1.021] (section 5) and [0.991, 1.210]
(defaults). Before each prompt the client waits until the page-migration and direct-reclaim counters of
/proc/vmstathavestood still for 3 s; a pair in which either prompt still met page migration (over 50,000 pages) or direct reclaim was dropped
and measured again (2 of 68 pairs, both on the defaults: a 32K prompt with the switch on and a 128K one with it off, which
met 365,000 and 161,000 migrated pages and were 0.51 s and 1.15 s slower than the median of their side; with them kept, 32K
and 128K give 1.011 (10 of 12 and 12 of 12 faster)). Times are
medians; off / on is the geometric mean of the 11 per-pair ratios with a 95% bootstrap interval:
So about 2.4% on top of section 5 and about 1.1% on the defaults, for a prompt that is not the first one after a start. With 36
gated-DeltaNet layers the layer figures predict about 0.55 s saved on a 32K prompt; 0.62 s (section 5) and 0.56 s (defaults) were
measured.
Builds. HIP:
kernels.cucompiles for gfx1030, gfx1100, gfx1103, gfx1151, gfx1152 and gfx1201 (the scan kernel holds 26 WMMAinstructions for gfx1100 / gfx1103 / gfx1151 and only a trap for gfx1152 / gfx1201, which the runtime gate never launches it on); the four HIP tests above (the three
hip_gdn_chunked*andhip_gdn_rec_head) pass on gfx1151. Run on gfx1151 only: nothing here has been run on another gfx11 card (gfx1103 joinedgfx_arch_is_gfx11_wmmaupstream after thiswas first written, and this path follows that list) or
with more than one GPU. CUDA (RTX 3060, CUDA 13.0, sm_86, Windows, this commit):
stratabuilds (155 of 155 steps, no error).gdn_rec_paritypassestoo, but it is a self-contained copy of the CUDA recurrence that does not link the engine, so it says nothing about this change.
Not built: SYCL (its own sources, none touched).
Extra Notes
STRATA_GDN_WY) to the same dispatch for gfx1100, where it loses to the serial kernel. This PR starts fromgfx1151's
gdn_rec_quad2c_kernel, uses 16x16x16 WMMA tiles for every product and reuses the existing switch instead of adding asecond one. They share no code that I found; whichever lands second needs a small rebase of the dispatch.
same values is untested.
🤖 Generated with Claude Code