为什么内核不能使用 SSE/AVX 寄存器和指令?

Eva*_*oll 17 kernel intel optimization syscalls assembly

StackOverflow 的这篇文章有这个

在某些环境中,对某些指令或使用某些寄存器存在限制。例如,在 Linux 内核中,通常不允许使用 SSE/AVX 或 FP 寄存器。因此,大多数优化的 memcpy 变体无法使用,因为它们依赖于 SSE 或 AVX 寄存器,并且在 x86 上使用了基于 mov 的纯 64 位副本。对于这些平台,使用 rep movsb 可以在不破坏 SIMD 代码限制的情况下获得优化的 memcpy 的大部分性能。

为什么 x86_64 内核不能使用 SSE/AVX?如果它会使memcopy()速度更快,似乎应该允许它。我只是在学习 Intel Assembly,当我看到这个评论时,我特别想学习 SEE/AVX。

对 Linux 内核中的 SSE/MME 和 AVX 优化特别感兴趣。

Ste*_*itt 24

正如Gilles 所提到的,在任何可能使用 FPU 的地方,内核都需要支持保存和恢复其状态。由于用户空间可以使用 FPU,因此在任何情况下都需要在上下文切换时处理(,当前 CPU 从一个线程切换到另一个线程时)——至少,当先前运行的线程使用 FPU 时。那么为什么不把它扩展到内核呢?

避免在内核中使用 FPU 的原因有两个:

  • 从可移植性的角度来看,有些架构根本不支持在内核中使用FPU,所以泛型代码不能依赖它;
  • 保存和恢复 FPU 状态是昂贵的,并且引入了某些与实现相关的约束(在 x86 Linux 上,这里特别需要仔细考虑抢占)。

让内核避免使用 FPU 意味着可以减少用户空间的成本:FPU 状态只需要在返回用户空间时在上下文切换后恢复(而不是在上下文切换后立即恢复),而不是在所有情况下情况(仅当所涉及的线程实际使用 FPU 时)。

然而,可以在内核中使用FPU(和MMX / SSE / AVX),在具体的x86的代码,其中利大于弊:因此它结束了在密码代码和RAID6被使用。这些来自 Linus 的电子邮件提供了更多详细信息。如果你想使用的FPU,则需要括所有代码的使用FPU,kernel_fpu_beginkernel_fpu_end,并确保它不能指责或睡眠。查看arch/x86/include/asm/fpu/api.harch/x86/kernel/fpu/core.c了解详情。

对于memcpy,性能提升不会超过使用 FPU 的成本。

(x86 具有相当复杂的 FPU 架构,但它提供了操作系统共享 FPU 所需的所有功能:它可以在发出 FPU 指令时捕获,这允许内核针对从不使用的进程进行优化FPU,它可以指示 CPU 和 FPU 状态何时容易发生分歧。它还提供了保存和恢复 FPU 状态的指令 — FSAVEFXSAVE,以及XSAVE取决于 FPU 的年份。FPU 支持可能是 8086 设计的一个方面,其中设计师最有远见。)