一、参数空间与基本权衡
SEW 与 LMUL 是软件唯一能在运行期改变的旋钮,二者的影响方向如下:
| 参数 | 增大时的收益 | 增大时的代价 |
|---|---|---|
| SEW(元素位宽) | 减少位宽转换次数,直接匹配数据类型 | VLMAX 下降,单条指令处理元素数减少 |
| LMUL(寄存器组倍数) | 单条指令覆盖更多元素,循环开销摊薄 | 寄存器压力上升,可用寄存器组数量减少 |
需要先建立一个基础认知:LMUL 与 SEW 的组合受 LMUL×SEW ≤ VLEN 约束,因此"更大 LMUL"并不总是可行------SEW=64 时 LMUL 的上限往往是 8 的一半甚至更低,具体取决于实现的 VLEN。
另一条容易被忽略的影响是配置切换代价。SEW 或 LMUL 变化会触发向量配置重载,在流水实现中可能带来额外开销。因此循环体内应固定一组参数,把参数切换移出热点循环;当算法不同阶段需要不同参数时,优先考虑分阶段处理而不是在同一循环内来回切换。
二、寄存器压力与 LMUL 选择
RVV 只有 32 个向量寄存器,LMUL 决定每个活跃向量组消耗其中多少个。由此可以直接推算活跃组上限:
| LMUL | 每个向量组占用寄存器数 | 理论最大活跃组数 | 工程可用组数 |
|---|---|---|---|
| 1 | 1 | 32 | 20 以上 |
| 2 | 2 | 16 | 8--12 |
| 4 | 4 | 8 | 4--6 |
| 8 | 8 | 4 | 2--3 |
"工程可用组数"低于理论值,原因是要为掩码(固定占用 v0)与临时结果预留寄存器。经验规则如下:
- LMUL=1 是安全起点,几乎所有实现都能获得良好表现,且寄存器压力最低;
- 计算密集型循环用 2 或 4,收益来自更长的向量操作与更少的循环开销;
- 访存密集型(流式)循环可用更高的 LMUL,使单次访存指令覆盖更多元素、减少地址计算与循环判断;
- 避免在需要多个中间结果的循环里使用 LMUL=8,寄存器溢出会让编译器插入大量寄存器搬运,抵消收益。
判断是否发生寄存器压力问题,最直接的手段是观察生成代码中是否出现额外的寄存器移动指令,或对比降低 LMUL 后的性能变化。
三、访存瓶颈的判断
向量单元的执行宽度提升并不总能转化为性能提升,原因在于很多循环的真实瓶颈在访存侧。判断方法遵循一个简单逻辑:若提高 LMUL 后性能不再改善,瓶颈就在向量单元之外。
| 症状 | 推断瓶颈 | 应对方向 |
|---|---|---|
| 提高 LMUL 无收益 | 访存带宽或访存延迟 | 提高数据复用率、分块、调整布局 |
| 性能随数据规模显著下降 | 缓存容量不足 | 数组分块,控制工作集大小 |
| 计算与访存比值低的循环提升明显 | 属访存受限 | 优先优化访存而非向量宽度 |
| LMUL=8 反而变慢 | 寄存器溢出 | 退回 LMUL=2 或 4 |
工程上可以用"算术强度"(每字节数据的运算次数)做初步分类:算术强度高的循环值得投入参数调优,算术强度低的循环应先解决数据复用问题,此时任何向量参数调整的收益都有限。
四、访存模式与数据布局
RVV 支持单位步长(unit-stride)、跨步(strided)与索引(indexed/gather-scatter)三类访存。三者的效率差异明显:
- 单位步长访存效率最高,可被硬件合并为连续访问;
- 跨步访存按固定间隔取值,访存事务数随步长增大而上升;
- 索引访存逐元素计算地址,开销最高,通常只用于无法通过重排解决的非规则访问。
因此调优的一条实用原则是:能通过调整数据布局把 gather 变成单位步长访问的,优先改布局而不是优化 gather 本身。典型场景是矩阵转置与卷积的 im2col 变换------先按向量友好布局重排数据,再用单位步长访存,整体收益通常高于在原地使用复杂访存模式。
此外,缓冲区的对齐值得始终按元素位宽与缓存行处理,非对齐与跨页访问虽然正确,但会产生额外的拆分开销,在高频循环中会累积成可观测的性能差距。
五、微基准与参数扫描
参数调优需要可靠的测量,方法上注意以下几点:
- 以每元素周期数(cycles/element)而非总时间作为指标,避免数据规模变化干扰结论;
- 防止编译器消除循环:结果需被实际校验或输出,否则可能只测到空循环;
- 锁定频率并关注温度:动态调频与温度变化会污染对比结果,测量期间应固定工作点;
- 同一次会话内完成参数扫描,避免跨会话的环境差异;
- 分别测量配置重载开销:若在循环内切换参数,需单独观察该部分的影响。
一个有代表性的实测经验是:某类逐元素计算循环中,LMUL 从 1 提升到 4 通常有明显收益,继续提升到 8 则收益消失甚至倒退;而在访存受限的拷贝类循环中,收益曲线会更早走平。拐点位置因平台而异,只能实测确定,无法靠经验外推。
六、平台参数核对与高频问题
不同实现提供的向量宽度、支持的 SEW 范围与推荐配置并不相同,参数选型前应确认目标平台的实际能力,而不是沿用其他平台的经验值。以玄铁 C930 为例,其向量扩展与矩阵引擎的具体规格、可用的元素类型以及配套工具链版本均可在产品页核对。确认平台能力后再做参数扫描,可以避免在不可行的组合上浪费时间。
| 现象 | 优先排查方向 |
|---|---|
| 提高 LMUL 无收益 | 瓶颈在访存侧,或已发生寄存器溢出 |
| 性能随规模阶梯式下降 | 工作集超过缓存容量,需分块 |
| 小数组性能差、大数组正常 | 循环启动开销占比高,考虑降低分块频率 |
| 同一代码在不同平台表现差异大 | 向量宽度与 SEW 支持范围不同,参数需重新扫描 |
| 单独测得的加速比在实际程序中不成立 | 实际程序中访存竞争与缓存压力更高 |
结语
RVV 参数调优的顺序应当是:先用微基准确定平台的可行组合,再判断循环是计算受限还是访存受限,最后才动 LMUL 与 SEW。反过来做------先扫参数、再看瓶颈------经常把时间花在收益有限的维度上。参数选择的有效区间由平台与算法共同决定,这部分结论不具备跨平台可移植性,必须实测。
后续可展开的方向是把这套方法用到具体算子实现上:卷积与矩阵乘在 RVV 上的分块策略、数据布局重排,以及算子库集成时的接口设计。