ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:120510] [Ruby master Bug#21007] Ractor scheduler issue when multiple threads in a ractor
@ 2025-01-06 22:13 luke-gru (Luke Gruber) via ruby-core
  2025-01-06 22:34 ` [ruby-core:120511] " luke-gru (Luke Gruber) via ruby-core
  0 siblings, 1 reply; 2+ messages in thread
From: luke-gru (Luke Gruber) via ruby-core @ 2025-01-06 22:13 UTC (permalink / raw)
  To: ruby-core; +Cc: luke-gru (Luke Gruber)

Issue #21007 has been reported by luke-gru (Luke Gruber).

----------------------------------------
Bug #21007: Ractor scheduler issue when multiple threads in a ractor
https://bugs.ruby-lang.org/issues/21007

* Author: luke-gru (Luke Gruber)
* Status: Open
* Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN
----------------------------------------
When there are multiple threads in a ractor, these threads can get in a state where they are yielding every 10ms instead of every 100ms.

This occurs because in `thread_sched_switch0`, which is called by `thread_sched_switch`, `ruby_thread_set_native` is called. This function calls
`rb_ractor_set_current_ec` for the next thread to run, but then when the next thread sets itself up before it runs, it calls `rb_ractor_thread_switch`,
but since the ec has already been changed, it never sets back `th->running_time_us` to `0`.

The yielding happens every 10ms because a very large value in `th->running_time_us` is always compared to `100ms` so it always yields.

This script takes a very long time due to this issue:

```ruby
ractors = 5.times.map do |i|
  Ractor.new(i) do |i0|
    ts = 4.times.map do
      Thread.new do
        counter = 0
        while counter < 30_000_000
          counter += 1
        end
      end
    end
    until ts.none? { |t| t.alive? }
      $stderr.puts "Ractor #{i0} main thread sleeping"
      sleep 1
    end
    ts.each(&:join)
    $stderr.puts "Ractor #{i0} done"
  end
end

while ractors.any?
  r, obj = Ractor.select *ractors
  ractors.delete(r)
end
```

The fix is to set `next_th->running_time_us` back to 0 in `thread_sched_switch0`.





-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 2+ messages in thread

* [ruby-core:120511] [Ruby master Bug#21007] Ractor scheduler issue when multiple threads in a ractor
  2025-01-06 22:13 [ruby-core:120510] [Ruby master Bug#21007] Ractor scheduler issue when multiple threads in a ractor luke-gru (Luke Gruber) via ruby-core
@ 2025-01-06 22:34 ` luke-gru (Luke Gruber) via ruby-core
  0 siblings, 0 replies; 2+ messages in thread
From: luke-gru (Luke Gruber) via ruby-core @ 2025-01-06 22:34 UTC (permalink / raw)
  To: ruby-core; +Cc: luke-gru (Luke Gruber)

Issue #21007 has been updated by luke-gru (Luke Gruber).


PR here: https://github.com/ruby/ruby/pull/12520

----------------------------------------
Bug #21007: Ractor scheduler issue when multiple threads in a ractor
https://bugs.ruby-lang.org/issues/21007#change-111304

* Author: luke-gru (Luke Gruber)
* Status: Open
* Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN
----------------------------------------
When there are multiple threads in a ractor, these threads can get in a state where they are yielding every 10ms instead of every 100ms.

This occurs because in `thread_sched_switch0`, which is called by `thread_sched_switch`, `ruby_thread_set_native` is called. This function calls
`rb_ractor_set_current_ec` for the next thread to run, but then when the next thread sets itself up before it runs, it calls `rb_ractor_thread_switch`,
but since the ec has already been changed, it never sets back `th->running_time_us` to `0`.

The yielding happens every 10ms because a very large value in `th->running_time_us` is always compared to `100ms` so it always yields.

This script takes a very long time due to this issue:

```ruby
ractors = 5.times.map do |i|
  Ractor.new(i) do |i0|
    ts = 4.times.map do
      Thread.new do
        counter = 0
        while counter < 30_000_000
          counter += 1
        end
      end
    end
    until ts.none? { |t| t.alive? }
      $stderr.puts "Ractor #{i0} main thread sleeping"
      sleep 1
    end
    ts.each(&:join)
    $stderr.puts "Ractor #{i0} done"
  end
end

while ractors.any?
  r, obj = Ractor.select *ractors
  ractors.delete(r)
end
```

The fix is to set `next_th->running_time_us` back to 0 in `thread_sched_switch0`.





-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2025-01-06 22:34 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-01-06 22:13 [ruby-core:120510] [Ruby master Bug#21007] Ractor scheduler issue when multiple threads in a ractor luke-gru (Luke Gruber) via ruby-core
2025-01-06 22:34 ` [ruby-core:120511] " luke-gru (Luke Gruber) via ruby-core

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).