现代x86成本模型



我正在编写一个带有x86后端的JIT编译器,并边学习x86汇编程序和机器代码。大约20年前,我使用了ARM汇编程序,并对这些架构之间的成本模型差异感到惊讶。

具体来说,内存访问和分支在ARM上是昂贵的,但等效的堆栈操作和跳跃在x86上是便宜的。我相信现代x86 CPU比ARM内核做的动态优化要多得多,我发现很难预测它们的效果。

在编写x86汇编程序时,需要记住什么是好的成本模型?哪些指令组合比较便宜,哪些比较昂贵?

例如,如果我的编译器总是生成加载整数或跳转到偏移量的长形式,即使整数很小或偏移量很近,它也会更简单,但这会影响性能吗?

我还没有做任何浮点运算,但我想尽快开始。普通代码和浮点代码之间的交互有什么不明显的地方吗?

我知道有很多关于x86优化的参考文献(例如Michael Abrash),但我有一种预感,几年前的任何东西都不适用于现代x86 CPU,因为它们最近变化太大了。我说得对吗?

最好的参考资料是《英特尔优化手册》,它提供了关于所有最新英特尔内核的体系结构危害和指令延迟的相当详细的信息,以及大量优化示例。

另一个很好的参考是Agner Fog的优化资源,其优点是也涵盖AMD核心。

请注意,特定的成本模型本质上是特定于微观架构的。没有"x86成本模型"这样的东西具有任何真正的有效性。在指令级别,Atom的性能特性与i7有很大不同。

我还要注意的是,在x86内核上,内存访问和分支实际上并不"便宜"——只是无序执行模型变得如此复杂,以至于它可以在许多简单的场景中成功地隐藏它们的成本。

Torbjörn Granlund针对AMD和Intel x86处理器的指令延迟和吞吐量也很好。

编辑

Granlund的文档关注的是在每个时钟周期可以发出多少特定类型的指令(即并行执行)的情况下的指令吞吐量。他还声称,英特尔的文件并不总是准确的。

当然,Agner Fog的报告以及"英特尔®;64与IA-32体系结构优化参考手册"都是必要且优秀的参考资料。AMD还有一本优化手册:

  • AMD系列15h处理器软件优化指南

然而,两个英特尔工具对于理解代码序列是必不可少的:

  • 英特尔®;体系结构代码分析器
  • 英特尔®;VTune™

IACA是您的成本模型。我在OSX上使用它,但VTune只在Windows和Linux上运行。

您还可以深入研究英特尔专利文献和各种英特尔论文,以更好地了解事情是如何工作的:

  • 下一代英特尔核心微体系结构
  • 哈斯韦尔:第四代英特尔核心处理器
  • 微操作缓存:可变指令长度ISA的电源感知前端

值得一看现有的后端开源编译器,如GCC和LLVM。这些有指令成本的模型,也有不错的(但理想化的)机器模型(例如,问题宽度、缓存大小等)。

我正在编写一个带有x86后端的JIT编译器,并学习x86汇编程序和机器代码。

这里的主要问题是JIT编译器不能花费大量的时间进行微观优化。由于"优化"发生在运行时,因此进行优化的成本需要小于优化节省的时间(否则,优化将成为性能的净损失)。

对于80x86,有多个具有不同行为/特性的不同CPU。如果你考虑到实际CPU的特定特性,那么进行优化的成本就会增加,你会直接陷入"成本大于收益"的障碍。对于像"理想指令调度"这样的事情尤其如此。

幸运的是,大多数(但不是所有)现代80x86 CPU都具有各种功能(无序、推测性执行、超线程),以减轻(部分)由"不完美"优化造成的性能成本。这往往会使昂贵的优化变得不那么有益。

你要做的第一件事是确定哪些代码应该优化,哪些不应该优化。不经常执行的事情(例如"只执行一次"初始化代码)根本不应该优化。只有经常执行的部分(例如内部循环等)才值得麻烦。一旦你确定了一个值得优化的部分,那么问题就变成了"多少?"。

作为一种粗暴的过度概括;我预计(平均而言)90%的代码根本不值得优化,而9%的代码只值得进行一些通用优化。剩下的1%(理论上可能受益于广泛的优化)最终将成为JIT编译器开发人员在实践中难以解决的问题(并将导致巨大的复杂性/可验证性噩梦,例如"只有在某些CPU上运行时才存在的错误"场景)。

最新更新