Skip to content

hip: AMD Instinct MI50 / MI60 / Radeon VII (gfx906, wave64) as an opt-in build - #638

Closed
JeanP00l wants to merge 6 commits into
Niko1221:mainfrom
JeanP00l:pr-gfx906
Closed

JeanP00l wants to merge 6 commits into
Niko1221:mainfrom
JeanP00l:pr-gfx906

Conversation

@JeanP00l

@JeanP00l JeanP00l commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

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 under STRATA_HIP_GFX906, a macro neither existing build defines.

Why a separate option and not STRATA_ENABLE_HIP + gfx906

The 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_rn contracted into FMA under HIP. They no longer do, so the elementwise and quantize_act parity tests pass bitwise.
  • ggml MMQ got NVIDIA compute capability 9.0 for gfx906 and hung the prompt path. It now gets the AMD arch code.
  • HIP's __byte_perm is a scratch-memory array. The IQ4 table lookup now uses llama.cpp's v_perm_b32 sequence: agent-request decode on 2x MI50 went from 29.9 to 39.2 tok/s.
  • gfx906's wall clock is 25 MHz, not 100: fixed in the stage profiler.
  • The CUDART_VERSION toolkit 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_bench on real GGUF rows, and the greedy text of a fixed request.

kernel change effect switch
grouped native experts mode 7: signs as dp4a(g ^ m, u) - dp4a(m, u) (gfx906 has no byte SIMD; __vcmpne4/__vsub4 were ~12 word ops each), grids and activations in LDS, one weight load per group verify window 60.0 -> 51.3 ms STRATA_EXP_MODE=2
MMVQ one wavefront per row, 64-lane butterfly +2.3% decode STRATA_MMVQ_WAVE=0
router top-10 one wavefront, register argmax bit-identical -
verify-window routing (256-expert router) one BF16 projection + one top-k per window -3 ms per window STRATA_ROUTE_PER_TOKEN=1
gr_down_multi (opt-in) split along K; sums in another order than the single-token read +2.9% STRATA_GR_SPLIT=1
hyper-connection read loads in flight, 8 lanes per row 51.3 -> 50.2 ms STRATA_GR_FAST=0

docs/AMD_HIP.md gets 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.

  • All 12,288 experts are in VRAM.
  • A 17K-token agent prompt is read in 43.5 s; decode on it runs at 57.7-59.3 tok/s.
  • 6/6 long agent requests and a 900 s two-client load test x6 (407 requests) ran with no stalls or faults.
  • For reference, llama.cpp on the same model and machine: 26.9 tok/s 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

  • Builds all with STRATA_HIP_GFX906=ON (gfx906, ROCm 7.14).
  • Builds all with STRATA_ENABLE_HIP=ON for gfx1100, so the RDNA backend is intact.
  • Builds all with 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

…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).
…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.
@JeanP00l

JeanP00l commented Oct 3, 2026

Copy link
Copy Markdown
Contributor Author

Re-run on 2x MI50 (gfx906). Running ctest on the cards found four things, now fixed on the branch:

  • 6a12d43 native_expert_grouped: the AMD layouts only handle the IQ packs' gate/up and down types. Unsloth's Q4_K / Q5_K gate/up and Q5_1 / Q8_0 down exited ("down type 7"). They now take the CUDA layout (native_grouped_parity).
  • 6a12d43 The K-split gr_down broke gr_parity's contract (multi-token read == T single-token calls, bitwise), because its fixed-order finish sums in another order. It is now opt-in (STRATA_GR_SPLIT=1). The latency-hidden norm/up (same sums, same order) stay on by default.
  • 6a12d43 Two tests did not know about gfx906:
    • mmvq_multi_parity's negative control has nothing to find, because the wave64 MMVQ is the same exact kernel at every column count. A second entry, mmvq_multi_parity_cuda_layout, runs it on the CUDA layout, where the control has power.
    • kv_hybrid_parity: the tensor-core prompt attention refuses on gfx906, as on RDNA.
  • 17beb33 The verify window's routing for the Coder's 256-expert router (one multi-column BF16 projection + one top-k), with a new route_window_parity. gfx906 build only, so CUDA/RDNA are unchanged. -3 ms per window, same text.
  • a914b13 Fixes the CUDA/RDNA compile break from 6a12d43, which my re-check of those builds caught.

Builds at a914b13 (all targets, compile only):

  • STRATA_HIP_GFX906=ON (gfx906, HIP 7.14)
  • STRATA_ENABLE_HIP=ON (gfx1100)
  • CUDA 13.0 (sm_86)

ctest on the cards: 35 of 35 pass, including route_window_parity and mmvq_multi_parity_cuda_layout. iq_parity and ple_parity were not run: they need fixture files (tools/iq_fixture.py, bench/micro/ple_*.bin) that the build does not make.

Greedy-text comparison with the port branch. Coder IQ1_M, 32K context, --layer-split 27, --spec 4, --adapt-every 100000 --suffix-draft 0; a greedy 400-token request ("BST") and a greedy 1,500-token code request; md5 prefixes of the generated text.

build settings BST 1,500 tokens ms / verify window
port branch (in daily use) STRATA_STAGE_TRIM=0 STRATA_GR_SPLIT=0 1938073e3b0b 79449b452413 53.1
this PR STRATA_IQ_MT_MIN=1 1938073e3b0b 79449b452413 52.3
this PR defaults 1938073e3b0b 43f4429cdc95 (3 runs, the last at a914b13) 52.0-52.2
port branch its defaults 1938073e3b0b 5be6772870f2 (3 runs) 50.3

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 COMMUNITY_BENCHMARKS.md format follows as its own PR.

Marking ready.

@JeanP00l
JeanP00l marked this pull request as ready for review October 3, 2026 20:01
Niko1221 added a commit that referenced this pull request Oct 4, 2026
… 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>
Niko1221 added a commit that referenced this pull request Oct 4, 2026
…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>
Niko1221 added a commit that referenced this pull request Oct 4, 2026
…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>
@Niko1221

Niko1221 commented Oct 4, 2026

Copy link
Copy Markdown
Owner

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.

@Niko1221 Niko1221 closed this Oct 4, 2026
@JeanP00l

JeanP00l commented Oct 4, 2026

Copy link
Copy Markdown
Contributor Author

Post-merge gfx906 re-run on the current upstream tree (6f32ec0), using the pinned llama.cpp revision from the checkout:

  • Build: all gfx906 targets compile with HIP/ROCm 7.14 on MI50. The HIP compatibility wrapper uses the function form of cudaFuncSetAttribute from hip/gfx906: cudaFuncSetAttribute must be a function, not a macro (ROCm 7.2.1 build fix) #808, which handles kernel template arguments containing commas.
  • CTest: 36 of 37 tests passed. ple_parity could not complete because its required Q2_0 GGUF fixture is not present. The IQ fixture tests were not registered because Python NumPy is unavailable in the build container.
  • Greedy smoke: with the Qwen3.8-Flash-Next Coder IQ1_M pack, explicit layer split 27, MTP 4, 128K context, INT8 KV and 32K resident KV, a fixed temperature-0 request produced identical assistant code on the merge candidate and the existing gfx906 build. The code SHA-256 was 114cf38b24ff3651c135481a4791a9f30597e7c71229d432ce5e2dd3d3956f63 on both.

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.

Niko1221 added a commit that referenced this pull request Oct 6, 2026
… 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.
Niko1221 added a commit that referenced this pull request Oct 6, 2026
…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.
Niko1221 added a commit that referenced this pull request Oct 6, 2026
…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).
anon761 pushed a commit to anon761/Strata-upstream that referenced this pull request Oct 6, 2026
…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.
anon761 pushed a commit to anon761/Strata-upstream that referenced this pull request Oct 6, 2026
…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.
anon761 pushed a commit to anon761/Strata-upstream that referenced this pull request Oct 6, 2026
…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).
anon761 pushed a commit to anon761/Strata-upstream that referenced this pull request Oct 6, 2026
…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>
anon761 pushed a commit to anon761/Strata-upstream that referenced this pull request Oct 6, 2026
…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>
anon761 pushed a commit to anon761/Strata-upstream that referenced this pull request Oct 6, 2026
…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>
phoenixclyde added a commit to phoenixclyde/Strata that referenced this pull request Oct 9, 2026
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.
phoenixclyde added a commit to phoenixclyde/Strata that referenced this pull request Oct 9, 2026
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.
Niko1221 pushed a commit that referenced this pull request Oct 10, 2026
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.
giridhart pushed a commit to giridhart/Strata that referenced this pull request Oct 15, 2026
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.
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