为什么LLVM执行引擎比编译代码更快?
我有一个针对LLVM的编译器,我提供了两种运行代码的方法:
- 自动运行。 该模式将代码编译为LLVM,并使用ExecutionEngine JIT将其编译为机器代码并运行,而不会生成输出文件。
- 编译并单独运行。 这个模式输出一个LLVM .bc文件,我手动优化(用
opt
),编译成本地程序集(用llc
)编译成机器代码和链接(用gcc
),然后运行。
我期待的方法#2比方法#1更快,或者至less是相同的速度,但是运行一些速度testing,我惊讶地发现#2的速度一直是大约两倍的速度。 这是一个巨大的速度差异。
这两种情况都运行相同的LLVM源代码。 有了方法#1,我还没有想过运行任何LLVM优化过程(这就是为什么我期望它会变慢)。 使用方法#2,我正在使用-O3
运行-std-compile-opts
和llc
,以便最大化优化,但是它并没有在#1附近。 下面是同一个程序的一个例子:
- #1没有优化:11.833s
- #2没有优化:22.262s
- #2优化(
-std-compile-opts
和-O3
):18.823s
ExecutionEngine是否做了一些我不知道的特殊事情? 有什么办法可以优化编译后的代码,以达到与ExecutionEngine JIT相同的性能?
具有JIT的VM运行某些应用程序比编译的应用程序更快是正常的。 这是因为带有JIT的虚拟机就像是一个模拟虚拟机的模拟器,也可以实时运行编译器。 由于这两个任务都是使用JIT构build到VM中的,因此机器模拟器可以将信息提供给编译器,以便代码可以重新编译以更高效地运行。 它提供的信息不可用于静态编译的代码。
Java VM和Python的PyPy VM等等也都注意到了这种效果。
另一个问题是alignment代码和其他优化。 现在的CPU非常复杂,很难预测哪种技术会导致最终二进制的执行速度更快。
作为一个真实的例子,让我们考虑一下Google的Native Client – 我的意思是原始的nacl编译方法,不包括LLVM(据我所知,目前支持“nativeclient”和“LLVM bitcode”码)。
正如你可以在演示文稿(签出youtube.com)或论文中看到的一样,例如Native Client:便携式,不可信x86本机代码的Sandbox ,甚至它们的alignment技术都会使代码大小变大,在某些情况下,这样的指令alignment例子与noops)给更好的caching命中。
alignment指令与noops和指令重新sorting它在并行计算中已知,在这里它也显示了它的影响。
我希望这个答案给出了一个想法,可能会影响代码速度执行的情况,并且有很多可能的原因,对于不同的代码片段,每一个都需要调查。 永远不会,这是一个有趣的话题,所以如果你find更多的细节,不要犹豫,重新回答你的答案,并让我们知道“Post-Scriptorium”,你有什么发现更多:)。 (也许链接到白皮书/ devblog与新的发现:))。 基准总是值得欢迎的 – 看看: http : //llvm.org/OpenProjects.html#benchmark 。