[ROCm] Add AMD GPU support via ROCm/HIP build path - #12
Open
jeffdaily wants to merge 1 commit into
Open
Conversation
This adds an AMD GPU backend to yalm built with ROCm/HIP, alongside the
existing NVIDIA CUDA backend. The CUDA build is unchanged: with no extra flags
the Makefile still drives nvcc exactly as before. Passing USE_HIP=1 instead
compiles the .cu translation unit with hipcc and links the HIP runtime; the
target architecture is selected with HIPARCH (default gfx90a, e.g.
HIPARCH=gfx1100), so no source edit is needed to retarget.
Review order:
1. src/cuda_to_hip.h (new) -- a compatibility shim. On the CUDA build it is a
thin pass-through to the CUDA runtime headers, so nvcc behavior is untouched.
On the HIP build it includes the HIP runtime and aliases only the CUDA
runtime symbols yalm uses to their hip* equivalents. It is included by
infer.cu (via hipcc) and by host C++ TUs (via model.h), so the host-side
graph/state structs see the same type aliases.
2. Makefile -- a USE_HIP=1 branch selecting hipcc, -lamdhip64, and
--offload-arch=$(HIPARCH); host C++ flags gain -DUSE_HIP
-D__HIP_PLATFORM_AMD__ and the link gets -no-pie. HIPARCH defaults to gfx90a
and is caller-overridable; the CUDA branch is the original recipe, unchanged.
3. src/infer.cu -- wave-width correctness, guarded so the CUDA path is unchanged:
- matmul launches use warps-per-block derived at runtime from the device's
warp size (max-threads-per-block / warp_size): 16 on a 64-wide wavefront,
32 on a 32-wide one, keeping the block at the 1024-thread cap on every
device. A compile-time arch macro cannot drive this, since the value is
used in host launch code where device macros are undefined.
- att_mix's __shared__ arrays are sized to the maximum wavefront width (64 on
HIP, 32 on CUDA), since the kernel launches warpSize threads (64 on AMD).
- The standalone kernel-test entry points query the device warp size and
max-threads-per-block lazily rather than assuming 32 / 1024.
- FULL_MASK is a 64-bit all-ones literal under HIP (ROCm's __shfl_*_sync
require a 64-bit mask); CUDA keeps 0xffffffff.
- Host-registered memory is handed to kernels via hipHostGetDevicePointer on
HIP, with buffers registered using the mapped flag. Whether a
host-registered pointer is directly device-addressable depends on the GPU's
BAR aperture (large/resizable BAR), not the OS, so the device pointer is
always resolved on HIP; on CUDA (UVA) this is a no-op.
4. src/model.h -- include the shim instead of cuda_runtime_api.h directly.
5. README.md -- ROCm/HIP build instructions next to the CUDA ones.
Test plan / validation:
The bundled kernel test (make test USE_HIP=1 HIPARCH=<arch> && ./build/test)
compares the GPU matmul / multi-head-attention / feedforward kernels against a
CPU reference at epsilon 1e-4 and runs the CPU regression guard. Built and run
on real AMD GPUs, deterministic across repeated runs:
- Linux gfx90a (Instinct MI250X, wave64), ROCm 7.2
- Linux gfx1100 (Radeon Pro W7800, RDNA3 wave32), ROCm 7.2
- Windows gfx1201 (Radeon RX 9070 XT, RDNA4) on ROCm
Both wavefront widths are covered, so the wave-width fixes are validated on real
hardware.
On gfx1100, full end-to-end inference was additionally validated:
Mistral-7B-Instruct-v0.2 (FP16) generates coherent text at ~26.7 tok/s, with the
hipGraph capture/replay path confirmed exercised (hipGraphInstantiate /
hipGraphLaunch succeed for prefill and decode), no NaN or GPU fault.
This work was authored with the assistance of Claude.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This adds an AMD GPU backend to yalm built with ROCm/HIP, alongside the existing NVIDIA CUDA backend. The CUDA build is unchanged: with no extra flags the Makefile still drives nvcc exactly as before. Passing
USE_HIP=1instead compiles the.cutranslation unit with hipcc and links the HIP runtime; the target architecture is selected withHIPARCH(defaultgfx90a, e.g.HIPARCH=gfx1100), so no source edit is needed to retarget.Review order:
src/cuda_to_hip.h(new) — a compatibility shim. On the CUDA build it is a thin pass-through to the CUDA runtime headers, so nvcc behavior is untouched. On the HIP build it includes the HIP runtime and aliases only the CUDA runtime symbols yalm uses to theirhip*equivalents. It is included byinfer.cu(via hipcc) and by host C++ TUs (viamodel.h), so the host-side graph/state structs see the same type aliases.Makefile— aUSE_HIP=1branch selecting hipcc,-lamdhip64, and--offload-arch=$(HIPARCH); host C++ flags gain-DUSE_HIP -D__HIP_PLATFORM_AMD__and the link gets-no-pie.HIPARCHdefaults togfx90aand is caller-overridable; the CUDA branch is the original recipe, unchanged.src/infer.cu— wave-width correctness, guarded so the CUDA path is unchanged:att_mix's__shared__arrays are sized to the maximum wavefront width (64 on HIP, 32 on CUDA), since the kernel launcheswarpSizethreads (64 on AMD).FULL_MASKis a 64-bit all-ones literal under HIP (ROCm's__shfl_*_syncrequire a 64-bit mask); CUDA keeps0xffffffff.hipHostGetDevicePointeron HIP, with buffers registered using the mapped flag. Whether a host-registered pointer is directly device-addressable depends on the GPU's BAR aperture (large/resizable BAR), not the OS, so the device pointer is always resolved on HIP; on CUDA (UVA) this is a no-op.src/model.h— include the shim instead ofcuda_runtime_api.hdirectly.README.md— ROCm/HIP build instructions next to the CUDA ones.Test plan / validation
The bundled kernel test (
make test USE_HIP=1 HIPARCH=<arch> && ./build/test) compares the GPU matmul / multi-head-attention / feedforward kernels against a CPU reference at epsilon 1e-4 and runs the CPU regression guard. Built and run on real AMD GPUs, deterministic across repeated runs:Both wavefront widths are covered, so the wave-width fixes are validated on real hardware.
On gfx1100, full end-to-end inference was additionally validated: Mistral-7B-Instruct-v0.2 (FP16) generates coherent text at ~26.7 tok/s, with the hipGraph capture/replay path confirmed exercised (hipGraphInstantiate / hipGraphLaunch succeed for prefill and decode), no NaN or GPU fault.
Authored with the assistance of Claude.