![[特殊字符] 从代码到基准:llama.cpp 的 chunk size 是怎么实现的?](http://pic.xiahunao.cn/yaotu/[特殊字符] 从代码到基准:llama.cpp 的 chunk size 是怎么实现的?)
从代码到基准llama.cpp 的 chunk size 是怎么实现的在上一篇中我们用“搬砖”类比了一个核心概念为了减少准备工作的固定开销我们需要一个合适的“块大小chunk size”来提高产出。但作为开发者我们不能只靠类比。我们需要看到代码看到数据看到这个逻辑是如何在llama.cpp的底层被实现的。1. 源码剖析分块调度是怎么写的在ggml/src/ggml-cpu/ggml-cpu.c中chunk_size的逻辑非常直接。它的核心流程分为三步第一步确定块大小代码首先判断当前是否处于tgtoken 生成场景。在 tg 阶段我们一次只生成一个 token此时nr1输入向量的列数等于 1。intchunk_size16;// 默认 16 行一块if(nr01||nr11){chunk_size64;// tg 场景一次只生成 1 个 token走这里}这里就定义了那个“神奇数字”64。第二步切分任务接下来代码将总行数nr0除以chunk_size计算出总共有多少个块chunk。例如如果权重矩阵有 4864 行那么4864÷64764864 \div 64 764864÷6476个块。第三步原子领取动态调度为了让多个 CPU 线程高效协作llama.cpp采用了动态领取机制。线程不是在开始时就分好活而是在做完一块后通过一个原子操作去“领”下一块// 做完一块后原子地领取下一块current_chunkatomic_fetch_add_explicit(params-threadpool-current_chunk,1,memory_order_relaxed);这就是类比中的“问工头”。atomic_fetch_add保证了同一时刻只有一个线程能领到某个特定的块避免了重复计算。2. 实验证明如果chunk_size 1会发生什么为了验证这个设计的合理性我们进行了一组破坏性实验。我们通过环境变量GGML_CHUNK_SIZE1强制让 CPU 每次只搬 1 行。测试环境Intel CPU, 8 threads, Qwen2.5-0.5B Q4_K_M 模型。chunk_size线程数tg128 (tok/s)性能变化64原版17.38基线1破坏版14.38↓\downarrow↓41%结论即使在单线程不存在线程竞争的情况下chunk_size1依然让性能暴跌了41%。这证明了性能下降的主因不是原子操作的竞争而是其他东西。3. 深度拆解消失的 41% 去了哪里既然不是原子操作Atomic的问题那慢在哪里我们通过一个“Dummy Atomic”实验发现即使在chunk64时人为加入数千次原子操作性能也只下降了约 7%。真正的罪魁祸首是固定开销的爆炸。当chunk_size1时CPU 每计算一行都要走一遍完整的流程函数调用开销进入和退出ggml_compute_forward_mul_mat_one_chunk函数。边界计算计算当前行的起始和结束索引。块分形失效代码内部有一个blck_016的微循环一次抓 16 行处理。当chunk1时这个高效的微循环每次只能跑 1 行就结束了导致 SIMD 指令集AVX2无法充分发挥。内存往返激活向量xxx必须被频繁地重新加载到寄存器中。简单来说chunk64时这些开销被 64 行均摊了而chunk1时每行都要独自承担全部开销。4. 全量扫描寻找最优拐点我们对chunk_size进行了全量扫描得到了一个典型的“倒 U 型”曲线chunk_size1 线程性能 (tok/s)状态14.38❌ 固定开销主导86.20 性能快速回升326.87 接近峰值647.38✅黄金平衡点1286.41 缓存溢出/负载不均10246.90 负载极不均衡为什么 64 之后又下降了因为 CPU 的 L1 缓存L1 Cache空间有限通常 32KB。当chunk_size过大时数据量超过了 L1 缓存的容量CPU 必须频繁地去更慢的 L2 或 L3 缓存中读取数据导致速度再次掉下来。️ 实践指南如何在本机验证如果你想在自己的机器上测试最佳chunk_size无需重新编译直接使用环境变量即可Windows (PowerShell):$env:GGML_CHUNK_SIZE64./build/bin/llama-bench.exe-m models/qwen2.5-0.5b-q4_k_m.gguf-t 1-n 128-p 0-r 3Linux/macOS:exportGGML_CHUNK_SIZE64./build/bin/llama-bench-mmodels/qwen2.5-0.5b-q4_k_m.gguf-t1-n128-p0-r3建议测试序列1 $\rightarrow$ 4 $\rightarrow$ 16 $\rightarrow$ 32 $\rightarrow$ 64 $\rightarrow$ 128 $\rightarrow$ 256。 那么这种“粒度调优”的思路只能用在llama.cpp里吗其实这种“通过调节粒度来均摊固定成本”的逻辑是计算机科学中一个极其普适的规律。无论是在数据库索引、网络数据包传输还是在你的日常工作流程中都存在类似的chunk_size。在下一篇中我们将把这个技术结论升华为一个通用效率模型看看如何把“搬砖思路”应用到你的生活和工作中。请阅读《性能调优手册把 chunk size 思路落地到你的项目》。