llama.cpp 启用 Vulkan 后端:编译与测试工作记录

日期:2026-08-23
机器:Deepin(glibc 2.28 / GCC 8.3 / CMake 3.22)· AMD Cezanne 核显(RADV RENOIR)
结论先行:编译成功、GPU 可用。提示处理提速 2.2 倍,逐 token 生成略慢于 CPU。


1. 任务目标

在本机 llama.cpp(llama.cpp,build 10470 / 34af94cd9)启用 Vulkan 后端,
并与纯 CPU 做简单会话及 token 输出速度对比。

2. 初始环境评估

检查项 结果 判定
GPU 04:00.0 VGA AMD/ATI Cezanne,amdgpu 驱动已加载
Vulkan 运行时 RADV RENOIR 正确枚举,API 1.2.195,UMA 8G
Vulkan Loader /usr/lib/x86_64-linux-gnu/libvulkan.so 存在
glslc 无(仅 2019 年 glslangValidator 7.10)
SPIRV-Headers 系统 2019 版且无 CMake config 文件
CMake ≥3.25 本地 3.22.1
LunarG SDK 预编译包 官方只提供 Ubuntu 20.04+ 构建,glibc 2.28 跑不起来 ❌ 放弃

关键源码确认(动手前必做):ggml-vulkan.cpp 仅在 api_version < VK_API_VERSION_1_2 时退出,
1.3 特性全部是 #if VK_HEADER_VERSION >= 235 条件编译 → 运行时只需 Vulkan 1.2,本机满足

3. 最终方案(全部无需 sudo,GitHub 走 ghfast.top 镜像)

~/vulkan-local 组装用户级工具链:

  1. Kitware 独立版 CMake 3.31.6(官方为老 glibc 构建,2.28 兼容)
  2. 源码编译 shaderc → glslc
    • 克隆 shaderc v2022.2 + 三个 third_party 依赖(depth=1)
    • commit 必须按 shaderc 的 DEPS 文件锁定,不能随意配 tag(见教训 §5.4)
    • cmake -DSHADERC_SKIP_TESTS=ON … && make -j12 glslc_exe
  3. Vulkan-Headers(最新 v360)+ SPIRV-Headers 各自 cmake install 到 ~/vulkan-local
  4. 用新 CMake 配置 llama.cpp:
    export VULKAN_SDK=/home/john/vulkan-local PATH=$VULKAN_SDK/bin:$PATH
    cmake -B build -DGGML_VULKAN=ON -DGGML_NATIVE=ON
    cmake --build build -j12 --target llama-bench llama-completion
    
  5. 纯 CPU 对照版:cmake -B build-cpu -DGGML_VULKAN=OFF

产物:

  • ~/vulkan-local/bin/glslc(shaderc v2022.2,配套 glslang/SPIRV-Tools commit 与 DEPS 一致)
  • llama.cpp/build/bin/libggml-vulkan.so.0.20.1(35MB,含全部预编译 shader)

4. 测试结果(qwen2.5-0.5B Q4_K_M · 8 线程 · 3 次均值)

llama-bench -m qwen2.5-0.5b-instruct-q4_k_m.gguf -t 8 -p 256 -n 128 -r 3 [-ngl 99]
后端 pp256 提示处理 tok/s tg128 逐 token 生成 tok/s
纯 CPU 322.7 ±12.1 63.0 ±10.8
Vulkan ngl=0(零拷贝) 578.6 ±7.0 58.5 ±1.3
Vulkan ngl=99(全 GPU) 716.9 ±36.1(+122% 51.0 ±4.0(−19%)

设备日志:AMD RADV RENOIR | uma: 1 | fp16: 1 | int dot: 0 | matrix cores: none

解读

  • 长提示(prefill,算力瓶颈型):GPU 全量 offload 快 2.2 倍 ✅
  • 逐 token(decode,带宽瓶颈型):UMA 共享内存带宽无优势,叠加老 RADV 缺 int dot/coopmat,
    量化矩阵走慢速 fp16 路径 → 反而略慢 ⚠️ 升级 Mesa ≥23.x 有望改善
  • 会话功能验证正常:"The capital of France is" → "Paris"

可用工具:llama-bench、llama-completion。
llama-cli / llama-server 编不过(GCC8 CTAD bug,见 §5.3)。

5. 经验教训(本次踩坑全记录)

5.1 检测方法错误导致误判

早期用 vulkaninfo | grep "Device Name" 得到空输出,误判"GPU 未被 Vulkan 识别"。
实际是 grep 模式写错——vulkaninfo 全量输出里明明有 deviceName = AMD RADV RENOIR

教训:验证"不支持"之前,先怀疑自己的检测命令。

5.2 手工伪造 CMake config 是死路

系统 spirv-headers 不带 SPIRV-HeadersConfig.cmake,曾尝试手写假 config 骗过 find_package。
即便能过配置阶段,后面 shader 编译仍需要真正的 glslc + 新版 headers,必然失败。

教训:缺依赖就补齐真依赖(或源码自建),不要伪造包元数据绕过。

5.3 GCC 8.3 的 CTAD bug 无法低成本绕过

tools/server/server-schema.* 有 30+ 处 new field_num(...) 类模板推导。
GCC8 对"类模板含默认成员初始化器(T min = std::numeric_limits<T>::lowest())"不生成推导指引;
实测显式加 deduction guide 也无效。上游本就要求新编译器。

教训:老编译器编新代码,先看上游 CI 的最低版本要求;修不动就换目标
(本次改用不依赖 server 的 llama-completion / llama-bench)。

5.4 shaderc 依赖必须按 DEPS 锁 commit

首次用 glslang tag 11.13.0 + SPIRV-Tools tag sdk-1.3.224.1 组合,编译即报
CreateAggressiveDCEPass 签名不匹配 等 API 冲突。改为 checkout shaderc DEPS
中锁定的三个精确 commit 后一次通过。

教训:多仓库联动的项目(shaderc/glslang/SPIRV-Tools)版本必须同源锁定,
单独选 tag 大概率 API 错位。

5.5 其他小坑

  • make glslc 只编了静态库,可执行目标名是 glslc_exe
  • grep … | head -N 提前退出会给 make 发 SIGPIPE 中断构建 → 长构建日志落盘再看
  • zsh 里 echo ===xxx=== 触发 =word 展开报错
  • 首次 GPU 推理很慢是 shader 编译预热,属正常现象,别误判为后端故障
  • UMA 核显上 ngl=0 时调度器仍把算子给 GPU(backend 列显示 Vulkan),
    要拿真 CPU 基线必须另建一份 GGML_VULKAN=OFF 的构建,而不是 -ngl 0
  • sudo 不可用的环境:apt / 写 /usr 都不行,方案设计从一开始就要走"用户级 prefix"路线

6. 复现步骤速查

# 0) 目录
mkdir -p ~/vulkan-build && cd ~/vulkan-build

# 1) CMake 3.31.6(ghfast.top 加速,免代理)
aria2c -x8 -o cmake.tar.gz "https://ghfast.top/https://github.com/Kitware/CMake/releases/download/v3.31.6/cmake-3.31.6-linux-x86_64.tar.gz"
tar xzf cmake.tar.gz

# 2) shaderc 及依赖(commit 按 DEPS 锁定)
git clone --depth 1 --branch v2022.2 https://ghfast.top/https://github.com/google/shaderc.git
cd shaderc/third_party
git clone --depth 1 https://ghfast.top/https://github.com/KhronosGroup/glslang.git
git clone --depth 1 https://ghfast.top/https://github.com/KhronosGroup/SPIRV-Tools.git spirv-tools
git clone --depth 1 https://ghfast.top/https://github.com/KhronosGroup/SPIRV-Headers.git spirv-headers
cd .. && git fetch --depth 1 origin f771c1293dce29e1ac3557cf994169136155c81f -q # glslang
(cd third_party/glslang      && git checkout -q FETCH_HEAD)
(cd third_party/spirv-tools  && git fetch --depth 1 origin 3a8a961cffb7699422a05dcbafdd721226b4547d -q && git checkout -q FETCH_HEAD)
(cd third_party/spirv-headers&& git fetch --depth 1 origin 0bcc624926a25a2a273d07877fd25a6ff5ba1cfb -q && git checkout -q FETCH_HEAD)
/usr/bin/cmake -B build -DCMAKE_BUILD_TYPE=Release -DSHADERC_SKIP_TESTS=ON \
  -DSHADERC_SKIP_EXAMPLES=ON -DSPIRV_SKIP_TESTS=ON -DENABLE_CTEST=OFF
make -C build -j12 glslc_exe && mkdir -p ~/vulkan-local/bin && cp build/glslc/glslc ~/vulkan-local/bin/

# 3) 两套头文件
NC=$HOME/vulkan-build/cmake-3.31.6-linux-x86_64/bin/cmake
for d in ~/vulkan-build/shaderc/third_party/spirv-headers <Vulkan-Headers克隆目录>; do
  (cd $d && $NC -B b -DCMAKE_INSTALL_PREFIX=$HOME/vulkan-local >/dev/null && $NC --install b)
done

# 4) llama.cpp
export VULKAN_SDK=$HOME/vulkan-local PATH=$VULKAN_SDK/bin:$PATH
cd llama.cpp
$NC -B build -DGGML_VULKAN=ON -DGGML_NATIVE=ON
$NC --build build -j12 --target llama-bench llama-completion

# 5) 测试(LD_LIBRARY_PATH 必须)
LD_LIBRARY_PATH=build/bin ./build/bin/llama-completion -m <model.gguf> -p "hi" -n 64 --device Vulkan0

7. 遗留事项

posted @ 2026-08-23 11:24  jiftle  阅读(2)  评论(0)    收藏  举报