为Erlang/OTP实施BeamAsm-A JIT

2020-09-12 00:06:35

BeamAsm提供将Erlang BEAM指令加载时转换为x86-64上的本机代码。这允许加载器消除任何指令分派开销,并根据其参数类型专门化每条指令。

BeamAsm不进行任何交叉指令优化,x和y寄存器阵列的工作方式与解释BEAM指令时相同。这允许Erlang运行时系统在很大程度上保持不变,除了需要使用加载的BEAM指令(如代码加载、跟踪和其他一些指令)的地方。

BeamAsm使用asmjit在运行时生成本机代码。只使用了asmjit的汇编器API的一小部分。目前,asmjit只支持x86 32/64位汇编器,但是也支持ARM 64位的工作正在进行中。

有关实现如何工作的更详细描述,您可以查看BeamAsm的内部文档。

BeamAsm比翻译器快多少?这在很大程度上取决于您的应用程序正在做什么。

例如,Estone基准测试套件计算的Estone数量增加了约50%,这意味着在同一时间段内可以多做约50%的工作。Estone基准测试套件中的各个基准测试从增加170%(模式匹配)到完全不变(巨大的消息)不等。因此,计算繁重的工作负载可以显示出相当大的收益,而通信繁重的工作负载保持不变,这并不令人惊讶。

如果我们运行Poison或Jason中的JSON基准测试,对于所有Erlang/Elixir实现,BeamAsm的每秒迭代次数增加了30%到130%(平均约为70%)。对于某些基准测试,BeamAsm甚至比纯C实现更快。

更复杂的应用程序往往会有更温和的性能提升,例如,RabbitMQ能够根据场景每秒多处理30%到50%的消息。

执行本机代码的一大好处是,一些用于分析C/C++/rust/go的实用程序可以用来分析Erlang代码。例如,Linux上的Perf运行可能如下所示:

关于如何实现这一点,BeamAsm的内部文档中有更多详细信息。

加载本机代码使用更多内存。我们希望使用BeamAsm时加载的代码比使用解释器时大10%左右。

此PR包括对Erlang代码加载器工作方式的重大重写。新的加载器不包括HIPE支持,这意味着它将不可能在OTP-24中运行HIPE编译代码。

我们仍然在寻找任何想要维持Hipe的人,这样它就可以继续突破高性能Erlang的极限。

我们期待您就BeamAsm的功能和性能提供任何反馈。要编译它,您需要一个相对现代的C++编译器和一个允许内存同时可执行和可写的操作系统(这是大多数操作系统,除了OpenBSD)。

请注意,这些测试是使用我们的内部夜间测试构建的,因此包含的更改比此PR包含的更改更多。