{"id":21807125,"url":"https://github.com/mmtk/mmtk-ruby","last_synced_at":"2025-10-19T14:08:31.101Z","repository":{"id":37349637,"uuid":"454695970","full_name":"mmtk/mmtk-ruby","owner":"mmtk","description":"Ruby binding for MMTk","archived":false,"fork":false,"pushed_at":"2023-12-14T05:26:55.000Z","size":158,"stargazers_count":6,"open_issues_count":10,"forks_count":4,"subscribers_count":7,"default_branch":"master","last_synced_at":"2023-12-14T06:27:57.797Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mmtk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-02-02T08:30:00.000Z","updated_at":"2023-12-20T16:35:39.705Z","dependencies_parsed_at":"2023-02-10T03:00:52.678Z","dependency_job_id":"1bef57ef-d906-403e-a0cf-dc4779ab37a2","html_url":"https://github.com/mmtk/mmtk-ruby","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmtk%2Fmmtk-ruby","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmtk%2Fmmtk-ruby/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmtk%2Fmmtk-ruby/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmtk%2Fmmtk-ruby/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mmtk","download_url":"https://codeload.github.com/mmtk/mmtk-ruby/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244759961,"owners_count":20505716,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-27T12:37:12.097Z","updated_at":"2025-10-19T14:08:31.096Z","avatar_url":"https://github.com/mmtk.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MMTk binding for CRuby\n\nThis repository hosts the binding code for MMTk Ruby.\n\n[CRuby 3.4] officially introduced the modular GC feature, and an [MMTk\nbinding][ruby-mmtk] has been included upstream as a bundled gem.\n\n[CRuby 3.4]: https://www.ruby-lang.org/en/news/2024/12/25/ruby-3-4-0-released/\n[ruby-mmtk]: https://github.com/ruby/mmtk\n\nThis repository, on the other hand, was created years before the introduction of\nmodular GC in the official Ruby code base.  It is the place we have been doing\nexperiments, and it still holds features that have not been upstreamed.\n\nThis repository depends on [our CRuby fork].  The fork took the approach of\noverriding the behavior of the default GC of CRuby and wiring related functions\nto this MMTk binding.  The fork also made aggressive changes to the CRuby\nruntime, such as introducing the `imemo:strbuf` and `imemo:objbuf` types to\neliminate the buffers allocated from `malloc` in `String`, `Array` and\n`MatchData`.\n\n[our CRuby fork]: https://github.com/mmtk/ruby\n\nThis repository is based on previous work of Angus Atkinson, and the original\nrepository can be found [here](https://github.com/angussidney/mmtk-ruby.git),\nand the original Ruby fork can be found\n[here](https://github.com/angussidney/ruby.git).\n\n## Building/installation instructions\n\n### Checkout repositories\n\nYou need to clone both the Ruby fork and the MMTk Ruby binding.  The location\ndoes not matter.\n\n```bash\ngit clone https://github.com/mmtk/ruby.git\ngit clone https://github.com/mmtk/mmtk-ruby.git\n```\n\nThe `mmtk-ruby` repository should be on the `dev/mmtk-overrides-default` branch.\nThe default branch changed recently.  If you cloned the repository before, make\nsure you checked out the right branch.\n\n### Build the MMTk binding, first.\n\n```bash\npushd mmtk-ruby/mmtk\ncargo build --release\npopd\n```\n\nThis will give you a `libmmtk_ruby.so` in the `target/release` directory.\n\nBy default, `mmtk-ruby` uses the `mmtk` crate from the `master` branch of [its\nofficial repository](https://github.com/mmtk/mmtk-core).  If you want to hack\nthe MMTk core itself, you can edit `mmtk-ruby/mmtk/Cargo.toml` to point to your\nlocal repository.\n\n### Then build our forked Ruby repository.\n\nRun `autogen.sh`.\n\n```bash\ncd ruby\n./autogen.sh\n```\n\nCreate a build directory and configure.  By separating the build directory for\nrelease and debug, we can let the release build coexist with the debug build,\nmaking it convenient for debugging.\n\n```bash\nmkdir build-release\ncd build-release\n../configure --with-mmtk-ruby=../../mmtk-ruby --prefix=$PWD/install\n```\n\nWith `--with-mmtk-ruby`, the `configure` script will enable MMTk, and search for\n`libmmtk_ruby.so` in `../../mmtk-ruby/mmtk/target/release`.  You need to make\nsure that `.so` has been built in the mmtk-ruby before executing `configure`.\n\nThen build a `miniruby` executable.\n\n```bash\nmake miniruby -j\n```\n\nThe `miniruby` executable should be able to execute simple Ruby programs.  You\ncan try the following commands:\n\n```bash\n# Run with vanilla Ruby GC\n./miniruby -e 'puts \"Hello world!\"'\n\n# Run with MMTk GC\n./miniruby --mmtk -e 'puts \"Hello world!\"'\n\n# You should see \"MMTk\" in the version string together with the current GC plan\n./miniruby --version\n./miniruby --mmtk --version\n```\n\nYou can continue to build the full Ruby and install it with\n\n```bash\nmake install -j\n```\n\nThen test it\n\n```bash\n./install/bin/ruby --mmtk --version\n./install/bin/ruby --mmtk -e 'puts \"Hello world!\"'\n```\n\n### Debug build\n\n**Building mmtk-ruby for debugging**\n\nRemove the `--release` option to build `mmtk-ruby` for debug.\n\n```bash\npushd mmtk-ruby/mmtk\ncargo build\npopd\n```\n\nThen you will have the debug build in `test/debug`.  Note that the Cargo build\nsystem is smart enough to let it coexist with the release build in\n`target/release`.\n\n**Building ruby for debugging**\n\nI assume you have executed `autogen.sh` in the `ruby` directory.  Then create a\ndirectory for the debug build.\n\n```bash\nmkdir build-debug\ncd build-debug\n```\n\nThen run `configure`.\n\n```bash\n../configure \\\n    --with-mmtk-ruby=../../mmtk-ruby \\\n    --with-mmtk-ruby-debug \\\n    --prefix=$PWD/install \\\n    --disable-install-doc \\\n    cppflags=\"-g3 -O0 -DRUBY_DEBUG=1 -DRUBY_DEVEL -DUSE_RUBY_DEBUG_LOG=1\"\n```\n\nWith the `--with-mmtk-ruby-debug` flag, `configure` will search for\n`libmmtk_ruby.so` in `../../mmtk-ruby/mmtk/target/debug`, instead.\n\n`--disable-install-doc` disables the generation of documentations, making the\nbuild process much faster.\n\n`-g3 -O0` generates debug info and disables optimization, making it good for\ndebugging.  You may try `-O1` if it is too slow.\n\n`-DRUBY_DEBUG=1` enables most assertions in Ruby.\n\nSet both `-DRUBY_DEVEL` and `-DUSE_RUBY_DEBUG_LOG=1` to enable logging.\n\nYou may use the `intercept-build` utility to generate the\n`compile_commands.json` file to be used for language servers.\n\n```bash\nintercept-build make miniruby -j\ncd ..\nln -s build-debug/compile_commands.json ./\n```\n\n## Use Ruby with MMTk\n\n### Selecting MMTk plans (GC algorithms)\n\nUse the `--mmtk-plan` command line option to select the GC algorithm.  This\noption implies `--mmtk`.  In MMTk, each \"plan\" corresponds to a GC algorithm.\nCurrently, supported plans include:\n\n-   `NoGC`: Not doing GC at all.  When the heap is exhausted, it crashes.\n\n-   `MarkSweep`: The classic mark-sweep algorithm.  Based on a free-list\n    allocator, it never moves any object.\n\n-   `Immix`: The [Immix] algorithm, a mark-region collector with opportunistic\n    evacuation.  It moves objects from time to time to prevent the heap from\n    being too fragmented.\n\n-   `StickyImmix`: A generational variant of [Immix].  It currently performs\n    non-moving nursery GC, and may defragment during full-heap GC.\n\n[Immix]: https://users.cecs.anu.edu.au/~steveb/pubs/papers/immix-pldi-2008.pdf\n\nExample:\n\n```bash\n./miniruby --mmtk --mmtk-plan=StickyImmix -e \"puts 'Hello world!'\"\n```\n\n### Adjusting heap size\n\nBy default, MMTk dynamically adjust the heap size between 1 MiB and 80% of the\nphysical memory.  It is convenient for production settings. However, when doing\nexperiments, you may want to set the heap size to a fixed value so the GC\nbehaviour becomes more deterministic.\n\nYou can set the heap size using the `--mmtk-max-heap` command line option.\n\nIt accepts IEC suffixes `KiB`, `MiB`, `GiB` and `TiB`.  Therefore, `16777216`\nand `16MiB` are equivalent.\n\nExample:\n\n```bash\n./miniruby --mmtk --mmtk-max-heap=512MiB -e \"puts 'Hello world!'\"\n```\n\n### Using the RUBYOPT environment variable\n\nAll of `--mmtk`, `--mmtk-plan` and `--mmtk-max-heap` options can be passed via\nthe `RUBYOPT` environment variable, too.\n\nExample:\n\n```bash\nRUBYOPT='--mmtk-plan=StickyImmix' ./miniruby --version\n```\n\n### MMTk-specific methods in the `GC::MMTk` module.\n\nThe `GC::MMTk` module contains methods specific to MMTk.\n\n-   `GC::MMTk.plan_name`: Return the current MMTk plan.\n-   `GC::MMTk.enabled?`: Return true if MMTk is enabled via the command line.\n    Note that if the Ruby interpreter is not compiled with MMTk support\n    (controlled by `./configure --with-mmtk-ruby`), the `GC::MMTk` module will\n    not exist.  Use `defined? GC::MMTk` to check.\n-   `GC::MMTk.harness_begin`: Call this before the interested part of a\n    benchmark to start collecting statistic data.\n-   `GC::MMTk.harness_end`: Call this before the interested part of a\n    benchmark to stop collecting statistic data, and print the statistic data\n    collected.\n\nIf you are running benchmarks, you should run the test case multiple times for\nwarming up, and measure the last iteration.  Call `harness_begin` and\n`harness_end` before and after the last iteration.  The statistic data will be\nprinted to stderr.\n\n## Test\n\n### Bootstrap tests\n\nWhen running `make btest`, use `RUN_OPTS` to pass additional parameters to the\n`miniruby` program to enable MMTk.\n\n```bash\nmake btest RUN_OPTS=\"--mmtk-plan=MarkSweep\"\nmake btest RUN_OPTS=\"--mmtk-plan=Immix\"\nmake btest RUN_OPTS=\"--mmtk-plan=StickyImmix\"\n```\n\n### All tests\n\nWe excluded some tests when testing against MMTk.  Those test cases are listed\nin `test/.excludes-mmtk` in the [`mmtk/ruby`](https://github.com/mmtk/ruby.git)\nrepository.\n\n-   Test cases that involve YJIT are excluded because we have not started\n    working on YJIT support, yet.\n-   Some tests involve implementation details of CRuby's default GC, such as\n    compaction and memsize.  Those test cases are excluded, too.\n-   Other excluded tests involve things that are not yet implemented properly in\n    the MMTk binding.\n\nTo run the tests, run the following command.\n\n```bash\nmake test-all RUN_OPTS=\"--mmtk-plan=StickyImmix\" TESTOPTS=\"-v --excludes-dir=../test/.excludes-mmtk\"\n```\n\nThat assumes you are in the `build-debug` or `build-release` directory.  Adjust\nthe path `../test/.excludes-mmtk` if you run it in a different directory.\n\n## Current status\n\nKnown working:\n - Supports MarkSweep, Immix and StickyImmix GC algorithms\n - Most test cases in `make btest`\n - Most test cases in `make test-all`\n - Liquid benchmark (https://github.com/Shopify/liquid/blob/master/performance/benchmark.rb)\n\nKnown issues:\n - `make test-rubyspec` is currently failing; need to find a way to exclude GC-specific specifications.\n - 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`)\n - MJIT is not supported.\n\n## TODO\n - Performance tuning\n\n## Licensing\n\nThis 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.\n\n\u003c!--\nvim: tw=80\n--\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmmtk%2Fmmtk-ruby","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmmtk%2Fmmtk-ruby","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmmtk%2Fmmtk-ruby/lists"}