[特殊字符] 搬砖的秘密:为什么一次搬 64 块砖最快?
搬砖的秘密为什么一次搬 64 块砖最快如果你在关注llama.cpp或者在尝试让大模型在 CPU 上跑得更快你可能会在源码或讨论中看到一个奇怪的数字chunk_size 64。为什么是 64为什么不是 1也不是 1024很多技术文档会跟你聊“原子操作”、“L1 缓存”、“矩阵-向量乘法GEMV”。但如果你不想被这些术语搞晕我们可以把这个问题简化成一个极其简单的场景搬砖。1. 场景设定一个巨大的搬砖任务想象一下你现在在一个工地你的任务是把一个巨大的砖堆这就是模型里的权重矩阵WWW搬到对面去处理。为了提高效率你雇了几个工人这就是CPU 线程。但这里有一个规定工人不能随便搬砖每次搬砖之前必须先走到工头面前问一句“工头我现在可以搬哪几块砖了”这就是代码里的原子操作atomic_fetch_add。chunk_size是什么它就是工头允许工人一次性搬走多少块砖。2. 三种搬砖方式的对比❌ 模式 Achunk_size 1极度勤快但极低效在这种模式下工人的工作流程是这样的走过去→问工头→搬 1 块砖→走回来→处理这 1 块砖\text{走过去} \rightarrow \text{问工头} \rightarrow \text{搬 1 块砖} \rightarrow \text{走回来} \rightarrow \text{处理这 1 块砖}走过去→问工头→搬1块砖→走回来→处理这1块砖然后他得重复这个过程 4864 次。结果工人一天到晚都在走路和问工头。虽然他看起来非常“勤快”每一步都在沟通但真正处理砖块的时间极少。绝大部分时间都被浪费在了“准备工作”上。✅ 模式 Bchunk_size 64高效的平衡点现在工头允许工人用一个小推车一次搬 64 块砖走过去→问工头→用推车一次搬 64 块砖→走回来→处理这 64 块砖\text{走过去} \rightarrow \text{问工头} \rightarrow \text{用推车一次搬 64 块砖} \rightarrow \text{走回来} \rightarrow \text{处理这 64 块砖}走过去→问工头→用推车一次搬64块砖→走回来→处理这64块砖结果工人走过去问工头的次数减少了 64 倍他把绝大部分时间都花在了真正处理砖块上。这就是所谓的**“固定开销被均摊了”**。❌ 模式 Cchunk_size 10000贪多嚼不烂你可能会想那一次搬 10000 块不更爽吗但问题来了推车太重工人的怀抱CPU 的L1 缓存空间有限。如果一次搬太多推车太重搬不动或者砖块掉在地上反而得重新捡速度变慢。分配不均如果总共只有 5000 块砖一个工人一次搬 10000 块那么他一个人干完了所有活其他工人全部在旁边闲逛。人力资源被浪费了。3. 结论寻找那个“黄金平衡点”所以chunk_size的选择其实是在玩一个平衡游戏不能太小→\rightarrow→否则你会死在“走路”和“问工头”的路上准备成本太高。不能太大→\rightarrow→否则你会因为“推车太重”而搬不动或者导致其他工人没活干缓存溢出/负载不均。在llama.cpp的 CPU 实现中经过大量的实测64刚好是一个神奇的数字它既能让工人大幅减少跑腿次数又能刚好装在 CPU 的 L1 缓存那个“小推车”里。一句话总结一次搬够才能跑得快。 想看这个类比在代码里是怎么实现的吗如果你想知道这个“搬砖逻辑”在ggml-cpu.c里对应哪几行代码以及真实的实验数据是如何证明 64 是最优的请阅读下一篇《从代码到基准llama.cpp 的 chunk size 是怎么实现的》。

相关新闻