在 Linux 内核中使用浮点数

我正在阅读罗伯特 · 洛夫的《 Linux 内核开发》 ,读到了下面这段话:

浮点数不易使用

当用户空间进程使用浮点指令时,内核管理从整数模式到浮点模式的转换。当使用浮点指令时,内核必须做的事情因体系结构而异,但是内核通常会捕捉到一个陷阱,然后开始从整数模式到浮点模式的转换。

与用户空间不同,内核没有对浮点数的无缝支持,因为它不能轻易地捕获自己。在内核中使用浮点需要手动保存和恢复浮点寄存器,以及其他可能的工作。简短的回答是: 别这么做!除了在极少数情况下,内核中没有浮点操作。

我从来没有听说过这些“整数”和“浮点”模式。它们到底是什么,为什么需要它们?这种区别是存在于主流硬件架构(例如 x86)上,还是特定于某些特殊环境?从进程和内核的角度来看,从整数模式到浮点模式的转换到底需要什么?

38295 次浏览

Because...

  • many programs don't use floating point or don't use it on any given time slice; and
  • saving the FPU registers and other FPU state takes time; therefore

...an OS kernel may simply turn the FPU off. Presto, no state to save and restore, and therefore faster context-switching. (This is what mode meant, it just meant that the FPU was enabled.)

If a program attempts an FPU op, the program will trap into the kernel, the kernel will turn the FPU on, restore any saved state that may already exist, and then return to re-execute the FPU op.

At context switch time, it knows to actually go through the state save logic. (And then it may turn the FPU off again.)

By the way, I believe the book's explanation for the reason kernels (and not just Linux) avoid FPU ops is ... not perfectly accurate.1

The kernel can trap into itself and does so for many things. (Timers, page faults, device interrupts, others.) The real reason is that the kernel doesn't particularly need FPU ops and also needs to run on architectures without an FPU at all. Therefore, it simply avoids the complexity and runtime required to manage its own FPU context by not doing ops for which there are always other software solutions.

It's interesting to note how often the FPU state would have to be saved if the kernel wanted to use FP . . . every system call, every interrupt, every switch between kernel threads. Even if there was a need for occasional kernel FP,2 it would probably be faster to do it in software.


1. That is, dead wrong.
2. There are a few cases I know about where kernel software contains a floating point arithmetic implementation. Some architectures implement traditional FPU ops in hardware but leave some complex IEEE FP operations to software. (Think: denormal arithmetic.) When some odd IEEE corner case happens they trap to software which contains a pedantically correct emulation of the ops that can trap.

With some kernel designs the floating-point registers are not saved when a "kernel" or "system" task is task-switched out. (This is because the FP registers are large and take both time and space to save.) So if you attempt to use FP the values will go "poof" randomly.

In addition, some hardware floating-point schemes rely on the kernel to handle "oddball" situations (eg, zero division) via a trap, and the required trap mechanism may be at a higher "level" than the kernel task is currently running.

For these reasons (and a couple more) some hardware FP schemes will trap when you use an FP instruction for the first time in a task. If you're permitted to use FP then a floating-point flag is turned on in the task, if not, you're shot by the firing squad.

I'm hitting this result regarding floating point usage in kernelspace. What I'm wondering is, isn't this an "old" implementation (compatibility) because of the older architectures in witch a dedicated FPU is implemented and FPU instructions are outsourced to a physical 'co-processor' having their own pipelines?

I can imagine that such an architecture should handle 'outsourced' instructions differently because of pipeline delays and such, but as I recall the current architectures (Arm.v8) has their IEEE754 instructions as part of the instruction set, not as an external FPU-module. So it can't be turned on or off, nor have the issue of pipeline delays. Yes, probably some CORE register that should be saved/ restored but that seems negligible (compared to overhead of stack management).

In my opinion there's no argument of not using Floats in the kernel. As already said above, it's already used in kernel-space for RAID.