<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ruby.git/thread_sync.c, branch v4.0.4</title>
<subtitle>The Ruby Programming Language</subtitle>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/'/>
<entry>
<title>thread_sync.c: rename mutex_trylock internal function</title>
<updated>2025-12-18T20:07:55+00:00</updated>
<author>
<name>Jean Boussier</name>
<email>jean.boussier@gmail.com</email>
</author>
<published>2025-12-18T19:17:45+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=fb1dd92d30a8df93f6fe2746aacc097f4c3ea62b'/>
<id>fb1dd92d30a8df93f6fe2746aacc097f4c3ea62b</id>
<content type='text'>
[Bug #21793]

To fix a naming conflict on solaris.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
[Bug #21793]

To fix a naming conflict on solaris.
</pre>
</div>
</content>
</entry>
<entry>
<title>thread_sync.c: declare queue_data_type as parent of szqueue_data_type.</title>
<updated>2025-12-18T19:57:05+00:00</updated>
<author>
<name>Jean Boussier</name>
<email>jean.boussier@gmail.com</email>
</author>
<published>2025-12-18T08:35:44+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=8cf4f373ff596aaef7aaec993c355b242d4fe2c1'/>
<id>8cf4f373ff596aaef7aaec993c355b242d4fe2c1</id>
<content type='text'>
Allows to remove some duplicated code like szqueue_length, etc.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Allows to remove some duplicated code like szqueue_length, etc.
</pre>
</div>
</content>
</entry>
<entry>
<title>thread_sync.c: simplify `check_array`</title>
<updated>2025-12-18T19:57:05+00:00</updated>
<author>
<name>Jean Boussier</name>
<email>jean.boussier@gmail.com</email>
</author>
<published>2025-12-18T08:11:53+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=bbc684d8300fc3fc02020a9a644b857d090f2215'/>
<id>bbc684d8300fc3fc02020a9a644b857d090f2215</id>
<content type='text'>
If the queue was allocated without calling initialize,
`ary` will be `0`.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
If the queue was allocated without calling initialize,
`ary` will be `0`.
</pre>
</div>
</content>
</entry>
<entry>
<title>thread_sync.c: eliminate GET_EC() from queue_do_pop</title>
<updated>2025-12-18T19:57:05+00:00</updated>
<author>
<name>Jean Boussier</name>
<email>jean.boussier@gmail.com</email>
</author>
<published>2025-12-17T08:22:54+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=57c4cd9a474ccd32caccee28a850ff8a041babb8'/>
<id>57c4cd9a474ccd32caccee28a850ff8a041babb8</id>
<content type='text'>
We receive the ec as argument, it's much cheaper to pass it
around that to look it up again.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
We receive the ec as argument, it's much cheaper to pass it
around that to look it up again.
</pre>
</div>
</content>
</entry>
<entry>
<title>thread_sync: Mutex keep `rb_thread_t *` instead of `VALUE`</title>
<updated>2025-12-18T18:37:14+00:00</updated>
<author>
<name>Jean Boussier</name>
<email>jean.boussier@gmail.com</email>
</author>
<published>2025-12-18T08:47:26+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=0e719239c2fa39804cdbf1f920a18fcec919e2ce'/>
<id>0e719239c2fa39804cdbf1f920a18fcec919e2ce</id>
<content type='text'>
We never need the actual thread object and this avoid any issue
if the thread object is ever moved.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
We never need the actual thread object and this avoid any issue
if the thread object is ever moved.
</pre>
</div>
</content>
</entry>
<entry>
<title>Rename fiber_serial into ec_serial</title>
<updated>2025-12-16T08:51:07+00:00</updated>
<author>
<name>Jean Boussier</name>
<email>jean.boussier@gmail.com</email>
</author>
<published>2025-12-15T23:43:41+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=e42bcd7ce76e75601ef3adf35467edf277471af2'/>
<id>e42bcd7ce76e75601ef3adf35467edf277471af2</id>
<content type='text'>
Since it now live in the EC.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Since it now live in the EC.
</pre>
</div>
</content>
</entry>
<entry>
<title>Store the fiber_serial in the EC to allow inlining</title>
<updated>2025-12-16T08:51:07+00:00</updated>
<author>
<name>Jean Boussier</name>
<email>jean.boussier@gmail.com</email>
</author>
<published>2025-12-14T09:46:52+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=28b195fc67788c03be59c2a4cbf0cad52ac3b90f'/>
<id>28b195fc67788c03be59c2a4cbf0cad52ac3b90f</id>
<content type='text'>
Mutexes spend a significant amount of time in `rb_fiber_serial`
because it can't be inlined (except with LTO).
The fiber struct is opaque the so function can't be defined as inlineable.

Ideally the while fiber struct would not be opaque to the rest of
Ruby core, but it's tricky to do.

Instead we can store the fiber serial in the execution context
itself, and make its access cheaper:

```
$ hyperfine './miniruby-baseline --yjit /tmp/mut.rb' './miniruby-inline-serial --yjit /tmp/mut.rb'
Benchmark 1: ./miniruby-baseline --yjit /tmp/mut.rb
  Time (mean ± σ):      4.011 s ±  0.084 s    [User: 3.977 s, System: 0.011 s]
  Range (min … max):    3.950 s …  4.245 s    10 runs

Benchmark 2: ./miniruby-inline-serial --yjit /tmp/mut.rb
  Time (mean ± σ):      3.495 s ±  0.150 s    [User: 3.448 s, System: 0.009 s]
  Range (min … max):    3.340 s …  3.869 s    10 runs

Summary
  ./miniruby-inline-serial --yjit /tmp/mut.rb ran
    1.15 ± 0.05 times faster than ./miniruby-baseline --yjit /tmp/mut.rb
```

```ruby
i = 10_000_000
mut = Mutex.new
while i &gt; 0
  i -= 1
  mut.synchronize { }
  mut.synchronize { }
  mut.synchronize { }
  mut.synchronize { }
  mut.synchronize { }
  mut.synchronize { }
  mut.synchronize { }
  mut.synchronize { }
  mut.synchronize { }
  mut.synchronize { }
end
```
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Mutexes spend a significant amount of time in `rb_fiber_serial`
because it can't be inlined (except with LTO).
The fiber struct is opaque the so function can't be defined as inlineable.

Ideally the while fiber struct would not be opaque to the rest of
Ruby core, but it's tricky to do.

Instead we can store the fiber serial in the execution context
itself, and make its access cheaper:

```
$ hyperfine './miniruby-baseline --yjit /tmp/mut.rb' './miniruby-inline-serial --yjit /tmp/mut.rb'
Benchmark 1: ./miniruby-baseline --yjit /tmp/mut.rb
  Time (mean ± σ):      4.011 s ±  0.084 s    [User: 3.977 s, System: 0.011 s]
  Range (min … max):    3.950 s …  4.245 s    10 runs

Benchmark 2: ./miniruby-inline-serial --yjit /tmp/mut.rb
  Time (mean ± σ):      3.495 s ±  0.150 s    [User: 3.448 s, System: 0.009 s]
  Range (min … max):    3.340 s …  3.869 s    10 runs

Summary
  ./miniruby-inline-serial --yjit /tmp/mut.rb ran
    1.15 ± 0.05 times faster than ./miniruby-baseline --yjit /tmp/mut.rb
```

```ruby
i = 10_000_000
mut = Mutex.new
while i &gt; 0
  i -= 1
  mut.synchronize { }
  mut.synchronize { }
  mut.synchronize { }
  mut.synchronize { }
  mut.synchronize { }
  mut.synchronize { }
  mut.synchronize { }
  mut.synchronize { }
  mut.synchronize { }
  mut.synchronize { }
end
```
</pre>
</div>
</content>
</entry>
<entry>
<title>thead_sync.c: directly pass the execution context to yield</title>
<updated>2025-12-12T09:08:05+00:00</updated>
<author>
<name>Jean Boussier</name>
<email>jean.boussier@gmail.com</email>
</author>
<published>2025-12-12T08:10:04+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=ff831eb0572b2d8f794acca478ea77c7bfefbc61'/>
<id>ff831eb0572b2d8f794acca478ea77c7bfefbc61</id>
<content type='text'>
Saves one more call to GET_EC()
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Saves one more call to GET_EC()
</pre>
</div>
</content>
</entry>
<entry>
<title>Define Thread::ConditionVariable in thread_sync.rb</title>
<updated>2025-12-12T09:07:39+00:00</updated>
<author>
<name>Jean Boussier</name>
<email>jean.boussier@gmail.com</email>
</author>
<published>2025-12-12T07:55:45+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=7e7a1db579dad504a26e42d5f3efa5b2968389af'/>
<id>7e7a1db579dad504a26e42d5f3efa5b2968389af</id>
<content type='text'>
It's more consistent with Mutex, but also the `#wait` method
benefits from receiving the execution context instead of having
to call `GET_EC`.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
It's more consistent with Mutex, but also the `#wait` method
benefits from receiving the execution context instead of having
to call `GET_EC`.
</pre>
</div>
</content>
</entry>
<entry>
<title>Mutex: avoid repeated calls to `GET_EC`</title>
<updated>2025-12-11T22:25:57+00:00</updated>
<author>
<name>Jean Boussier</name>
<email>jean.boussier@gmail.com</email>
</author>
<published>2025-12-10T10:44:27+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=07b2356a6ad314b9a7b2bb9fc0527b440f004faa'/>
<id>07b2356a6ad314b9a7b2bb9fc0527b440f004faa</id>
<content type='text'>
That call is surprisingly expensive, so trying doing it once
in `#synchronize` and then passing the EC to lock and unlock
saves quite a few cycles.

Before:

```
ruby 4.0.0dev (2025-12-10T09:30:18Z master c5608ab4d7) +YJIT +PRISM [arm64-darwin25]
Warming up --------------------------------------
               Mutex     1.888M i/100ms
             Monitor     1.633M i/100ms
Calculating -------------------------------------
               Mutex     22.610M (± 0.2%) i/s   (44.23 ns/i) -    113.258M in   5.009097s
             Monitor     19.148M (± 0.3%) i/s   (52.22 ns/i) -     96.366M in   5.032755s
```

After:
```
ruby 4.0.0dev (2025-12-10T10:40:07Z speedup-mutex 1c901cd4f8) +YJIT +PRISM [arm64-darwin25]
Warming up --------------------------------------
               Mutex     2.095M i/100ms
             Monitor     1.578M i/100ms
Calculating -------------------------------------
               Mutex     24.456M (± 0.4%) i/s   (40.89 ns/i) -    123.584M in   5.053418s
             Monitor     19.176M (± 0.1%) i/s   (52.15 ns/i) -     96.243M in   5.018977s
```

Bench:

```
require 'bundler/inline'

gemfile do
  gem "benchmark-ips"
end

mutex = Mutex.new
require "monitor"
monitor = Monitor.new

Benchmark.ips do |x|
  x.report("Mutex") { mutex.synchronize { } }
  x.report("Monitor") { monitor.synchronize { } }
end
```
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
That call is surprisingly expensive, so trying doing it once
in `#synchronize` and then passing the EC to lock and unlock
saves quite a few cycles.

Before:

```
ruby 4.0.0dev (2025-12-10T09:30:18Z master c5608ab4d7) +YJIT +PRISM [arm64-darwin25]
Warming up --------------------------------------
               Mutex     1.888M i/100ms
             Monitor     1.633M i/100ms
Calculating -------------------------------------
               Mutex     22.610M (± 0.2%) i/s   (44.23 ns/i) -    113.258M in   5.009097s
             Monitor     19.148M (± 0.3%) i/s   (52.22 ns/i) -     96.366M in   5.032755s
```

After:
```
ruby 4.0.0dev (2025-12-10T10:40:07Z speedup-mutex 1c901cd4f8) +YJIT +PRISM [arm64-darwin25]
Warming up --------------------------------------
               Mutex     2.095M i/100ms
             Monitor     1.578M i/100ms
Calculating -------------------------------------
               Mutex     24.456M (± 0.4%) i/s   (40.89 ns/i) -    123.584M in   5.053418s
             Monitor     19.176M (± 0.1%) i/s   (52.15 ns/i) -     96.243M in   5.018977s
```

Bench:

```
require 'bundler/inline'

gemfile do
  gem "benchmark-ips"
end

mutex = Mutex.new
require "monitor"
monitor = Monitor.new

Benchmark.ips do |x|
  x.report("Mutex") { mutex.synchronize { } }
  x.report("Monitor") { monitor.synchronize { } }
end
```
</pre>
</div>
</content>
</entry>
</feed>
