Repository navigation
Conversation
…ped expert kernels) Ported from shinbunbun/llama-cpp-p100-patches (MIT), patches 29 `mmvq-iq3xxs-grid-smem` and 30 `mmvq-ksigns-smem`: the grouped expert kernels stage the 256-word iq3xxs_grid and two 128-word tables of per-byte sign masks once per block, and apply a mask as (g ^ mask) + (mask & 0x01010101) instead of the per-lookup unpack_ksigns / __vcmpne4 / __vsub4 chain (iq3xxs_grid's bytes are all >= 4, so no carry crosses a byte). Bitwise the same output: checked end to end on a PH402 (GP100), greedy, three prompts x three interleaved rounds, identical replies with and without. Measured only on GP100, where it is within noise (+0-4% decode), so it is the default on compute capability 6.x only; STRATA_IQ_STAGE_GRID18=1 / 0 forces it on / off on any card.
GP100 has no __dp4a, and on a GP100 die the verify window's dense projections read their weights at 40-80 GB/s of ~730. With STRATA_Q8_SM60=1 every Q8_0 dense matrix (any shape) and the head get the packed planes of STRATA_Q8_PACKED and run src/kernels/cuda/q8_sm60.cuh: a warp (half / quarter warp for narrow rows) per row, 16-byte weight loads through the read-only cache, the window's q8_1 activations copied once per workgroup into shared memory as an int8 plane plus float scales, STRATA_DP4A (vmad on sm_60), a shuffle sum with no barrier per row, persistent workgroups (4 per SM, STRATA_Q8_SM60_BPS). Shapes it declines (> 48 KiB of shared memory: a 6144-wide row with 7-8 columns) keep the usual kernel. Not bitwise the exact kernels (summation order); the packed copies cost their size in VRAM (Flash-Next: 2.9 GiB of dense projections over the stages, 0.6 GiB head). The GSQ-RCO packs have no Q8_0 dense matrices: tools/q8_dense_gguf.py writes a shard 1 whose natively served projections and head are Q8_0, keeping the tensor-info block's length so every expert keeps its offset (the native pack is reused) and hard-linking the other shards beside it. PH402 SKU 200 (four GP100 dies), clocks locked at 1050 MHz, Flash-Next IQ3_XXS, 32K, layer split 12,24,36, --prefill 2048, greedy, decode tok/s (medians, interleaved starts): GSQ-RCO shard 28.3, Q8_0 shard with STRATA_Q8_PACKED 31.1, Q8_0 shard with STRATA_Q8_SM60 38.9 (+37%); per window dense 19.2 -> 11.2 ms, head 4.25 -> 2.1 ms; prompt reads unchanged. tools/q8_sm60_check.cu: 57 shape x column cases against a CPU reference, max relative error < 1e-5. docs/OLDER_GPUS.md has the table, the conditions and how to use it.
The tool converted only the shard it was given and hard-linked the others, which is enough for Flash-Next (every natively served projection and the head are in shard 1) but not for Swift 1.5 IQ3_XXS, which keeps 78 of them in shard 1 and 223 in shard 2: one run left three quarters of them in their K- / i-quants, silently, and the kernel only runs Q8_0 matrices. Now any shard of the model may be named; every shard that holds such a matrix is written as before (same tensor-info length, Q8_0 blocks appended, offsets checked) and the others are hard-linked. Checked: Swift 1.5 IQ3_XXS in one run gives both shards byte-identical to two single-shard runs (301 tensors); Flash-Next IQ3_XXS converts 301 tensors in shard 1 and links shard 2.
IQ3_S was the one i-quant gate/up format whose codebook the grouped expert kernels still read from global memory (IQ2_XXS / IQ2_XS / IQ2_S stage theirs everywhere, IQ3_XXS on 6.x since the first commit of this branch). Its 512 codebook words are now staged per block with two 256-word tables of byte masks - IQ3_S keeps one explicit sign byte per 8 values, so the tables hold the masks of a sign byte's bits 0-3 and 4-7 - applied as (g ^ mask) + (mask & 0x01010101): every iq3s_grid byte is odd, so a negated byte never carries into the next. Bitwise the same output (iq_multi_parity and native_grouped_parity on a GP100 die, with and without STRATA_IQ_STAGE_GRID_MMVQ=1). One GP100 die, a verify window's layer of real Swift 1.5 IQ3_S experts (20 experts, 24 entries): 517 -> 393 us with Q2_0 down, 492 -> 369 us with IQ4_NL down. Swift 1.5 IQ3_XXS (13 of 48 layers IQ3_S), four GP100 dies, 1M context, decode tok/s, medians of three interleaved engine starts: 36.0 -> 37.2 (10.7K document), 36.3 -> 37.4 (cached), 43.1 -> 44.5 (reasoning), 41.6 -> 43.0 (code), with the same drafts accepted. The switch covers both formats and is renamed accordingly: stage_tables_on(), STRATA_IQ_STAGE_TABLES=1|0 (was STRATA_IQ_STAGE_GRID18). Still the default on compute capability 6.x only.
The staged IQ3_XXS / IQ3_S tables trade a per-block copy and barrier for cheaper lookups, which pays only where the grouped expert kernels are decode-bound. On GP100 (6.0: no __dp4a, 70-140 GB/s) it does; on an RTX 3090 Ti (sm_86), forced on with STRATA_IQ_STAGE_TABLES=1, the same real Swift 1.5 IQ3_S layers (20 experts, 24 entries) took 3-13% longer (71-76 -> 75-84 us; those kernels read at 490-665 GB/s there) and IQ3_XXS was unchanged, the output bitwise the same. 6.1 cards (P40, GTX 10) have __dp4a and are unmeasured, so the default now asks for 6.0 rather than any 6.x; STRATA_IQ_STAGE_TABLES=1 still turns it on anywhere. docs/OLDER_GPUS.md says so, and that neither STRATA_Q8_SM60 nor the tables is measured on 6.1: both build for sm_61, and tools/q8_sm60_check.cu passes on an RTX 3090 Ti, where the kernel's dot is the hardware __dp4a.
d4f5f76 to
ec407eb
Compare
|
Thank you for this. We ported it and gated it on the cards we have (RTX 3060, RTX A4000, Tesla P100, R9700, Arc A750), and found the group it came in with slowed default decode on an sm_86 card by about 3-4% on a long-context prompt after the merge, which we could not yet tie to one commit. A default must not get slower, so the Volta/Pascal group moves to 0.1.46, where we find the cause first. Your commits stay credited to you on our branch f-145-pp-volta. Nothing was declined for being wrong. |
…e default on cc 6.0: no end-to-end gain on a Tesla P100 (#1424)
|
Thanks for the pull request. Your change is already in If part of your work did not make it in and you want it considered, open a new pull request on top of |
Title
Pascal GP100: a Q8_0 decode GEMV (
STRATA_Q8_SM60=1, opt-in) and IQ3_XXS / IQ3_S tables in shared memorySummary
Two sm_60 changes for Pascal GP100 (the chip from #124), measured on a PH402 SKU 200: two boards, four GP100 dies of
48 SMs and 32 GB HBM2 each.
GP100 is the one Pascal chip without
__dp4a, and on a GP100 die the decode window's dense projections read theirweights at 40-80 GB/s of ~730: the K- and i-quant blocks are decoded one int at a time. With
STRATA_Q8_SM60=1and ashard whose dense projections and head are Q8_0, decode goes from 28.3 to 38.9 tok/s (+37%) on Flash-Next
IQ3_XXS; prompt reads are unchanged. Everything is off by default except the IQ3_XXS and IQ3_S tables, which are
bitwise the same output and on by default for compute capability 6.0 (GP100) only; the IQ3_S ones add +3.2%
decode on Swift 1.5 IQ3_XXS.
STRATA_Q8_PACKED=1STRATA_Q8_SM60=1GPU time per verify window (
STRATA_VERIFY_PROFILE): dense projections 19.2 -> 11.2 ms, head 4.25 -> 2.1 ms; thedraft policy then picks longer windows (2.10 -> 2.31 tokens per window). Prompt reads: 437-438 tok/s at 10.7K in
every row.
Conditions: application clocks locked at 1050 MHz, Windows 11, driver 581.80 (TCC), CUDA 12.9, engine 0.1.40.2 (the
branch is rebased on 0.1.40.3, which touches none of these files),
--layer-split 12,24,36 --prefill 2048, greedy,256 new tokens, medians of 2-3 interleaved engine starts, the engine kept on its own logical CPUs (Extra Notes).
What changed
src/kernels/cuda/q8_sm60.cuh(new): the GP100 Q8_0 GEMV. A warp (half / quarter warp for rows under 2048 / 1024wide) per row; 16-byte weight loads through the read-only cache; the window's q8_1 activations copied once per
workgroup into shared memory as an int8 plane plus float scales, so every activation read is a 16-byte shared load;
STRATA_DP4A(vmad on sm_60); a shuffle sum with no barrier per row; persistent workgroups, 4 per SM(
STRATA_Q8_SM60_BPS). Shapes needing more than 48 KiB of shared memory (a 6144-wide row with 7-8 columns) aredeclined and keep the usual kernel. Also a device-side GGUF-block -> planes repack for the head.
src/kernels/cuda/native_mmvq.cu,include/strata/kernels/native_mmvq.hpp:STRATA_Q8_SM60=1makes every Q8_0matrix eligible for the packed planes and dispatches registered matrices to the new kernel (any ncols it accepts,
independent of the exact-layout requirement);
native_q8_0_sm60_pack/native_q8_0_sm60_releaseown the head'spacked copy. Not compiled into HIP builds. Without the variable nothing changes.
src/core/native_head.cpp: a Q8_0 head is packed whenSTRATA_Q8_SM60=1(the MTP draft head reads the same matrix).src/kernels/cuda/iq_kernels.cu: IQ3_XXS and IQ3_S join the types whose codebook the grouped expert kernels stagein shared memory, each with sign-mask tables applied as
(g ^ mask) + (mask & 0x01010101)(two 128-word tables forIQ3_XXS's 7-bit sign fields, two 256-word tables for IQ3_S's sign bytes; no codebook byte is 0, so a negated byte
never carries). IQ3_XXS's are ported from
shinbunbun/llama-cpp-p100-patches (MIT), patches 29
mmvq-iq3xxs-grid-smemand 30mmvq-ksigns-smem; IQ3_S's are the same idea - IQ3_S was the one gate/up formatwhose codebook these kernels still read from global memory. Bitwise the same output (
iq_multi_parityandnative_grouped_parityon a GP100 die; identical greedy replies, and the same drafts accepted in the A/B below).IQ3_XXS's alone: within noise on GP100 (+0-4%). IQ3_S's: a verify window's layer of real IQ3_S experts (20 experts,
24 entries) on one die 517 -> 393 us with a Q2_0 down projection and 492 -> 369 us with IQ4_NL; Swift 1.5 IQ3_XXS
(13 of its 48 layers IQ3_S), 1M context, otherwise the conditions below, decode tok/s:
STRATA_Q8_SM60=1Medians of three interleaved engine starts per build; on every prompt each of the three runs with both tables was
faster than each run without. The staging only pays where these kernels are decode-bound: on an RTX 3090 Ti (sm_86),
forced on, the same IQ3_S layers took 3-13% longer (71-76 -> 75-84 us; there they already read at 490-665 GB/s) and
IQ3_XXS was unchanged. So the default is compute capability 6.0 only (GP100 has no
__dp4a; 6.1 cards do and areunmeasured);
STRATA_IQ_STAGE_TABLES=1|0forces it on or off on any card.tools/q8_dense_gguf.py(new): the GSQ-RCO packs have no Q8_0 dense matrices, so this writes a copy of the modelwhose natively served projections and head are Q8_0 (Flash-Next IQ3_XXS: 301 tensors, +3.5 GiB, requantization
error at most 0.4% of a tensor's |w|max). Every shard that holds such a matrix is converted - Swift 1.5 keeps 78 of
them in shard 1 and 223 in shard 2 - and the others are hard-linked (
--copycopies). The tensor-info block keepsits byte length, so every expert keeps its absolute offset and the existing native pack is reused.
tools/q8_sm60_check.cu(new, built by hand likesm60_dp4a_check.cu): 57 shape x column cases (the Flash-NextQ8_0 shapes, 1-8 columns) against a CPU double reference, max relative error < 1e-5, then times them.
docs/OLDER_GPUS.md: a "Pascal GP100: a Q8_0 decode kernel (opt-in)" section with the table, the conditions and howto use it; the P100 row of the support matrix points to it.
Extra Notes
STRATA_Q8_SM60is not bitwise the exact kernels (Q8_0 requantization of the dense matrices and anothersummation order). Greedy replies to five prompts (arithmetic, logic, Chinese, code, a question on a 10K-token
document) gave the same answers, with wording differences after the first sentence or two.
over the stages, 0.6 GiB for the head).
759 MHz and a layer split leaves each die idle most of a window, so the dies decode below 1050 MHz unless locked
(
nvidia-smi -ac 715,1050; 25.0 -> 29.1 tok/s at 10.7K context); and a second engine on the same PC that pins itsthreads to the same logical CPUs halved this one's decode while it ran - keeping them on different logical CPUs
(SMT siblings) avoided it.
__dp4a. Both changes build for sm_61,and where
__dp4aexists the Q8_0 kernel's dot is the hardware instruction (tools/q8_sm60_check.cupasses on anRTX 3090 Ti). Numbers from a 6.1 card with
STRATA_Q8_SM60=1(and a Q8_0 dense shard) or withSTRATA_IQ_STAGE_TABLES=1would show whether either helps there.-DSTRATA_EXPERIMENTAL_SM60=ON -DCMAKE_CUDA_ARCHITECTURES=60); also for sm_86,where
iq_multi_parityandnative_grouped_paritypass with the tables on and off. Not built for HIP; the new kernelonly runs with the variable set, and HIP builds leave it out.