Skip to content

poly, HIP: --kv q8_0 on AMD cards - #29

Merged
VecSzn merged 2 commits into
simplexai-labs:mainfrom
donschen:amd-kv-q8
Oct 17, 2026
Merged

VecSzn merged 2 commits into
simplexai-labs:mainfrom
donschen:amd-kv-q8

Conversation

@donschen

Copy link
Copy Markdown
Contributor

--kv q8_0 was rejected on HIP builds only because no ROCm machine had run it (docs/Q8_KV.md). This removes the rejection, builds poly_kv_q8_test on HIP too, and adds the AMD measurements to docs/Q8_KV.md.

Measured on an RX 9070 XT (16 GB, gfx1201), Ryzen 7 9800X3D, 30 GB RAM, Fedora, ROCm 7 from AMD's wheels, Tiel Coder 35B-A3B UD-Q4_K_XL with --kv-whole.

Kernels

The kernels are portable. poly_kv_q8_test passes on gfx1201, with 91,530 values checked.

Speed and VRAM

Each row is a fresh server:

Experts in VRAM 256-token answer 4.5K prompt 64K prompt Answer after 64K
fp16, 131072 4,415 110–127 tok/s 1,814–1,822 tok/s 2,065 tok/s 66 tok/s
Q8_0, 196608 4,729 106–130 tok/s 1,843–1,862 tok/s 2,075 tok/s 63 tok/s

Answers

Greedy decoding with --no-draft, seven prompts:

  • The four short prompts gave identical answers.
  • The three longer ones diverged after a while: a docstring, a summary of a 24K-character prompt, and a list taken from a 60K-character prompt. Each Q8_0 answer was as correct as the fp16 one.

Testing

  • These numbers were taken on the 0.1.44.1 source with the AMD expert cache fix from poly, HIP: the expert cache gives VRAM back and grows again on AMD (#13) #28 also applied. The expert counts depend on that fix; the comparison between Q8_0 and fp16 does not.
  • This branch was built and unit-tested together with that fix, not on its own. On its own it only removes the check in main.cpp and changes the test's CMake condition.

🤖 Generated with Claude Code

The Q8_0 KV cache was rejected on HIP builds only because no ROCm machine had run it.  Its kernels are plain HIP-
portable code beside the fp16 attention ones, and on an RX 9070 XT (gfx1201, ROCm 7 wheels) they pass
poly_kv_q8_test (now built on HIP too) and serve Tiel Coder UD-Q4_K_XL: Q8_0 at 196608 tokens against fp16 at
131072, 4729 experts in VRAM against 4415, the same speed on a 4.5K prompt (1,843-1,862 / 1,814-1,822 tok/s) and
a 64K one (2,075 / 2,065 tok/s), 256-token answers at 106-130 / 110-127 tok/s.  Greedy without drafts, short
answers are the same and longer ones take other, equally right, words (docs/Q8_KV.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@donschen

Copy link
Copy Markdown
Contributor Author

Overlaps with #27, which also lifts this HIP check and replaces the q8_0 readers with int8 ones. This is the light-touch version: it enables the existing q8_0 path on AMD with measurements from an RX 9070 XT. Happy to rebase onto #27 if that lands first, or rerun these tests on AMD against #27.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@VecSzn
VecSzn merged commit 90b6349 into simplexai-labs:main Oct 17, 2026
@VecSzn

VecSzn commented Oct 17, 2026

Copy link
Copy Markdown
Collaborator

Merged, thanks. This one went in first since it's the small change and comes with AMD numbers. #27 has been asked to split into separate PRs. If its int8 cache comes back, a run on your RX 9070 XT against q8_0 as it is now would help a lot: same model, context and prompts as the table here.

jpb18 pushed a commit to jpb18/PolyStrata-HIP that referenced this pull request Oct 18, 2026
…ain (issue simplexai-labs#29, engine 0.1.12)

On a card with most experts in VRAM (RTX 4090) generation could stop for
good after thousands of tokens: the GPU "100%" at low power, one CPU core
busy, no tokens, no error.

- The pool's workers sleep after 20 ms without work (issue simplexai-labs#4). With most
  experts resident many layers have no CPU work, so they also slept
  mid-request, and a worker that woke late was still counted as parked: it
  could claim from the next batch while the host was writing it, run a job
  twice, or add to `done` after the reset - and `done != n` then never
  ended while the GPU waited on the pool. Every claim now carries its
  batch: `head` is one 64-bit word (epoch | njobs | index), a claim is a
  CAS that only succeeds for the epoch the worker woke for, and the host
  waits with `<` instead of `!=`. Same speed (pool_test 47.2 GB/s).
- Every pool wait is bounded (60 s: a message and the engine stops), and
  --serve runs a watchdog: a request with no progress (tokens, prompt
  chunks, verify windows) for STRATA_WATCHDOG_S (120) seconds ends the
  engine with where it was stuck (strata/core/progress.hpp). The server
  (issue simplexai-labs#27) answers with an error, names the cause from the log, and
  starts the engine again on the next request.
- pool_stress: tiny batches with sleeping workers; STRATA_POOL_SPIN_US
  shortens the spin to make them sleep constantly.

Tested: pool_test, pool_stress; 25,000-token generation at 262K with KV
streaming and constantly sleeping workers (73.9 tok/s, unchanged); the
watchdog deliberately tripped (2 s): error, log line, restart, next answer.
jpb18 pushed a commit to jpb18/PolyStrata-HIP that referenced this pull request Oct 18, 2026
…implexai-labs#31

Prompt path (bench/results/2026-09-28-prefill-speed):
- `--prefill auto`: chunks up to 8192 tokens, sized to the cache slots the prompt path may borrow; a
  request borrows only what its prompt needs (Prefill::relayout). setup writes it and switches old
  `--prefill 2048` configs once the engine supports it.
- The attention and MoE halves share one scratch region (~260 KB less per token).
- Experts through llama.cpp's MMQ kernels (ggml-cuda mmq.cuh, compiled from the same checkout as ggml
  into strata_mmq; Strata Q2_0 blobs converted to GGUF blocks on the gather; IQ1_M layers keep FP16).
- Chunks >= 2048: every non-resident expert streams through a ring in a fixed order across layers, so
  the next layer's arrive during its attention half (384 slots when the arena is pinned, else 96).
- The PLE block for the whole chunk at once; the next chunk's PLE rows read on a thread; unpinned
  experts copied by stager threads (epoch-tagged claims).
- STRATA_PREFILL_TIMING=1 prints a per-phase GPU timeline.
Q2_0 32K prompt 572 -> 1290 tok/s, IQ3_S 383 -> 1208 (RTX 5070 12 GB). Needles 5/5 1K-262K.

Issue simplexai-labs#31 / simplexai-labs#29: the serve watchdog (now 60 s) prints a stall report - each expert-pool thread's state,
the verify window's flags, layers served during the stall, memory and page faults - and on Windows
writes a minidump with every thread's stack; Release builds keep a PDB. The engine prints its version.
jpb18 pushed a commit to jpb18/PolyStrata-HIP that referenced this pull request Oct 18, 2026
…implexai-labs#29); setup and profile fixes (simplexai-labs#46, simplexai-labs#49, simplexai-labs#45)

- --pcie-mode auto is the copy kernel for native packs too. Issue simplexai-labs#31's thread
  dumps show the host stuck for good in the DMA path's cudaMemcpyAsync (a driver
  lock) inside a verify window while the GPU spins on the flag those copies
  raise. The copy kernel needs no host CUDA call there; IQ3_S decode 45.3 -> 44.8
  tok/s. --pcie-mode dma keeps the old path.
- setup: a locally compiled engine records its version; one kept after a failed
  compile is recognised by the version in its binary, and a config it cannot
  read (--prefill auto on 0.1.12) goes back to 2048 (simplexai-labs#49).
- setup: nvcc in /opt/cuda (Arch), a clearer message off Ubuntu/Debian (simplexai-labs#46);
  a failed build is tried once more (simplexai-labs#45: ptxas's intermittent PTX parse error).
- data/expert-profile.bin ranks all 24,576 experts (the first 8,000 unchanged):
  the cache stopped at 8,000 slots on 24-32 GB cards (simplexai-labs#46). tools/make_profile.py
  builds or extends a profile from --dump-routing traces; --expert-cache 0 with a
  profile now means auto.
jpb18 pushed a commit to jpb18/PolyStrata-HIP that referenced this pull request Oct 18, 2026
jpb18 pushed a commit to jpb18/PolyStrata-HIP that referenced this pull request Oct 18, 2026
…OG_IO_S) while the OS is still reading the file tier (#1407)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants