通过在 Ruby 中重写 C…来加快 Ruby 的速度

主要观点:

  • 近期一个语言比较仓库显示 CRuby 在某些基准测试中表现不佳,仅优于 R 和 Python。
  • 仓库包含两个基准测试,“Loops”和“Fibonacci”,分别强调不同方面的性能。
  • 运行在不同设备上,Ruby 的性能有所差异,与 node.js 相比在某些基准测试中表现较差。
  • YJIT 能显著提升 Ruby 的性能,尤其是在 Fibonacci 计算和循环迭代方面。
  • CRuby 中一些核心方法如Range#eachInteger#timesArray#each在不同版本中从 C 转换为 Ruby,YJIT 对 Ruby 代码的优化有重要作用。
  • 作者创建了“Ruby Microbench”仓库来测试不同 Ruby 实现的性能。
  • 可以通过 monkey patch 等方式优化Range#each的性能,展示了将代码移出 C 让 YJIT 优化的力量。
  • 核心 YJIT 团队创建了with_yjit块,实现了 C 代码和 Ruby 实现的切换,YJIT 可懒初始化。
  • 深入研究 YJIT 生成的机器码,了解其优化过程,如对Integer#succ的优化。

关键信息:

  • 语言比较仓库地址:https://github.com/bddicken/l...
  • 可视化代码地址:https://benjdd.com/languages/
  • 仓库描述:用于协作构建比较语言的小基准测试
  • 基准测试示例代码:包括“Loops”和“Fibonacci”的 Ruby 代码
  • 不同 Ruby 版本及 YJIT 运行的性能测试结果
  • 关于Range#eachInteger#timesArray#each从 C 到 Ruby 的转换及优化细节
  • “Ruby Microbench”仓库地址:https://github.com/jpcamara/r...
  • YJIT 相关代码如with_yjit的实现方式

重要细节:

  • Ruby 3.3.6 在 M3 MacBook Pro 上运行“Loops”示例需 28 秒,“Fibonacci”示例需 12 秒,node.js 约 1 秒多。
  • 在 M2 MacBook Air 上运行“Loops”示例需 33.43 秒,“Fibonacci”示例需 16.33 秒,node.js 约 1 秒多。
  • Range#each由 C 实现,YJIT 无法优化,其实现位于range.c文件的Init_Range函数中。
  • Ruby 3.3 中Integer#times从 C 函数转换为 Ruby 方法,更易被 YJIT 优化。
  • Ruby 3.4 中Array#each从 C 转换为 Ruby,经历了从简单到避免race conditions的过程。
  • 在“Ruby Microbench”仓库中,不同 Ruby 实现在各种基准测试中的性能差异。
  • 通过 monkey patch 优化Range#each的简单实现及性能提升。
  • YJIT 生成的机器码中对Integer#succ的优化细节,包括对 Fixnum 的检查和加法操作。
阅读 9
0 条评论