'cp -r SRC DST/' with a missing DST creates DST as a copy of SRC and drops a directory level, so rocblas/library/* landed as lib/rocblas/* and hipblaslt's arch subdirectories landed one level high. Nothing complains at load time: the engine reads 29 GiB of weights, answers /health, and dies on the first request with rocBLAS error: Cannot read .../lib/rocblas/library/TensileLibrary.dat: No such file or directory for GPU arch : gfx1201 Declare the destination and copy contents, both trees.
148 lines
7.7 KiB
Bash
Executable File
148 lines
7.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Build mainline llama.cpp for Dankserver's two Radeon AI PRO R9700 (gfx1201,
|
|
# Navi 48) with DFlash2 speculative decoding.
|
|
#
|
|
# Run on Dankserver. Produces a self-contained build: the binary carries an
|
|
# RPATH of $ORIGIN/../lib and the ROCm runtime is copied beside it, so nothing
|
|
# depends on the host's ROCm packages (Ubuntu's 7.1) or on LD_LIBRARY_PATH.
|
|
#
|
|
# bash scripts/build-llama-rdna4.sh
|
|
#
|
|
# WHY A PRIVATE TOOLCHAIN (ROCm 7.14.0a20260624, ~17 GiB extracted): the host's
|
|
# ROCm is Ubuntu's 7.1 packaging, and the pre-existing RDNA4 llama.cpp build on
|
|
# this box (charlie12345/ROCmFPX) was built against this same TheRock nightly.
|
|
# Reusing it keeps the toolchain that is known to emit working gfx1201 code
|
|
# objects; the tarball is only downloaded when the prefix is missing.
|
|
#
|
|
# WHY THIS REF: master at fb27a525 carries what this service needs and nothing
|
|
# older does:
|
|
# * DFlash2 (`DFlash2DraftModel`): grouped dynamic depthwise convolution plus
|
|
# the candidate selector, detected from the draft GGUF
|
|
# (`selector_top_k > 0`) and served through the ordinary `--spec-type
|
|
# draft-dflash` path. Landed with ggml-org/llama.cpp#27342.
|
|
# * qwen35 MTP: the `draft-mtp` implementation covers qwen35's single trained
|
|
# MTP head (common/speculative.cpp), which the target GGUF carries.
|
|
# Do not "update to latest" casually: both features landed days apart and the
|
|
# service depends on the pair.
|
|
#
|
|
# gfx1201 IS NOT gfx1200. The ROCmFPX fork's docs/BUILD-AMD-ARCHITECTURES.md
|
|
# records that a gfx1200 build links, loads the model and then segfaults on
|
|
# these cards, so the arch list here is exactly gfx1201 and no other.
|
|
set -euo pipefail
|
|
|
|
LLAMA_SRC="${LLAMA_SRC:-/home/dank/GitPackages/llama.cpp-dflash2}"
|
|
LLAMA_REPO="${LLAMA_REPO:-https://github.com/ggml-org/llama.cpp.git}"
|
|
LLAMA_REF="${LLAMA_REF:-fb27a525d28381a16a4bb038858a10e4927381ca}"
|
|
BUILD_DIR="${BUILD_DIR:-$LLAMA_SRC/build-rdna4-rocm714}"
|
|
JOBS="${JOBS:-$(nproc)}"
|
|
ROCM_VERSION="${ROCM_VERSION:-7.14.0a20260624}"
|
|
ROCM_LOCAL_PATH="${ROCM_LOCAL_PATH:-${XDG_DATA_HOME:-$HOME/.local/share}/rocm-${ROCM_VERSION}}"
|
|
HIP_ARCH="${HIP_ARCH:-gfx1201}"
|
|
|
|
# ── Source ────────────────────────────────────────────────────────────
|
|
if [[ ! -d "$LLAMA_SRC/.git" ]]; then
|
|
echo "cloning $LLAMA_REPO into $LLAMA_SRC"
|
|
git clone "$LLAMA_REPO" "$LLAMA_SRC"
|
|
fi
|
|
git -C "$LLAMA_SRC" fetch --quiet origin "$LLAMA_REF" 2>/dev/null || git -C "$LLAMA_SRC" fetch --quiet origin
|
|
git -C "$LLAMA_SRC" checkout --detach "$LLAMA_REF"
|
|
echo "building llama.cpp $(git -C "$LLAMA_SRC" rev-parse --short HEAD) from $LLAMA_SRC"
|
|
|
|
# ── ROCm toolchain ────────────────────────────────────────────────────
|
|
if [[ ! -x "$ROCM_LOCAL_PATH/llvm/bin/clang" ]]; then
|
|
TARBALL_URL="https://rocm.nightlies.amd.com/tarball-multi-arch/therock-dist-linux-gfx120X-all-${ROCM_VERSION}.tar.gz"
|
|
TARBALL="$LLAMA_SRC/rocm-${ROCM_VERSION}.tar.gz"
|
|
if [[ ! -s "$TARBALL" ]]; then
|
|
echo "downloading ROCm $ROCM_VERSION from TheRock nightlies"
|
|
curl -fL --retry 5 -o "$TARBALL" "$TARBALL_URL"
|
|
fi
|
|
echo "extracting into $ROCM_LOCAL_PATH"
|
|
mkdir -p "$ROCM_LOCAL_PATH"
|
|
tar --use-compress-program=gzip -xf "$TARBALL" -C "$ROCM_LOCAL_PATH" --strip-components=1
|
|
fi
|
|
CLANG="$ROCM_LOCAL_PATH/llvm/bin/clang"
|
|
CLANGXX="$ROCM_LOCAL_PATH/llvm/bin/clang++"
|
|
[[ -x "$CLANG" && -x "$CLANGXX" ]] || { echo "no clang/clang++ under $ROCM_LOCAL_PATH" >&2; exit 1; }
|
|
|
|
# ggml-hip's CMake falls back to $ENV{ROCM_PATH} or /opt/rocm when these are
|
|
# unset, which links a second, mismatched HIP runtime next to the local one.
|
|
export ROCM_PATH="$ROCM_LOCAL_PATH"
|
|
export HIP_PATH="$ROCM_LOCAL_PATH"
|
|
|
|
# ── Configure ─────────────────────────────────────────────────────────
|
|
# GGML_HIP_RCCL stays OFF: this host's second card cannot dispatch a RCCL
|
|
# kernel at all (its PCIe path has no atomic routing), and layer-split serving
|
|
# needs no collectives. With RCCL off, llama.cpp logs "internal AllReduce init
|
|
# failed ... falling back to meta-backend butterfly" and only --split-mode
|
|
# tensor pays for it.
|
|
cmake -S "$LLAMA_SRC" -B "$BUILD_DIR" \
|
|
-G Ninja \
|
|
-DCMAKE_BUILD_TYPE=Release \
|
|
-DCMAKE_C_COMPILER="$CLANG" \
|
|
-DCMAKE_CXX_COMPILER="$CLANGXX" \
|
|
-DCMAKE_CXX_FLAGS="-I${ROCM_LOCAL_PATH}/include" \
|
|
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
|
|
-DGGML_HIP=ON \
|
|
-DGGML_HIP_RCCL=OFF \
|
|
-DGGML_CUDA=OFF \
|
|
-DGGML_VULKAN=OFF \
|
|
-DGGML_NATIVE=OFF \
|
|
-DCMAKE_HIP_ARCHITECTURES="$HIP_ARCH" \
|
|
-DGPU_TARGETS="$HIP_ARCH" \
|
|
-DLLAMA_BUILD_SERVER=ON \
|
|
-DLLAMA_BUILD_WEBUI=OFF \
|
|
-DLLAMA_USE_PREBUILT_WEBUI=OFF \
|
|
-DLLAMA_BUILD_TESTS=OFF \
|
|
-DGGML_BUILD_TESTS=OFF \
|
|
-DCMAKE_PREFIX_PATH="$ROCM_LOCAL_PATH" \
|
|
-DROCM_DIR="$ROCM_LOCAL_PATH" \
|
|
-DBUILD_SHARED_LIBS=OFF
|
|
|
|
# ── Build ─────────────────────────────────────────────────────────────
|
|
cmake --build "$BUILD_DIR" -j "$JOBS" \
|
|
--target llama-server llama-cli llama-quantize llama-bench
|
|
|
|
# ── Bundle the runtime ────────────────────────────────────────────────
|
|
if command -v patchelf >/dev/null; then
|
|
LIB_DIR="$BUILD_DIR/lib"
|
|
mkdir -p "$LIB_DIR"
|
|
for pat in libamdhip64 librocblas libhipblas libhipblaslt librocsolver \
|
|
libroctx64 libamd_comgr libhsa-runtime64 librocm_kpack \
|
|
librocroller librocprofiler-register; do
|
|
cp -v "$ROCM_LOCAL_PATH/lib/$pat".so* "$LIB_DIR/" 2>/dev/null || true
|
|
done
|
|
cp -v "$ROCM_LOCAL_PATH/lib/llvm/lib"/libLLVM.so* \
|
|
"$ROCM_LOCAL_PATH/lib/llvm/lib"/libclang-cpp.so* \
|
|
"$ROCM_LOCAL_PATH/lib/llvm/lib"/libomp.so* \
|
|
"$ROCM_LOCAL_PATH/lib/llvm/lib"/libomptarget.so* "$LIB_DIR/" 2>/dev/null || true
|
|
cp -v "$ROCM_LOCAL_PATH/lib/rocm_sysdeps/lib"/librocm_sysdeps_*.so* "$LIB_DIR/" 2>/dev/null || true
|
|
# rocBLAS and hipBLASLt look for their device code at a FIXED depth under
|
|
# the binary's lib dir: $ORIGIN/../lib/rocblas/library and
|
|
# $ORIGIN/../lib/hipblaslt/library/<arch>. `cp -r SRC DST/` with a missing
|
|
# DST creates DST as a copy of SRC and flattens the source by one level, so
|
|
# the engine loads, serves nothing, and dies on the FIRST request with
|
|
# rocBLAS error: Cannot read .../lib/rocblas/library/TensileLibrary.dat:
|
|
# No such file or directory for GPU arch : gfx1201
|
|
# (measured 2026-09-16, after a build that looked perfectly healthy).
|
|
# Declare the destination, then copy the contents into it.
|
|
if [[ -d "$ROCM_LOCAL_PATH/lib/rocblas/library" ]]; then
|
|
mkdir -p "$LIB_DIR/rocblas/library"
|
|
cp -r "$ROCM_LOCAL_PATH/lib/rocblas/library/." "$LIB_DIR/rocblas/library/"
|
|
fi
|
|
if [[ -d "$ROCM_LOCAL_PATH/lib/hipblaslt/library" ]]; then
|
|
mkdir -p "$LIB_DIR/hipblaslt/library"
|
|
cp -r "$ROCM_LOCAL_PATH/lib/hipblaslt/library/." "$LIB_DIR/hipblaslt/library/"
|
|
fi
|
|
for bin in "$BUILD_DIR"/bin/llama-*; do
|
|
[[ -f "$bin" ]] && patchelf --set-rpath '$ORIGIN/../lib' "$bin"
|
|
done
|
|
else
|
|
echo "patchelf missing; run with LD_LIBRARY_PATH=$ROCM_LOCAL_PATH/lib:$ROCM_LOCAL_PATH/lib/llvm/lib" >&2
|
|
fi
|
|
|
|
echo
|
|
echo "built for $HIP_ARCH:"
|
|
"$BUILD_DIR/bin/llama-server" --version 2>&1 | head -3
|
|
ldd "$BUILD_DIR/bin/llama-server" 2>/dev/null | grep -E "not found" && exit 1 || true
|
|
echo " $BUILD_DIR/bin/llama-server"
|