|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Capped Vulkan / optional CUDA build for SP1+SP2 (turbo4_0 Vulkan FA / paged-attn oracle). |
| 3 | +# |
| 4 | +# WHY: this host has 15GB RAM / 8 cores. An uncapped `cmake --build -j` of the |
| 5 | +# CUDA backend OOM-killed the box on 2026-06-28. This wrapper makes that |
| 6 | +# impossible: |
| 7 | +# * CUDA is OFF by default -> nvcc/cudafe++ (the RAM hogs) never run. |
| 8 | +# * WITH_CUDA=1 enables CUDA (sm_61 / GTX1070) with a conservative -j2. |
| 9 | +# * the build runs inside a transient systemd --user scope with a hard |
| 10 | +# MemoryMax -> any OOM is contained to the build cgroup, never the system. |
| 11 | +# * CPUQuota=700% -> leaves cores/RAM for the live services. |
| 12 | +# |
| 13 | +# Usage: build-vk.sh [target] (default target: test-backend-ops) |
| 14 | +# WITH_CUDA=1 build-vk.sh [target] (dual-backend build, slow but capped) |
| 15 | +set -euo pipefail |
| 16 | + |
| 17 | +REPO=/home/kmbandy/GitHub/llama.cpp |
| 18 | +BUILD="$REPO/build-vk" |
| 19 | +TARGET="${1:-test-backend-ops}" |
| 20 | + |
| 21 | +# Adaptive cgroup limits, sized from actual free RAM (2026-06-29 rewrite). |
| 22 | +# LESSON: the old -j1 + MemoryHigh=5G was the *cause* of "painfully slow", not a |
| 23 | +# safety net — the big ggml-vulkan.cpp TU peaks ~5G and a 5G MemoryHigh throttled it |
| 24 | +# into a full swap mid-compile (thrash). So: floor the ceiling at 6G so that TU runs |
| 25 | +# un-throttled, give the cgroup most of free RAM (keep a ~2.5G host buffer), and scale |
| 26 | +# -j to the ceiling so the ~300 shader-wrapper TUs build in parallel. MemoryMax stays |
| 27 | +# a HARD host-protective cap — overflow kills the build cgroup, never the host. |
| 28 | +avail=$(awk '/MemAvailable/{print int($2/1024)}' /proc/meminfo) # MiB |
| 29 | +load=$(cut -d' ' -f1 /proc/loadavg) |
| 30 | +if [ "$avail" -lt 3000 ]; then |
| 31 | + echo "[build-vk] ABORT: <3000MiB available — free memory before building." >&2 |
| 32 | + exit 1 |
| 33 | +fi |
| 34 | +cap_mib=$(( avail - 2560 )) # keep host buffer |
| 35 | +[ "$cap_mib" -lt 6144 ] && cap_mib=6144 # big TU needs ~5G |
| 36 | +[ "$cap_mib" -gt 11264 ] && cap_mib=11264 # cap at 11G |
| 37 | +high_mib=$(( cap_mib - 1536 )) |
| 38 | +jobs=$(( cap_mib / 2048 )) # ~1 job / 2G ceiling |
| 39 | +[ "$jobs" -lt 1 ] && jobs=1 |
| 40 | +maxj=$(( $(nproc) - 1 )); [ "$jobs" -gt "$maxj" ] && jobs=$maxj |
| 41 | + |
| 42 | +CUDA_FLAGS="-DGGML_CUDA=OFF" |
| 43 | +if [ "${WITH_CUDA:-0}" = "1" ]; then |
| 44 | + CUDA_FLAGS="-DGGML_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=61" # GTX1070 = sm_61 |
| 45 | +fi |
| 46 | +# CUDA TUs are RAM-heavy: force conservative parallelism regardless of cap_mib |
| 47 | +[ "${WITH_CUDA:-0}" = "1" ] && jobs=2 |
| 48 | + |
| 49 | +CAP=(systemd-run --user --scope --quiet |
| 50 | + -p MemoryMax=${cap_mib}M -p MemoryHigh=${high_mib}M -p CPUQuota=700%) |
| 51 | +echo "[build-vk] pre-flight: avail=${avail}MiB load=${load} -> MemoryMax=${cap_mib}M MemoryHigh=${high_mib}M -j${jobs} target=${TARGET}" |
| 52 | + |
| 53 | +# Wipe a stale CMakeCache when switching from CUDA OFF → ON (reconfigure needed). |
| 54 | +if [ "${WITH_CUDA:-0}" = "1" ] && [ -f "$BUILD/CMakeCache.txt" ] && ! grep -q "GGML_CUDA:BOOL=ON" "$BUILD/CMakeCache.txt"; then |
| 55 | + echo "[build-vk] reconfiguring for CUDA (wiping stale CMakeCache)…"; rm -f "$BUILD/CMakeCache.txt" |
| 56 | +fi |
| 57 | + |
| 58 | +# Configure once: Vulkan ON, CUDA per WITH_CUDA flag. |
| 59 | +if [ ! -f "$BUILD/CMakeCache.txt" ]; then |
| 60 | + echo "[build-vk] configuring (${CUDA_FLAGS}, Vulkan ON, Ninja)…" |
| 61 | + "${CAP[@]}" cmake -S "$REPO" -B "$BUILD" -G Ninja \ |
| 62 | + -DCMAKE_BUILD_TYPE=Release \ |
| 63 | + -DGGML_VULKAN=ON ${CUDA_FLAGS} -DGGML_NATIVE=ON -DLLAMA_CURL=OFF |
| 64 | +fi |
| 65 | + |
| 66 | +echo "[build-vk] building target '${TARGET}' (capped: MemoryMax=${cap_mib}M, -j${jobs})…" |
| 67 | +"${CAP[@]}" cmake --build "$BUILD" -j${jobs} --target "$TARGET" |
| 68 | +echo "[build-vk] done: $BUILD/bin/${TARGET}" |
0 commit comments