0.8MB 跑通 Qwen|第 4-3 篇:核绑定实验——推理引擎在 ARM 大小核上为什么叮嘱"勿设 8 线程"

简介: 本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎,实测RK3588(4×A76+4×A55)上适配Qwen3-VL-2B/8B及30B-A3B模型。通过三组真机实验揭示“核多≠快”本质:仅绑4大核最优,设8线程反降效12%,验证大小核架构下线程配置需严守硬件特性。(239字)

系列:《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 篇 · 总纲(阿里云社区)

上一篇:4-2《vllm_tp_parfor:调用线程也干活》 | 下一篇:第 5 天《量化地基:Q8/Q4 从哪来》

真机实测通过:本文实验已在 RK3588 板端实测完成(2026-09;方法学与原始记录见仓库 docs 与《实验脚本》目录)

一句话导读:推理引擎的核绑定实验:从 RK3588 四颗 A76 大核加四颗 A55 小核的不对称架构出发,解释绑核目标只写大核簇的取舍,落点在纯计算、真实 prefill 与开绑核三组线程数对照实验,验证勿设 8 线程。

关键词:手搓 Qwen 推理引擎、千问大模型推理、核绑定、大小核、线程数、A76、RK3588、Qwen3-VL、零依赖纯 C

导语:RK3588 有 8 个核,默认却只用 4 个——因为它是 4 颗 A76 大核加 4 颗 A55 小核的大小核。本篇用三组实验钉死「核多≠快」:纯算下 8 线程最快、真实 prefill 打平、一开绑核反而慢约 12%,说清工程为何叮嘱「勿设 8 线程」。

4-1 里那行 nthreads = (nc > 4) ? 4 : nc 留下了悬念:RK3588 明明有 8 个逻辑核,为什么默认只用 4?因为它是 4×Cortex-A76(大核)+ 4×Cortex-A55(小核)的大小核——"核多"不等于"算得快"。这一篇我们用三组实验把这句话钉死。

1. 知识点:大小核不对称与"绑核"

A76 与 A55 是两种完全不同的核心:A76 主频高、乱序执行,是干活主力;A55 面积小、省电,性能约为 A76 的 1/3–1/2。推理引擎的 GEMM 是 A76 大核的菜;把线程扔到 A55 上,等于让主力在快车道、干活的却在小路。

所以线程池有"绑核"(affinity)机制:把每个 worker 钉到指定物理核,避免调度器乱丢。看 vllm_tp.c 第 115–125 行:

static void tp_bind_worker(int slot, int nthreads) {
   
    (void)nthreads;
    if (tp_bind_disabled()) return;
    long n_cpus = sysconf(_SC_NPROCESSORS_ONLN);
    if (n_cpus <= 0) n_cpus = 8;
    int core = (n_cpus > 4) ? (4 + (slot % 4)) : (slot % n_cpus); /* A76 cluster */
    cpu_set_t cs;
    CPU_ZERO(&cs);
    CPU_SET(core, &cs);
    sched_setaffinity(0, sizeof(cs), &cs);
}

注意两件事:

  1. 绑核目标只写 A76 集群(核 4–7),slot 对 4 取模——4 个 worker 各占一个大核;
  2. 但绑核默认是关的(VLLM_TP_BIND=1 才开启,第 105–113 行注释:x86 基准机实测不绑更快)。也就是说:默认情况下线程靠 Linux 调度器自由飘,8 线程就可能飘到 A55 上。

于是问题变成:8 线程在这块板上到底是赚是亏? 文档里有过明确警告(技术文档.md 环境变量表与 §11.4):VLLM_THREADS 默认 4、"绑定 4×A76 大核;勿设 8(A55 拖累,见 §11.4)",§11.4 记录同板实测 8 线程反而慢约 2 倍(图片编码 21.7→47s,文本 prefill 也变慢)。下面我们用当前代码在板端亲手验证,顺便看清"绑核开与关"两种世界。

2. 对应代码:线程数从哪来

回顾 4-1:线程数取 OMP_NUM_THREADS,否则取别名 VLLM_THREADS,再默认 nc > 4 ? 4 : nc。真实推理走 VLLM_THREADS=4(技术文档环境变量表 + 部署脚本 start.sh 均写死 4)。所以工程给这台板的出厂建议是 4 线程——本节的实验就是验证这个建议。

3. 改动后果:三组实验,看"线程更多"到底带来什么

实验 1:纯计算缩放(微基准,说明"更多核在纯算下有收益")

一个只做浮点运算的 parfor(4M 项),分别用 1/2/4/6/8 线程。板端实测(RK3588 / gcc 11.4 / 2026-09):

VLLM_THREADS=1 : 0.0784s
VLLM_THREADS=2 : 0.0704s
VLLM_THREADS=4 : 0.0428s
VLLM_THREADS=6 : 0.0280s
VLLM_THREADS=8 : 0.0255s

单调改善,8 线程最快——纯计算、无内存瓶颈的负载,核越多越好。这说明"A55 拖累"不是无条件的,它只出现在真实推理负载(GEMM/带宽受限)里。所以别用玩具程序下结论,要跑真负载。

实验 2:真实引擎 prefill(2B 模型,同一 prompt),默认不绑核

起服务 → 发一次约 5 秒的文本 prefill 请求,4 线程 vs 8 线程各两轮:

VLLM_THREADS=4 : 5.06s / 5.25s
VLLM_THREADS=8 : 4.97s / 4.97s

8 线程没有变慢,还略快 ~2–4%——为什么没复现文档的"慢 2 倍"?因为当前代码默认不绑核,调度器把多余线程放到 A55 上,但 4 个 A76 大核仍被核心工作占满,A55 分担了少量杂活,净效果接近打平。

实验 3:开绑核(VLLM_TP_BIND=1),同一请求

VLLM_THREADS=4 VLLM_TP_BIND=1 : 4.64s / 4.73s
VLLM_THREADS=8 VLLM_TP_BIND=1 : 5.24s / 5.33s

绑核后 8 线程比 4 线程慢约 12%(5.3s vs 4.7s)。为什么?绑核代码 4 + (slot % 4) 把 7 个 worker 全塞进 4 个大核——后 4 个 worker 与先 4 个双绑在同一物理核上互抢执行槽,反而添乱。这就复现了"勿设 8 线程"的机制:在这台板上,4 就是 A76 集群的容量上限,再多线程只是在同一个核上排队。

三组实验拼起来的结论:线程数的最优值取决于"负载是否饱和 A76"。玩具纯算饱和 8 核 → 8 线程好;真实推理的 GEMM 在 4 个大核上就接近饱和 → 8 线程无益;一旦绑核,超过 4 线程更是直接负优化。文档里那个"慢 2 倍"来自更重、更吃小核的负载与当时的测量口径——量级随负载浮动,方向一致:不要盲目设 8。

工程启示:为什么默认绑核是"关"的?因为绑核在 x86 基准机上是负优化(调度器比你懂),而在这块 ARM 板上又可能想要。所以做成开关(VLLM_TP_BIND),把"要不要绑"留给实测——这是"配置即诚实"的又一例:代码不替你赌。

4. 学员调试任务

  • A 档(板端动手):找你的板子(或有模型资产的环境)跑实验 2/3 的姿势:
    1. nproc 看核数,lscpu 或 /sys/devices/system/cpu/ 确认是否大小核;
    2. 同一 prompt 下,对比 VLLM_THREADS=4/8 与 VLLM_TP_BIND=1 开/关四组合,各自记录耗时;
    3. 说出你的板子"最优线程数"(不必等于 4,可能是 6/8——关键是你测出来的)。
  • B 档(纯读源码):读 vllm_tp.c 第 101–148 行(亲和三函数)与第 281–293 行(线程数策略),画一张"RK3588 8 核 → 4 worker + 调用线程"的分配图,标注绑核时 slot 4–7 会落在哪。

预期输出:你能解释"核多≠快"的大小核原因、"绑核默认关"的取舍,以及为什么实验必须跑真负载而不是玩具程序。

收尾

  • 本篇源码点名:vllm_tp.c(tp_bind_worker/tp_bind_caller/线程数策略)、技术文档.md(环境变量表与 §11.4 线程数)。
  • 开源仓库:Kestrel-LLM (Gitee)(AGPL-3.0-or-later 或商业许可,二选一)
  • 下篇预告:并行把"活"分下去了,可"活"本身是浮点数——4 字节存一个权重,2B 模型就要 8GB,板上根本放不下。第 5 天进入量化地基:Q4/Q8 是怎么把内存和带宽需求砍到 1/2、1/4 的。
相关文章
|
21天前
|
调度 C++
0.8MB 跑通 Qwen|第 7-3 篇:推理引擎的预热与测量抖动——为什么报告要"重复 3 次取中位"
本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎开发,实测适配Qwen3-VL多模型,在RK3588上验证性能抖动——单内核耗时波动达1.7倍,确立“预热+3次取中位”为可信基准口径。(239字)
|
22天前
|
定位技术 Python
0.8MB 跑通 Qwen|第 3-2 篇:推理引擎的字节序与十六进制纪律——一个字节序错误,引擎当场翻脸
本文以RK3588真机实测为基础,深入剖析字节序陷阱:揭示VQF格式中小端落盘导致魔数“VQFW”在磁盘呈现为“FQFW”,并用篡改version字段的实验直观展示——小端机器误读大端数据会直接拒载(报错33554432≠2)。强调“先问字节序,再读数字”的十六进制读法铁律。(239字)
102 1
0.8MB 跑通 Qwen|第 3-2 篇:推理引擎的字节序与十六进制纪律——一个字节序错误,引擎当场翻脸
|
21天前
|
机器学习/深度学习 区块链 C++
0.8MB 跑通 Qwen|第 10-1 篇:大模型推理的长上下文为什么必须稀疏——O(n²) 的注意力 vs O(n·k) 的"只看该看的"
本系列手搓0.8MB纯C推理引擎,零依赖跑通Qwen3-VL多模型。本文聚焦长上下文瓶颈:RK3588实测显示,注意力耗时占比从18%飙升至71%。提出块稀疏方案——将O(n²)注意力压至O(n·k),实现每词成本与上下文长度无关,为端侧大模型长文本推理提供关键路径。(239字)
105 0
|
21天前
|
定位技术 C语言 C++
0.8MB 跑通 Qwen|第 7-1 篇:大模型量化的 Q4_0 格式——与 GGUF 对齐的 4bit 布局
本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎,适配Qwen3-VL多模态模型,在RK3588上实测通过。详解GGUF对齐的Q4_0量化:32个float压缩至18字节(f16 scale + 16 nibble),剖析nibble打包规则与11倍误差代价,为端侧高效部署夯实底层基础。(239字)
|
21天前
|
缓存 JSON 安全
《0.8MB 跑通 Qwen:从零实现 ARM 零依赖纯 C 推理引擎》系列教程 · 总纲
本系列教程以开源引擎Kestrel为教材,30天90篇纯C实战,聚焦ARM边缘端LLM推理:从零实现mmap加载、NEON加速GEMM、q8 KV缓存、稀疏注意力、磁盘KV恢复、推测解码、OpenAI兼容服务及国密SM2/3/4全栈安全,全程代码驱动、调试验证。(239字)
123 0
|
23天前
|
编译器 C语言
0.8MB 跑通 Qwen|第 2-1 篇:推理引擎的 C11 `_Static_assert`——让编译器守卫你的内存布局
本文详解C11 `_Static_assert` 在内存布局守卫中的关键作用:针对mmap直挂场景,通过编译期断言钉死VQF格式三结构体(200/432/64字节),杜绝因对齐差异导致的静默错位。真机RK3588实测验证,实现错误前移。
0.8MB 跑通 Qwen|第 2-1 篇:推理引擎的 C11 `_Static_assert`——让编译器守卫你的内存布局
|
21天前
|
缓存 C语言 C++
0.8MB 跑通 Qwen|第 9-3 篇:推理引擎的 q8 KV 精度对照——量化进注意力,输出差多少
本系列《0.8MB跑通Qwen》手搓零依赖纯C推理引擎,适配Qwen3-VL多尺寸模型,在RK3588上实测q8 KV量化:输出误差仅≈0.01,端到端PPL损失<1%,带宽降为52%,精度与效率达成教科书级平衡。(239字)
|
21天前
|
编译器 C语言
0.8MB 跑通 Qwen|第 6-1 篇:推理引擎的 ARMv8.2 dotprod——`vdotq_s32` 一条指令做 4 个点积
本系列《0.8MB跑通Qwen》聚焦ARM零依赖纯C推理引擎,实测RK3588平台,适配Qwen3-VL多模型。本文详解ARMv8.2 dotprod指令(vdotq_s32)如何在真实大内核中释放性能,破除微基准误导,揭示寄存器压力下加速本质。(239字)
|
23天前
|
缓存 测试技术 C语言
0.8MB 跑通 Qwen|第 1-3 篇:推理引擎的自检门——没有模型的确定性测试,第一次读懂 PASS/FAIL
本文介绍RK3588平台LLM推理引擎的“自检门”机制:无需模型文件,通过标量参考对拍、固定种子随机与确定性PASS/FAIL测试,快速验证编译后代码正确性;实测覆盖L3缓存、量化点积等核心逻辑,体现工业级可信验证思想。(239字)
136 0
 0.8MB 跑通 Qwen|第 1-3 篇:推理引擎的自检门——没有模型的确定性测试,第一次读懂 PASS/FAIL
|
21天前
|
C++ 芯片
0.8MB 跑通 Qwen|第 6-2 篇:推理引擎的 8x8 布局重排——把"取数"提前到转换期
本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎,适配Qwen3-VL多模态模型,在RK3588芯片实测落地。核心创新是Q8权重的8×8内存重排,使宽矩阵GEMM提速约1.7倍,且位级结果一致,兼顾性能与精度。(239字)