为什么copy_user_enhanced_fast_string不使用AVX(如果可用)?

时间:2019-12-30 04:34:50

标签: linux assembly linux-kernel x86-64

当了解我的应用程序的分析结果(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在复制可用位置方面没有性能优势吗?

1 个答案:

答案 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(如果有人针对内核模式strcpystrlenmemcpy进行基准测试)。