在旧的Mali Vulkan驱动上成功运行Llama.cpp
Jetson Tan | 12 Jul 2026
Warning: 自2026/8/20起, 本文已无法复现!
大多数人在旧手机上运行Llama.cpp时都选择使用CPU后端, 因为它最稳定, 且性能也不错. 然而GPU更适合大模型推理, 还有Vulkan这样的高效推理API, GPU在安卓的特殊环境中却难以利用. 有了Llama.cpp-For-AArch64这个项目, 在旧手机上利用GPU成为了可能.
本文将带领读者走完碰壁->调试/反汇编->跑通的全流程, 并将成果发布于上述的Github仓库中.
一些准备
首先, 下载 Termux. 然后运行以下命令(换源和setup storage自己处理):
现在应该能看见GPU型号.
初见错误
如果你按照官方文档编译Llama.cpp并运行, 可能会遇到这样的报错:
即程序访问了非法内存且api版本低, 由于CPU后端没有此类问题, 所以猜测Vulkan驱动还有未实现函数, 即"骗子驱动".
现在有几种解决办法:
- 手动替换驱动文件(需要root)
- 让Llama.cpp无视apiVersion
- 卸载Termux, 然后嘤嘤嘤
由于我没有root权限, 而且不爱哭, 所以选择第二种办法.
把6725行的if逻辑删掉即可, 重新编译
再次报错
重新运行之后, 确实没有apiVersion的错误了, 但依旧报出Segmentation fault. 尝试用GDB调试一下, 结果如下:
不难看出问题出在ggml_vk_create_buffer(), 所以就回到ggml/src/ggml-vulkan/ggml-vulkan.cpp看看情况.
深入源码
搜到了下面的代码片段:
由此可以猜测bda_addr就是解决问题的关键, 先去查查驱动
反汇编vulkan驱动
在反汇编之前, 可以先用nm查一下导出表:
大一统驱动libGLES_mali.so里没有vkGetBufferDeviceAddress, 而马甲驱动libvulkan.so里有. 骗子驱动实锤了. 再反汇编libvulkan.so看看:
可以看到libvulkan.so没有任何防御措施, 再去libGLES_mali.so里查证一下
libGLES_mali.so不语, 只是一味写入NULL. 一大堆没实现的函数, 只能考虑用低速方法来实现CPU和GPU之间的数据传输.
放弃Vulkan拓展
把buf->bda_addr设为0, 再次编译运行
成功!
一些结果及反思
llama-cli测试
| 模型体量 |
后端类型 |
Prompt 速度 |
Generation 速度 |
| 0.5b |
gpu |
3.5 t/s |
15.8 t/s |
| cpu |
37.2 t/s |
19.3 t/s |
| 1.5b |
gpu |
4.1 t/s |
6.8 t/s |
| cpu |
12.2 t/s |
8.5 t/s |
| 4b |
gpu |
1.1 t/s |
2.9 t/s |
| cpu |
2.5 t/s |
1.8 t/s |
8b (已撞 Swap 墙) |
gpu |
0.4 t/s |
1.6 t/s |
| cpu |
2.3 t/s |
1.6 t/s |
注: 根据进一步测试, CPU后端的prompt速度可以远超GPU后端. 但generation速度则会在多轮对话后被GPU反超(2倍).
llama-bench测试
由于I/O瓶颈和兼容操作, GPU性能并未得到充分发挥. 但至少与CPU相差不大. 若在旗舰机上运行, Mali GPU也许能超越CPU. 说实话, ARM最近放出来的新一代GPU "G1 Ultra" 还是很令人期待的.
我实际上有一个构想, 用mmap划一块RAM给GPU, 让GPU访问以降低I/O瓶颈.
值得一提的是, 用同样的方法修改OpenCL后端并不能成功, 因为没有适配Mali的OpenCL算子.
日后将尝试Adreno上的Vulkan/OpenCL后端, 以及MTK的APU和Qualcomm的Hexagon NPU.
回到主页