What is This?

This page distributes a code patch to eliminate the Global Interpreter Lock (GIL), or the Giant VM Lock (GVL), in CRuby through the Hardware Transactional Memory (HTM) of IBM POWER and Intel TSX. We presented our paper at PPoPP 2014. See this page for our paper and presentation slides.

Patching and Building HTM-enabled Ruby

We are distributing a patch for ruby-1.9.3-p547. Download our patch from this link. Also you may download ruby-1.9.3-p547 from: https://www.ruby-lang.org/en/news/2014/05/16/ruby-1-9-3-p547-released/ . We believe with minor modifications our patch can be applied to any patch levels of ruby-1.9.3.

After extracting the source tree, apply the patch.

> cd ruby-1.9.3-p547
> patch -p1 < $PATH_TO_YOUR_PATCH/ruby_htm_gvl-1.9.3-p547_v3.patch

We recommend touching the *.inc files to avoid unnecessary regeneration of the *.inc files.

> touch *.inc

Specify --enable-htm-gvl for the configure script and then build:

> ./configure --enable-htm-gvl
> make
# make install

Running HTM-enabled Ruby

By default, the rebuilt Ruby binary uses HTM to replace the GVL (Giant VM Lock). The users need a processor that implements the IBM POWER HTM or Intel TSX. The patch was tested on AIX/POWER8 and Linux/Intel Haswell processors. The patch includes some code fragments for the IBM System z (mainframe) HTM, but that hardware is not supported because Ruby itself cannot yet be built on System z.

Note: the HTM is used only for multithreaded Ruby programs. Single-threaded Ruby programs still use the GVL, because it has lower overhead. To always use the GVL, even for multithreaded Ruby programs, specify the runtime option --disable-htm, or set the environmental variable RUBY_DISABLE_HTM to yes.

> ruby --disable-htm your_app.rb
> export RUBY_DISABLE_HTM=yes; ruby your_app.rb

There are several runtime options that can be specified by environmental variables to tune the behavior of the HTM and GVL. The users generally do not need to modify them because the default values are well tuned.

Long nameShort nameDescriptionValid valuesDefault value
RUBY_HTM_SCHED_INTERVAL RH_INTV Transaction length. See our paper for the details. A positive integer means a fixed transaction length of that value, while a negative integer enables dynamic transaction length adjustment starting from the absolute value of the specified negative number. For example, RH_INTV=-255 will initialize the transaction lengths with 255 and dynamically shrink them based on the abort statistics. Integer, [-255, -1] or [1 -255
RUBY_HTM_TX_SIZE_RECALC_THRESHOLD RH_RECALC Target abort ratio. Valid only when a negative value is specified for RH_INTV. Floating-point number, [0.0, 100.0] 6.0
RUBY_HTM_PERSISTENT_RETRY_MAX RH_PRETRY How many persistent aborts can occur before reverting to the GVL. Positive integer 3
RUBY_HTM_TRANSIENT_RETRY_MAX RH_TRETRY How many transient aborts can occur before reverting to the GVL. Positive integer 3
RUBY_HTM_GVL_RETRY_MAX RH_GRETRY How many times the runtime will wait for a GVL release and then retry before acquiring the GVL. Positive integer 16
RUBY_GVL_SPIN_MAX RB_GSPIN How many times the GVL will spin-wait before sleeping on a Pthread conditional variable. Positive integer 100000000
RUBY_PRINT_HTM_STATS RH_STATS Print the HTM statistics at the end of execution. Any value {none}

In addition, although it is not directly related to the HTM or GVL, an option is supported to prevent the Ruby heap from shrinking. We used this option in our measurements in our paper, because we extended the Ruby heap by RUBY_HEAP_MIN_SLOTS to reduce the GC frequency, but without this option the Ruby heap shrank too quickly.

Long nameShort nameDescriptionValid valuesDefault value
RUBY_DO_NOT_SHRINK_HEAP N/A Do not shrink the Ruby heap. Any value {none}

Reproducing the results in the PPoPP paper

Set up the following environmental variables.

> export RH_STATS=yes
> export RUBY_HEAP_MIN_SLOTS=10000000
> export RUBY_DO_NOT_SHRINK_HEAP=yes

For HTM-1, -16, and -256, set RH_INTV to 1, 16, and 256, respectively. For HTM-dynamic, set RH_INTV to -255 (the default value). For “GIL”, we used an executable binary built without specifying --enable-htm-gvl in the configure script.

The Ruby version of the NAS Parallel Benchmarks 3.0 is available from: http://www-hiraki.is.s.u-tokyo.ac.jp/members/tknose/npb3.0-ruby.tar.gz

The benchmark can be executed with this command:

> ruby -I . BT.rb -CLASSS -np4

WEBrick is included in the Ruby distribution. We used a very simple HTTP server based on WEBrick.

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

Since Verison 4, Ruby on Rails is concurrent and thread-safe by default, but it handles WEBrick in a special way and does not allow it to run concurrently. We modified the source code of Ruby on Rails as described in this link to enable the concurrent execution of WEBrick: https://github.com/rails/rails/issues/10772

License

The license of our code patch is the same as the original Ruby's license: https://www.ruby-lang.org/en/about/license.txt

Bug reports and comments

Contact Rei Odaira (rodaira [at] us . ibm . com). Twitter: @ReiOdaira (I am twitting in Japanese, but you can talk to me in English.)