Repository navigation
Conversation
…in build, STRATA_HIP_GFX906=ON The HIP backend (STRATA_ENABLE_HIP) is wave32 RDNA only, and the engine refuses a wave64 card. This adds a separate opt-in build for gfx906: the CUDA sources compiled as HIP through a small compat layer, with a CUDA warp as a logical half of the 64-lane wavefront. With the option off nothing changes for CUDA or the RDNA backend; every new code path is under STRATA_HIP_GFX906. Build: -DSTRATA_HIP_GFX906=ON -DCMAKE_HIP_ARCHITECTURES=gfx906 (implies STRATA_ENABLE_CUDA's targets, refuses STRATA_ENABLE_HIP). The CUDA runtime/cuBLAS names come from include/strata/platform/hip_compat/ (first on the include path), CUDA::cudart / CUDA::cublas become aliases of hip::host / roc::hipblas, every .cu (and the ggml MMQ sources, with GGML_USE_HIP) is compiled as HIP. The native kernels' --use_fast_math (an nvcc flag) is not passed. Correctness fixes found on the way (each one changed results or hung, not only speed): - __fmul_rn / __fadd_rn / __fsub_rn contracted into FMA under HIP; they no longer do (as on NVIDIA) - the elementwise and quantize_act parity tests pass bitwise; - the device check of the gfx906 build reads the card's gcnArchName (the wave32 check is the RDNA backend's); - ggml MMQ got NVIDIA compute capability 9.0 for gfx906 and hung the prompt path; it gets the AMD arch code; - __byte_perm is a scratch-memory array in HIP: the IQ4 table lookup uses llama.cpp's v_perm_b32 sequence (agent-request decode 29.9 -> 39.2 tok/s on 2x MI50); - the stage profiler's wall clock runs at 25 MHz on gfx906, not 100 MHz; - a CUDA toolkit-mismatch check that reads CUDART_VERSION is skipped (no CUDART_VERSION under HIP); - gdn_rec_parity (cp.async, CUDA occupancy API) is not built for gfx906. wave64 kernels (gfx906 only; the CUDA layout stays one env switch away for A/B, every one bitwise-checked): - grouped native experts, STRATA_EXP_MODE=7 (default): gfx906 has no packed byte SIMD, so __vcmpne4/__vsub4 became ~12 word ops each; signs are now dp4a(g ^ m, u) - dp4a(m, u) (exact in integers), grids and the group's activations sit in LDS, one weight load serves every token of the group. Same k-to-lane order, so the output is bitwise the old layout's (native_expert_bench, real GGUF rows). Verify window 60.0 -> 51.3 ms. STRATA_EXP_MODE=2 is the previous layout; - MMVQ: one wavefront per row with a 64-lane butterfly, no LDS/barrier, same kernel for 1..8 columns (+2.3% decode; STRATA_MMVQ_WAVE=0: CUDA layout); - router top-10 in one wavefront (register argmax, no block barriers), bit-identical (router_top10_parity); - gr_down_multi split along K (8 rows x 5 slices of 2048 per block, fixed-order finish) (+2.9%; STRATA_GR_SPLIT=0: old); - hyper-connection read: norm with its loads in flight and xn in registers, up with 8 lanes per row (51.3 -> 50.2 ms per window; STRATA_GR_FAST=0: old); - the QSA prompt-attention tensor-core/WMMA kernels are not used on gfx906 (the FP32 kernel runs). Benches (not ctest; they need a model shard): native_expert_bench (one expert layout against another, bitwise, with timings) and fused_gr_bench (the fast hyper-connection kernels against the old ones).
…asurements in AMD_HIP.md
…it opt-in; gfx906-aware ctest - native_expert_grouped: the AMD layouts handle the IQ packs' gate/up and down types only; Unsloth's Q4_K / Q5_K gate/up and Q5_1 / Q8_0 down now take the CUDA layout instead of exiting (native_grouped_parity found it). - fused_gr_read_multi: the K-split gr_down (fixed-order finish) sums in another order than the single-token fused_gr_read, so it broke gr_parity's multi == single contract; it is now opt-in (STRATA_GR_SPLIT=1). The latency-hidden norm/up (same sums, same order) run in the default read (STRATA_GR_FAST=0: off). - mmvq_multi_parity: on gfx906 the wave64 MMVQ is the same exact kernel for every column count, so the negative control has nothing to find; a second ctest entry runs it on the CUDA layout (STRATA_MMVQ_WAVE=0), where it has power. - kv_hybrid_parity: the tensor-core prompt attention refuses on gfx906 as on the RDNA backend. ctest on 2x MI50 (gfx906): 34 of 34 pass (iq_parity and ple_parity need fixture files and are not counted).
… top-k (bitwise the per-token calls) The Coder's router is 256 experts, which the native 512 x 10 router does not take, so a verify window routed each token with its own projection and top-k. moe_route_window does the window in one multi-column BF16 projection (bf16_gemv_fp32_mmvf_cols over the existing multi-row kernel) and one n-token top-k; each token's route is bitwise what moe_route gives it (route_window_parity, new ctest). gfx906 build only, so the CUDA and RDNA paths are unchanged; STRATA_ROUTE_PER_TOKEN=1 restores the per-token calls. 2x MI50, Coder IQ1_M, 32K, greedy 1,500-token request: verify window 55.5 -> 52.5 ms, generated text identical.
…CUDA and RDNA did not compile)
|
Re-run on 2x MI50 (gfx906). Running ctest on the cards found four things, now fixed on the branch:
Builds at a914b13 (
ctest on the cards: 35 of 35 pass, including Greedy-text comparison with the port branch. Coder IQ1_M, 32K context,
Same settings, same text, bitwise. The port's defaults differ from this PR in three things, each of which changes which expert a GPU or the CPU computes, or the summation order:
Every run is deterministic: repeats gave the same hashes. The QSA scorer this PR leaves as upstream's (the scalar HIP kernel, not my FP32 variant) gave the same text as mine. With #639 and #640 merged in, the 128K configuration decodes at 61 tok/s (numbers in #639). A community benchmark in the Marking ready. |
… gfx906 build; tests.list dropped The RDNA backend (STRATA_ENABLE_HIP) compiles mrope.hpp as before; tests.list was a local test runner's list, not part of the build. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ine and how to opt in docs/OLDER_GPUS.md: Pascal / Volta through the CUDA 12 engine (#395 #600 #540 #655), RTX 20's STRATA_BF16_TC opt-in, AMD gfx1031 (#524), gfx1012 (#442) and gfx906 (#638, #677) with the reporters' numbers; README, AI_SETUP, AMD_HIP and NVIDIA_V100 point to it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…y there too; pinned.cu's std::max beside windows.h PR #638 was cut from 0.1.38. 0.1.39's segmented expert cache (#533) keeps its cuMem* code out of HIP builds through STRATA_USE_HIP, which the gfx906 compat build does not define, so it included <cuda.h>. Its virtual-memory blocks are now behind STRATA_EC_NO_VMM (STRATA_USE_HIP or STRATA_HIP_GFX906); the CUDA and RDNA preprocessor output is unchanged. (std::max) keeps windows.h's max macro out of two Windows-only lines (found by a Windows gfx906 compile check). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Merged for the next release, as its own opt-in build (STRATA_HIP_GFX906), with your commits. Changes on top: 0.1.39's segmented expert cache (#533) kept its cuMem* code out of HIP builds through STRATA_USE_HIP, which your build does not define, so expert_cache.cpp included <cuda.h>. Its virtual-memory parts are now off in the gfx906 build too. mrope.hpp's hip_runtime include is limited to the gfx906 build, and tests.list is left out. The gfx906 engine compiles and links for gfx906 with TheRock's ROCm on Windows. The CUDA release build's device code is unchanged, and the identity gate on an RTX 5070 is 10/10 identical on four models. The RDNA Windows build compiles. We have no gfx906 card, so a re-run of your ctest and greedy comparison on the merged branch would be welcome. |
|
Post-merge gfx906 re-run on the current upstream tree (
This is a short smoke request, not the earlier 1,500-token greedy comparison or the long 128K/multi-client acceptance run. The only CTest failure was the unavailable external PLE model fixture; it did not report a parity mismatch. |
… gfx906 build; tests.list dropped The RDNA backend (STRATA_ENABLE_HIP) compiles mrope.hpp as before; tests.list was a local test runner's list, not part of the build.
…y there too; pinned.cu's std::max beside windows.h PR #638 was cut from 0.1.38. 0.1.39's segmented expert cache (#533) keeps its cuMem* code out of HIP builds through STRATA_USE_HIP, which the gfx906 compat build does not define, so it included <cuda.h>. Its virtual-memory blocks are now behind STRATA_EC_NO_VMM (STRATA_USE_HIP or STRATA_HIP_GFX906); the CUDA and RDNA preprocessor output is unchanged. (std::max) keeps windows.h's max macro out of two Windows-only lines (found by a Windows gfx906 compile check).
…y in the gfx906 build; tests.list dropped The RDNA backend (STRATA_ENABLE_HIP) compiles mrope.hpp as before; tests.list was a local test runner's list, not part of the build.
…ine and how to opt in docs/OLDER_GPUS.md: Pascal / Volta through the CUDA 12 engine (Niko1221#395 Niko1221#600 Niko1221#540 Niko1221#655), RTX 20's STRATA_BF16_TC opt-in, AMD gfx1031 (Niko1221#524), gfx1012 (Niko1221#442) and gfx906 (Niko1221#638, Niko1221#677) with the reporters' numbers; README, AI_SETUP, AMD_HIP and NVIDIA_V100 point to it.
…CUDA-only there too; pinned.cu's std::max beside windows.h PR Niko1221#638 was cut from 0.1.38. 0.1.39's segmented expert cache (Niko1221#533) keeps its cuMem* code out of HIP builds through STRATA_USE_HIP, which the gfx906 compat build does not define, so it included <cuda.h>. Its virtual-memory blocks are now behind STRATA_EC_NO_VMM (STRATA_USE_HIP or STRATA_HIP_GFX906); the CUDA and RDNA preprocessor output is unchanged. (std::max) keeps windows.h's max macro out of two Windows-only lines (found by a Windows gfx906 compile check).
…y in the gfx906 build; tests.list dropped The RDNA backend (STRATA_ENABLE_HIP) compiles mrope.hpp as before; tests.list was a local test runner's list, not part of the build. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ine and how to opt in docs/OLDER_GPUS.md: Pascal / Volta through the CUDA 12 engine (Niko1221#395 Niko1221#600 Niko1221#540 Niko1221#655), RTX 20's STRATA_BF16_TC opt-in, AMD gfx1031 (Niko1221#524), gfx1012 (Niko1221#442) and gfx906 (Niko1221#638, Niko1221#677) with the reporters' numbers; README, AI_SETUP, AMD_HIP and NVIDIA_V100 point to it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…CUDA-only there too; pinned.cu's std::max beside windows.h PR Niko1221#638 was cut from 0.1.38. 0.1.39's segmented expert cache (Niko1221#533) keeps its cuMem* code out of HIP builds through STRATA_USE_HIP, which the gfx906 compat build does not define, so it included <cuda.h>. Its virtual-memory blocks are now behind STRATA_EC_NO_VMM (STRATA_USE_HIP or STRATA_HIP_GFX906); the CUDA and RDNA preprocessor output is unchanged. (std::max) keeps windows.h's max macro out of two Windows-only lines (found by a Windows gfx906 compile check). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Prefill::arm_cpu_share() asks "is this AMD?" with #if !defined(STRATA_USE_HIP), but the gfx906 compat build (PR Niko1221#638) compiles as HIP *without* STRATA_USE_HIP -- see src/core/expert_cache.cpp :5-6, which guards the same question with #if defined(STRATA_USE_HIP) || defined(STRATA_HIP_GFX906). On gfx906 the CUDA branch is therefore live: the CPU share is armed by default for chunks below 1,024 tokens and prints its banner, against this file's own note at :161 ("the layer split, batch slots and HIP stay off"). Seven other sites already carry the || defined(STRATA_HIP_GFX906) form. Measured on one MI50 32 GB (gfx906), CLI generate, a 4-token prompt, one binary with one set of weights and one config, only the environment differing, power saving off: default experts streamed 309 (295 by DMA, host 174.0 ms), resident 607, on the CPU 197 (share 0.90) prefill 928.3 ms =0 experts streamed 506 (492 by DMA, host 177.3 ms), resident 606, on the CPU 0 (share 0.00) prefill 929.5 ms Output token ids are identical (271 248068 198 760) and the 0.13% difference is inside this machine's run-to-run spread (1.2-1.7%), so on this card the share engages and buys nothing. Niko1221#1595 and Niko1221#1729 report the default costing on CUDA; this is the mechanism that turns it on for AMD. CUDA and SYCL do not define STRATA_HIP_GFX906, so the added check is a no-op there and nothing on those backends changes.
Prefill::arm_cpu_share() asks "is this AMD?" with #if !defined(STRATA_USE_HIP), but the gfx906 compat build (PR Niko1221#638) compiles as HIP *without* STRATA_USE_HIP -- see src/core/expert_cache.cpp :5-6, which guards the same question with #if defined(STRATA_USE_HIP) || defined(STRATA_HIP_GFX906). On gfx906 the CUDA branch is therefore live: the CPU share is armed by default for chunks below 1,024 tokens and prints its banner, against this file's own note at :161 ("the layer split, batch slots and HIP stay off"). Seven other sites already carry the || defined(STRATA_HIP_GFX906) form. Measured on one MI50 32 GB (gfx906), CLI generate, a 4-token prompt, one binary with one set of weights and one config, only the environment differing, power saving off: default experts streamed 309 (295 by DMA, host 174.0 ms), resident 607, on the CPU 197 (share 0.90) prefill 928.3 ms =0 experts streamed 506 (492 by DMA, host 177.3 ms), resident 606, on the CPU 0 (share 0.00) prefill 929.5 ms Output token ids are identical (271 248068 198 760) and the 0.13% difference is inside this machine's run-to-run spread (1.2-1.7%), so on this card the share engages and buys nothing. Niko1221#1595 and Niko1221#1729 report the default costing on CUDA; this is the mechanism that turns it on for AMD. CUDA and SYCL do not define STRATA_HIP_GFX906, so the added check is a no-op there and nothing on those backends changes. Hardware the numbers come from: Xeon E5-2696 v4 (Broadwell, 22C/44T, no AVX-512), one Radeon Instinct MI50 32 GB (gfx906, PCI 1002:66a1, VBIOS 113-D1631711-100, 34,342,961,152 B of VRAM), PCIe 3.0 x16 effective (the root port runs 8 GT/s x16 and the bridge above the card is downgraded; the card's own hop negotiates 16 GT/s, about 15.75 GB/s end to end), 128 GB RAM, Ubuntu, kernel 7.0.0-34-generic, ROCm 7.14 in a container, built with -DSTRATA_HIP_GFX906=ON and -DCMAKE_HIP_ARCHITECTURES=gfx906.
Prefill::arm_cpu_share() asks "is this AMD?" with #if !defined(STRATA_USE_HIP), but the gfx906 compat build (PR #638) compiles as HIP *without* STRATA_USE_HIP -- see src/core/expert_cache.cpp :5-6, which guards the same question with #if defined(STRATA_USE_HIP) || defined(STRATA_HIP_GFX906). On gfx906 the CUDA branch is therefore live: the CPU share is armed by default for chunks below 1,024 tokens and prints its banner, against this file's own note at :161 ("the layer split, batch slots and HIP stay off"). Seven other sites already carry the || defined(STRATA_HIP_GFX906) form. Measured on one MI50 32 GB (gfx906), CLI generate, a 4-token prompt, one binary with one set of weights and one config, only the environment differing, power saving off: default experts streamed 309 (295 by DMA, host 174.0 ms), resident 607, on the CPU 197 (share 0.90) prefill 928.3 ms =0 experts streamed 506 (492 by DMA, host 177.3 ms), resident 606, on the CPU 0 (share 0.00) prefill 929.5 ms Output token ids are identical (271 248068 198 760) and the 0.13% difference is inside this machine's run-to-run spread (1.2-1.7%), so on this card the share engages and buys nothing. #1595 and #1729 report the default costing on CUDA; this is the mechanism that turns it on for AMD. CUDA and SYCL do not define STRATA_HIP_GFX906, so the added check is a no-op there and nothing on those backends changes. Hardware the numbers come from: Xeon E5-2696 v4 (Broadwell, 22C/44T, no AVX-512), one Radeon Instinct MI50 32 GB (gfx906, PCI 1002:66a1, VBIOS 113-D1631711-100, 34,342,961,152 B of VRAM), PCIe 3.0 x16 effective (the root port runs 8 GT/s x16 and the bridge above the card is downgraded; the card's own hop negotiates 16 GT/s, about 15.75 GB/s end to end), 128 GB RAM, Ubuntu, kernel 7.0.0-34-generic, ROCm 7.14 in a container, built with -DSTRATA_HIP_GFX906=ON and -DCMAKE_HIP_ARCHITECTURES=gfx906.
Prefill::arm_cpu_share() asks "is this AMD?" with #if !defined(STRATA_USE_HIP), but the gfx906 compat build (PR Niko1221#638) compiles as HIP *without* STRATA_USE_HIP -- see src/core/expert_cache.cpp :5-6, which guards the same question with #if defined(STRATA_USE_HIP) || defined(STRATA_HIP_GFX906). On gfx906 the CUDA branch is therefore live: the CPU share is armed by default for chunks below 1,024 tokens and prints its banner, against this file's own note at :161 ("the layer split, batch slots and HIP stay off"). Seven other sites already carry the || defined(STRATA_HIP_GFX906) form. Measured on one MI50 32 GB (gfx906), CLI generate, a 4-token prompt, one binary with one set of weights and one config, only the environment differing, power saving off: default experts streamed 309 (295 by DMA, host 174.0 ms), resident 607, on the CPU 197 (share 0.90) prefill 928.3 ms =0 experts streamed 506 (492 by DMA, host 177.3 ms), resident 606, on the CPU 0 (share 0.00) prefill 929.5 ms Output token ids are identical (271 248068 198 760) and the 0.13% difference is inside this machine's run-to-run spread (1.2-1.7%), so on this card the share engages and buys nothing. Niko1221#1595 and Niko1221#1729 report the default costing on CUDA; this is the mechanism that turns it on for AMD. CUDA and SYCL do not define STRATA_HIP_GFX906, so the added check is a no-op there and nothing on those backends changes. Hardware the numbers come from: Xeon E5-2696 v4 (Broadwell, 22C/44T, no AVX-512), one Radeon Instinct MI50 32 GB (gfx906, PCI 1002:66a1, VBIOS 113-D1631711-100, 34,342,961,152 B of VRAM), PCIe 3.0 x16 effective (the root port runs 8 GT/s x16 and the bridge above the card is downgraded; the card's own hop negotiates 16 GT/s, about 15.75 GB/s end to end), 128 GB RAM, Ubuntu, kernel 7.0.0-34-generic, ROCm 7.14 in a container, built with -DSTRATA_HIP_GFX906=ON and -DCMAKE_HIP_ARCHITECTURES=gfx906.
What
The HIP backend (
STRATA_ENABLE_HIP) is wave32 RDNA only, and the engine refuses a wave64 card. AMD Instinct MI50 / MI60 and Radeon VII (gfx906) are cheap 16/32 GB cards with ~1 TB/s HBM2. This PR adds an opt-in build for them:-DSTRATA_HIP_GFX906=ON -DCMAKE_HIP_ARCHITECTURES=gfx906.It compiles the CUDA sources as HIP through a small compat layer (
include/strata/platform/hip_compat/). A CUDA warp is a logical half of the 64-lane wavefront: 32-wide shuffles, and a ballot of its own half. With the option off, nothing changes for CUDA or the RDNA backend. Every new path is underSTRATA_HIP_GFX906, a macro neither existing build defines.Why a separate option and not
STRATA_ENABLE_HIP+ gfx906The RDNA backend's kernels and compat layer assume wave32 throughout. Treating the CUDA warp as half a wavefront let the CUDA path run unchanged on gfx906 first, and then the hot kernels got wave64 layouts of their own. If you'd rather fold gfx906 into
STRATA_ENABLE_HIP/cmake/hip_backend.cmake, I'm happy to rework it that way. Tell me which you prefer.Correctness fixes found on the way (each changed results or hung)
__fmul_rn/__fadd_rn/__fsub_rncontracted into FMA under HIP. They no longer do, so the elementwise and quantize_act parity tests pass bitwise.__byte_permis a scratch-memory array. The IQ4 table lookup now uses llama.cpp'sv_perm_b32sequence: agent-request decode on 2x MI50 went from 29.9 to 39.2 tok/s.CUDART_VERSIONtoolkit check is skipped under HIP.gdn_rec_parity(cp.async, CUDA occupancy API) is not built for gfx906.wave64 kernels (gfx906 only; each has an env switch back to the CUDA layout for A/B)
Each was checked bitwise against the layout it replaces: parity tests,
native_expert_benchon real GGUF rows, and the greedy text of a fixed request.dp4a(g ^ m, u) - dp4a(m, u)(gfx906 has no byte SIMD;__vcmpne4/__vsub4were ~12 word ops each), grids and activations in LDS, one weight load per groupSTRATA_EXP_MODE=2STRATA_MMVQ_WAVE=0STRATA_ROUTE_PER_TOKEN=1gr_down_multi(opt-in)STRATA_GR_SPLIT=1STRATA_GR_FAST=0docs/AMD_HIP.mdgets a gfx906 section: the build recipe on the community ROCm 7.14 image (AMD dropped gfx906 from current ROCm), the table above, and measurements.Measured (on the port this is cut from)
2x MI50 16 GB (85 W each, PCIe 3.0 x16), Xeon E5-2666 v3, 32 GB DDR4. Coder IQ1_M, 128K context,
--kv int8 --kv-resident 32768,--layer-split 27,--prefill 4096, MTP--spec 4.tg128.These numbers also include #639 (layer-split weight trim) and #640 (mapped arena for small RAM), which are separate PRs.
Verified for this branch
allwithSTRATA_HIP_GFX906=ON(gfx906, ROCm 7.14).allwithSTRATA_ENABLE_HIP=ONfor gfx1100, so the RDNA backend is intact.allwith CUDA 13.0 for sm_86, so the CUDA path is intact.Status
Re-run on 2x MI50 with this branch: ctest 35/35 on the cards and the greedy-text comparison with the port branch are in the comment below; builds checked for gfx906, gfx1100 and CUDA sm_86 at the branch head.
🤖 Generated with Claude Code