当了解我的应用程序的分析结果(I / O繁重)时,我面临着copy_user_enhanced_fast_string
是最热门的区域之一。在用户空间和内核空间之间进行复制时将调用它。 x86上的The implementation如下:
ENTRY(copy_user_enhanced_fast_string)
ASM_STAC
cmpl $64,%edx
jb .L_copy_short_string /* less then 64 bytes, avoid the costly 'rep' */
movl %edx,%ecx
1: rep
movsb
xorl %eax,%eax
ASM_CLAC
ret
.section .fixup,"ax"
12: movl %ecx,%edx /* ecx is zerorest also */
jmp .Lcopy_user_handle_tail
.previous
_ASM_EXTABLE_UA(1b, 12b)
ENDPROC(copy_user_enhanced_fast_string)
为什么不使用vmovaps
/ vmovups
?难道不是证明AVX在复制可用位置方面没有性能优势吗?
答案 0 :(得分:6)
内核代码只能安全地在kernel_fpu_begin()
/ kernel_fpu_end()
之间使用FPU / SIMD来触发xsave
(和xrstor
之前返回用户空间)。或xsaveopt或其他任何东西。
这是很多开销,在少数情况下(例如md
RAID5 / RAID6奇偶校验创建/使用)是不值得的。
不幸的是,这意味着大多数内核代码只能使用GP整数寄存器。 AVX memcpy循环和rep movsb
memcpy之间的区别并不值得在每次系统调用时都进行xsave / xrstor。
上下文切换与仅进入内核背景:
在用户空间中,内核处理用户空间任务之间的上下文切换时的状态保存/恢复。在内核中,要避免每次要返回相同的用户空间时进入内核(例如,进行系统调用)时都保存大量的FPU,因此只需保存GP整数寄存器
对于已知大小的副本,没有SSE / AVX并不算太糟,尤其是在具有ERMSB功能的CPU上(使用此副本功能时,因此名称为enhanced_fast_string
)。对于大中型对齐副本,rep movsb
至少在Intel CPU上几乎一样快,希望与AMD一样快。参见Enhanced REP MOVSB for memcpy。或没有ERMSB,至少要进行rep movsq
+清理。
在64位内核中,GP整数寄存器的大小是XMM寄存器的一半。对于较小的副本(低于内核的64字节阈值),与通常的系统调用开销相比,8倍GP整数8字节负载和8字节存储应该非常有效。 4倍XMM加载/存储量是不错的选择,但这是在保存FPU状态方面的权衡。
对于strlen
/ strcpy
,如果pcmpeqb
非常好而不是一次4或8字节的bithack,则没有SIMD的情况会更糟。而且SSE2是x86-64的基线,因此,如果不存在保存FPU状态的问题,则x86-64内核可以依靠它而无需动态分配。
从理论上讲,您可以吃掉SSE / AVX转换损失,并像某些不良的Windows驱动程序一样,仅需使用旧版SSE指令手动保存/恢复矢量reg的低128位。 (这就是为什么旧版SSE指令不会将完整YMM / ZMM的高字节清零的原因)。 IDK(如果有人针对内核模式strcpy
或strlen
或memcpy
进行基准测试)。