我知道当应用程序想要执行浮点操作时,必须将英特尔处理器配置为在浮点模式下工作。每次我需要执行浮点操作时,更改模式是不是太昂贵了?谁负责做这个"模式改变":编译器还是操作系统?考虑到浮点寄存器与整数寄存器分开,为什么FPU并不总是准备好工作?
这不是一个整数与FP模式,只有x87和SSE控制寄存器位,使任何FP指令错误。(或MMX或XMM regs中的整数SIMD)。
现在大多数进程都在使用XMM regs,例如,即使对于内存,和"急切"。上下文切换上的FPU保存策略更有意义,在切换到新的用户空间任务之前,总是保存/恢复FP/SIMD寄存器。(特别是当负载/存储吞吐量相对于中断开销有所改善时。)进入内核进行系统调用或中断仍然只保存GP整数寄存器,但是内核避免使用FP指令本身,而不会触发可能不干净的用户空间状态的保存。(所以它是昂贵的,只有少数情况下,如RAID5/RAID6和加密驱动程序可以这样做。)
旧的Linux内核使用"lazy"FPU储蓄在上下文切换时清除这些位,这样任何这样的指令都会出错,希望被切换到的新任务能够在没有出错的情况下结束它的时间片。在这种情况下,FP/SIMD寄存器可以保持不变,使用最后运行FP/SIMD指令的用户空间任务的值。
该故障机制允许内核介入并保存旧的FP寄存器,然后使用恢复的FP寄存器恢复当前任务。但是,一旦完成了FP/SIMD上下文切换,以后的指令就可以在其时间片的剩余时间内执行而不会出错。
热心保存/恢复是几年前的默认设置,而"懒惰"mode已经从Linux源代码树中完全移除。同样,因为中断在深度流水线的OoO执行cpu上非常昂贵,并且因为在给定当前缓存/内存带宽的情况下保存/恢复FP regs并不那么昂贵。
顺便说一句,你在问题中的描述(除了你的评论)听起来可能是在使用x87指令之前需要在MMX整数simd之后需要emms
。
这就是为什么MMX几乎从不使用的几个原因之一,而是使用没有这个问题的SSE2。(x87本身几乎从不在64位代码中使用,再次支持SSE2寄存器中的标量操作,使用平面寄存器文件而不是堆栈。)