3 ms·
Some silly multi threaded questions incoming. I ran a quick benchmark here is the code require 'benchmark' require 'prime' Benchmark.bm do |x| x.repo
by bestinterest 6y ago
Some silly multi threaded questions incoming.
I ran a quick benchmark here is the code
require 'benchmark'
require 'prime'
Benchmark.bm do |x|
x.report('single'){
8.times do
10_000_000.times.each do |num|
num.prime?
end
end
}
x.report('thread'){
8.times.map do
Thread.new do
10_000_000.times.each do |num|
num.prime?
end
end
end.each(&:join)
}
x.report('parallel'){
8.times.map do
Ractor.new do
10_000_000.times.each do |num|
num.prime?
end
end
end.each(&:take)
}
end
results
single -> 121.66s
thread -> 122.14s
parallel -> 52.84s
The single and threaded version were the same and this is mostly expected since we don't have any I/O in the threads which would of given up the thread and scheduled another to be run.
For prime calculations, we are just bound by pure CPU and limited by ruby's global interpreter lock I assume this would be the same case in Python.
1) A silly question and more language irrelevant, when looking at my CPU logical core usage during the single and fake threaded version I could see tiny spikes in all the cores. [0] No one core dominated the task how does this work? Does the CPU know to workshare single threaded tasks and branch prediction etc comes into play here? How are modern CPU's achieving this at a lower level? In my head this task would just spike a single core to do all the work.
2) Running the 10_00_000 primes just once completes in 15.3s shouldn't this be the same amount of time for 80_00_000 if the Ractor implementation was optimized across my 8 logical cores? Not a punch or anything at guys working on lang its freaking awesome to see my CPU being maxed out with my 8 logical processors being used in Ruby! [1] but just want to double check my understanding.
[0] https://postimg.cc/rKjB9kQP https://postimg.cc/rKjB9kQP
[1] https://postimg.cc/WtvpWswN https://postimg.cc/WtvpWswN
- chrisseaton 6y ago> when looking at my CPU logical core usage during the single and fake threaded version I could see tiny spikes in all the cores What do you mean by 'fake threaded'? Ruby threads were already fully concurrent OS threads. They're likely scheduled on different physical cores, so will spike your different cores each time they manage to get the GIL and run. > if the Ractor implementation was optimized across my 8 logical cores? There's synchronisation. Many VM services are global.
- bestinterest 6y agoAh okay in that case that makes much more sense to me for the threaded version, I was meaning fake threaded in the sense only one thread is ever ran at a time but of course they are scheduled onto different OS threads like you say which means they will run across my logical cores. But for the single threaded version I still seen spikes across all cores is this some CPU magic and if so what techniques are involved? Or am I just misreading my CPU usage like a doughnut? > There's synchronisation. Many VM services are global. What do you mean by this? And I just realized I'm talking to Chris Seaton thank you for your work on TruffleRuby super awesome project.
- chrisseaton 6y ago> But for the single threaded version I still seen spikes across all cores is this some CPU magic and if so what techniques are involved? The kernel must be moving the Ruby process around if you're looking at the single-threaded case. That doesn't sound right though - moving a process to a different core damages its cache. But Ruby doesn't influence that it's down to the OS. Maybe the kernel has some subtle good reason to do it if you're running other services in the background? > What do you mean by this? Ractors acquire locks and CAS to do things to update the VM on what they're doing. They don't run entirely purely in parallel. GC is the big example. This benchmark shouldn't really need to use the GC... but maybe it does. Does your system malloc have a global lock too?
- JW_00000 6y ago> Maybe the kernel has some subtle good reason to do it I think OSes spread load across cores to prevent unequal heating across the chip.
- chrisseaton 6y agoHmm that’d be a disaster for cache I think that’s extremely unlikely but I’m not an OS expert.
- kenhwang 6y agoInterestingly, on my machine, all 3 implementations took the same amount of realtime (~30s), but the ractor implementation took ~200s in systemtime. I'm guessing the ractor switching overhead ate up whatever parallelization gain it got.
- ckolkey 6y agoFyi, `.times` is enumerable, you don't need to call `.each` after it.