Rei Odaira
contact information



links
Professional Associations
Professional Associations: ACM | Information Processing Society of Japan (IPSJ)- Profile
- Publications
- Patents
- Code Patch to the STAMP Benchmarks for Hardware Transdactional Memory (HTM)
- IISWC 2014 Paper
- PPoPP 2014 Paper
- IISWC 2013 Paper
- Research Report: Eliminating GIL in Ruby through HTM
- ASPLOS 2012 Paper
- CGO 2010 Paper
- VEE 2010 Paper
- ISCA 2015 Paper
- Code Patch to Eliminate Global Interpreter Lock (GIL) in Ruby through Hardware Transactional Memory
- RubyのGVLにHTMを用いるパッチ
これは何?
オリジナルのRuby VMの実装(CRuby, MRI)は大域VMロック(Giant VM Lock; GVL)を用いています。GVLのおかげでVMと拡張ライブラリの開発者は並列プログラミングについて考える必要が無く実装が容易になります。しかしそのせいで、Rubyでマルチスレッドプログラムを書いても同時に一つのスレッドしか実行されないという性能上の問題がありました。一方、近年のCPUにはハードウェアトランザクショナルメモリ(Hardware Transactional Memory; HTM)と呼ばれる新しい機能が実装されています。HTMをロックの代わりに用いると、開発者は並列プログラミングについてほとんど考える必要が無いまま、同時に複数のスレッドが動作可能になり性能問題が解決する、と言われています。我々はRuby VMのGVLをHTMで置き換えた実験を行い、PPoPP 2014で発表しました。英語の論文と発表資料はこちらにあります。また、内容は少し古いですが日本語の発表資料はこちら(PDF)にあります。
このページでは実験で用いたコードをRuby VMに対するパッチとして公開しています。
履歴
2015年7月29日: Eメールアドレスを修正
2015年5月24日: IBM USへの移動に伴いページを新規作成
2014年9月18日: バグを修正、RUBY_DISABLE_HTMを導入
2014年9月8日: 修正パッチを適用(contributed by Masahiro Ide)
2014年6月24日: パッチとビルド方法を公開
パッチとビルド方法
我々はruby-1.9.3-p547に対するパッチを公開しています。パッチはこちらからダウンロードしてください。 また、ruby-1.9.3-p547は以下のリンクからダウンロードできます。https://www.ruby-lang.org/ja/news/2014/05/16/ruby-1-9-3-p547-released/ 我々のパッチはruby-1.9.3の他のパッチレベルに対しても(確認はしていませんが)少しの修正で適用できるはずです。
ソースツリーを展開した後、以下のようにパッチを適用してください。
> cd ruby-1.9.3-p547
> patch -p1 < $PATH_TO_YOUR_PATCH/ruby_htm_gvl-1.9.3-p547_v3.patch
パッチ適用後、*.incファイルを不要に再生成しないようにtouchしておくことをお勧めします。
> touch *.inc
configureスクリプトに--enable-htm-gvlオプションを付けてからビルドしてください:
> ./configure --enable-htm-gvl
> make
# make install
実行方法
ビルドされたRubyのバイナリはデフォルトでGVLにHTMを用います。実行するにはIBM POWER HTMかIntel TSXを実装したCPUが必要です。パッチはAIX/POWER8とLinux/Intel Haswellプロセッサ上でテストしています。パッチにはIBM System z(メインフレーム)のHTMのためのコードが一部含まれていますが、Ruby自体がSystem zでは現状動きません。
HTMはマルチスレッドのRubyプログラムでのみ用いられます。シングルスレッドのRubyプログラムではGVLの方が速いのでGVLが用いられます。マルチスレッドプログラムでも常にGVLを用いたい場合は実行時オプションとして--disable-htmを指定するか環境変数RUBY_DISABLE_HTMをyesにセットしてください。
> ruby --disable-htm your_app.rb
> export RUBY_DISABLE_HTM=yes; ruby your_app.rb
HTMとGVLの挙動をチューニングするために、環境変数で指定できるオプションがいくつか用意されています。ただしデフォルトの値は既にチューニングされているので通常は値を変更する必要はありません。
環境変数名 | 短縮名 | 説明 | 有効な値 | デフォルトの値 |
---|---|---|---|---|
RUBY_HTM_SCHED_INTERVAL | RH_INTV | トランザクション長。詳細はPPoPP 2014の論文を参照してください。正の整数値は固定トランザクション長を意味します。負の整数値はトランザクション長の動的な調整を有効化し、初期値は指定された負の整数値の絶対値となります。例えばRH_INTV=-255はトランザクション長を255で初期化し、アボート統計に応じて動的にトランザクション長を短くしていきます。 | 整数:-255以上-1以下、または1以上 | -255 |
RUBY_HTM_TX_SIZE_RECALC_THRESHOLD | RH_RECALC | ターゲットとするアボート率。RH_INTVに負の値が指定された時のみ有効。 | 浮動小数点数: [0.0, 100.0] | 6.0 |
RUBY_HTM_PERSISTENT_RETRY_MAX | RH_PRETRY | 何回persistentアボートが起きてからGVLを獲得するか。 | 正の整数 | 3 |
RUBY_HTM_TRANSIENT_RETRY_MAX | RH_TRETRY | 何回transientアボートが起きてからGVLを獲得するか。 | 正の整数値 | 3 |
RUBY_HTM_GVL_RETRY_MAX | RH_GRETRY | 他のスレッドがGVLを獲得している場合に、何回GVL解放を待ってリトライしてからGVLを獲得するか。 | 正の整数 | 16 |
RUBY_GVL_SPIN_MAX | RB_GSPIN | GVLが何回スピンウェイトしてからPthread条件変数で寝るか。 | 正の整数 | 100000000 |
RUBY_PRINT_HTM_STATS | RH_STATS | 実行の最後にHTMの統計を出力する。 | どんな値でも可 | {指定されず} |
また、直接HTMやGVLとは関係しませんが、Rubyのヒープが縮むことを防ぐオプションが提供されます。我々の論文の実験ではGCの頻度を下げるためにRUBY_HEAP_MIN_SLOTSでRubyヒープの初期サイズを拡張しましたが、このオプションが無いとRubyヒープが急速に縮んでしまいます。
環境変数名 | 短縮名 | 説明 | 有効な値 | デフォルトの値 |
---|---|---|---|---|
RUBY_DO_NOT_SHRINK_HEAP | なし | Rubyヒープを縮めない。 | どんな値でも可 | {指定されず} |
PPoPP論文の結果の再現方法
以下の環境変数をセットしてください。
> export RH_STATS=yes
> export RUBY_HEAP_MIN_SLOTS=10000000
> export RUBY_DO_NOT_SHRINK_HEAP=yes
HTM-1, -16, -256のためにはRH_INTVをそれぞれ1, 16, 256にセットしました。HTM-dynamicのためにはRH_INTVを-255(デフォルト値)にセットしました。 “GIL”のためには--enable-htm-gvlをconfigureスクリプトに指定せずにビルドしたバイナリを用いました。
Ruby版のNAS Parallel Benchmarks 3.0はこちらからダウンロードできます: http://www-hiraki.is.s.u-tokyo.ac.jp/members/tknose/npb3.0-ruby.tar.gz
以下のコマンドで実行できます:
> ruby -I . BT.rb -CLASSS -np4
WEBrickはRubyに添付して配布されています。我々はWEBrickベースの非常に単純なHTTPサーバを用いました。
require 'webrick'
include WEBrick
ARGV[0] ||= 8008
s = HTTPServer.new(:Port => ARGV[0].to_i,
:MaxClients => 1000,
:Logger => Log.new($stderr, BasicLog::ERROR),
:DocumentRoot => File.join(Dir::pwd, "public_html"),
:AccessLog => [[ File.open("log.txt", "w"), AccessLog::COMMON_LOG_FORMAT]]
)
trap("INT") {
s.shutdown
}
s.start
Ruby on Railはバージョン4以降はデフォルトでスレッドセーフとなり並列実行されますが、WEBrickだけは特別扱いして並列実行されません。我々はRuby on Railsのソースコードを以下のリンク先にあるように修正して、WEBrickでも並列実行されるようにしました: https://github.com/rails/rails/issues/10772
ライセンス
我々のパッチのライセンスは元のRubyのライセンスと同一です:https://www.ruby-lang.org/en/about/license.txt
バグレポートとコメント
大平怜(rodaira [at] us . ibm . com)まで。Twitter: @ReiOdaira