neon 和 sve 可以加速内存拷贝吗(copy_to_user/copy_from_user)

原始问题:neon 和 sve 可以加速内存拷贝吗,尤其是在 copy_to_user/copy_from_user 上面 · 2026-07-01

NEON / SVE 能否加速内存拷贝(copy_to_user / copy_from_user)

一、简短结论

技术 能否加速 memcpy 能否加速 copy_to_user/copy_from_user
NEON 技术上可以,但内核未采用 ❌ 不适用
SVE 技术上可以,但内核未采用 ❌ 不适用
MOPS (ARMv8.8+) ✅ 已采用 ✅ 已采用

核心原因:NEON/SVE 在内核 uaccess 路径存在不可忽略的上下文开销和机制限制,使得收益为负。ARMv8.8 的 MOPS 指令集才是官方推荐的硬件加速方案。

二、为什么 NEON 不能加速 copy_to_user/copy_from_user

2.1 内核当前实现现状

内核的 __arch_copy_to_user 和 __arch_copy_from_user(arch/arm64/lib/copy_to_user.S、copy_from_user.S)全部使用通用寄存器(GPR),主循环用 ldp/stp 对每次 16 字节×8 = 128 字节/轮,完全不涉及 NEON 或 SVE 寄存器。

实际代码路径:

copy_template.S
  ├── MOPS (ARMv8.8+) → CPYP/CPYM/CPYE 硬件指令
  └── 通用路径       → ldp/stp 对 (每次128B)

2.2 障碍 1:kernel_neon_begin/end 的开销不可接受

操作 延迟
kernel_neon_begin() 保存 32×128-bit NEON regs + FPSR/FPCR ~200-500 ns
后续返回用户空间时状态恢复 ~200-500 ns
合计 NEON 上下文切换开销 ~0.5-2 µs
SVE 变体(VL=2048 bit,保存 32×Z reg) 10-50+ µs

对比一个典型 copy_to_user 拷贝 4KB 数据的时间(L1 命中场景):

操作 时间
4KB GPR ldp/stp 拷贝(L1 命中) ~1-2 µs
NEON 上下文切换开销 ~0.5-2 µs
SVE 上下文切换开销 ~10-50 µs

对于小拷贝(<4KB),NEON 上下文切换开销就占拷贝本身的 50-100%,SVE 则直接比拷贝本身还慢一个数量级。

2.3 障碍 2:无 unprivileged load/store 变体

copy_to_user/copy_from_user 必须使用 unprivileged load/store(LDTR/STTR),才能让内核在访问用户空间地址时触发正确的缺页异常机制。NEON 指令(如 LD1/ST1、LD2/ST2 等)没有对应的 unprivileged 变体,无法区分用户空间 vs 内核空间的地址访问。

无 unprivileged 变体意味着:

2.4 障碍 3:page fault 处理复杂

copy_from_user 访问非法用户地址时,需要精确跳到修复标签,返回未拷贝的字节数。NEON 指令是多元素加载,遇到页错误时:

三、为什么 SVE 更不能用于 uaccess

SVE 除了继承 NEON 的所有问题外,还有额外负担:

问题 SVE 更严重的程度
上下文开销 SVE 保存 32×Z 寄存器(VL=128~2048 bit),最大 8KB+,比 NEON 大一个数量级
抢占延迟 SVE 长向量操作可能导致内核不可抢占时间显著增加
页错误处理 SVE 的 gather/scatter 指令(LD1FF、LDNT1)单条指令跨多页,异常恢复极为复杂
无社区支持 内核社区明确反对在内核态使用 SVE 做数据搬移

当前主线内核 没有任何代码路径 在内核态使用 SVE 指令进行用户空间数据访问。

四、ARM 官方推荐的硬件加速方案:MOPS(ARMv8.8+)

ARMv8.8 引入了 MOPS (Memory Operations) 指令集,专门解决内存拷贝的硬件加速问题:

操作 copy_to_user 使用 copy_from_user 使用 copy_page 使用
CPYP (prologue) cpyfpwt (write+test) cpyfprt (read+test) cpypwn
CPYM (main) cpyfmwt cpyfmrt cpymwn
CPYE (epilogue) cpyfewt cpyfert cpyewn

MOPS 相比 NEON/SVE 的优势:

比较项 MOPS NEON SVE
上下文开销 零(使用 GPR) 高(需保存 32 regs) 极高
unprivileged 变体 ✅ 有 wt/rt 后缀 ❌ 无 ❌ 无
异常恢复 ✅ 精确 ❌ 不精确 ❌ 更差
内核主线已采用 ✅ v6.5+ ❌ ❌

内核中的切换逻辑(arch/arm64/lib/copy_template.S):

#ifdef CONFIG_AS_HAS_MOPS
alternative_if_not ARM64_HAS_MOPS
    b    .Lno_mops
alternative_else_nop_endif
    // copy_to_user 路径
    cpyfpwt  [dst]!, [src]!, count!
    cpyfmwt  [dst]!, [src]!, count!
    cpyfewt  [dst]!, [src]!, count!
    b    .Lexitfunc
.Lno_mops:
#endif

五、如果只需要内核内部 memcpy,NEON 可以吗?

如果仅仅做内核空间内部(kernel→kernel)的大块内存拷贝,技术上 NEON 可以加速,但实际情况是:

场景 是否推荐 NEON 原因
小拷贝 (≤4KB) ❌ NEON 上下文开销占比过大
中拷贝 (4KB-64KB) ⚠️ 勉强可用 收益不确定
大拷贝 (>64KB) ❌ 带宽瓶颈在内存子系统而非计算;ldp/stp 足够饱和
有 cache 预热的流拷贝 ❌ 应使用 DC ZVA + ldp/stp,而非 NEON

kernel→kernel 的 memcpy 同样不存在页错误和权限区分的顾虑,所以障碍 2 和 3 不存在,但障碍 1(上下文切换开销)依然存在,因此社区同样没有采用 NEON 加速通用 memcpy。

六、总结

需求 推荐方案 内核是否使用
copy_to_user / copy_from_user 加速 MOPS (ARMv8.8+) ✅ 已合并主线(v6.5+)
内核内部 memcpy 加速 MOPS 或 GPR ldp/stp ✅ MOPS 已采用;NEON ❌
copy_page MOPS 或 GPR ldp/stp ✅ MOPS 已采用
cache 清理拷贝 DC CVAC + ldp/stp 或 NT load 现有实现

结论:NEON 和 SVE 不能用于加速 copy_to_user/copy_from_user,原因有三:

  1. kernel_neon_begin/end 的上下文保存开销太大(0.5-50 µs),小数据时超过拷贝本身
  2. NEON/SVE 没有 unprivileged load/store 变体,无法区分用户/内核空间访问
  3. NEON/SVE 多元素加载的页错误恢复语义不精确,无法正确实现 copy_from_user 的部分拷贝语义

ARMv8.8 MOPS 指令(主线内核 v6.5 起对 ARM64_HAS_MOPS 的支持)才是当前及未来 ARM 平台内核 uaccess 路径的硬件加速方向。


⚠️ 免责声明

本站内容均由 AI 基于公开知识辅助生成,仅供学习参考,请勿直接引用作为依据。作者不对信息的准确性、完整性及适用性作保证,亦不对因使用本站内容产生的任何损失承担责任。