在循环优化上花费了太多时间

这是一系列关于在 Rust 中推动编程语言解释器性能的博客文章的一部分。

什么?谁?

作者的博士研究是关于 AST 解释器的运行时性能,去年发表了“AST 与字节码:元编译时代的解释器”论文,比较了基于两种不同元编译系统(GraalVM 和 RPython)的 AST 和字节码解释器,得出 AST 解释器性能良好的结论。有人质疑 AST 解释器是否只在依赖高级语言的元编译系统上表现好,作者尝试在 Rust 中让解释器性能达到现有水平甚至更好。Nicolas Polomack 编写了 som-rs 解释器,作者对其进行性能优化,几个月后取得了显著成果。

本周发生了什么?

  • 对于 SOM 语言的解释器,循环是方法调用,速度不是最快的,通常可以通过降低(如在字节码级别或直接在解释器中处理)来提高性能,作者已经为whileTrue:实现了一些优化。
  • 常见的循环方式Integer>>#to:do:目前没有被特殊处理以获得更好性能,作者决定将其实现为一个原始函数(primitive),即直接在解释器中处理为特殊情况。实现的to:do:原始函数通过检查栈上的参数类型来执行循环体,但缺少执行块的关键部分。
  • 执行块的方式是将 50 个新的块帧压入栈中,但这样会导致解释器出错,因为每个方法或块都有返回值,而这里不需要关心块的返回值,需要在每个块执行后弹出栈顶值。作者通过添加am_i_ugly标志来解决这个问题,但代码很丑陋且在某些情况下会导致性能下降。
  • 更好的解决方案是执行一个自我清理的修改版本的块,通过在每个RETURN之前添加POP来清空栈,但这需要修改字节码集,增加了复杂性和开发时间。也可以在编译时生成块,但由于需要在运行时访问块的来源,实现起来并不容易。最终采用在运行时创建修改块的方案,取得了巨大的性能提升。

我们学到了什么?

  • 解释器的设计很重要,选择不同的执行方式会影响性能。
  • 优化循环操作可以显著提高运行时性能。
  • 快速简单的解决方案往往并不简单,需要对系统和解释器设计有深入的了解。

感谢 Stefan Marr 的反馈和帮助,作者将继续分享相关内容。

阅读 12
0 条评论