为什么LLVM执行引擎比编译代码更快?

mgi*_*uca 44 llvm

我有一个针对LLVM的编译器,我提供了两种运行代码的方法:

  1. 自动运行它.此模式将代码编译为LLVM,并使用ExecutionEngine JIT将其编译为机器代码,并在不生成输出文件的情况下运行它.
  2. 编译它并单独运行.此模式输出LLVM .bc文件,我手动优化(使用opt),编译为本机程序集(使用llc)编译为机器代码并链接(使用gcc),然后运行.

我期待方法#2比方法#1更快,或者至少相同的速度,但运行一些速度测试,我惊讶地发现#2持续运行大约两倍的速度.这是一个巨大的速度差异.

两种情况都运行相同的LLVM源代码.方法#1,我还没有打算运行任何LLVM优化传递(这就是为什么我期望它更慢).随着办法#2,我正在opt-std-compile-optsllc-O3,最大限度地优化,但它是不是接近#1成气候.以下是同一程序的示例运行:

  • 没有优化的#1:11.833s
  • 没有优化的#2:22.262s
  • #2优化(-std-compile-opts-O3):18.823s

ExecutionEngine是否做了一些我不知道的特殊事情?有没有办法让我优化编译代码以实现与ExecutionEngine JIT相同的性能?

Mic*_*lon 30

具有JIT的VM运行某些应用程序比编译应用程序更快是正常的.这是因为带有JIT的VM就像是模拟虚拟计算机的模拟器,并且还可以实时运行编译器.由于这两个任务都是使用JIT构建到VM中的,因此机器模拟器可以将信息提供给编译器,以便可以重新编译代码以更有效地运行.它提供的信息不适用于静态编译的代码.

Java VM和Python的PyPy VM等也注意到了这种效果.

  • 实际上,JIT或在线二进制重编译方法可以快10倍以上.当前系统的关键性能问题是缓存性能的巨大差距.片上存储器RANDOM访问时间约为1 ns,芯片外5nS(1 Gops)RANDOM访问时间为50-500 nS(20 Mops至2Mops)光盘随机访问超过1M(1 Kop)JIT可以优化以避免这些未命中 - 轻松2x和100x,带有大量或深层的多核心.没有什么是免费的 - 通常使用的机制都是耗电的. (6认同)

Grz*_*cki 14

另一个问题是调整代码和其他优化.现在cpu是如此复杂,以至于很难预测哪种技术会导致最终二进制文件的执行速度更快.

作为一个真实的例子,让我们考虑一下Google的Native Client - 我的意思是原始的nacl编译方法,而不是LLVM(因为据我所知,目前有支持"nativeclient"和"LLVM bitcode"的方向(modyfied)码).

正如您在演示文稿(请查看youtube.com)或论文中看到的那样,如本机客户端:便携式沙箱,不受信任的x86本机代码,甚至它们的对齐技术也会使代码大小更大,在某些情况下会使这些指令对齐(对于使用noops的示例)提供更好的缓存命中.

将指令与noops和指令重新排列在并行计算中已知,这里也显示了它的影响.

我希望这个答案给出了一个想法很多情况下会如何对代码执行速度的影响,而且对于不同的代码片段许多可能的原因,和他们每个人都需要调查.从来没有,这是一个有趣的话题,所以如果你找到更多的细节,不要犹豫重复你的答案,让我们知道"Post-Scriptorium",你发现了什么:).(也许链接到白皮书/ devblog与新发现:)).我们随时欢迎基准测试 - 请查看:http://llvm.org/OpenProjects.html#benchmark.