零依赖极客头像
33 · PSRAM 只有 1.31×:把输出头拆给两个核,以及先修好带宽仪表封面图

33 · PSRAM 只有 1.31×:把输出头拆给两个核,以及先修好带宽仪表

33 · PSRAM 只有 1.31×:把输出头拆给两个核,以及先修好带宽仪表

本篇对应源码:main/kmcu.c · main/main.c · docs/optimization_plan.zh-CN.md

目标:输出头占单 token 的 43%,能不能用第二颗核把它砍一半。
结论:双核聚合带宽只有 1.31×(不是 2×),输出头 91.8 → 82.3 ms,端到端 −5%。

关键词:双核 · PSRAM 带宽 · 输出头 · 分核
封面:双核只有 1.31×,输出头 91.8 → 82.3 ms

一、结论先行

项单核双核
输出头扫描(正式模型,20 次均值)91.82 ms82.28 ms(1.12×)
稳定 decode178–188 ms/token170–173 ms/token(5.8 tok/s)
Agent 8 步1739–1755 ms1677 ms
top-8 / 全量 logits 哈希—MATCH / 一致

收益只有 1.12×,因为瓶颈不在核数,在 PSRAM 带宽。

二、先修仪表:原来的探针测的是延迟

最初的带宽探针是:

for (i = 0; i < n; i++) sum += r[i];   /* 单链依赖 */

sum += r[i] 每一步都依赖上一步,测到的是加法延迟,不是读带宽。换成
8 路独立累加后数字立刻变了:

探针结果
朴素单链106–107 MB/s
8 路独立累加(单核)120–122 MB/s
双核各读 8 MB、同时进行157 MB/s(core0/core1 各 101.3 ms)

双核 1.31×,不是 2×。这直接决定了后面所有「要不要多核」的判断:
如果按 2× 估算收益,会得出「拆两半就能省一半时间」的错误结论。

三、拆法:按词表区间分核,按 id 升序重放

core0: rows [0, V/2)   → 本地 top-k
core1: rows [V/2, V)   → 本地 top-k
合并:把 2k 个候选按 id 升序重放,用与单核完全相同的「严格 >」规则

为什么必须按 id 升序重放?单核扫描的隐含规则是「先出现者优先」。
如果直接比较两边的最大值,遇到浮点相等时 Tie-break 会和单核不同,
top-8 顺序会变——虽然 argmax 通常不变,但位级门禁会挂。

/* 合并后按 id 升序,逐条套用单核规则 */
for (int i = 0; i < n; i++) {
    float acc = cv[i];
    if (acc > best) { best = acc; best_id = ci[i]; }
    ...
}

四、门禁:哈希路径强制单核

if (km_head_dual_enabled && out_hash == NULL && vocab >= 1024) { ...双核... }

out_hash != NULL 说明这次调用要输出「全量 logits 的哈希」用于位级对拍——
双核路径只保留 top-k,拿不到全量,所以这种情况直接走单核。
这不是为了正确性(top-k 双核本身是对的),而是为了让对拍路径保持可比的实现。

五、几何探针:先量天花板,再改代码

正式模型不方便反复加载(每次开机展开 86 秒),所以做了一个不依赖模型文件的
几何探针:在 PSRAM 里构造 32002 行 × 10 块的真实形状,用真实内核扫描。

扫描方式时间
单核89 ms
双核(按区间分核)79 ms(1.13×)
双核(行交替分核)79 ms(1.13×)

两种分法一样快,说明瓶颈不是负载不均,而是共享的 PSRAM 总线。
这一步把「双核能拿多少」在上真模型之前就锁死了。

六、为什么不做 attention(E-1 判否)

分桶显示 attn 只有 3.4 ms,占 2%。「单遍 QK」这种改写要动归约顺序,
按规则必须重新对拍,收益上限 3.4 ms——投入产出比不成立,直接出局。

七、诚实边界

  • 1.13× 是几何合成的结果,上真模型后是 1.12×,一致性很好,但两者不能混用。
  • 双核路径每次调用要创建/销毁一个任务(20 次/token),这部分开销已包含在
    170–173 ms 里;若将来 token 更短,任务开销占比会上升。
  • 收益与上下文长度无关(输出头不吃 KV),但会随词表增大而线性放大。

八、一句话

先证明双核只能拿到 1.31× 的带宽,再把输出头按词表拆开——预期 2×、
实测 1.12×,端到端 −5%;同时得到一个可复用的结论:这台机器上,任何
「多核并行读 PSRAM」的方案都别指望超过 1.3 倍。


对应源码

文件关键符号 / 位置支撑本文哪部分
main/main.cprobe_psram_dual() / bw_read()带宽仪表修正(106 → 121/157)
main/kmcu.chead_from_hidden() 双核分支、km_head_job_body()按区间分核与升序重放
main/main.cKMCU_HEADBW_PROBE 几何探针89 → 79 ms 的上限测量
main/kmcu.ckm_head_dual_enabled运行期逃生舱

《Kestrel-MCU 手记》 · 全系列 37 篇:在 ESP32-P4 上从零训练并部署 64M 参数 MoE 大模型(5.8 tok/s),源码、权重、训练脚本与全部文章开源可复现。

仓库:https://gitee.com/pei-xiaoguang/kestrel-llm-mcu · 觉得有用欢迎 Star

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/weixin_55790517/article/details/169231587

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--