Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Ruby および Rails 用の JIT コンパイラー:YJIT、MJIT、および TenderJIT でパフォーマンスを向上

プログラムは、実行前コンパイルとは異なる方法を使用して実行時にコンパイルされます。このプロセスは、ジャストインタイム コンパイルまたは動的変換として知られています。

この投稿では、利用可能ないくつかのオプション (YJIT、MJIT、TenderJIT) とそれらのインストール方法を説明する前に、JIT コンパイルが Ruby on Rails アプリに適した選択肢である理由を説明します。

まず最初に、JIT コンパイルはどのように機能するのでしょうか?

JIT コンパイラの仕組み

ジャストインタイム コンパイルは、プログラムの実行中にコンパイルが必要なコンピューター コードを実行する方法です。

これにはソース コードの変換が必要になる場合もありますが、最も頻繁に行われるのは、バイトコードをマシン コードに変換し、直接実行することです。

実行中のコードは、多くの場合、JIT コンパイラーを使用するシステムによって継続的に分析されます。これにより、コンパイルまたは再コンパイルの利点 (速度の点で) がコストを上回るコードのセクションが特定されます。

Ruby の JIT コンパイルの利点

JIT コンパイルは、プログラムをマシンコードに変換する 2 つの従来の方法、解釈と事前コンパイル (AOT) の利点 (および欠点) の一部を組み合わせたものです。

大まかに言うと、解釈の柔軟性と、生成されたコードの速度、および (解釈だけでなく) コンパイルとリンクの追加のオーバーヘッドが組み合わされます。

JIT コンパイルは、動的再コンパイルや特定のマイクロアーキテクチャに合わせた高速化などの適応最適化手法を可能にする動的コンパイルの一種です。ランタイム システムは遅延バインド データ型を処理し、セキュリティ保証を課す機能があるため、Ruby のような動的プログラミング言語は解釈と JIT コンパイルに特に適しています。

GCC のような最適化コンパイラーは、命令をより効率的に最適化できます。これは、レジスター指向のアーキテクチャーを採用することの大きな利点です。コンパイラは、レジスタベースのアーキテクチャによる中間表現で動作します。

コンパイル中に命令が中間表現に達すると、GCC は追加のパスを実行して、CPU による命令の実行を高速化します。

Ruby 用 JIT コンパイラー:YJIT、MJIT、および TenderJIT

ここで、Ruby で利用できるさまざまな JIT コンパイラ (YJIT、MJIT、TenderJIT) とその設定方法を見てみましょう。

Ruby 用 MJIT (メソッドベースのジャストインタイム コンパイラ)

Vladimir Makarov は MJIT を実装しました。これは、C 言語に基づいて Ruby に実装された最初のコンパイラ手法でした。これは Ruby 2.6 で動作し、YARV 命令を使用し、バイナリ コードでよく使用される命令をコンパイルします。

入出力に依存しないプログラムの場合、MJIT はパフォーマンスを向上させます。

YJIT は、パフォーマンスの点でこのオリジナルの C ベースのコンパイラよりも優れています。 Ruby 3 の JIT は、MRI がこれまでに備えた中で最も高速な JIT であり、MJIT の優れた働きによって可能になりました。

MJIT の使用方法

MJIT を使用するには、Ruby 2.6 で --jit を使用して JIT を有効にします。 オプション。

 

この部分をスキップすると、MJIT はエラーを表示します。

 

Ruby 2.6 に含まれる JIT 固有の設定のコレクションは、Ruby 2.6 がどのように機能するかを理解するのに役立ちます。 ruby --help を実行します これらのオプションを表示するには。

つまり、MJIT は別のスレッドで実行され、非同期です。最初の 5 回の計算実行後に、ジャストインタイム コンパイルが開始されます。

Ruby on Rails の YJIT

YJIT と呼ばれる最近の JIT コンパイラーが Ruby 3.1 でリリースされました。これは、多くの改善とパフォーマンスの向上を約束します。まだ実験結果を基に Shopify によって設計された進行中のプロジェクトであるため、特に大規模なアプリケーションでは注意して使用する必要があります。

これを念頭に置いて、YJIT は Ruby on Rails アプリケーションのパフォーマンスを強化します。実際のソフトウェアの大部分は、YJIT 基本ブロック バージョン管理 JIT コンパイラによって提供される高速ウォームアップとパフォーマンス強化の恩恵を受けています。

JIT コンパイラは、YJIT プロジェクトの一部として CRuby に徐々に組み込まれ、最終的にはコード実行の大部分でインタプリタを置き換える予定です。

公式ベンチマーク — 「YJIT:CRuby 用の新しい JIT コンパイラーの構築」を参照 — YJIT がデフォルトの CRuby インタープリターよりも次のようなパフォーマンスを向上させたことを示しています。

  • レールベンチで 20%
  • リキッド テンプレートのレンダリングで 39%
  • アクティブレコードで 37%

ただし:

Railsbench の命令の約 79% のみが YJIT によって実行され、残りはデフォルトのインタープリタで実行されます。

出典:YJIT:CRuby 用の新しい JIT コンパイラの構築

これは、YJIT の現在の結果を改善するには、まだ多くのことを行う必要があることを意味します。

それでも、YJIT は、ハードストーンであっても、すべてのベンチマークでインタープリターと少なくとも同等のパフォーマンスを発揮し、すべてのベンチマークを 1 回繰り返すだけでほぼピークのパフォーマンスに達します。

YJIT の使用方法

注意 :YJIT は現在、x86-64 プラットフォーム上の macOS および Linux に限定されています。また、前述したように、YJIT は大規模なアプリケーションには (まだ) 推奨されていません。

YJIT はデフォルトでは無効になっています。有効にしたい場合は、最初に --yjit を指定します。 コマンドライン オプション。

インストールされているかどうかを確認する必要があるため、ruby --enable-yjit -v を実行します。 。 warning: unknown argument for --enable: の場合 yjit'' が表示されるので、インストールする必要があります。

次に、irb を開きます。 RUBY_YJIT_ENABLE=1 を設定します 。終了すれば、YJIT を使用できるようになります。コマンド ruby --enable-yjit -v ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [arm64-darwin21] のようなものを返す必要があります

テンダージット

主に YJIT に基づいた設計を備えた TenderJIT は、Ruby 用の実験的な JIT コンパイラーです。 TenderJIT の違いは、純粋な Ruby で書かれていることです。

これはデモ プロジェクトであり、gem として出荷することが目的です。それまでの間、試してみることはできますが、まだ開発中であることに留意してください。 TenderJIT には Ruby 3.0.2 以降が必要です。

TenderJIT の使用方法

TenderJIT は現在、メソッドのコンパイルを自動的に実行しません。メソッドをコンパイルするには、TenderJIT を手動で構成する必要があります。

リポジトリのクローンを作成し、次のコマンドを実行します。

 

コード上で手動で設定する必要があります。

 

ターゲット メソッド内の各 YARV 命令は TenderJIT によって読み取られ、マシン コードに変換されます。

TenderJIT のその他の例については、次のビデオのいずれかを確認してください:Aaron Patterson による Ruby 用の JIT コンパイラーと TenderJIT のハッキング!

まとめ

この投稿では、Ruby 用の 3 つの JIT コンパイラー (MJIT、YJIT、および TenderJIT) とそれらの設定方法を簡単に説明しました。各オプションは実験的なものであり、独自の制限があります。

しかし、YJIT は現時点で最も成熟しており、成長し規模を拡大する可能性が最も大きくあります。これは他の Ruby JIT よりも優れたパフォーマンスを示し、Ruby 3.1.0 で開発され、急速に CRuby の重要な部分になりつつあります。

Ruby 用の独自のコンパイラを構築したい場合は、この投稿を参照してください。

コーディングを楽しんでください!

追記Ruby Magic の投稿を報道後すぐに読みたい場合は、Ruby Magic ニュースレターを購読して、投稿を 1 つも見逃さないようにしてください。

Ruby および Rails 用の JIT コンパイラー:YJIT、MJIT、および TenderJIT でパフォーマンスを向上

レナタ・マルケス

ゲスト著者の Renata は、Ruby と Javascript を専門とするソフトウェア エンジニア兼コンピューター サイエンティストです。彼女は、オープンソース プロジェクトに貢献することで開発者コミュニティを支援することに喜びを感じています。自由時間には、映画やテレビ番組を見たり話し合ったり、本を読んだり、音楽を聴いたり、写真を撮ったり、ビデオを作成したりすることが好きです。

Renata Marques によるすべての記事


  1. ActionCableとTurboを使用してRailsでリアルタイムチャットアプリを構築する

    Facebookにアクセスして、ページを更新せずに通知を受け取ったことはありますか?この種のリアルタイム機能は、状態管理を介したReactなどのJavaScriptフレームワークを使用するほとんどのアプリケーションで実現されます。これらのアプリケーションのほとんどは、データをリアルタイムで更新するために使用中にページをリロードする必要がないため、シングルページアプリケーションとして機能します。Railsアプリケーションは、通常、ページのリロードが必要であるという意味で、ステートレスでした。アプリケーションの現在の状態。たとえば、劇場で利用可能な映画のリストを表示するRailsアプリを使用してい

  2. AppSignal が長時間実行ストリーミング ラック応答サポートで Ruby 監視を強化

    AppSignal で、長時間実行されるストリーミング ラック応答の監視が強化されたことを発表できることを嬉しく思います。 Rack 応答モニタリングの強化により、Ruby アプリケーションの長時間実行応答の健全性をより詳細に把握できるようになり、リクエスト本文が処理されてから数分、場合によっては数時間後に発生する可能性のあるエラーを検出できるようになります。 この新しい可観測性層は、Cheddar Payments のエンジニアリング ディレクターである Julik Tarkhanov 氏の貴重な貢献によって生まれました。彼の働きにより、Ruby gem 内で長時間実行される応答を監視でき