源码精读篇:本文为源码/方法论精读,无独立实测;文中数字均引述仓库 docs 的板端实测记录
一句话导读:4x4 asm 内核:讲清为何用提取脚本从 llama.cpp 原样搬运约 450 行 NEON asm 而非手写重写,并对照 MIT 许可的文件头要素与删除署名的三层后果。
8x8 是引擎自己排的,可"宽 GEMM 的最优形状"llama.cpp 早就研究过,x86 侧甚至有更狠的 4x4 手写 asm。自己重写一遍?没必要——MIT 允许提取。今天讲的不只是内核,更是"把别人代码搬进来"的工程伦理与许可边界。
1. 知识点:为什么"提取一小段"比"重写一遍"更专业
llama.cpp 的ggml_gemm_q4_0_4x4_q8_0是一段约 450 行的手写 NEON asm(.inst sdot、16 个累加器、软件流水线预取)。这种代码有一个特性:人工重写几乎必然引入转录错误——一条sdot的 lane 写错、一个偏移算错,结果就全错,还极难排查(对拍只能告诉你错了,不能告诉你在哪一行)。
所以仓库的做法不是"照着写一遍",而是写了个机械提取脚本(tools/extract_llama_asm.py),把 llama.cpp 源文件里那个__asm__ __volatile__(...)块按行号原样抠出来。脚本头注释写明了动机:
"""Extract ggml_gemm_q4_0_4x4_q8_0 (asm kernel) verbatim from llama.cpp into a standalone C function, so the ~480 lines of hand-written NEON sdot asm are ported mechanically (zero transcription risk). ... The asm block is the `__asm__ __volatile__( ... )` spanning lines 1852-2301. """"Zero transcription risk"(零转录风险)是这句话的灵魂:能用脚本原样搬的,就不该用手抄。工程上,越是"又复杂又不可读"的代码,越要机械搬运——人只负责把它正确地组装进去,不负责逐行翻译它。
2. 对应代码:许可边界长什么样
搬代码有红线:许可证要跟着走。看 tools/llama_gemm_q4_0_4x4_asm.c 的文件头(第 1–30 行):
/* llama_gemm_q4_0_4x4_asm.c - mechanically extracted from llama.cpp * (ggml/src/ggml-cpu/arch/arm/repack.cpp, lines 1852-2301), MIT license. * ... * This file is a verbatim (mechanically extracted) portion of llama.cpp and * is redistributed under the MIT License. Original upstream: * https://github.com/ggerganov/llama.cpp ... * MIT License * Copyright (c) 2023-2026 The ggml authors * Permission is hereby granted, free of charge, ...(完整 MIT 文本) */要素齐全:来源文件与行号、上游仓库、MIT 许可全文、版权持有人、再分发声明。而在仓库根的 LICENSE(第 24–27 行与第 60–63 行)里,引擎把自己代码的双许可与"第三方段各自保留原许可"的关系交代清楚:
- 源自 llama.cpp 的代码段(tools/llama_gemm_q4_0_4x4_asm.c,以及 src/model/vllm_safetensors.c 中标注的 ggml_gemm/gemv/vec_dot 派生内核): MIT License, Copyright (c) 2023-2026 The ggml authors(版权声明与许可文本见各文件头)。同样的署名也出现在引擎内的移植注释里(vllm_safetensors.c 第 4184–4186 行:源自 llama.cpp,MIT (c) 2023-2026 The ggml authors,全文见本文件头)。每一处引入都原地署名,不搞"搬了但不说"。
3. 改动后果:删掉署名,会发生什么
把上面的文件头 MIT 文本删掉,只留内核代码——编译照过、性能照旧,代码层面"零影响"。这就是许可问题的狡猾之处:它不靠编译器拦你,靠的是合规与信任。
后果分三层:
- 法律:MIT 的条件只有一条——"再分发必须带上版权声明与许可文本"。删掉它,就是违约再分发;对引擎这种要商用授权(双许可)的项目,等于在自己最看重"许可合规"的地方埋雷;
- 工程:文件头里的"来源 + 行号 + 上游"是可追溯性资产。半年后这个 asm 出了数值问题,你要回上游 diff;没有出处,你只能对着 450 行汇编发呆;
- 信任:仓库 README 自称"源码可得双许可 + 第三方成分透明",而透明清单(README「体量与依赖」表 + LICENSE 第三节)正是建立在"每个文件头都写清楚"之上。删署名 = 拆自己台。
这也是本系列"诚实基调"在代码层的体现:自己的代码可以锁,别人的代码必须还。双许可只约束引擎自研部分,第三方段永远保留上游许可。
4. 学员调试任务
- A 档(动手读代码):
<ol> - 读
tools/extract_llama_asm.py全文,说出它从上游哪一行取到哪一行、输出到哪个文件; - 打开
tools/llama_gemm_q4_0_4x4_asm.c,在文件头找全五要素(来源/行号/上游链接/许可文本/版权人); - 在
LICENSE里找到第三方段声明,用自己的话复述"双许可 vs MIT 段"的边界。 - B 档(纯读源码):在
vllm_safetensors.c里 grepggml/llama.cpp,列出所有"源自上游"的注释锚点,验证是否每处都带 MIT 与版权年份。
实战排查示例(B 档):在仓库根目录执行以下 grep,把vllm_safetensors.c里所有涉及上游的注释锚点一次性捞出来:
grep -n -E "ggml|llama\.cpp" src/model/vllm_safetensors.c输出会是一长串行号 + 匹配行,例如:
4184: // 源自 llama.cpp,MIT (c) 2023-2026 The ggml authors,全文见本文件头 4185: // ggml_gemm_q4_0_4x4_q8_0 派生内核,上游见 llama.cpp repack.cpp 4186: // 版权声明与 MIT 许可文本见本文件头拿到输出后,逐条核对三件事:
- 是否带 MIT:注释里是否出现
MIT字样,或明确指向「本文件头」的许可文本; - 是否带版权年份:是否出现
(c) 2023-2026 The ggml authors这类版权持有人与年份; - 是否带来源:是否写明
源自 llama.cpp或给出上游文件/行号,保证可追溯。
若某条注释只写了ggml却漏了 MIT 与年份,就说明该处署名不完整,需要补全——这正是 B 档要验证的「每处引入都原地署名」。
预期输出:你能讲清"机械提取 vs 手写重写"的取舍、MIT 的唯一硬性条件(保留声明),以及"自研锁许可 + 第三方还许可"的工程姿态。
收尾
- 本篇源码点名:tools/extract_llama_asm.py、tools/llama_gemm_q4_0_4x4_asm.c、LICENSE 第三节。
- 开源仓库:Kestrel-LLM (Gitee)(源码可得双许可:学习 / 学术研究免费)
- 下篇预告:矩阵会算了,可引擎里有 Q8 也有 Q4——什么时候用谁?第 7 天讲混合精度路由:同一层里,为什么 FFN 走 Q4、attention 走 Q8。
关键词:4x4 asm、llama.cpp、MIT 许可、NEON、推理引擎
上一篇:Day 6·2 8x8 布局重排:把“取数”提前到转换期,让宽矩阵 GEMM 快 1.7 倍
下一篇:Day 7·1 Q4_0 格式——与 GGUF 对齐的 4bit 布局