From: "tenderlovemaking (Aaron Patterson) via ruby-core" Date: 2025-02-09T19:30:38+00:00 Subject: [ruby-core:120927] [Ruby master Bug#19288] Ractor JSON parsing significantly slower than linear parsing Issue #19288 has been updated by tenderlovemaking (Aaron Patterson). byroot (Jean Boussier) wrote in #note-16: > I profiled this repro out of curiosity, and ractors spend 32% of their time waiting for the VM lock (`vm_lock_enter` + the unlock) to be able to lookup in the `fstring` table: https://share.firefox.dev/4152X8a > > Currently this is done explicitly by the `json` gem, but even if `json` wasn't attempting to do it, Ruby would do the same thing once we're trying to insert string keys: https://share.firefox.dev/4hsVPbC > > I suppose there are various solutions to this with their own tradeoffs: > > - Don't intern hash keys when not on the main ractor. > - Protect the `fstring` table with its own dedicated Read-write lock, so that concurrent Ractors can lookup string (but only one insert). And also reduce contention for other areas still protected by the remaining VM lock. I'm not sure if this one is possible. If some Ractor is updating the hash, it could be in an inconsistent state when another Ractor is trying to read. Maybe st table updates are atomic, but I don't know (and I kind of doubt it). > - Somehow replace the fstring table by a truly lockfree hash table. This would be ideal IMO, but seems hard ���� We could also add an fstring table to each Ractor. I know the purpose of the fstring table is to limit the number of instances of a string, but at least we would be limited to the number of Ractors (rather than no limit when there are multiple Ractors). ---------------------------------------- Bug #19288: Ractor JSON parsing significantly slower than linear parsing https://bugs.ruby-lang.org/issues/19288#change-111810 * Author: maciej.mensfeld (Maciej Mensfeld) * Status: Open * ruby -v: ruby 3.2.0 (2022-12-25 revision a528908271) [x86_64-linux] * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- a simple benchmark: ```ruby require 'json' require 'benchmark' CONCURRENT = 5 RACTORS = true ELEMENTS = 100_000 data = CONCURRENT.times.map do ELEMENTS.times.map do { rand => rand, rand => rand, rand => rand, rand => rand }.to_json end end ractors = CONCURRENT.times.map do Ractor.new do Ractor.receive.each { JSON.parse(_1) } end end result = Benchmark.measure do if RACTORS CONCURRENT.times do |i| ractors[i].send(data[i], move: false) end ractors.each(&:take) else # Linear without any threads data.each do |piece| piece.each { JSON.parse(_1) } end end end puts result ``` Gives following results on my 8 core machine: ```shell # without ractors: 2.731748 0.003993 2.735741 ( 2.736349) # with ractors 12.580452 5.089802 17.670254 ( 5.209755) ``` I would expect Ractors not to be two times slower on the CPU intense work. -- 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/