Download docs/KV_CACHE_BENCHMARK_20260922.md from Sariel00/Ling-3.0-tiny-RKNN: direct link, hf CLI and curl.
- Browser
- Download file 6.38 kB
-
https://huggingface.co/Sariel00/Ling-3.0-tiny-RKNN/resolve/main/docs/KV_CACHE_BENCHMARK_20260922.md
- Command line
-
hf download hf://Sariel00/Ling-3.0-tiny-RKNN/docs/KV_CACHE_BENCHMARK_20260922.md
-
curl -L -o KV_CACHE_BENCHMARK_20260922.md https://huggingface.co/Sariel00/Ling-3.0-tiny-RKNN/resolve/main/docs/KV_CACHE_BENCHMARK_20260922.md
RK3588 KV 缓存容量与长输入测试(2026-09-22)
后续 16K/64 复测、CPU/NPU 曲线和优化分析见 占用分析。
测试设备:NanoPi M6(RK3588,物理内存 15959 MiB,RKNPU 驱动 0.9.8),Ling3 v6 混合 W4A8/W8A8 权重。只比较 BF16 MLA KV 和 INT8 MLA KV(批量注意力采用原生 NPU INT8 矩阵乘,即此处的 W8A8 KV 路径);其他模型权重、KDA FP32 状态不变。FP16 仍保留为可选实验模式,不参与此表。
测试期间暂时停止 MindNano WebUI、OpenAI 适配服务、安卓视频桥、redroid 和 GNOME 会话;CPU 小核 1.8 GHz、大核 2.304/2.352 GHz,NPU 1 GHz,DMC 2.4 GHz,均固定最高频率。测试后恢复此前服务与调频设置。每一容量档独立启动服务,关闭历史会话快照和前缀检查点,以隔离模型及常驻 KV 内存。
上下文容量
RSS 是服务完成模型加载和预热时的进程常驻内存,已经包含该档 KV 容量;不是后续还要加上 KV 容量。KV 是按 6 层 MLA、每层 16 头计算的缓存字节数,BF16 每元素 2 字节,INT8 每元素 1 字节另加每 token/head 两个 FP32 scale。余量 是测量时系统的 MemAvailable,不是可供该服务独占的配额;RSS 也包含 NPU 共享映射。
| 上下文 | BF16 KV | BF16 启动 RSS | BF16 余量 | INT8 KV | INT8 启动 RSS | INT8 余量 |
|---|---|---|---|---|---|---|
| 8K | 480 MiB | 5750 MiB | 7006 MiB | 246 MiB | 5512 MiB | 7411 MiB |
| 16K | 960 MiB | 6230 MiB | 6482 MiB | 492 MiB | 5760 MiB | 7116 MiB |
| 32K | 1920 MiB | 7192 MiB | 5473 MiB | 984 MiB | 6253 MiB | 6570 MiB |
| 64K | 3840 MiB | 9115 MiB | 3642 MiB | 1968 MiB | 7242 MiB | 5583 MiB |
| 128K | 7680 MiB | 12457 MiB | 334 MiB | 3936 MiB | 9217 MiB | 3605 MiB |
| 256K | 15360 MiB | 约 19–21 GiB(推测,未启动) | 不适用 | 7872 MiB | 12745 MiB | 95 MiB |
BF16 128K 和 INT8 256K 虽完成初始化,但内存余量过低并观察到少量系统 swap 增长,不适合作为此设备的可靠工作档位;BF16 256K 明显超过 16GB,因此没有强行启动。INT8 256K 只是初始化成功,位置大于模型原生 128K 尚未验证质量,不能算作 256K 长文本可用。
容量阶段原始 JSONL 中早期脚本产生的 predicted_filled_rss_mib 错误地在启动 RSS 上再次叠加 KV,不要使用;表中的 rss_mib、kv_capacity_mib 和 mem_available_mib 是实测值或直接按布局计算的值。现有脚本已改为根据 8K 基线只外推容量的增量。
输入与输出性能
请求的目标是 输入 token/最多输出 64 token,相同模型与 ASCII 数字输入,各请求独立、缓存命中 0、关闭 thinking。小于等于 4096 输入使用 8K 上下文;8K、16K、32K、64K 输入分别使用 16K、32K、64K、128K 上下文,以给输出留足空间。下表填写实际 tokenizer 与 API 返回的 token 数、TTFT 和解码计算速度;每档运行一次,无法代表统计分布。初次短输入可能由于自动调度未达到 NPU 注意力启用门槛,不能归因于 INT8 矩阵乘。
| 输入/输出 | BF16 TTFT (s) | INT8 TTFT (s) | INT8 TTFT 改善 | BF16 解码 tok/s | INT8 解码 tok/s |
|---|---|---|---|---|---|
| 128/64 | 0.778 | 0.808 | -4% | 18.38 | 18.53 |
| 256/64 | 1.487 | 1.485 | 0% | 18.18 | 18.19 |
| 512/64 | 2.834 | 2.755 | 3% | 17.15 | 17.71 |
| 1024/64 | 5.902 | 5.559 | 6% | 16.08 | 16.16 |
| 2048/64 | 13.217 | 12.111 | 8% | 13.45 | 13.51 |
| 4096/64 | 32.731 | 28.834 | 12% | 10.64 | 10.22 |
| 8192/64 | 90.562 | 76.846 | 15% | 7.11 | 7.11 |
| 16384/64 | 285.410 | 231.574 | 19% | 4.28 | 4.45 |
| 32768/64 | 986.870 | 772.622 | 22% | 2.32 | 2.53 |
| 65536/64 | 内存余量不足 | 2780.517 | 不可直接比较 | 不适用 | 1.35 |
BF16 128K 上下文启动时只剩约 334 MiB 可用,本次速度测试启动后最低仅约 65 MiB,故未请求 65536/64;不能把该项写成实测性能。短输入 128 token 两格式均为 mla_npu_calls=0;256 输入起逐步进入 NPU 路径,32K 输入为 1530 次 NPU MLA 调用、390 次 CPU MLA 调用(主要对应解码)。长输入下 TTFT 增长显著快于输入长度,32K 后解码仅约 2.3–2.5 token/s。单次结果用于观察趋势,不能据此断言百分比差异的统计显著性。
32K 输入时 MLA NPU 路径记录的耗时约 BF16 840 秒、INT8 624 秒,已占 TTFT 的 81%~85%;64K INT8 约 2484 秒,占 TTFT 的 89%。此字段包含排布、内存同步及 attention 计算,并非纯 NPU 矩阵乘耗时。这说明继续优化长输入,应优先检查 MLA 的历史 KV 搬运与批量注意力,而不仅是启动内存。
INT8 的 65536/64 在 128K 上下文中完整返回:输入、输出 token 数均准确,finish_reason=length,3066 次 NPU MLA 调用、0 回退,进程峰值 RSS 9225 MiB、进程 VmSwap=0,系统测试时余量约 3593 MiB。TTFT 约 46 分 21 秒,64-token 解码约 47 秒,证明这档能运行但不适合交互响应。INT8 256K 只是启动成功且仅余 95 MiB,超过模型原生 128K 位置范围,不做 128K 以上实际输入测试。
在本机同时考虑内存余量时,可先以 BF16 64K、INT8 128K 作为有余量的初始化档位;这不是交互可用长度的建议。即便 INT8,4096 输入的 TTFT 也约 29 秒,32K 达约 13 分钟;对低延迟应用仍需压缩输入或改进长预填充。这里只测速度和内存,不代表两种 KV 格式的长文本回答质量相同。
脚本:kv_context_benchmark.py;板端原始 JSONL 和逐请求引擎日志保存在测试设备的独立运行目录,未纳入仓库。FP16 独立实验仍可用相同脚本指定 --mode fp16 重测,旧版 mla_int8_api_benchmark.py 与既有 FP16 数据保留在板端 run/;本次正式结论不混入 FP16。
复现时在仓库根目录执行 python3 engine/source/tests/kv_context_benchmark.py --help,分别对 --mode bf16 和 --mode int8 运行 --phase capacity 与 --phase perf,使用相对路径传入 --binary、--model 和 --output-dir 即可。脚本只停止自己启动的测试服务,不会自动暂停其他系统服务或调整频率;测试前应检查可用内存与电源、散热状态。