From: Grigory Petrov Date: 2012-02-28T19:43:11+09:00 Subject: [ruby-core:42999] Re: 50$ for answering my stackoverflow question about Ruby and GIL > This test code doesn't show switch time, it shows how fast two ruby threads can append items to a list. �Each thread may switch multiple times during appending the item, or may not switch at all, but resume executing the same thread. Ok, i spelled it incorrectly. The test code shows amount of time a Ruby thread is working before scheduler suspends it (due to GIL) and gives time to another Ruby thread. This may or may not correlate with physical threads - i'm not very good with Ruby scheduling code on different OS'es. For example, if resulting list looks like [ 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 ] i can say that scheduler gives threads a small splice. And if resulting list looks like [ 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2 ] = splice is big. As numbers shows, splice is VERY big on Windows and OS :(. Tk lags on OSX and priority trick illustrates this. But on Windows priority trick don't work and GUI lag is MUCH bigger. I need to know why :). On Tue, Feb 28, 2012 at 4:36 AM, Eric Hodel wrote: > On Feb 27, 2012, at 12:10 PM, Grigory Petrov wrote: >> I'm not so sure about that. > > Since TIME_QUANTUM_USEC is divided by 1000 for the call to WaitForSingleObject(), it's in microseconds, but this is only the maximum amount of time a thread may run for before being interrupted. > >> I assembled the following test code. It's very straightforward and >> simple and will calculate an average splice time ( time scheduler will >> assign to a thread that is not giving it up via Thread.pass): >> >> require 'thread' >> require 'time' >> time = 10 >> items = [] >> threads = [] >> threads << Thread.new { loop { items << 1 } } >> threads << Thread.new { loop { items << 2 } } >> sleep time >> threads.each( &:exit ).each( &:join ) >> changes = 0 >> for i in 1 ... items.count do >> �changes += 1 if items[ i ] != items[ i - 1 ] >> end >> printf( "Switch time is %.3f seconds\n", time.to_f / (changes + 1) ) > > This test code doesn't show switch time, it shows how fast two ruby threads can append items to a list. �Each thread may switch multiple times during appending the item, or may not switch at all, but resume executing the same thread. > > The constants changed in USA's patch decrease the maximum possible runtime of a thread before the GVL is given to another thread. �This helps prevent a CPU bound threads from starving another process (which you are doing). �As USA also pointed out, running two CPU-heavy threads is not very good to the GVL, same as in Python. > >> The results are astonishing: >> Ubuntu: 0.010 second, ok >> OSX 10.7: 0.200 second, wtf? >> Windows XP: 0.350 second!!! WTF. >> >> Switching threads 3-4 times per second on most popular OS'es is VERY >> weird. Python slice is constant, around 10ms. And default thread >> scheduling on all OS'es is around 10ms too. > > I ran this under Instruments on OS X, and got this report from the Scheduling instrument (counts thread context switches and intervals at the POSIX level): > > thread_start_func_1 150284 intervals in 10.72 seconds, average CPU usage of 38.89 �s > thread_start_func_2 170662 intervals in 10.72 seconds, average CPU usage of 30.37 �s > > Running this yourself, you can look at the chart to see that sometimes ruby keeps running one thread for many milliseconds, but sometimes it rapidly switches between the two threads.