Ruby 1.9.2 : Io performance when application use multithread

Hello,

The file attachment is an simple script for measure performance
between client TCP and server, in Mbyte/s.

With Ruby 1.9.2, when the server run in multi thread
( Thread.new(serv.accept()) {...} ) the script give
a very poor transfer rate ( 3Mbyte on connection on localhost ).

When none-multi thread, performance is good :
same as jruby and MRI ( 470 Mbyte/s )
(ironRuby give a stange 110 Mbyte/s).

Usage :

ruby gbits.rb server 4040 # server (monothread)
ruby gbits.rb server 4040 t # server (multihread)

ruby gbits.rb client 127.0.0.1 4040 10 # 10=> 10 MB data length

OS: Windows 7
Proc: core i7, 1 Gbps ethernet
Ruby: 1.9.2dev (2010-07-02) [i386-mingw32]
jruby: 1.5.0
ir: 1.1.0.0 on .NET 4.0.30319.1
ruby: 1.8.6

Tested on Linux
Ubuntu 10.4 (same machine with Virtalbox)
ruby 1.9.1p378 (2010-01-10 revision 26273) [i486-linux]

server threaded : 844 MB/s
server non-threaded: 989 MB/s
same delta with jruby

thanks
Regis

Attachments:
http://www.ruby-forum.com/attachment/5547/gbits.rb

···

--
Posted via http://www.ruby-forum.com/\.

On OS X 10.6 I don't see a performance drop for threaded vs non threaded. I ran your script with an argument of 1000 instead of 10 as the results for 10 were too variable.

ruby 1.9.3dev (2010-12-04 trunk 30078) [x86_64-darwin10.5.0] runs ~ 420MB/s both
ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-darwin10.4.0] runs ~ 420MB/s both
ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-darwin10.2.0] runs ~ 460MB/s without t
ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-darwin10.2.0] runs ~ 455MB/s with t
ruby 1.8.7 (2009-06-12 patchlevel 174) [universal-darwin10.0] runs ~ 490MB/s without t
ruby 1.8.7 (2009-06-12 patchlevel 174) [universal-darwin10.0] runs ~ 470MB/s with t

···

On Dec 14, 2010, at 05:34, Regis d'Aubarede wrote:

The file attachment is an simple script for measure performance
between client TCP and server, in Mbyte/s.

With Ruby 1.9.2, when the server run in multi thread
( Thread.new(serv.accept()) {...} ) the script give
a very poor transfer rate ( 3Mbyte on connection on localhost ).

When none-multi thread, performance is good :
same as jruby and MRI ( 470 Mbyte/s )
(ironRuby give a stange 110 Mbyte/s).

Usage :

ruby gbits.rb server 4040 # server (monothread)
ruby gbits.rb server 4040 t # server (multihread)

ruby gbits.rb client 127.0.0.1 4040 10 # 10=> 10 MB data length

OS: Windows 7
Proc: core i7, 1 Gbps ethernet
Ruby: 1.9.2dev (2010-07-02) [i386-mingw32]
jruby: 1.5.0
ir: 1.1.0.0 on .NET 4.0.30319.1
ruby: 1.8.6

Tested on Linux
Ubuntu 10.4 (same machine with Virtalbox)
ruby 1.9.1p378 (2010-01-10 revision 26273) [i486-linux]

server threaded : 844 MB/s
server non-threaded: 989 MB/s
same delta with jruby

By increasing the sending and receiving buffer sizes to 64KB and using syswrite/sysread I was able to increase performance to 565MB/s with 1.9.3dev. I suspect you'll see a similar increase on other versions as well.

You can find my modified version here: http://paste.segment7.net/jc.html

For the windows slowdown, perhaps better buffer sizes will help. It's possible that in threaded mode your odd-sized buffers are causing some kind of starvation.

If this doesn't help your speed issue try reporting this to the ruby-core mailing list.

···

On Dec 14, 2010, at 11:07, Eric Hodel wrote:

On Dec 14, 2010, at 05:34, Regis d'Aubarede wrote:

The file attachment is an simple script for measure performance
between client TCP and server, in Mbyte/s.

With Ruby 1.9.2, when the server run in multi thread
( Thread.new(serv.accept()) {...} ) the script give
a very poor transfer rate ( 3Mbyte on connection on localhost ).

When none-multi thread, performance is good :
same as jruby and MRI ( 470 Mbyte/s )
(ironRuby give a stange 110 Mbyte/s).

Usage :

ruby gbits.rb server 4040 # server (monothread)
ruby gbits.rb server 4040 t # server (multihread)

ruby gbits.rb client 127.0.0.1 4040 10 # 10=> 10 MB data length

OS: Windows 7
Proc: core i7, 1 Gbps ethernet
Ruby: 1.9.2dev (2010-07-02) [i386-mingw32]
jruby: 1.5.0
ir: 1.1.0.0 on .NET 4.0.30319.1
ruby: 1.8.6

Tested on Linux
Ubuntu 10.4 (same machine with Virtalbox)
ruby 1.9.1p378 (2010-01-10 revision 26273) [i486-linux]

server threaded : 844 MB/s
server non-threaded: 989 MB/s
same delta with jruby

On OS X 10.6 I don't see a performance drop for threaded vs non threaded. I ran your script with an argument of 1000 instead of 10 as the results for 10 were too variable.

ruby 1.9.3dev (2010-12-04 trunk 30078) [x86_64-darwin10.5.0] runs ~ 420MB/s both

Eric Hodel wrote in post #968393:

For the windows slowdown, perhaps better buffer sizes will help. It's
possible that in threaded mode your odd-sized buffers are causing some
kind of starvation.

Test of your version with ruby 1.9.1 on linux : 30% better flow,
but 10% diff between thread/no thread keep on.

Perhaps the GIL cost is effective : the reading loop is very
short :
while(len>0) len-=io.read(x) end

and so GIL do
while() release(GIL); io.read; get(GIL) end

And GIL cost is perhaps less heavy on OSX then on Windows.

If this doesn't help your speed issue try reporting this to the
ruby-core mailing list.

Its done, but no response...

Thank you very much for your suggestions,
Regis

···

On Dec 14, 2010, at 11:07, Eric Hodel wrote:

--
Posted via http://www.ruby-forum.com/\.

Thanks for all the valueable info.
Does ruby's threads have great improvement than multi-processes?
Since the threads for ruby is green-threads.

Regards.

···

2010/12/15 Regis d'Aubarede <regis.aubarede@gmail.com>:

Eric Hodel wrote in post #968393:

On Dec 14, 2010, at 11:07, Eric Hodel wrote:

For the windows slowdown, perhaps better buffer sizes will help. It's
possible that in threaded mode your odd-sized buffers are causing some
kind of starvation.

Test of your version with ruby 1.9.1 on linux : 30% better flow,
but 10% diff between thread/no thread keep on.

Eric Hodel wrote in post #968393:

For the windows slowdown, perhaps better buffer sizes will help. It's
possible that in threaded mode your odd-sized buffers are causing some
kind of starvation.

Test of your version with ruby 1.9.1 on linux : 30% better flow,
but 10% diff between thread/no thread keep on.

Thanks for all the valueable info.
Does ruby's threads have great improvement than multi-processes?

I am not sure what you are asking here. Are you talking about current
situation or the future development?

Since the threads for ruby is green-threads.

This is not true any more since the advent of JRuby and 1.9. However,
there are still limitations in YARV (GIL).

Kind regards

robert

···

On Thu, Dec 16, 2010 at 3:56 AM, zuerrong <zuerrong@gmail.com> wrote:

2010/12/15 Regis d'Aubarede <regis.aubarede@gmail.com>:

On Dec 14, 2010, at 11:07, Eric Hodel wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

What I'm asking is, does ruby's threads behave better on performance
than forking?

Thanks.

···

2010/12/16 Robert Klemme <shortcutter@googlemail.com>:

Thanks for all the valueable info.
Does ruby's threads have great improvement than multi-processes?

I am not sure what you are asking here. Are you talking about current
situation or the future development?

It depends. Generally even Ruby's green threads work pretty well for things doing IO on multiple channels. It depends on the problem, IO bandwidth you need and other computations that you need to do in between. Processes might be better but then again, if you constantly keep forking short lived processes chances are that fork is not your friend.

Cheers

  robert

···

On 16.12.2010 14:27, zuerrong wrote:

2010/12/16 Robert Klemme<shortcutter@googlemail.com>:

Thanks for all the valueable info.
Does ruby's threads have great improvement than multi-processes?

I am not sure what you are asking here. Are you talking about current
situation or the future development?

What I'm asking is, does ruby's threads behave better on performance
than forking?

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Thanks. good answer.

···

2010/12/17 Robert Klemme <shortcutter@googlemail.com>:

Processes might
be better but then again, if you constantly keep forking short lived
processes chances are that fork is not your friend.