Skip to content

Latest commit

 

History

History
298 lines (212 loc) · 9.06 KB

README.md

File metadata and controls

298 lines (212 loc) · 9.06 KB

MMTk binding for Ruby

This repository hosts the binding code for MMTk Ruby.

In order for this binding to work, changes have been made to the Ruby core language to support generic third party heaps. Eventually, the aim is to upstream these changes. Until then, the modifications can be found under our fork here, on the default branch named mmtk.

This repository is based on previous work of Angus Atkinson, and the original repository can be found here, and the original Ruby fork can be found here.

Building/installation instructions

Checkout repositories

You need to clone both the Ruby fork and the MMTk Ruby binding. The location does not matter.

git clone https://github.com/mmtk/ruby.git
git clone https://github.com/mmtk/mmtk-ruby.git

The mmtk-ruby repository should be on the dev/mmtk-overrides-default branch. The default branch changed recently. If you cloned the repository before, make sure you checked out the right branch.

Build the MMTk binding, first.

pushd mmtk-ruby/mmtk
cargo build --release
popd

This will give you a libmmtk_ruby.so in the target/release directory.

By default, mmtk-ruby uses the mmtk crate from the master branch of its official repository. If you want to hack the MMTk core itself, you can edit mmtk-ruby/mmtk/Cargo.toml to point to your local repository.

Then build our forked Ruby repository.

Run autogen.sh.

cd ruby
./autogen.sh

Create a build directory and configure. By separating the build directory for release and debug, we can let the release build coexist with the debug build, making it convenient for debugging.

mkdir build-release
cd build-release
../configure --with-mmtk-ruby=../../mmtk-ruby --prefix=$PWD/install

With --with-mmtk-ruby, the configure script will enable MMTk, and search for libmmtk_ruby.so in ../../mmtk-ruby/mmtk/target/release. You need to make sure that .so has been built in the mmtk-ruby before executing configure.

Then build a miniruby executable.

make miniruby -j

The miniruby executable should be able to execute simple Ruby programs. You can try the following commands:

# Run with vanilla Ruby GC
./miniruby -e 'puts "Hello world!"'

# Run with MMTk GC
./miniruby --mmtk -e 'puts "Hello world!"'

# You should see "MMTk" in the version string together with the current GC plan
./miniruby --version
./miniruby --mmtk --version

You can continue to build the full Ruby and install it with

make install -j

Then test it

./install/bin/ruby --mmtk --version
./install/bin/ruby --mmtk -e 'puts "Hello world!"'

Debug build

Building mmtk-ruby for debugging

Remove the --release option to build mmtk-ruby for debug.

pushd mmtk-ruby/mmtk
cargo build
popd

Then you will have the debug build in test/debug. Note that the Cargo build system is smart enough to let it coexist with the release build in target/release.

Building ruby for debugging

I assume you have executed autogen.sh in the ruby directory. Then create a directory for the debug build.

mkdir build-debug
cd build-debug

Then run configure.

../configure \
    --with-mmtk-ruby=../../mmtk-ruby \
    --with-mmtk-ruby-debug \
    --prefix=$PWD/install \
    --disable-install-doc \
    cppflags="-g3 -O0 -DRUBY_DEBUG=1 -DRUBY_DEVEL -DUSE_RUBY_DEBUG_LOG=1"

With the --with-mmtk-ruby-debug flag, configure will search for libmmtk_ruby.so in ../../mmtk-ruby/mmtk/target/debug, instead.

--disable-install-doc disables the generation of documentations, making the build process much faster.

-g3 -O0 generates debug info and disables optimization, making it good for debugging. You may try -O1 if it is too slow.

-DRUBY_DEBUG=1 enables most assertions in Ruby.

Set both -DRUBY_DEVEL and -DUSE_RUBY_DEBUG_LOG=1 to enable logging.

You may use the intercept-build utility to generate the compile_commands.json file to be used for language servers.

intercept-build make miniruby -j
cd ..
ln -s build-debug/compile_commands.json ./

Use Ruby with MMTk

Selecting MMTk plans (GC algorithms)

Use the --mmtk-plan command line option to select the GC algorithm. This option implies --mmtk. In MMTk, each "plan" corresponds to a GC algorithm. Currently, supported plans include:

  • NoGC: Not doing GC at all. When the heap is exhausted, it crashes.

  • MarkSweep: The classic mark-sweep algorithm. Based on a free-list allocator, it never moves any object.

  • Immix: The Immix algorithm, a mark-region collector with opportunistic evacuation. It moves objects from time to time to prevent the heap from being too fragmented.

  • StickyImmix: A generational variant of Immix. It currently performs non-moving nursery GC, and may defragment during full-heap GC.

Example:

./miniruby --mmtk --mmtk-plan=StickyImmix -e "puts 'Hello world!'"

Adjusting heap size

By default, MMTk dynamically adjust the heap size between 1 MiB and 80% of the physical memory. It is convenient for production settings. However, when doing experiments, you may want to set the heap size to a fixed value so the GC behaviour becomes more deterministic.

You can set the heap size using the --mmtk-max-heap command line option.

It accepts IEC suffixes KiB, MiB, GiB and TiB. Therefore, 16777216 and 16MiB are equivalent.

Example:

./miniruby --mmtk --mmtk-max-heap=512MiB -e "puts 'Hello world!'"

Using the RUBYOPT environment variable

All of --mmtk, --mmtk-plan and --mmtk-max-heap options can be passed via the RUBYOPT environment variable, too.

Example:

RUBYOPT='--mmtk-plan=StickyImmix' ./miniruby --version

MMTk-specific methods in the GC::MMTk module.

The GC::MMTk module contains methods specific to MMTk.

  • GC::MMTk.plan_name: Return the current MMTk plan.
  • GC::MMTk.enabled?: Return true if MMTk is enabled via the command line. Note that if the Ruby interpreter is not compiled with MMTk support (controlled by ./configure --with-mmtk-ruby), the GC::MMTk module will not exist. Use defined? GC::MMTk to check.
  • GC::MMTk.harness_begin: Call this before the interested part of a benchmark to start collecting statistic data.
  • GC::MMTk.harness_end: Call this before the interested part of a benchmark to stop collecting statistic data, and print the statistic data collected.

If you are running benchmarks, you should run the test case multiple times for warming up, and measure the last iteration. Call harness_begin and harness_end before and after the last iteration. The statistic data will be printed to stderr.

Test

Bootstrap tests

When running make btest, use RUN_OPTS to pass additional parameters to the miniruby program to enable MMTk.

make btest RUN_OPTS="--mmtk-plan=MarkSweep"
make btest RUN_OPTS="--mmtk-plan=Immix"
make btest RUN_OPTS="--mmtk-plan=StickyImmix"

All tests

We excluded some tests when testing against MMTk. Those test cases are listed in test/.excludes-mmtk in the mmtk/ruby repository.

  • Test cases that involve Ractors are excluded because it is currently not a priority to support Ractors.
  • Test cases that involve YJIT are excluded because we have not started working on YJIT support, yet.
  • Some tests involve implementation details of CRuby's default GC, such as compaction and memsize. Those test cases are excluded, too.
  • Other excluded tests involve things that are not yet implemented properly in the MMTk binding.

To run the tests, run the following command.

make test-all RUN_OPTS="--mmtk-plan=StickyImmix" TESTOPTS="-v --excludes-dir=../test/.excludes-mmtk"

That assumes you are in the build-debug or build-release directory. Adjust the path ../test/.excludes-mmtk if you run it in a different directory.

Current status

Known working:

Known issues:

  • make test-rubyspec is currently failing; need to find a way to exclude GC-specific specifications.
  • GC implementation-specific modules (e.g. ObjectSpace, GC, WeakRef) and anything that relies on them (e.g. Coverage) are not supported. For now, there are no plans to implement these as many of the APIs are irrelevant (e.g. GC.stat); however some may be fixed in the future (e.g. ObjectSpace.each_object)
  • MJIT is not supported.

TODO

  • Performance tuning

Licensing

This work is dual-licensed under the MIT and Apache licenses, to be compatible with the MMTk-Core project. See the license notices in the root of this repository for further details.