Whenever we run into an inline cache miss when we try to set
an ivar, we may need to take the global lock, just to be able to
lookup inside `shape->edges`.
To solve that, when we're in multi-ractor mode, we can treat
the `shape->edges` as immutable. When we need to add a new
edge, we first copy the table, and then replace it with
CAS.
This increases memory allocations, however we expect that
creating new transitions becomes increasingly rare over time.
```ruby
class A
def initialize(bool)
@a = 1
if bool
@b = 2
else
@c = 3
end
end
def test
@d = 4
end
end
def bench(iterations)
i = iterations
while i > 0
A.new(true).test
A.new(false).test
i -= 1
end
end
if ARGV.first == "ractor"
ractors = 8.times.map do
Ractor.new do
bench(20_000_000 / 8)
end
end
ractors.each(&:take)
else
bench(20_000_000)
end
```
The above benchmark takes 27 seconds in Ractor mode on Ruby 3.4,
and only 1.7s with this branch.
Co-Authored-By: Étienne Barrié <etienne.barrie@gmail.com>
Fixup 4c26a38ed3c
https://rubyci.s3.amazonaws.com/amazon2/ruby-master/log/20250601T213003Z.fail.html.gz
```
1)
An exception occurred during: Mock.verify_count
File.birthtime accepts an object that has a #to_path method FAILED
Mock 'path' expected to receive to_path(:any_args) exactly 1 times
but received it 0 times
/home/chkbuild/chkbuild/tmp/build/20250601T213003Z/ruby/spec/ruby/core/file/birthtime_spec.rb:4:in 'block in <top (required)>'
/home/chkbuild/chkbuild/tmp/build/20250601T213003Z/ruby/spec/ruby/core/file/birthtime_spec.rb:3:in '<top (required)>'
```
To prevent the following strange error, prepare IDs at first.
```
<internal:ractor>:596:in 'Ractor#monitor': symbol :exited is already registered with 98610c (fatal)
from <internal:ractor>:550:in 'Ractor#join'
from <internal:ractor>:574:in 'Ractor#value'
from bootstraptest.test_ractor.rb_2013_1309.rb:12:in '<main>'
```
BTW, the error should be fixed on ID management system.
`make test-bundler-parallel` prints many errors, so try to
downgrade rake version.
```
219) bundle install --standalone run in a subdirectory with --binstubs creates stubs that can be symlinked
Failure/Error:
raise <<~ERROR
#{error_header}
----------------------------------------------------------------------
#{stdboth}
----------------------------------------------------------------------
ERROR
RuntimeError:
Commands:
$ /home/ko1/ruby/build/trunk/ruby -I/home/ko1/ruby/src/trunk/spec/bundler -r/home/ko1/ruby/src/trunk/spec/bundler/support/artifice/compact_index.rb -r/home/ko1/ruby/src/trunk/spec/bundler/support/hax.rb /home/ko1/ruby/src/trunk/tmp/2.13/gems/system/bin/bundle config set --local path /home/ko1/ruby/src/trunk/tmp/2.13/bundled_app/bundle
# $? => 0
Invoking `/home/ko1/ruby/build/trunk/ruby -I/home/ko1/ruby/src/trunk/spec/bundler -r/home/ko1/ruby/src/trunk/spec/bundler/support/artifice/compact_index.rb -r/home/ko1/ruby/src/trunk/spec/bundler/support/hax.rb /home/ko1/ruby/src/trunk/tmp/2.13/gems/system/bin/bundle install --standalone --binstubs` failed with output:
----------------------------------------------------------------------
[DEPRECATED] The --binstubs option will be removed in favor of `bundle binstubs --all`
Could not find compatible versions
Because every version of rails depends on rake = 13.3.0
and rake = 13.3.0 could not be found in rubygems repository https://gem.repo1/ or installed locally,
rails cannot be used.
So, because Gemfile depends on rails >= 0,
version solving has failed.
Fetching gem metadata from https://gem.repo1/...
Resolving dependencies...
----------------------------------------------------------------------
Shared Example Group: "bundle install --standalone" called from ./spec/bundler/install/gems/standalone_spec.rb:532
# /home/ko1/ruby/src/trunk/spec/bundler/support/command_execution.rb:26:in 'Spec::CommandExecution#raise_error!'
# /home/ko1/ruby/src/trunk/spec/bundler/support/subprocess.rb:66:in 'Spec::Subprocess#sh'
# /home/ko1/ruby/src/trunk/spec/bundler/support/helpers.rb:216:in 'Spec::Helpers#sys_exec'
# /home/ko1/ruby/src/trunk/spec/bundler/support/helpers.rb:107:in 'Spec::Helpers#bundle'
# /home/ko1/ruby/src/trunk/spec/bundler/install/gems/standalone_spec.rb:482:in 'block (3 levels) in <top (required)>'
# /home/ko1/ruby/src/trunk/spec/bundler/spec_helper.rb:107:in 'block (4 levels) in <top (required)>'
# /home/ko1/ruby/src/trunk/spec/bundler/spec_helper.rb:107:in 'block (3 levels) in <top (required)>'
# /home/ko1/ruby/src/trunk/spec/bundler/support/helpers.rb:355:in 'block in Spec::Helpers#with_gem_path_as'
# /home/ko1/ruby/src/trunk/spec/bundler/support/helpers.rb:369:in 'Spec::Helpers#without_env_side_effects'
# /home/ko1/ruby/src/trunk/spec/bundler/support/helpers.rb:350:in 'Spec::Helpers#with_gem_path_as'
# /home/ko1/ruby/src/trunk/spec/bundler/spec_helper.rb:106:in 'block (2 levels) in <top (required)>'
```
RDoc markdown parser requires exact 4 spaces or tab as indentation.
Also the first nested bullet list must be separated from the enclosing
bullet list item by a blank line.
```
1) Failure:
TestProcess#test_warmup_frees_pages [/tmp/ruby/src/trunk-random1/test/ruby/test_process.rb:2772]:
<164348> expected but was
<165985>.
```
can someone investigate it?
* Added `Ractor::Port`
* `Ractor::Port#receive` (support multi-threads)
* `Rcator::Port#close`
* `Ractor::Port#closed?`
* Added some methods
* `Ractor#join`
* `Ractor#value`
* `Ractor#monitor`
* `Ractor#unmonitor`
* Removed some methods
* `Ractor#take`
* `Ractor.yield`
* Change the spec
* `Racotr.select`
You can wait for multiple sequences of messages with `Ractor::Port`.
```ruby
ports = 3.times.map{ Ractor::Port.new }
ports.map.with_index do |port, ri|
Ractor.new port,ri do |port, ri|
3.times{|i| port << "r#{ri}-#{i}"}
end
end
p ports.each{|port| pp 3.times.map{port.receive}}
```
In this example, we use 3 ports, and 3 Ractors send messages to them respectively.
We can receive a series of messages from each port.
You can use `Ractor#value` to get the last value of a Ractor's block:
```ruby
result = Ractor.new do
heavy_task()
end.value
```
You can wait for the termination of a Ractor with `Ractor#join` like this:
```ruby
Ractor.new do
some_task()
end.join
```
`#value` and `#join` are similar to `Thread#value` and `Thread#join`.
To implement `#join`, `Ractor#monitor` (and `Ractor#unmonitor`) is introduced.
This commit changes `Ractor.select()` method.
It now only accepts ports or Ractors, and returns when a port receives a message or a Ractor terminates.
We removes `Ractor.yield` and `Ractor#take` because:
* `Ractor::Port` supports most of similar use cases in a simpler manner.
* Removing them significantly simplifies the code.
We also change the internal thread scheduler code (thread_pthread.c):
* During barrier synchronization, we keep the `ractor_sched` lock to avoid deadlocks.
This lock is released by `rb_ractor_sched_barrier_end()`
which is called at the end of operations that require the barrier.
* fix potential deadlock issues by checking interrupts just before setting UBF.
https://bugs.ruby-lang.org/issues/21262
Remove the unused constant HAS_MOVED_GFIELDSTBL and related methods.
In the mmtk/mmtk-ruby repo, we are now able to find the global field
(IV) table of a moved object during copying GC without using the
HAS_MOVED_GFIELDSTBL bit. We synchronize some of the code, although we
haven't implemented moving GC in ruby/mmtk, yet.
See: 13080acdf5https://github.com/ruby/mmtk/commit/400ba4e747
MAX_IV_COUNT is a hint which determines the size of variable width
allocation we should use for a given class. We don't need to scope this
by namespace, if we end up with larger builtin objects on some
namespaces that isn't a user-visible problem, just extra memory use.
Similarly variation_count is used to track if a given object has had too
many branches in shapes it has used, and to use too_complex when that
happens. That's also just a hint, so we can use the same value across
namespaces without it being visible to users.
Previously variation_count was being incremented (written to) on the
RCLASS_EXT_READABLE ext, which seems incorrect if we wanted it to be
different across namespaces
When creating fibers in multiple ractors at the same time there were
issues with the manipulation of this structure, causing segfaults.
I didn't add any tests for this because I'm making a more general
PR in the very near future to be able to run test methods (test-all suite)
inside multiple ractors at the same time. This is how this bug was
caught, running test/ruby/test_fiber.rb inside 10 ractors at once.