Add opencl support for llamacpp

This commit is contained in:
2026-07-09 15:31:47 +02:00
vanhempi 2ca14ce150
commit 178192bfe5
2 muutettua tiedostoa jossa 274 lisäystä ja 0 poistoa
+178
Näytä tiedosto
@@ -0,0 +1,178 @@
#!/usr/bin/env bash
###############################################################################
# build-mesa.sh
#
# Builda Mesa dal repository ufficiale upstream (gitlab.freedesktop.org),
# che su main contiene gia' il fix subgroup per Freedreno (commit
# 185c89084ab7 "freedreno/a6xx: Expose subgroup ops", non ancora presente in
# alcuna release stabile 26.1.x). Produce pacchetti .deb pronti da
# installare, salvati in ./deb/
#
# Nessun fork necessario: il fix e' gia' su main upstream.
#
# Uso:
# ./build-mesa.sh # clona main upstream in /tmp e builda
# ./build-mesa.sh /path/gia/clonato # usa un checkout gia' esistente
# ./build-mesa.sh <url-alternativo> # clona un repo/fork diverso, se serve
###############################################################################
set -euo pipefail
echo "=== Installazione dipendenze di build (primo step) ==="
sudo apt-get update
sudo apt-get build-dep -y mesa || {
echo "build-dep su pacchetto 'mesa' fallito o non disponibile, installo un set minimo esplicito."
sudo apt-get install -y \
git meson ninja-build pkg-config python3-mako python3-pip \
libdrm-dev libx11-dev libxext-dev libxfixes-dev libxcb1-dev \
libxcb-glx0-dev libxxf86vm-dev libxrandr-dev libwayland-dev \
wayland-protocols llvm-dev clang libclc-dev spirv-tools \
libspirv-tools-dev rustc cargo libelf-dev libzstd-dev \
libexpat1-dev bindgen cbindgen dpkg-dev debhelper devscripts
}
echo
UPSTREAM_URL="https://gitlab.freedesktop.org/mesa/mesa.git"
ARG="${1:-}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEB_OUT_DIR="${SCRIPT_DIR}/deb"
# Determina se l'argomento e' un path esistente o un URL alternativo da clonare
if [ -n "${ARG}" ] && [ -d "${ARG}/.git" ]; then
MESA_SRC="${ARG}"
echo "=== Uso checkout gia' esistente: ${MESA_SRC} ==="
elif [ -n "${ARG}" ]; then
# argomento passato ma non e' una dir .git valida: trattalo come URL alternativo
CLONE_URL="${ARG}"
else
CLONE_URL="${UPSTREAM_URL}"
fi
if [ -z "${MESA_SRC:-}" ]; then
CLONE_DIR="/tmp/mesa-$(date +%Y%m%d-%H%M%S)"
echo "=== Clono ${CLONE_URL} in ${CLONE_DIR} ==="
git clone "${CLONE_URL}" "${CLONE_DIR}"
MESA_SRC="${CLONE_DIR}"
fi
BUILD_DIR="${MESA_SRC}/build-deb"
LOG_FILE="/tmp/build-mesa-$(date +%Y%m%d-%H%M%S).log"
echo "=== build-mesa.sh ==="
echo "Sorgente Mesa: ${MESA_SRC}"
echo "Output .deb: ${DEB_OUT_DIR}"
echo "Build dir: ${BUILD_DIR}"
echo "Log: ${LOG_FILE}"
echo
echo "=== Verifica commit fix subgroup presente ==="
mkdir -p "${DEB_OUT_DIR}"
cd "${MESA_SRC}"
if git log --oneline | grep -q "185c89084ab7\|Expose subgroup ops"; then
echo "OK: commit fix subgroup trovato nella history."
else
echo "ATTENZIONE: non trovo il commit atteso nella history di questo checkout." >&2
echo "Verifica di essere sul branch/commit giusto prima di continuare." >&2
read -p "Continuare comunque? [y/N] " -n 1 -r
echo
[[ $REPLY =~ ^[Yy]$ ]] || exit 1
fi
echo
echo "=== Build Mesa (meson/ninja) ==="
rm -rf "${BUILD_DIR}"
meson setup "${BUILD_DIR}" "${MESA_SRC}" \
-Dprefix=/usr \
-Dgallium-drivers=freedreno \
-Dvulkan-drivers= \
-Dgallium-rusticl=true \
-Dgallium-rusticl-enable-drivers=freedreno \
-Dopencl-spirv=true \
-Dbuildtype=release \
2>&1 | tee -a "${LOG_FILE}"
ninja -C "${BUILD_DIR}" 2>&1 | tee -a "${LOG_FILE}"
echo
echo "=== Packaging .deb ==="
# Se il repo ha tooling Debian (cartella debian/), usalo.
if [ -d "${MESA_SRC}/debian" ]; then
echo "Trovata cartella debian/, uso dpkg-buildpackage."
cd "${MESA_SRC}"
dpkg-buildpackage -us -uc -b 2>&1 | tee -a "${LOG_FILE}"
# dpkg-buildpackage mette i risultati nella dir padre di MESA_SRC
find "$(dirname "${MESA_SRC}")" -maxdepth 1 -name "*.deb" -newer "${LOG_FILE}" \
-exec cp -v {} "${DEB_OUT_DIR}/" \;
else
echo "Nessuna cartella debian/ trovata: creo un pacchetto .deb minimale"
echo "con i soli file installati dalla build (DESTDIR + fpm/dpkg-deb)."
DESTDIR="${BUILD_DIR}/install-root"
rm -rf "${DESTDIR}"
DESTDIR="${DESTDIR}" ninja -C "${BUILD_DIR}" install 2>&1 | tee -a "${LOG_FILE}"
PKG_ROOT="${BUILD_DIR}/deb-pkg"
PKG_NAME="mesa-freedreno-subgroups"
PKG_VERSION="26.2.0-devel+subgroups1"
PKG_ARCH="arm64"
PKG_DIR="${PKG_ROOT}/${PKG_NAME}_${PKG_VERSION}_${PKG_ARCH}"
rm -rf "${PKG_ROOT}"
mkdir -p "${PKG_DIR}/DEBIAN"
cp -a "${DESTDIR}/usr" "${PKG_DIR}/"
cat > "${PKG_DIR}/DEBIAN/control" << EOF
Package: ${PKG_NAME}
Version: ${PKG_VERSION}
Section: libs
Priority: optional
Architecture: ${PKG_ARCH}
Maintainer: local-build
Description: Mesa build from local fork with Freedreno subgroup support
Build locale da fork Mesa (commit 185c89084ab7 "freedreno/a6xx: Expose
subgroup ops", non ancora presente in alcuna release stabile 26.1.x,
disponibile solo su trunk verso 26.2).
.
Sostituisce i file installati da mesa-libgallium / mesa-opencl-icd
di Debian con la build patchata. Da usare solo per test.
EOF
cat > "${PKG_DIR}/DEBIAN/README-patch.md" << 'EOF'
# Nota sulla patch inclusa
Commit: 185c89084ab7 "freedreno/a6xx: Expose subgroup ops"
Autore: upstream Mesa (author date 2026-02-11, committer/merge date 2026-05-18)
Motivo assenza in Debian: il branch stabile 26.1 e' stato diramato da main il
2026-04-14 (tag mesa-26.1.0 il 2026-05-06), quindi questo fix e' arrivato su
main DOPO la diramazione. Essendo una feature (non un bugfix), non verra'
backportato al branch 26.1.x per policy standard di Mesa. Il fix esiste solo
su trunk, verso la futura 26.2.
Verificato (vedi indagine precedente):
- Nessuna dipendenza da ioctl/kernel driver msm: i campi
shader_subgroup_supported_features / max_subgroups / subgroup_sizes sono
popolati da tabelle statiche compilate (freedreno_devices.py).
- Nessuna condizione che esclude a690 (FD690 e' CHIP.A6XX).
- Nessun commit successivo modifica subgroup/ballot/shuffle in freedreno tra
questo fix e HEAD: e' completo e autosufficiente, non un WIP parziale.
Questo pacchetto installa i file prodotti da una build meson/ninja pulita
di questo checkout, con gallium-drivers=freedreno e rusticl abilitato per
freedreno. Non tocca Vulkan/Turnip.
EOF
dpkg-deb --build --root-owner-group "${PKG_DIR}" "${DEB_OUT_DIR}/${PKG_NAME}_${PKG_VERSION}_${PKG_ARCH}.deb"
fi
echo
echo "=== Contenuto pacchetto/i .deb prodotti ==="
for deb in "${DEB_OUT_DIR}"/*.deb; do
[ -e "${deb}" ] || continue
echo "--- ${deb} ---"
dpkg -c "${deb}"
echo
done
echo "=== Fatto ==="
echo "Pacchetti .deb disponibili in: ${DEB_OUT_DIR}"
echo "Log completo: ${LOG_FILE}"
@@ -0,0 +1,96 @@
### LLaMACpp Builder Container with OpenCL for Qualcomm Adreno GPUs
### Build from source with GGML_OPENCL=ON since no official Linux OpenCL release exists
###
### BUILD: podman build -t llamacpp:opencl-arm64 -f llamacpp-opencl.Containerfile .
### Export: podman save -o /home/badstorm/llamacpp-opencl-arm64.tar localhost/llamacpp:opencl-arm64
FROM debian:13-slim
USER root
EXPOSE 8090
# Copia il/i pacchetto/i .deb con la Mesa patchata (fix subgroup Freedreno,
# commit 185c89084ab7, non presente in alcuna release Debian/backports).
# Generati da build-mesa.sh nella sottocartella ./deb accanto a questo file.
COPY deb/*.deb /tmp/mesa-deb/
RUN apt-get update \
&& apt-get install -y curl tar grep sed git ffmpeg nano python3-pip python3 python3-wheel \
ocl-icd-libopencl1 \
# Installa la Mesa patchata locale (fornisce mesa-opencl-icd / mesa-libgallium
# equivalenti, con il fix subgroup). Se il .deb ha dipendenze non risolte,
# il secondo apt-get -f install le completa dai repo standard.
&& (dpkg -i /tmp/mesa-deb/*.deb || true) \
&& apt-get install -y -f \
&& rm -rf /tmp/mesa-deb \
&& pip install --break-system-packages --upgrade setuptools \
&& pip install --break-system-packages -U "huggingface_hub[cli]" \
&& if [ -f requirements.txt ]; then pip install --break-system-packages -r requirements.txt; fi \
&& apt autoremove -y \
&& apt clean -y \
&& rm -rf /tmp/* /var/tmp/* \
&& rm -rf /var/lib/apt/lists/* \
&& find /var/cache/apt/archives /var/lib/apt/lists -not -name lock -type f -delete \
&& find /var/cache -type f -delete
WORKDIR /build
RUN git clone --depth 1 https://github.com/ggml-org/llama.cpp
# --- PATCH: riconosci device Rusticl/Freedreno (es. "FD690") come Adreno ---
# Il backend OpenCL controlla dev_ctx->device_name cercando le stringhe
# "Adreno" o "Qualcomm" (vedi ggml_opencl_is_device_supported in
# ggml/src/ggml-opencl/ggml-opencl.cpp). Il driver Mesa/Rusticl riporta pero'
# il device come "FD690" (Freedreno + numero modello), non "Adreno 690", quindi
# il controllo fallisce e il device viene scartato con "unsupported GPU".
# Questa patch resta necessaria SEMPRE, indipendentemente dalla versione Mesa,
# perche' riguarda solo il nome con cui Rusticl si presenta, non le capability
# del device. Aggiungiamo il pattern "FD6" (copre la serie Adreno 6xx via
# Freedreno) alla condizione che marca il device come GPU_FAMILY::ADRENO.
#
# NOTA: la patch precedente che bypassava il controllo "does not support
# subgroups" NON e' piu' necessaria ne' presente qui: con la Mesa patchata
# (vedi deb/ - fix upstream "freedreno/a6xx: Expose subgroup ops") il device
# dichiara realmente cl_khr_subgroups, quindi il controllo originale del
# codice passa senza bisogno di bypass. Se in futuro si torna a una Mesa
# senza quel fix, il controllo tornera' a scartare il device correttamente
# (comportamento voluto: meglio un fallback esplicito che un bypass silente).
RUN cd llama.cpp \
&& grep -n 'strstr(dev_ctx->device_name.c_str(), "Adreno")' ggml/src/ggml-opencl/ggml-opencl.cpp \
&& sed -i \
's/strstr(dev_ctx->device_name.c_str(), "Adreno") ||/strstr(dev_ctx->device_name.c_str(), "Adreno") ||\n strstr(dev_ctx->device_name.c_str(), "FD6") ||/' \
ggml/src/ggml-opencl/ggml-opencl.cpp \
&& grep -n -A5 'strstr(dev_ctx->device_name.c_str(), "Adreno")' ggml/src/ggml-opencl/ggml-opencl.cpp
RUN cd llama.cpp \
&& mkdir build && cd build \
&& cmake .. -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DGGML_OPENCL=ON \
-DGGML_OPENCL_EMBED_KERNELS=ON \
-DGGML_OPENCL_USE_ADRENO_KERNELS=ON \
-DBUILD_SHARED_LIBS=ON \
&& cmake --build . --config Release -j$(nproc)
# Copy the built binaries and libraries into /app, matching the layout the runtime expects
RUN mkdir -p /app \
&& find /build/llama.cpp/build/bin -maxdepth 1 -type f -exec cp {} /app/ \; \
&& find /build/llama.cpp/build -maxdepth 3 -iname "*.so*" -exec cp -P {} /app/ \; \
&& chmod +x /app/llama-server \
&& rm -rf /build
WORKDIR /app
ENV PATH=/app:$PATH
ENV LD_LIBRARY_PATH=/app:$LD_LIBRARY_PATH
ENV HF_HUB_ENABLE_HF_TRANSFER=1
ENV LLAMA_ARG_HOST=0.0.0.0
ENV LLAMA_ARG_PORT=8090
ENV LLAMA_ARG_HF_REPO=unsloth/Qwen3.5-35B-A3B-GGUF:Q2_K_XL
ENV LLAMA_ARG_NO_MMAP=true
ENV LLAMA_ARG_CTX_SIZE=128000
# Adreno-specific: make sure Rusticl/OpenCL device is picked correctly
ENV GGML_OPENCL_PLATFORM=0
ENV GGML_OPENCL_DEVICE=0
# NECESSARIA: senza questa, Rusticl carica la piattaforma OpenCL ma con 0
# device (il driver Freedreno non viene attivato). Con questa variabile
# clinfo/ggml_opencl vedono correttamente il device Adreno (es. FD690).
ENV RUSTICL_ENABLE=freedreno
ENTRYPOINT ["/app/llama-server"]
CMD ["--no-warmup"]