Writing an OS in Rust

Philipp Oppermann's blog

Disable SIMD

单指令多数据 指令允许在一个操作符(比如加法)内传入多组数据,以此加速程序执行速度。x86_64 架构支持多种SIMD标准:

  • MMX: 多媒体扩展 指令集于1997年发布,定义了8个64位寄存器,分别被称为 mm0mm7,不过,这些寄存器只是 x87浮点执行单元 中寄存器的映射而已。
  • SSE: 流处理SIMD扩展 指令集于1999年发布,不同于MMX的复用浮点执行单元,该指令集加入了一个完整的新寄存器组,即被称为 xmm0xmm15 的16个128位寄存器。
  • AVX: 先进矢量扩展 用于进一步扩展多媒体寄存器的数量,它定义了 ymm0ymm15 共16个256位寄存器,但是这些寄存器继承于 xmm,例如 xmm0 寄存器是 ymm0 的低128位。

通过应用这些SIMD标准,计算机程序可以显著提高执行速度。优秀的编译器可以将常规循环自动优化为适用SIMD的代码,这种优化技术被称为 自动矢量化

尽管如此,SIMD会让操作系统内核出现一些问题。具体来说,就是操作系统在处理硬件中断时,需要保存所有寄存器信息到内存中,在中断结束后再将其恢复以供使用。所以说,如果内核需要使用SIMD寄存器,那么每次处理中断需要备份非常多的数据(512-1600字节),这会显著地降低性能。要避免这部分性能损失,我们需要禁用 ssemmx 这两个特性(avx 默认已禁用)。

我们可以在编译配置文件中的 features 配置项做出如下修改,加入以减号为前缀的 mmxsse 即可:

"features": "-mmx,-sse"

浮点数

还有一件不幸的事,x86_64 架构在处理浮点数计算时,会用到 sse 寄存器,因此,禁用SSE的前提下使用浮点数计算LLVM都一定会报错。 更大的问题在于Rust核心库里就存在着为数不少的浮点数运算(如 f32f64 的数个trait),所以试图避免使用浮点数是不可能的。

幸运的是,LLVM支持 soft-float 特性,这个特性可以使用整型运算在软件层面模拟浮点数运算,使得我们为内核关闭SSE成为了可能,只需要牺牲一点点性能。

要为内核打开 soft-float 特性,我们只需要在编译配置文件中的 features 配置项做出如下修改即可:

"features": "-mmx,-sse,+soft-float"

Comments

你有问题需要解决,想要分享反馈,或者讨论更多的想法吗?请随时在这里留下评论!请使用尽量使用英文并遵循 Rust 的 code of conduct. 这个讨论串将与 discussion on GitHub 直接连接,所以你也可以直接在那边发表评论

Instead of authenticating the giscus application, you can also comment directly on GitHub.