系列:《0.8MB 跑通 Qwen:从零实现 ARM 零依赖纯 C 推理引擎》(30 天 × 90 篇) | 适配模型:Qwen3-VL-8B-Instruct(千问3_VL_8B_Instruct)· Qwen3-VL-2B-Instruct · Qwen3-30B-A3B | 测试设备:RK3588(4×Cortex-A76 + 4×Cortex-A55,aarch64)
系列总纲:《0.8MB 跑通 Qwen》30 天 90 篇 · 总纲(阿里云社区)
上一篇:6-2《8x8 布局重排:把取数提前到转换期》 | 下一篇:第 7 天《Q4 与混合精度》
源码精读篇:本文为源码/方法论精读,无独立实测;文中数字均引述仓库 docs 的板端实测记录
一句话导读:推理引擎的 4x4 asm 内核:讲清为何用提取脚本从 llama.cpp 原样搬运约 450 行 NEON asm 而非手写重写,并对照 MIT 许可的文件头要素与删除署名的三层后果。
关键词:手搓 Qwen 推理引擎、千问大模型推理、4x4 asm、llama.cpp、MIT 许可、NEON、Qwen3-VL、零依赖纯 C
导语:面对 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 许可全文、版权持有人、再分发声明。而在仓库根的 LICENSING.md 第三节「第三方组件」里,引擎把自己代码的双许可与"第三方段各自保留原许可"的关系交代清楚:
| 组件 | 位置 | 许可 |
| llama.cpp 派生 4x4 asm GEMM 内核 | tools/kernels/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 自称"AGPL 双许可 + 第三方成分透明",而透明清单(README「体量与依赖」表 + LICENSING.md 第三方组件)正是建立在"每个文件头都写清楚"之上。删署名 = 拆自己台。
这也是本系列"诚实基调"在代码层的体现:自己的代码可以锁,别人的代码必须还。双许可只约束引擎自研部分,第三方段永远保留上游许可。
4. 学员调试任务
- A 档(动手读代码):
- 读
tools/extract_llama_asm.py全文,说出它从上游哪一行取到哪一行、输出到哪个文件; - 打开
tools/llama_gemm_q4_0_4x4_asm.c,在文件头找全五要素(来源/行号/上游链接/许可文本/版权人); - 在
LICENSING.md第三节里找到第三方组件声明,用自己的话复述"双许可 vs MIT 段"的边界。
- 读
- B 档(纯读源码):在
vllm_safetensors.c里 grepggml/llama.cpp,列出所有"源自上游"的注释锚点,验证是否每处都带 MIT 与版权年份。
预期输出:你能讲清"机械提取 vs 手写重写"的取舍、MIT 的唯一硬性条件(保留声明),以及"自研锁许可 + 第三方还许可"的工程姿态。
收尾
- 本篇源码点名:tools/extract_llama_asm.py、tools/llama_gemm_q4_0_4x4_asm.c、LICENSE 第三节。
- 开源仓库:Kestrel-LLM (Gitee)(AGPL-3.0-or-later 或商业许可,二选一)
- 下篇预告:矩阵会算了,可引擎里有 Q8 也有 Q4——什么时候用谁?第 7 天讲混合精度路由:同一层里,为什么 FFN 走 Q4、attention 走 Q8。