我正在阅读 Robert Love 的“Linux Kernel Development”,我遇到了以下段落:
否(容易)使用浮点 当用户空间进程使用浮点指令时,内核管理从整数到浮点模式的转换。内核在使用浮点指令时必须做什么因架构而异,但内核通常会捕获一个陷阱,然后启动从整数模式到浮点模式的转换。与用户空间不同,内核没有对浮点的无缝支持的奢侈,因为它不能轻易地陷入困境。在内核中使用浮点需要手动保存和恢复浮点寄存器,以及其他可能的琐事。简短的回答是:不要这样做!除了极少数情况外,内核中没有浮点运算。
我从未听说过这些“整数”和“浮点”模式。它们到底是什么,为什么需要它们?这种区别是否存在于主流硬件架构(例如 x86)上,还是特定于一些更奇特的环境?从进程和内核的角度来看,从整数模式到浮点模式的转换究竟需要什么?
kernel_fpu_begin()
/ kernel_fpu_end()
以确保用户空间 FPU 状态为t 损坏。这就是 Linux 的 md
代码对 RAID5 / RAID6 所做的。
因为...
许多程序不使用浮点或不在任何给定的时间片上使用它;和
保存 FPU 寄存器和其他 FPU 状态需要时间;所以
...操作系统内核可能会简单地关闭 FPU。 Presto,没有要保存和恢复的状态,因此更快的上下文切换。 (这就是模式的意思,它只是意味着启用了 FPU。)
如果程序尝试 FPU 操作,程序将陷入内核,内核将打开 FPU,恢复任何可能已经存在的保存状态,然后返回以重新执行 FPU 操作。
在上下文切换时,它知道实际执行状态保存逻辑。 (然后它可能会再次关闭 FPU。)
顺便说一句,我相信这本书对内核(而不仅仅是 Linux)避免 FPU 操作的原因的解释是......并不完全准确。1
内核可以陷入自身并在很多事情上都这样做。 (定时器、页面错误、设备中断等。)真正的原因是内核并不特别需要 FPU 操作,并且还需要在根本没有 FPU 的架构上运行。因此,它只是避免了管理自己的 FPU 上下文所需的复杂性和运行时间,因为它不执行总是有其他软件解决方案的操作。
有趣的是,如果内核想要使用 FP ,必须多久保存一次 FPU 状态。 . .每一次系统调用,每一次中断,每一次内核线程之间的切换。即使偶尔需要内核 FP,2 在软件中执行它可能会更快。
1.也就是说,大错特错。 2. 我知道一些关于内核软件包含浮点算术实现的情况。一些架构在硬件中实现了传统的 FPU 操作,但将一些复杂的 IEEE FP 操作留给了软件。 (想想:非正规算术。)当一些奇怪的 IEEE 极端情况发生时,它们会陷入软件,该软件包含可以陷阱的操作的迂腐正确仿真。
对于某些内核设计,当“内核”或“系统”任务被任务切换时,浮点寄存器不会被保存。 (这是因为 FP 寄存器很大,需要时间和空间来保存。)因此,如果您尝试使用 FP,值将随机“噗”。
此外,一些硬件浮点方案依赖内核通过陷阱处理“奇数”情况(例如,零除法),并且所需的陷阱机制可能处于比内核任务当前运行的更高“级别”。
由于这些原因(以及更多原因),当您在任务中第一次使用 FP 指令时,一些硬件 FP 方案将陷入困境。如果您被允许使用 FP,则在任务中打开一个浮点标志,如果没有,您将被行刑队枪杀。
kernel_fpu_begin()
/ kernel_fpu_end()
来触发用户空间 FPU 状态的保存/恢复(我猜你的内核 FPU 状态反对抢占)。
关于内核空间中的浮点使用,我得到了这个结果。我想知道的是,这不是一个“旧的”实现(兼容性),因为旧的架构在巫婆中实现了专用的 FPU,并且 FPU 指令被外包给拥有自己的管道的物理“协处理器”?
我可以想象,由于流水线延迟等原因,这样的架构应该以不同的方式处理“外包”指令,但我记得当前架构(Arm.v8)将其 IEEE754 指令作为指令集的一部分,而不是作为外部 FPU-模块。所以无法开启或关闭,也不存在流水线延迟的问题。是的,可能一些应该保存/恢复的 CORE 寄存器,但这似乎可以忽略不计(与堆栈管理的开销相比)。
在我看来,没有理由不在内核中使用浮点数。如上所述,它已经在内核空间中用于 RAID。