Ruby 3.3 的速度再次提升

在「Ruby 3.3's YJIT Runs Shopify's Production Code 15% Faster」這篇提到了 Ruby 3.3 的速度再次提升的消息。

Shopify 上面的測試,3.3.0-preview2 的速度已經比 3.2.2 (兩者都有開啟 YJIT) 快了 13%,而且 p50/p90/p99 都有對應的改善:

不過有提到一些要注意的點,像是記憶體的用量又會再更高 (本來開 YJIT 的時候就已經有增加了),如果是對記憶體比較敏感的環境,會需要注意這點:

Since Ruby 3.3.0-preview2 YJIT generates more code than Ruby 3.2.2 YJIT, this can result in YJIT having a higher memory overlead. We put a lot of effort into making metadata more space-efficient, but it still uses more memory than Ruby 3.2.2 YJIT. We’re looking into skipping compilation of paths that are less frequently executed.

但 server 端應該是還好 (記憶體給多一點),整體是個可以期待的方向...

Ruby 再引入另外一套 JIT 實做:RJIT

Hacker News Daily 上看到「RJIT #7448」這個,Ruby 上一套新的 JIT 實做。

這次的 RJIT 取代掉先前的 MJIT:

This PR replaces the current implementation of MJIT with a new JIT called "RJIT"

有些特點,其中一個是 RJIT 在 buildtime 與 runtime 都不需要 compiler,這是因為 RJIT 直接用 Ruby 實做:

RJIT uses a pure-Ruby assembler to generate native code

  • MJIT requires a C compiler at runtime. YJIT requires a Rust compiler at build time. RJIT doesn't require them.
  • This means that RJIT's warmup could be slower than YJIT, but it's still much faster than MJIT's.

另外值得注意的是,RJIT 的作者 k0kubunYJIT 的作者 Maxime Chevalier-Boisvert 都是 Shopify 的員工,可以看出 Shopify 對於 Ruby 效能的痛?決定直接自己養人改善效能。

回到 RJIT 這邊跑的測試,可以看到他是用 YJIT 的測試套件測,這也就不會太奇怪了。

跟這次取代掉的 MJIT 相比,RJIT 在 Headline 這包測試都 OK,在 Other 這包則是有來有回,而在 Micro 這包則是有不少項目輸掉 (相比於前兩者):

這樣整體看起來算是有進步,下一版 Ruby 更新應該就會有了。

Ruby 3.2.0 把 YJIT 列為穩定功能了

去年有寫過 RubyYJIT 帶來的效能提昇:「YJIT 帶給 Ruby 大量的效能提昇」。

在這次的 Ruby 3.2.0 發布就把 YJIT 列為穩定功能了:「Ruby 3.2.0」。

  • YJIT is no longer experimental
    • Has been tested on production workloads for over a year and proven to be quite stable.

另外就是支援的平台,看起來是多了 arm64 這邊的支援,所以馬上列表就多了一堆新機器:

  • YJIT now supports both x86-64 and arm64/aarch64 CPUs on Linux, MacOS, BSD and other UNIX platforms.
    • This release brings support for Apple M1/M2, AWS Graviton, Raspberry Pi 4 and more.

另外是每個程式語言幾乎都會遇到的 regexp 類的問題,這次 Ruby 3.2.0 利用 Memoization 的方式降低某些 regexp 的消耗:

# This match takes 10 sec. in Ruby 3.1, and 0.003 sec. in Ruby 3.2
/^a*b?a*$/ =~ "a" * 50000 + "x"

而另外一組 regexp 也可以看出類似的效果:

用一些記憶體空間換取效能,降低被 DoS 的一些機會。另外一方面,引入了 regexp timeout 的 workaround,緩解真的被打的時候的資源消耗上限:

The optimization above cannot be applied to some kind of regular expressions, such as those including advanced features (e.g., back-references or look-around), or with a huge fixed number of repetitions. As a fallback measure, a timeout feature for Regexp matches is also introduced.

Fork 自微軟的 Pyjion 專案的 Python 3.10 + JIT 方案

Hacker News 上看到「Pyjion – A Python JIT Compiler (trypyjion.com)」這個專案,也是一個想要透過 JIT 加速 Python 的專案:

Pyjion is a drop-in JIT Compiler for Python 3.10. It can be pip installed into a CPython 3.10 installation on Linux, Mac OS X, or Windows.

看了一下是從微軟的 Pyjion 專案 fork 出來的,原來的專案最後一次 commit 是一年前,而且專案也已經標示為 archived (read-only mode),但有留下轉移的說明,也就是上面提到的專案:

Development has moved to https://github.com/tonybaloney/Pyjion

可以看到大部分的效能都已經進入改善階段 (很多導入 JIT 的專案在初期時會先變慢):

跟其他的 JIT 方案相比,Pyjion 的目標是高度相容現有 Python 的程式,包括各種 extension,這點的確是在用 PyPy 這些軟體時的痛點沒錯...

看起來透過 pip 裝好後就可以直接 import 進來用,後續就會生效:

import pyjion; pyjion.enable()

另外提一下,翻 Hacker News 留言的時候翻到這個害我笑出來,有夠新 XD

zatarc 3 days ago | unvote | prev | next [–]

Pyjion requires: CPython 3.10 and .NET 6

.NET 6 Release: 19 hours ago (https://github.com/dotnet/core/blob/main/release-notes/6.0/6...)

... ok.

YJIT 帶給 Ruby 大量的效能提昇

Hacker News 首頁上看到的消息,由 Shopify 贊助的 YJIT 被 Ruby 官方接受了:「Merge YJIT: an in-process JIT compiler (github.com/ruby)」。

YJIT currently provides average speedups of 23% over the CRuby interpreter on realistic benchmarks, and near-instant warm-up time.

實做 YJIT 的 Maxime Chevalier-Boisvert 在他自己的 blog 上有提到這次的實做:「YJIT: Building a New JIT Compiler Inside CRuby」,裡面選擇的方法是他的 PhD 論文:「Simple and Effective Type Check Removal through Lazy Basic Block Versioning」。

可以看到在六月寫文章的時候,改善其實還沒這麼大,而且作者提到有不少可以再提昇的空間:

That being said, according to our benchmarks, we’ve been able to achieve speedups over the CRuby interpreter of 7% on railsbench, 19% on liquid template rendering, and 19% on activerecord.

Currently, only about 50% of instructions in railsbench are executed by YJIT, and the rest run in the interpreter, meaning that there is still a lot we can do to improve upon our current results.

本來的 MJIT 看起來會慢慢淡出...

PyPy JIT 的改善

PyPy 這邊看到 JIT 的重大進展:「Better JIT Support for Auto-Generated Python Code」。

他們在 Tornado 上重製出來效能問題,後面也都是用這個例子在測試:

If you render a big HTML template (example) using the Tornado templating engine, the template rendering is really not any faster than CPython.

看起來上的 workaround 是在撞到 trace limit 時標記起來,之後再遇到時就可以跳進 special mode,接著處理下去避免浪費掉之前處理過的 trace:

After we have hit the trace limit and no inlining has happened so far, we mark the outermost function as a source of huge traces. The next time we trace such a function, we do so in a special mode. In that mode, hitting the trace limit behaves differently: Instead of stopping the tracer and throwing away the trace produced so far, we will use the unfinished trace to produce machine code.

效能可以看到改善很多:

看起來這個概念有打算在 3.8 的時候放進去:

The work described in this post tiny bit experimental still, but we will release it as part of the upcoming 3.8 beta release, to get some more experience with it. Please grab a 3.8 release candidate, try it out and let us know your observations, good and bad!

Django 的 template engine 不怎麼快,用 Jinja2 可能是一個方法,但既有的 project 如果有遇到 template engine 的效能問題,也許也可以翻看看 PyPy 解得如何...

Facebook 推出了 Hermes,為了 React Native 而生的 JS Engine

Facebook 提供了一個對 React Native 最佳化的 JS engine:「Hermes: An open source JavaScript engine optimized for mobile apps, starting with React Native」。

裡面有提到兩個比較重要的的部份是 No JIT 與 Garbage collector strategy,針對行動裝置的特性而設計:避免 JIT 產生的 overhead,以及降低記憶體使用量。

官方給的改善主要也都是偏這兩塊:

不過沒有提到 CPU usage 會上升多少,只是帶過去:

Notably, our primary metrics are relatively insensitive to the engine’s CPU usage when executing JavaScript code.

對於 Facebook 也許是可以接受的數量,但對於其他人就沒概念了... 要入坑的人自己衡量這部份的風險 XD

PHP 的 JIT 翻修計畫

在「JIT for PHP project」這邊看到 PHP 新的翻修計畫:

I'm glad to say that we have started a new JIT for PHP project and hope to deliver some useful results for the next PHP version (probably 8.0).

We are very early in the process and for now there isn't any real performance improvement yet. So far we spent just 2 weeks mainly working on JIT infrastructure for x86/x86_64 Linux (machine code generation, disassembling, debugging, profiling, etc), and we especially made the JIT code-generator as minimal and simple as possible. The current state, is going to be used as a starting point for research of different JIT approaches and their usability for PHP.

不知道會帶來多少效能提昇 :o

Webkit 推出 B3 JIT Compiler (Bare Bones Backend)

Webkit 推出了 B3 加快 optimization 的速度,取代原來 LLVM 的工作:「Introducing the B3 JIT Compiler」。

在文章後方 Performance Results 的部份可以看到最主要的差異在啟動時間:

另外也可以看到其他各種 performance benchmark 也幾乎都是小勝 LLVM。

接下來會有 ARM64 與其他平台的計畫:

B3 is not yet complete. We still need to finish porting B3 to ARM64. B3 passes all tests, but we haven’t finished optimizing performance on ARM. Once all platforms that used the FTL switch to B3, we plan to remove LLVM support from the FTL JIT.