AMD GPU support via HIP (single-source backend) + CUDA_EXTEND VRAM-only expert tier#112
AMD GPU support via HIP (single-source backend) + CUDA_EXTEND VRAM-only expert tier#112noobdev-ph wants to merge 9 commits into
Conversation
β¦ backend_gpu_compat.h backend_cuda.cu compiles unchanged under nvcc (CUDA=1, unchanged) and hipcc (HIP=1, new) through a 29-line CUDA->HIP mapping header, following the same one-shim-header pattern compat.h uses for the Windows port. make hip-test runs the existing kernel correctness test on ROCm. Verified on RX 9070 XT (gfx1201, ROCm 7.2.4): q8/q4/q2/f32 kernels correct.
β¦m-only slots) With CUDA_EXTEND=1 the VRAM budget pins the NEXT experts in the frequency ranking instead of mirroring experts already resident in RAM: each is loaded once at startup, uploaded, and its host slab freed β extra pinned capacity at zero RAM cost (RSS measured flat). Legacy mirror stays the default. Safety: cached device tensors are callable without live host pointers (backend check order fix + test); a GPU failure on a vram-only slot emits zeros, is repaired in-loop by one disk reload + CPU recompute, and the pin lookup skips the slot afterwards; REPIN won't swap into slab-less slots. Measured (RX 9070 XT 16GB, HIP, GLM-5.2 int4, --ram 40): pinned coverage 620 -> 1254 experts, expert hit 35.1% -> 45.0%, 0.25 -> 0.26 tok/s single run (MTP acceptance dropped 40% -> 33% from GPU float numerics, absorbing most of the caching win; multi-run median pending).
cdc1d14 to
bbcb78a
Compare
rajpratham1
left a comment
There was a problem hiding this comment.
Thanks for the contributionβthis is an ambitious feature that adds HIP support while also introducing VRAM-only expert caching and build system changes.
Before this can be merged, I think it would benefit from additional validation:
- Please add CI or documented test results for both CUDA and HIP builds to demonstrate that the shared backend works correctly across both toolchains.
- The new VRAM-only expert path introduces significant changes to memory ownership and fallback behavior. It would be helpful to include tests covering upload failures, CPU fallback, and repeated execution after host memory has been released.
- Since this changes the build system substantially (CUDA/HIP selection, new compatibility layer, Makefile updates), adding documentation describing the supported environments and expected build commands would make the feature easier to adopt and maintain.
The direction looks promising, but I'd like to see these validations before approving such a large cross-platform feature.
|
I built the code directly from noobdev-ph's repo, and it doesn't detect my MI50s hip-test seems to pass but with some warnings. Edit also tried pulling the PR just incase I messed up same result |
|
So I pointed qwen 3.6 27B at this problem and it added a rocm smi parser function to resource_plan.py ... so not sure how it works at all on your system without that! my local copy detects both GPUS and functions after that. Also for some reason usage of the GPUS does not show up in rocm-smi or nvtop (I forgot to pass CUDA_EXPERT_GB) |
β¦njection, CI, docs Addresses PR review feedback: - tests/test_backend_cuda.cu: upload-failure cases (invalid device/format, missing scales/data, ~16 TB alloc) with stats-integrity checks; 64x sustained matmul reuse after host pointers are gone; upload-from-freed- temporary (the VRAM-only slot lifecycle); fault-injection coverage. - backend_cuda.cu: COLI_GPU_FAIL_AFTER=N test hook (fail matmuls after N successes; unset = no effect). FIX found by the new tests: a failed allocation left a sticky runtime error that poisoned the next healthy launch's cudaGetLastError() check β now consumed in cuda_ok(). - .github/workflows/gpu-build.yml: CI compiling the shared backend, test binary and engine under BOTH toolchains (nvcc sm_80 / hipcc gfx1100 containers) plus the standard CPU make check; new 'gpu-compile' target. - GPU_BACKENDS.md: supported environments, build commands, runtime knobs, validation matrix and known-behavior notes. Engine-level validation (RX 9070 XT, GLM-5.2 int4): with CUDA_EXTEND=1 and COLI_GPU_FAIL_AFTER=0 (every GPU matmul fails, 1689 tensors degraded) the repair path reproduces the pure-CPU greedy output BYTE-IDENTICAL; mid-run injection (N=2000, 1423 tensors) completes cleanly. hip-test: 5/5 stable runs, including concurrently with a full 12 GB expert tier on the device.
|
Thanks for the thorough review β all three points were fair, and addressing them made the branch better. Everything below is pushed ( 1. CI + documented results for both toolchains Added Honest scoping: hosted runners have no GPUs, so CI is compile-level. Runtime execution is covered by 2. Tests for the VRAM-only path
You were right to ask β the new failure tests immediately caught a real bug: a failed allocation left a sticky runtime error that poisoned the next healthy launch's For the engine-level repair/fallback behavior, the fault hook enables an end-to-end validation with a strong invariant: with 3. Documentation Added Happy to iterate further β and if you'd like the workflow to live elsewhere or trigger differently in your repo, easy to adjust. |
β¦retired in favor of upstream CUDA_RELEASE_HOST Reconciliation of feat/hip-backend with upstream's Metal backend, PIN=auto, CUDA_RELEASE_HOST/expert_host_ensure, tensor-core (WMMA) paths, grouped expert kernels, attention pipe, and Windows CUDA-DLL loader: - glm.c: taken from upstream unchanged. CUDA_EXTEND and its vram_only slot machinery are retired: upstream's PIN=auto + PIN_FILL + CUDA_RELEASE_HOST achieve the same VRAM capacity extension with deeper integration, and expert_host_ensure supersedes our in-loop repair. - backend_cuda.cu: upstream base + our deltas re-applied (compat include, cached-tensor upload reorder, sticky-error consume, fault hook). The fault hook now gates all 19 GPU compute entry points. WMMA tensor-core dispatch is compile-gated (COLI_GPU_HAS_WMMA): gfx GPUs report compute_major >= 12, so the runtime check alone would launch empty kernel bodies under HIP. - backend_gpu_compat.h: extended for the grown runtime surface (streams, events, pinned host memory, peer copies, Memcpy2D, fp16 header). - Makefile: HIP block, GPUCC indirection, hip-test and gpu-compile rewoven into upstream's new structure (Metal, CUDA_DLL, expanded TEST_BINS). - tests: ours + upstream's tensor_update test (ordered: update mutates t8). - GPU_BACKENDS.md: validated properties recalibrated on the merged tree β graceful + deterministic (frozen usage) under total GPU failure; byte-identity vs pure CPU does not hold post-merge (fallback kernel/shape selection differs; consistent with JustVugg#100) and is documented as such. Validation on RX 9070 XT (gfx1201, ROCm 7.2.4): make check green, hip-test green (incl. tensor_update), engine survives COLI_GPU_FAIL_AFTER=0 with coherent deterministic output, and normal GPU operation measures 0.32 tok/s at 61% expert hit on GLM-5.2 β the machine's best result to date.
β¦re remaining test binaries The committed binary was built against glibc 2.43 and shipped a newer mtime than its source, so 'make check' on CI ran it stale instead of rebuilding: tests/test_kv_alloc: libm.so.6: version GLIBC_2.43 not found. Also adds the test binaries missing from .gitignore so this cannot recur.
rocm/dev-ubuntu-22.04:latest grew past the hosted runner's free disk (container init failed with ENOSPC). Pin a slimmer tag that is fully sufficient for compile-only validation, and switch the job from container: syntax to an explicit docker run so the disk can be freed before the pull.
β¦ objects into the engine (ld: failed to set dynamic section sizes)
β¦not link ROCm runtime libs; engine link documented as hardware-validated
|
Synced the branch with
One functional addition worth your attention: WMMA gating for HIP. Your new tensor-core kernels guard their bodies with Validation on the merged tree (RX 9070 XT, ROCm 7.2.4, GLM-5.2 int4; the fault hook now gates all 19 GPU compute entry points):
Two CI/housekeeping findings that apply upstream too: (1) Performance on the merged tree: your |
|
Could you rewrite this against current It's 24 commits behind Yours is the closest to landing β only 24 commits behind. An AMD/HIP backend has the same problem as #84 though: nobody here can run it, so the CI can only prove it compiles. Worth thinking about what would let it be verified rather than trusted. What changed under you, which makes a rewrite cheaper than it sounds:
What would help it land fast: the smallest version that does one thing. A 300β700 line PR touching If you'd rather not, say so and I'll close it with thanks β no hard feelings either way. And if you think I've misjudged and it should go in as-is, push back: I've been wrong twice today already and both times a contributor caught it. |
|
Done as requested β rewritten against
Closing this one in favor of those two. Thanks for the direct feedback β the 24-commit rot was real, and the split genuinely improved both halves. The full history (benchmarks, the WMMA silent-garbage finding, validation methodology) lives in this thread and both new PRs link back. |
Summary
Two additions, both opt-in, CPU default untouched:
1. AMD GPU support via HIP/ROCm (
make HIP=1,make hip-test) β the existing CUDA expert backend compiles unchanged for AMD GPUs through a 29-linebackend_gpu_compat.hmapping header, following the same one-shim-header patterncompat.huses for the Windows port. One source, two vendors: nvcc path is byte-identical to today; hipcc maps the exact CUDA runtime surfacebackend_cuda.cuuses onto HIP 1:1 (the kernels use no vendor-specific intrinsics). First AMD datapoint below.2.
CUDA_EXTEND=1: the VRAM tier holds experts beyond the RAM pin β today the VRAM tier promotes experts already resident in the RAM pin (a compute mirror; ideal for matmul-bound machines). On disk-bound machines it adds no cache coverage. WithCUDA_EXTEND=1, the VRAM budget pins the next experts in the frequency ranking: loaded once at startup, uploaded, host slab freed β extra pinned capacity at zero RAM cost (RSS measured flat). Legacy mirror stays the default.Safety for VRAM-only slots: cached device tensors are callable without live host pointers (upload check-order fix, pinned by a new test assertion); if the GPU ever refuses a VRAM-only expert mid-run, the matmul flags it and emits zeros, the expert loop repairs in place with one disk reload + CPU recompute (not even that token is wrong), and the pin lookup skips the dead slot from then on; REPIN won't swap into slab-less slots.
Validation
make -C c check(CPU build + all C/Python tests pass; default path untouched)make -C c hip-test HIP_ARCH=gfx1201β q8/q4/q2/f32 kernel correctness on AMD, including the new cached-tensor-without-host-pointers assertion--ram 40 --topp 0.7 --temp 0 --ngen 32, greedy fixed prompt, 10 runs per config (full per-run logs in the linked issue thread; same methodology as [Performance]: Ryzen 7 5700G + Gen5 NVMe capped at Gen3 β int8 MTP confirmed at 40%, learning-cache curve measured over 20 controlled runsΒ #93):CUDA_EXPERT_GB=12)CUDA_EXTEND=1Honest reading: the extension structurally lifts hit-rate ~10 points (620 β 1,254 pinned experts) but GPU float numerics shift the greedy trajectory, dropping MTP acceptance from the CPU's steady 40% to ~31% mean β the extra forwards absorb most of the caching win. When acceptance happened to recover (run 9: 46%), throughput hit 0.30 tok/s, +36% over CPU median. Follow-up that would make ~0.30 the steady state: a numerics-matched GPU kernel (int8 activation quant + integer dot, mirroring the CPU IDOT path). Happy to iterate on that in a second PR.
The mirror-mode neutrality on this box also confirms the README's design note: streaming stays CPU-side, and the mirror tier targets matmul-bound machines β this machine is disk-bound (51%), which is exactly what
CUDA_EXTEND=1addresses.Compatibility
Context: hardware and baseline measurements are the same machine as #93.