news 2026/10/31 14:42:09

34 · 两行 GEMV 共享激活,只换来 0.6%:一个反向证明

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
34 · 两行 GEMV 共享激活,只换来 0.6%:一个反向证明

34 · 两行 GEMV 共享激活,只换来 0.6%:一个反向证明

本篇对应源码:main/pie_dotprod.S·main/kmcu.c

目标:单核 GEMV 只跑到 PSRAM 上限的 66–78%,怀疑是「每行重装激活」的开销。
结论:省掉 12.5% 的指令,端到端只快 0.6%——这不是指令受限,是字节带宽受限。

关键词:PIE 汇编 · 两行 GEMV · 带宽受限
封面:省 12.5% 指令,只快 0.6%

一、结论先行

阶段单行内核两行内核
ffn25.5 ms25.1 ms
qkv18.6 ms18.4 ms
o10.0 ms9.8 ms
ple9.6 ms9.6 ms
total(19 token 均值)159.9 / 160.0 ms159.0 / 159.0 ms

位级:20 token 序列完全一致,sd fnv = 817147c7、kv fnv = 739dd3ef两侧相同。

二、动机:每块 64 B 激活 vs 32 B 权重

单行内核处理一个 32 元素块时要做的事:

  • 装 4 个 128-bit 的xq(32 个 int16 = 64 B)
  • 装 2 个vldext的权重(32 个 int8 = 32 B)
  • 4 条vmulas+ 1 条srs+ 约 5 条标量

激活的字节数是权重的两倍。对 gate/up 这种「同一份激活、几十行权重」的
形状,看起来明显浪费。

三、内核:一次装载,两条点积链

pie_gemv_row2: /* a0=qa a1=qb a2=x a3=da a4=db a5=nblk a6=ya a7=yb */ esp.vld.128.ip q2, a2, 16 /* 激活块 32 个 int16,两行共用 */ esp.vld.128.ip q3, a2, 16 esp.vld.128.ip q4, a2, 16 esp.vld.128.ip q5, a2, 16 /* 行 A */ esp.zero.xacc esp.vldext.s8.ip q0, q1, a0, 16 esp.vmulas.s16.xacc q0, q2 esp.vmulas.s16.xacc q1, q3 esp.vldext.s8.ip q0, q1, a0, 16 esp.vmulas.s16.xacc q0, q4 esp.vmulas.s16.xacc q1, q5 esp.srs.s.xacc t3, t4 /* 行 B 同样一遍,只是权重指针换成 a1 */

PIE 只有一个xacc累加器,所以「共享激活」只能在寄存器层做:先把 32 个
激活装进 q2–q5,然后两行依次把权重流过去。每块从 32 条指令降到 28 条。

两个硬件约束值得记下来(踩过一次):

  1. srs/vldext的 GPR 只能编码 x8–x15 / x24–x31,所以右移量放t4(x25)、
    结果暂存用t3(x24)/t5(x26),指针留在 a0–a5;
  2. esp.vldext.s8.ip一次只能出 2 个寄存器(16 个 int8 符号扩展成两个
    8×int16),所以 32 个 int8 要两条。

objdump复核:函数体 0x1a0–0x22d,没有栈帧、没有寄存器溢出。

四、C 侧:成对调用,奇数回退

intr=0;for(;r+1<n_rows;r+=2){pie_gemv_row2(q+r*align,q+(r+1)*align,xq,d+r*nblk,d+(r+1)*nblk,nblk,&y[r],&y[r+1]);y[r]*=coeff;y[r+1]*=coeff;}for(;r<n_rows;r++)y[r]=pie_gemv_row(q+r*align,xq,d+r*nblk,nblk,0)*coeff;

行数为奇数时最后一行回退单行内核,所以任何形状都能用。

五、为什么只快 0.6%(这篇的真正价值)

  • 每块指令数:32 → 28(−12.5%)
  • 端到端:159.9 → 159.0 ms(−0.6%)

两者差了一个数量级,只能说明一件事:这些阶段的时间不是被指令吞吐决定的,
而是被从 PSRAM 搬权重决定的。逐阶段算有效带宽(单核上限 121 MB/s):

阶段字节量耗时有效带宽占上限
ffn2.4 MB25.5 ms94 MB/s78%
qkv1.62 MB18.6 ms87 MB/s72%
o0.8 MB10.0 ms80 MB/s66%

省指令不会让 PSRAM 变快,所以两行内核只能把「剩下的那点非带宽开销」挤掉一点。

顺带得到一个可用的预算式:每 token 必须过 15.4 MB(head 10.24 + ffn 2.4 +
qkv 1.6 + o 0.8 + 其余),按双核 157 MB/s 是 98 ms,加 PLE 行读 14.4 ms,
理论上限约 113–117 ms。当前 159–170 ms,剩余空间全在「让这几段也吃满双核」。

六、诚实边界

  • 0.9 ms 的收益在任何单次测量里都不显眼,它是两次开、两次关交替得到的
    稳定差值(159.0/159.0 vs 159.9/160.0),不是一次跑出来的。
  • 收益虽小但位级一致,所以保留默认开启(KMCU_GEMV2=1),并留了运行期
    g键与构建期-DKMCU_GEMV2=0两条退路。
  • 这个内核只对「同一 tensor 的相邻两行」有效;输出头本身是带宽打满的,
    用不上它(也没有收益)。

七、一句话

这是一次「反向证明」:花力气省掉 12.5% 的指令只换来 0.6%,反而确认了
瓶颈是 PSRAM 字节带宽——从此不必再在 GEMV 指令级上找空间。


对应源码

文件关键符号 / 位置支撑本文哪部分
main/pie_dotprod.Spie_gemv_row2两行共享激活的内核
main/kmcu.cgemv_q8_pre()的成对循环C 侧接入与奇数回退
main/kmcu.ckm_gemv2_selftest()与单行内核的逐位比较
main/main.ccase 'g'运行期逃生舱

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

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/31 14:37:09

将一块数据盘扩容到/目录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/31 14:23:37

基于AT89S52单片机的蘑菇大棚环境监测系统论文(附录代码)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/31 14:23:21

【优化求解】基于无序灰狼算法求解多目标问题matlab代码

1 简介Mirjalili 等人提出了一种新的群体智能算法———灰狼优化算法(GWO)&#xff0c;并通过多个基准测试函数进行测试&#xff0c;从结果上验证了该算法的可行性&#xff0c;通过对比&#xff0c;GWO 算法已被证明在算法对函数求解精度和稳定性上要明显优于 PSO、DE 和 GSA 算…

作者头像 李华
网站建设 2026/10/31 14:23:02

STEP 7 V5.x 老项目升级:HSP 硬件支持包安装与排查实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/31 14:23:02

振镜装好没反应?五步配置法从接线到出光排查指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华