パフォーマンスの問題の報告

TruffleRubyでRubyの他の実装よりもパフォーマンスが低くなった場合は、お知らせください。「互換性」ガイドには、低速で、高速化の可能性が低いことがわかっている機能がリストされています。

一般的な問題とその理由

TruffleRubyは、非常に高度な手法を使用してRubyプログラムを最適化します。これらの最適化の適用には時間がかかるため、多くの場合、TruffleRubyは、ウォームアップするまで、他の実装よりも大幅に遅くなります。

また、TruffleRubyはプログラムの安定状態を検出し、Rubyの動的な状態が必要ない場所ではそれを自動的に除去することを試みますが、これは、安定状態が妨げられた場合は、TruffleRubyが新しい安定状態に適応できるまで、パフォーマンスが再度低下することを意味します。

もう1つの問題は、TruffleRubyは、必要ない計算や作業を含まないループなどの、不要な作業の除去に非常に優れていることです。

これらのすべての問題により、TruffleRubyのベンチマークが困難になっています。このことはオラクル社固有の問題ではなく、多くの高度な仮想マシンに該当しますが、ほとんどのRuby実装では、これらの問題が発生するには最適化がまだ十分強力でないため、Rubyコミュニティの一部の方にとっては初めて知ることである可能性があります。

GraalVMのEnterprise Editionの使用

TruffleRubyの速度を試すには、GraalVMのEnterprise Editionを使用して、Ruby実行可能イメージを再ビルドすることをお薦めします。

JVM構成の使用

最大のピーク・パフォーマンスを得るには、--jvmを使用してJVM構成を使用します。デフォルトのネイティブ構成はより高速に起動しますが、同じピーク・パフォーマンスには完全には到達しません。ただし、次に説明するbenchmark-ipsなどの適切なベンチマーク・ツールを使用してベンチマークを実行する必要があります。そうしないと、ウォームアップ時間が長くなることで、TruffleRubyの実際のパフォーマンスがベンチマークで示されなくなります。単純なタイマーでwhileループを単に実行する、より単純なベンチマークを記述する(お薦めしません)場合は、起動時間とウォームアップ時間が短くなるように、デフォルトのネイティブ・モードを使用します。

基本的なパフォーマンスの問題を確認する方法

TruffleRubyのパフォーマンスを調べる場合は、常に--engine.TraceCompilationフラグを指定して実行することをお薦めします。コンパイルが失敗するか、同じメソッドのコンパイルが繰り返される場合は、何かが意図したとおりに動作していないことを示しているため、その理由を調べるか、そのためのサポートを依頼する必要があります。このフラグを指定して実行しないと、TruffleRubyによってエラーの回避が試行され、問題があることを確認できません。

パフォーマンス・ベンチマークの記述方法

TruffleRubyチームは、benchmark-ipsを使用してTruffleRubyのパフォーマンスを確認することをお薦めします。benchmark-ipsのレポートを使用して潜在的なパフォーマンスの問題を報告していただくと助かります。

ベンチマークは次のようになります:

require 'benchmark/ips'

Benchmark.ips do |x|
  x.iterations = 2

  x.report("adding") do
    14 + 2
  end
end

benchmark-ipsx.iterations =拡張機能を使用して、benchmark-ipsのウォームアップおよび測定サイクルを2回実行し、結果が安定し、十分なウォームアップが提供されたことを確認します(x.warmup = 5で調整できます)。

次のように表示されます:

Warming up --------------------------------------
              adding    20.933k i/100ms
              adding     1.764M i/100ms
Calculating -------------------------------------
              adding      2.037B (±12.7%) i/s -      9.590B in   4.965741s
              adding      2.062B (±11.5%) i/s -     10.123B in   4.989398s

最後の行を見てみると、これは、TruffleRubyではこのブロックの反復が毎秒20億6200万回実行され、±11.5%の誤差があることを示しています。

これをRubiniusのような実装と比較します:

Warming up --------------------------------------
              adding    71.697k i/100ms
              adding    74.983k i/100ms
Calculating -------------------------------------
              adding      2.111M (±12.2%) i/s -     10.302M
              adding      2.126M (±10.6%) i/s -     10.452M

ここで、TruffleRubyのパフォーマンスはRubiniusよりも1000倍速いと言えます。これはかなり大きい差に見受けられ、ここでTruffleRubyが実際に行っていることは、ベンチマークの最適化です。最適化できない複雑なコードでは、この効果はこれほど顕著ではありません。

最終的なテクニカル・ノート: ブラックホールと値プロファイリング

他の言語の一部のベンチマーク・ツールには、ブラックホールと呼ばれる機能があります。これらは値を囲み、実際には定数であっても実行時に変数に見えるようにするため、オプティマイザは、値を削除しないで、その値を使用する計算を実際に実行します。ただし、TruffleRubyでは広範な値プロファイリング(値のキャッシュおよび定数への変換)が使用されるため、値をソースで変数のように見せても、中間ステージで値プロファイリングが行われる可能性があります。一般的に、注釈を手動で追加して重要な機能を無効にするよりも、値プロファイリングの有用性が自然になくなるような、より複雑なベンチマークをお薦めします。