ik_llama.cpp sweep-bench 输出格式演进:从 JSONL 转向 Markdown 表格的性能扫描基准
2026/9/19 13:07:31 网站建设 项目流程

ik_llama.cpp sweep-bench 输出格式演进:从 JSONL 转向 Markdown 表格的性能扫描基准

【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp

导读

本文围绕 ik_llama.cpp 仓库中 sweep-bench 性能扫描基准工具 的一次关键更新(PR #289)展开:该更新让 sweep-bench 与其他基准工具保持一致,以人类可读的 Markdown 表格形式边跑边输出结果,并将配套的绘图脚本从解析 JSONL 改为直接解析 Markdown 表格。读完本文,你将掌握 sweep-bench 的完整基准原理、全部命令行参数,以及如何把扫描结果一键绘制成「Prompt 处理 / Token 生成 vs 上下文长度」的性能曲线图。

一、背景:这次更新改了什么

PR #289(作者 saood06,2025-03-25,评审人 ikawrakow 审批通过)是一次聚焦的维护型改动,核心变更有三点:

  1. 输出格式对齐其他 bench 工具:sweep-bench 改为默认输出人类可读的 Markdown 表格,并且结果逐行实时打印("print results as they occur"),不再等到全部扫描结束才输出;
  2. 绘图脚本同步更新:Python 脚本从解析.jsonl文件改为基于 Markdown 表格生成图表;
  3. README 渲染修复:修正了文档格式,使其能在仓库中正确渲染。

从当前仓库源码看,这些改动已全部落地:--output-format参数同时支持jsonlmd两种取值(common/common.cpp),而绘图脚本中读取 JSONL 的代码段已被注释掉,改为用pd.read_csv解析 Markdown 表格(sweep-bench-plot.py)。

二、sweep-bench 是什么:按上下文长度逐窗扫描的基准工具

在深入输出格式之前,先理解 sweep-bench 的定位。官方 README 给出精确定义:

Benchmark the prompt processing and token generation performance ofik_llama.cppby doing a sweep over a whole context size and gathering performance metrics in each ubatch-sized window. Only a single token sequence is used.

它与llama-bench的本质区别在于:sweep-bench 不做全上下文平均,而是把整个上下文切成一个个 ubatch 大小的窗口,在每个窗口上分别测量性能,从而可视化"性能随上下文长度如何变化"——例如 KV cache 增大后 attention 退化导致的 prompt 处理速率下滑曲线。

2.1 基准扫描步骤

README 明确了每个窗口内的执行流程,与 sweep-bench.cpp 的主循环一一对应:

for each ubatch-sized window in context: 1. 生成 ubatch/4 个 token(不生成整个窗口以节省时间) 2. 测量生成性能(TG) 3. 从 KV cache 中移除已生成的 token 4. 准备一个 ubatch 大小的随机 token 批次 5. 处理该批次(PP) 6. 测量 prompt 处理性能

源码实现中,tg的默认值正是params.n_ubatch / 4(sweep-bench.cpp),与 README 所述一致;每个窗口会先测生成(llama_decode单 token 循环),再通过llama_kv_cache_seq_rm回卷 KV cache 后测 prompt 处理(sweep-bench.cpp)。对于需要 checkpoint 的模型(如部分 MLA/MoE 架构),还会用llama_state_seq_get_data/llama_state_seq_set_data保存并恢复序列状态,保证每次测量起点一致。

2.2 输出指标含义

README 定义了表格中每个指标的含义:

指标含义
PP每个 ubatch 的 prompt token 数(prompt tokens per ubatch)
TG每个 ubatch 的生成 token 数(generated tokens per ubatch)
N_KV当前 KV cache 大小
T_PPprompt 处理耗时(即首个 token 的时间)
S_PPprompt 处理速度((B*PP)/T_PPPP/T_PP
T_TG生成所有批次的总耗时
S_TG文本生成速度((B*TG)/T_TG

三、输出格式的两种形态:Markdown 表格与 JSONL

PR #289 之后,sweep-bench 通过--output-format参数在两种格式间切换,取值在 common/common.cpp 中解析:

--output-format FORMAT # 取值:table(默认)或 jsonl,等价取值 md / jsonl

源码中jsonlmd是互斥开关:--output-format jsonlsweep_bench_output_jsonl = true--output-format md则置回false(common/common.cpp)。

3.1 默认输出:Markdown 表格

默认(或显式--output-format md)时,程序在扫描开始前先打印一行配置摘要(n_kv_maxn_batchn_ubatchflash_attnn_gpu_layers、线程数),随后每测完一个窗口立即打印一行(sweep-bench.cpp 与 sweep-bench.cpp)。README 中的示例结果(-c 8704 -ub 512,Meta-Llama-3.2-3B-Instruct Q8_0):

| PP | TG | N_KV | T_PP s | S_PP t/s | T_TG s | S_TG t/s | |-------|--------|--------|----------|----------|----------|----------| | 512 | 128 | 0 | 1.100 | 465.51 | 2.311 | 55.38 | | 512 | 128 | 512 | 1.183 | 432.97 | 1.895 | 67.55 | | 512 | 128 | 1024 | 1.305 | 392.38 | 2.071 | 61.81 | ... | 512 | 128 | 8192 | 2.196 | 233.15 | 3.854 | 33.21 |

可以清晰看到:随着N_KV从 0 增长到 8192,S_PP(prompt 处理速度)从 465 t/s 逐步衰减到 233 t/s,这正是"性能随上下文长度变化"的可视化证据。

3.2 兼容保留:JSONL 输出

尽管 PR 将默认输出改为表格,JSONL 能力并未删除——README 明确说明--output-format jsonl可输出 JSONL 格式,每行一个 JSON 对象,携带完整的运行配置与测量值:

{"n_kv_max": 8704, "n_batch": 2048, "n_ubatch": 512, "flash_attn": 0, "n_gpu_layers": -1, "n_threads": 32, "n_threads_batch": 32, "pp": 512, "tg": 128, "n_kv": 0, "t_pp": 1.093814, "speed_pp": 468.086884, "t_tg": 1.780312, "speed_tg": 71.897514 } {"n_kv_max": 8704, "n_batch": 2048, "n_ubatch": 512, "flash_attn": 0, "n_gpu_layers": -1, "n_threads": 32, "n_threads_batch": 32, "pp": 512, "tg": 128, "n_kv": 512, "t_pp": 1.169302, "speed_pp": 437.868073, "t_tg": 1.897474, "speed_tg": 67.458099 }

对应源码位于 sweep-bench.cpp:无--sweep-memory时输出 14 个字段;开启后追加"rss_hwm_mib""vram_delta_mib"两个字段(不可用平台输出null)。

四、绘图脚本:从 JSONL 迁移到 Markdown 表格

PR 的核心配套变更在 sweep-bench-plot.py。该脚本用 pandas + matplotlib 把扫描结果画成两条曲线:

  1. Prompt Processing Performance Comparison:横轴 Context Length(tokens),纵轴 Prompt Processing Rate(t/s),输出performance_comparison_pp.png
  2. Token Generation Performance Comparison:横轴 n_kv,纵轴 Token Generation Rate(t/s),输出performance_comparison_tg.png

4.1 关键改动:解析目标换成了 Markdown

旧实现通过pd.read_json(jsonl_file, lines=True)逐文件读取 JSONL(该代码段现已被注释保留在脚本头部,sweep-bench-plot.py);新实现改为:

df_part = pd.read_csv(md_file, sep=r'\s*\|\s*', engine='python', header=0, skiprows=[1]) df_part = df_part.iloc[:, 1:-1] # 去掉 Markdown 分隔线产生的空列 df_part.columns = [col.strip() for col in df_part.columns] df_part = df_part.rename(columns={'N_KV': 'n_kv', 'S_PP t/s': 'speed_pp', 'S_TG t/s': 'speed_tg'})

要点:以\s*\|\s*作为列分隔符解析表格行,跳过第二行分隔线(skiprows=[1]),裁掉首尾空列后重命名,再统一转为数值类型(sweep-bench-plot.py)。

4.2 多组对比与误差棒

脚本支持一次传入多个 Markdown 文件做对比,并具备统计聚合能力:

  • label(即文件名)与n_kv分组,对speed_pp/speed_tg计算meanstd,用误差棒绘制(sweep-bench-plot.py);
  • 单次测量时 std 为 NaN,会被fillna(0)填充为 0;
  • 横轴刻度超过 16 个时自动隔一个抽稀(x_ticks = x_ticks[::2]),保证图面可读;
  • 每组数据用 rainbow 色系区分,PP 用圆形o、TG 用方形s标记。

典型用法是把基准输出重定向保存为 Markdown 文件,再交给脚本:

./llama-sweep-bench -m model.gguf -c 8192 -b 2048 -ub 512 > result.md python3 examples/sweep-bench/sweep-bench-plot.py result.md # 生成 performance_comparison_pp.png 与 performance_comparison_tg.png

五、完整使用指南与参数详解

5.1 基础用法

README 给出的最小可用命令:

./llama-sweep-bench -c 8704 -ub 512 -m models/Meta-Llama-3.2-3B-Instruct-Q8_0.gguf

print_usage中的等价示例为-m model.gguf -c 8192 -b 2048 -ub 512(sweep-bench.cpp)。工具由 examples/sweep-bench/CMakeLists.txt 构建,目标名为llama-sweep-bench

5.2 sweep-bench 专属参数

除通用gpt_params-m-c-b-ub-ngl-t-fa等)外,PR 相关与扫描控制的专属参数如下(sweep-bench.cpp,参数默认值见 common/common.h 与 common/common.h):

参数说明默认值
-nrep, --n-repetitions N每个上下文尺寸重复测量的次数(结果取均值)1
--sweep-stride N每隔 N 个扫描行测量一次(跳过中间窗口以省时间)1
--sweep-memory额外报告 RSS 高水位与采样的 VRAM 增量关闭
-wb, --warmup-batch测量前先跑一个预热批次关闭
--output-format FORMAT输出格式:table/md(默认)或jsonltable
--minilog精简日志,过滤模型加载等冗长输出关闭

几个值得注意的实现细节:

  • nrepsweep_stride在解析后会被钳制到至少 1(sweep-bench.cpp);
  • --sweep-stride N生效时,被跳过的窗口仍会推进 KV cache 与随机 token 流((void) std::rand()保持流对齐,sweep-bench.cpp),避免与 stride=1 的扫描结果产生系统性偏差;
  • --sweep-memory开启后:RSS 高水位通过getrusage读取ru_maxrss(macOS 需除以 1024²,Linux 除以 1024,sweep-bench.cpp),VRAM 增量通过ggml_backend_cuda_get_device_memory在 CUDA 下采样空闲显存差值(sweep-bench.cpp),非 CUDA 或数据不可用时输出n/a
  • 表格模式带--sweep-memory时会在右端追加RSS HWMVRAM delta两列(sweep-bench.cpp)。

5.3 结果的可重复性提示

README 指出基准只使用单条 token 序列("Only a single token sequence is used"),prompt 与生成 token 均由std::rand() % n_vocab生成(sweep-bench.cpp)。因此每次运行的具体 token 不同,但统计意义上的趋势一致;需要严格可比的数值时,应固定模型、量化格式、后端(-ngl-fa)与线程数,并优先使用-nrep取多次测量均值。

六、一次完整的性能扫描工作流

综合以上内容,一次规范的 sweep-bench 使用流程如下:

# 1. 构建(在 build 目录) cmake --build build --target llama-sweep-bench # 2. 以 Markdown 表格输出并保存(同时开启内存报告与预热) ./build/bin/llama-sweep-bench \ -m models/Meta-Llama-3.2-3B-Instruct-Q8_0.gguf \ -c 8704 -b 2048 -ub 512 -nrep 3 -wb --sweep-memory \ --output-format md > sweep_result.md # 3. 用绘图脚本生成性能曲线(可同时对比多组结果) python3 examples/sweep-bench/sweep-bench-plot.py sweep_result.md

若仍需机器可读的原始数据做二次分析,将--output-format md换成--output-format jsonl即可,两套格式在当前仓库中均可正常使用。

七、小结

PR #289 让 sweep-bench 完成了从"运行结束后一次性输出 JSONL"到"逐窗口实时输出 Markdown 表格"的转变,使基准过程对使用者透明可见,也让默认输出无需二次解析即可直接阅读或交给绘图脚本。当前仓库中:输出层双格式并存(--output-format jsonl|md,common/common.cpp),绘图层已完全迁移到 Markdown 表格解析(sweep-bench-plot.py),文档层则同步修复渲染(sweep-bench/README.md)。对于需要评估长上下文场景下 prompt 处理与生成性能衰减曲线的开发者,这套"扫描 + 表格 + 绘图"的组合是目前仓库中最直接的观测手段。

【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询