Llama.cpp配置文档
现在需要配置使用vscode用于调试llama.cpp代码 在本地机(x86)使用交叉编译产生客户端(arm)的二进制文件 需要的工具以及操作顺序 1. 本地安装vscode 2. 本地安装cmake 3. 下载ndk 4. 下载llama.cpp源码 5. 配置vscode的llama.cpp项目完成调试功能
本地安装vscode
vscode官方地址
安装插件:cmake,codelldb,c/c++(没有也行,但是这个很常用)

本地安装cmake
下载ndk
下载源码
配置llama.cpp工程
在服务器端配置(有手机设备连接)
为了实现在服务器上编译,调试,需要按照以下步骤进行 1. 代码文件放在手机的/data/local/tmp/文件夹下 2. lldb-server放在/data/local/tmp/文件夹下(这个文件可以在~/android-ndk-r28-linux/android-ndk-r28/toolchains/llvm/prebuilt/linux-x86_64/lib/clang/19/lib/linux/aarch64的路径下找到,这条信息只是为了方便更新文件所作提示(如有必要)) 接下来请按照步骤进行:
step 1 生成makefile
方式一:直接使用命令:
直接运行下面这条命令可以生成makefile,相关的配置文件在build-android文件夹下 请修改为你的CMAKE_TOOLCHAIN_FILE为你的ndk下的toolchain路径
cmake \
-DCMAKE_TOOLCHAIN_FILE=
~/Android/Sdk/ndk/28.0.12674087/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=arm64-v8a \
-DANDROID_PLATFORM=android-28 \
-DCMAKE_C_FLAGS="-march=armv8.7a" \
-DCMAKE_CXX_FLAGS="-march=armv8.7a" \
-DGGML_OPENMP=OFF \
-DGGML_LLAMAFILE=OFF \
-B build-android
${系统的ndk编译工具链地址}
方式二:使用vscode搭配CMakePreset.json
这里是CMakePresets.json的一个示例,编译后的文件在"binaryDir": "${sourceDir}/out/build/${presetName}"
{
"version": 4,
"configurePresets": [
{
"name": "NDK-cross-compile",
"displayName": "NDK",
"description": "make",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_TOOLCHAIN_FILE": "~/Android/Sdk/ndk/28.0.12674087/build/cmake/android.toolchain.cmake",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
"CMAKE_C_FLAGS": "-march=armv8.7a",
"CMAKE_CXX_FLAGS": "-march=armv8.7a",
"GGML_OPENMP": "OFF",
"GGML_LLAMAFILE": "OFF",
"ANDROID_ABI": "arm64-v8a",
"ANDROID_PLATFORM": "android-28"
}
}
]
}
step 2 生成二进制文件
如果之前使用命令行形式,那么使用下面这条命令
如果使用vscode配置图形化命令 点这里:
最终生成的二进制文件在out/build/ndk/bin下
step 3 将生成的二进制文件传送到手机设备
step 4 调试代码
如果需要运行代码,直接到设备端对应的目录下运行二进制文件 现在想要提供一个图形界面的调试方式 具体原理是lldb-server监控设备端程序运行并把信息发送给主机端,主机端使用codelldb以提供图形界面
step4.1
首先需要写一个launch.json脚本以便在程序运行时连接到设备端并将lldb附加到程序上("./vscode/launch.json")
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "lldb launch",
"program": "/data/local/tmp/workspace/ndk/bin/llama-cli",
"args": [
"-m",
"/data/local/tmp/ggml-model-q4_0.gguf"
],
"preLaunchTask": "build task",
"initCommands": [
"platform select remote-android",
"platform connect connect://localhost:9090",
"settings set target.inherit-env false",
"platform settings -w /data/local/tmp/",
"platform status"
],
"env": {
"LD_LIBRARY_PATH": "/data/local/tmp/workspace/ndk/bin"
}
}
]
}
step 4.2
接着写一个tasks.json(./vscode/tasks.json)用于配置前置任务
{
"version": "2.0.0",
"tasks": [
{
"label": "build task",
"type": "shell",
"command": "bash debug.sh"
}
]
}
step 4.3
tasks.json运行debug.sh中的命令用于执行前置任务(./debug.sh),接下来写一个debug.sh
#!/bin/bash
# adb push /home/gyh/llama-test/llama.cpp-b3173/out/build/* /data/local/tmp/workspace/
adb forward tcp:9090 tcp:9090
# adb shell "cd /data/local/tmp && ./data/local/tmp/lldb-server platform --server --listen '*:9090'"
gnome-terminal -- bash -c "adb shell 'cd /data/local/tmp && ./lldb-server platform --listen *:9090 --server'"
之后可以在run and debug界面选择设置的登陆调试进行图形化调试

在本地端配置(没有手机设备连接)
首先参照前文在本地配置好编译出二进制文件[step 2 生成二进制文件]这一节
step 1 安装qemu
请安装qemu,官方有一个教程 这里有一个qemu官方关于sve特性的说明可以参考
修改cmakepresets.json如下
{
"name": "ndk",
"displayName": "NDK",
"description": "使用NDK工具链交叉编译",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_TOOLCHAIN_FILE": "~/Android/Sdk/ndk/29.0.13113456/build/cmake/android.toolchain.cmake",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
"CMAKE_C_FLAGS": "-march=armv8.7a+sve+sve2 -g -static",
"CMAKE_CXX_FLAGS": "-march=armv8.7a+sve+sve2 -g -static",
"GGML_OPENMP":"OFF",
"GGML_LLAMAFILE":"OFF",
"BUILD_SHARED_LIBS":"OFF",
"ANDROID_ABI": "arm64-v8a",
"ANDROID_PLATFORM": "android-35"
}
}
请修改toolchain路径为你本机安装路径 这里关闭共享库的构建,以便于构建静态二进制文件
用户模式运行llama-cli的命令,-m 后是你的模型地址。
可以使用相同的格式运行其他二进制文件。本地可以验证你的代码运行是否正常,如果想要在本地调试运行,请自行搜索qemu的调试教程,qemu提供了一套调试接口。由于本次使用的是用户模式,并没有模拟cpu寄存器特性,所以想要观察特定的寄存器动作,仍然需要到设备端DEBUG。本地使用打印输出和断言判断即可。
测试性能
step1 编写测试脚本
编写监控脚本monitor.sh
#!/system/bin/sh
# monitor.sh
# 启动 llama-cli 并获取 PID
./llama.cpp-b3173/build-android/bin/llama-cli -m ./q4_0/ggml-model-Q4_0.gguf -p "what is the meaning of life" -n 128 &
PID=$!
# # 启动 simpleperf,监控 llama-cli 进程
# ./simpleperf stat -e cache-references,cache-references:u,cache-references:k \
# -e cache-misses,cache-misses:u,cache-misses:k,instructions \
# -p $PID &
./simpleperf record -g -o perf.data -p $PID & --dump
SIMPLEPERF_PID=$!
# 等待 llama-cli 进程结束
wait $PID
# 等待 simpleperf 结束(如果它还在运行)
wait $SIMPLEPERF_PID
# 在此时,llama-cli 和 simpleperf 都已经结束
echo "Monitoring finished, perf.data generated."
step2 推送monitor.sh到设备
运行脚本:
拉取perf.data文件:
step3 处理数据
使用ndk下的simpleperf文件夹下的工具处理数据 例如我的simpleperf地址是:~/Android/Sdk/ndk/28.0.12674087/simpleperf 代码中也附加有mysimpleperf以供使用
simpleperf report 生成报告
分析生成report.txt
"simpleperf report -i /sdcard/perf.data -o /sdcard/report.txt"
"simpleperf report -g -i /sdcard/perf.data -o /sdcard/report_g.txt"
生成调用关系图
simpleperf report -g --symfs . >report
生成report.html
python report_html.py -i ./perf.data -o ./perf.html
report.html示意:

火焰图: