<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ruby.git/gc/mmtk/src, branch master</title>
<subtitle>The Ruby Programming Language</subtitle>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/'/>
<entry>
<title>[ruby/mmtk] Switch logging from debug to info level</title>
<updated>2026-05-23T13:04:55+00:00</updated>
<author>
<name>Peter Zhu</name>
<email>peter@peterzhu.ca</email>
</author>
<published>2026-05-23T01:56:55+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=6c6df00bbcefe7986111606948e96a9c1815c9c6'/>
<id>6c6df00bbcefe7986111606948e96a9c1815c9c6</id>
<content type='text'>
https://github.com/ruby/mmtk/commit/9f730cc709
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
https://github.com/ruby/mmtk/commit/9f730cc709
</pre>
</div>
</content>
</entry>
<entry>
<title>[ruby/mmtk] Add cpu heap mode based on Tavakolisomeh et al. (MPLR '23)</title>
<updated>2026-05-23T13:04:55+00:00</updated>
<author>
<name>Ufuk Kayserilioglu</name>
<email>ufuk.kayserilioglu@shopify.com</email>
</author>
<published>2026-05-07T14:51:24+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=06190d1f5c051eddf141839c0d52db0fb9eaea8d'/>
<id>06190d1f5c051eddf141839c0d52db0fb9eaea8d</id>
<content type='text'>
Adds MMTK_HEAP_MODE=cpu, a dynamic heap-sizing policy that grows
or shrinks the heap after each GC cycle to keep measured GC CPU
overhead near a configurable target. The control law follows
Tavakolisomeh et al., 'Heap Size Adjustment with CPU Control', MPLR
'23: a sigmoid of the (averaged) GC CPU overhead error in (-inf, +inf)
maps to a heap-size adjustment factor in (0.5, 1.5).

Implementation lives alongside the existing 'ruby' delegated trigger
in gc/mmtk/src/heap/. T_GC is wall-clock GC duration; T_APP is process
CPU time delta read via clock_gettime(CLOCK_PROCESS_CPUTIME_ID), which
correctly credits multi-threaded mutator parallelism. Nursery-only
generational GCs are skipped so the trigger only re-sizes at full
collections.

Configuration:

  MMTK_GC_CPU_TARGET   target GC CPU overhead, percent. Default 5.
  MMTK_GC_CPU_WINDOW   number of recent cycles averaged. Default 3.

The default differs from the paper's recommended 15. The paper
targets ZGC, a concurrent generational collector; MMTk-Ruby currently
ships stop-the-world Immix, where every percent of GC CPU also blocks
the mutator. An empirical sweep of MMTK_GC_CPU_TARGET across
ruby-bench (railsbench, lobsters, psych-load, liquid-render, lee)
found 5-6 to be Pareto-optimal vs the existing 'ruby' heap mode:
about 6 percent geomean throughput improvement at essentially equal
peak RSS. Targets &gt;=10 trade large amounts of throughput for modest
RSS savings on this collector.

bin/smoke-test, bin/ruby-mmtk-mode, bin/compare-heap-modes, and
doc/testing-cpu-heap-mode.md are included so reviewers and future
contributors can reproduce the sweep against ruby/ruby-bench.

https://github.com/ruby/mmtk/commit/1f223f5ad5

Co-Authored-By: Claude Opus 4.7 &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Adds MMTK_HEAP_MODE=cpu, a dynamic heap-sizing policy that grows
or shrinks the heap after each GC cycle to keep measured GC CPU
overhead near a configurable target. The control law follows
Tavakolisomeh et al., 'Heap Size Adjustment with CPU Control', MPLR
'23: a sigmoid of the (averaged) GC CPU overhead error in (-inf, +inf)
maps to a heap-size adjustment factor in (0.5, 1.5).

Implementation lives alongside the existing 'ruby' delegated trigger
in gc/mmtk/src/heap/. T_GC is wall-clock GC duration; T_APP is process
CPU time delta read via clock_gettime(CLOCK_PROCESS_CPUTIME_ID), which
correctly credits multi-threaded mutator parallelism. Nursery-only
generational GCs are skipped so the trigger only re-sizes at full
collections.

Configuration:

  MMTK_GC_CPU_TARGET   target GC CPU overhead, percent. Default 5.
  MMTK_GC_CPU_WINDOW   number of recent cycles averaged. Default 3.

The default differs from the paper's recommended 15. The paper
targets ZGC, a concurrent generational collector; MMTk-Ruby currently
ships stop-the-world Immix, where every percent of GC CPU also blocks
the mutator. An empirical sweep of MMTK_GC_CPU_TARGET across
ruby-bench (railsbench, lobsters, psych-load, liquid-render, lee)
found 5-6 to be Pareto-optimal vs the existing 'ruby' heap mode:
about 6 percent geomean throughput improvement at essentially equal
peak RSS. Targets &gt;=10 trade large amounts of throughput for modest
RSS savings on this collector.

bin/smoke-test, bin/ruby-mmtk-mode, bin/compare-heap-modes, and
doc/testing-cpu-heap-mode.md are included so reviewers and future
contributors can reproduce the sweep against ruby/ruby-bench.

https://github.com/ruby/mmtk/commit/1f223f5ad5

Co-Authored-By: Claude Opus 4.7 &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>[ruby/mmtk] Remove dead ractor_check_mode field</title>
<updated>2026-05-14T23:54:55+00:00</updated>
<author>
<name>Peter Zhu</name>
<email>peter@peterzhu.ca</email>
</author>
<published>2026-05-14T01:34:12+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=356c0cd0e7953baafd240914476213566f526c85'/>
<id>356c0cd0e7953baafd240914476213566f526c85</id>
<content type='text'>
https://github.com/ruby/mmtk/commit/a46b68fe5b
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
https://github.com/ruby/mmtk/commit/a46b68fe5b
</pre>
</div>
</content>
</entry>
<entry>
<title>[ruby/mmtk] Remove unnecessary null check.</title>
<updated>2026-05-08T15:13:14+00:00</updated>
<author>
<name>Matt Valentine-House</name>
<email>matt@eightbitraptor.com</email>
</author>
<published>2026-05-07T14:19:34+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=33744d25cfdd056552ab9a464ac250d56dfaaf2c'/>
<id>33744d25cfdd056552ab9a464ac250d56dfaaf2c</id>
<content type='text'>
the only caller of this unconditionally constructs a binding options
object now, So actually this is dead code

https://github.com/ruby/mmtk/commit/d832004e89
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
the only caller of this unconditionally constructs a binding options
object now, So actually this is dead code

https://github.com/ruby/mmtk/commit/d832004e89
</pre>
</div>
</content>
</entry>
<entry>
<title>[ruby/mmtk] Introduce support for ractor_belonging.</title>
<updated>2026-05-08T15:13:14+00:00</updated>
<author>
<name>Matt Valentine-House</name>
<email>matt@eightbitraptor.com</email>
</author>
<published>2026-05-07T13:24:58+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=06caa59cc3b2787ade201a5ecbe3339930e85105'/>
<id>06caa59cc3b2787ade201a5ecbe3339930e85105</id>
<content type='text'>
This is a debug mode in Ruby where an extra word is used after each
object to store the address of the Ractor that owns the object, used for
debug purposes only.

While we're working on Ractors, we also need to be able to test with
MMTk enabled, so we should introduce support for this to the MMTk
binding as well.

As implemented we'll default the binding options to have everything
disabled and hardcoded to 0, as was always the case, but if
RACTOR_CHECK_MODE is enabled, we'll build and pass a valid RubyBinding
object to MMTk.

https://github.com/ruby/mmtk/commit/83cb291313
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This is a debug mode in Ruby where an extra word is used after each
object to store the address of the Ractor that owns the object, used for
debug purposes only.

While we're working on Ractors, we also need to be able to test with
MMTk enabled, so we should introduce support for this to the MMTk
binding as well.

As implemented we'll default the binding options to have everything
disabled and hardcoded to 0, as was always the case, but if
RACTOR_CHECK_MODE is enabled, we'll build and pass a valid RubyBinding
object to MMTk.

https://github.com/ruby/mmtk/commit/83cb291313
</pre>
</div>
</content>
</entry>
<entry>
<title>[ruby/mmtk] Add moving_gc_count to GC.stat</title>
<updated>2026-04-01T00:10:17+00:00</updated>
<author>
<name>Peter Zhu</name>
<email>peter@peterzhu.ca</email>
</author>
<published>2026-03-30T23:18:41+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=d926f4077568c30eec1342f3cf522667509a5a13'/>
<id>d926f4077568c30eec1342f3cf522667509a5a13</id>
<content type='text'>
Outputs the number of GC cycles that are moving.

https://github.com/ruby/mmtk/commit/fef8f04186
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Outputs the number of GC cycles that are moving.

https://github.com/ruby/mmtk/commit/fef8f04186
</pre>
</div>
</content>
</entry>
<entry>
<title>[ruby/mmtk] Cargo format</title>
<updated>2026-03-04T11:02:36+00:00</updated>
<author>
<name>Matt Valentine-House</name>
<email>matt@eightbitraptor.com</email>
</author>
<published>2026-02-12T23:12:19+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=4d7f3ba286f3bc67554417008d4707f014520ce6'/>
<id>4d7f3ba286f3bc67554417008d4707f014520ce6</id>
<content type='text'>
https://github.com/ruby/mmtk/commit/7889da7c0e
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
https://github.com/ruby/mmtk/commit/7889da7c0e
</pre>
</div>
</content>
</entry>
<entry>
<title>[ruby/mmtk] Distribute batch candidates across parallel buckets</title>
<updated>2026-03-04T11:02:35+00:00</updated>
<author>
<name>Matt Valentine-House</name>
<email>matt@eightbitraptor.com</email>
</author>
<published>2026-02-12T22:59:02+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=45dabe3382bc71fbb40ec60eb3eaa0e21de2564d'/>
<id>45dabe3382bc71fbb40ec60eb3eaa0e21de2564d</id>
<content type='text'>
Instead of sending all 128 buffered objects to one bucket,
round-robin distribute them across all worker buckets so
parallel obj_free work stays balanced.

https://github.com/ruby/mmtk/commit/e1f926cd21
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Instead of sending all 128 buffered objects to one bucket,
round-robin distribute them across all worker buckets so
parallel obj_free work stays balanced.

https://github.com/ruby/mmtk/commit/e1f926cd21
</pre>
</div>
</content>
</entry>
<entry>
<title>[ruby/mmtk] Fix Cargo format issues</title>
<updated>2026-03-04T11:02:35+00:00</updated>
<author>
<name>Matt Valentine-House</name>
<email>matt@eightbitraptor.com</email>
</author>
<published>2026-02-12T15:40:56+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=092620090a3e639b223a7f03fbdfdd088d93a141'/>
<id>092620090a3e639b223a7f03fbdfdd088d93a141</id>
<content type='text'>
https://github.com/ruby/mmtk/commit/26ec9f7f89
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
https://github.com/ruby/mmtk/commit/26ec9f7f89
</pre>
</div>
</content>
</entry>
<entry>
<title>[ruby/mmtk] Buffer obj_free candidates.</title>
<updated>2026-03-04T11:02:35+00:00</updated>
<author>
<name>Matt Valentine-House</name>
<email>matt@eightbitraptor.com</email>
</author>
<published>2026-02-12T15:20:56+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=fa8b6aff710e97923cbf80ac8627b798cfe476e4'/>
<id>fa8b6aff710e97923cbf80ac8627b798cfe476e4</id>
<content type='text'>
Previously, every object allocation in rb_gc_impl_new_obj made a
per-object FFI call into Rust (mmtk_add_obj_free_candidate), which
acquired a mutex on one of the WeakProcessor's candidate vecs, pushed a
single element, and released the mutex. That's an FFI crossing + mutex
lock/unlock on every single allocation.

Now, each MMTk_ractor_cache has two local buffers (parallel-freeable and
non-parallel-freeable, 128 entries each). On allocation, we just store
the pointer into the local buffer. When a buffer fills up, we flush the
entire batch in one FFI call using mmtk_add_obj_free_candidates, which
does a single mutex acquisition and extend_from_slice for the whole
batch.

We picked 128 as our buffer size at random. We should probably
investigate further what an optimum size for this is

https://github.com/ruby/mmtk/commit/23c4a9a676
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Previously, every object allocation in rb_gc_impl_new_obj made a
per-object FFI call into Rust (mmtk_add_obj_free_candidate), which
acquired a mutex on one of the WeakProcessor's candidate vecs, pushed a
single element, and released the mutex. That's an FFI crossing + mutex
lock/unlock on every single allocation.

Now, each MMTk_ractor_cache has two local buffers (parallel-freeable and
non-parallel-freeable, 128 entries each). On allocation, we just store
the pointer into the local buffer. When a buffer fills up, we flush the
entire batch in one FFI call using mmtk_add_obj_free_candidates, which
does a single mutex acquisition and extend_from_slice for the whole
batch.

We picked 128 as our buffer size at random. We should probably
investigate further what an optimum size for this is

https://github.com/ruby/mmtk/commit/23c4a9a676
</pre>
</div>
</content>
</entry>
</feed>
