Project

General

Profile

Actions

Feature #6154

closed

Eliminate extending WaitReadable/Writable at runtime

Added by headius (Charles Nutter) over 10 years ago. Updated about 9 years ago.

Status:
Closed
Priority:
Normal
Target version:
[ruby-core:43325]

Description

The nonblocking IO operations started extending WaitReadable or WaitWritable into the Errno::EAGAIN instance some time during the 1.9 series. This has a rather high cost, since a singleton class must be created and the global method cache must be flushed.

The attached patch instead creates two new classes of the following form, and raises them rather than raising a singleton EAGAIN:

class IO::EAGAINReadable < Errno::EAGAIN
include WaitReadable
end

class IO::EAGAINWritable < Errno::EAGAIN
include WaitWritable
end

The performance of repeatedly doing unsuccessful nonblocking reads improves by about 20%:

BEFORE:

system ~/projects/ruby $ ./ruby2.0.0 -rbenchmark -rsocket -e "sock = TCPSocket.new('localhost', 22); 10.times { puts Benchmark.measure { 100_000.times { begin; sock.read_nonblock(10); rescue IO::WaitReadable; end } } }"
1.210000 0.110000 1.320000 ( 1.328921)
1.220000 0.120000 1.340000 ( 1.326136)
1.220000 0.110000 1.330000 ( 1.334026)
1.230000 0.110000 1.340000 ( 1.349927)
1.310000 0.130000 1.440000 ( 1.426608)
1.210000 0.110000 1.320000 ( 1.333530)
1.220000 0.120000 1.340000 ( 1.330352)
1.230000 0.110000 1.340000 ( 1.350455)
1.220000 0.120000 1.340000 ( 1.327550)
1.220000 0.110000 1.330000 ( 1.337785)

AFTER:

system ~/projects/ruby $ ./ruby2.0.0 -rbenchmark -rsocket -e "sock = TCPSocket.new('localhost', 22); 10.times { puts Benchmark.measure { 100_000.times { begin; sock.read_nonblock(10); rescue IO::WaitReadable; end } } }"
0.980000 0.110000 1.090000 ( 1.092166)
1.010000 0.120000 1.130000 ( 1.129877)
1.090000 0.120000 1.210000 ( 1.202066)
0.960000 0.110000 1.070000 ( 1.076274)
0.970000 0.100000 1.070000 ( 1.078000)
0.970000 0.110000 1.080000 ( 1.078156)
0.970000 0.110000 1.080000 ( 1.078005)
0.970000 0.110000 1.080000 ( 1.078266)
0.980000 0.110000 1.090000 ( 1.093039)
1.000000 0.110000 1.110000 ( 1.112519)

This benchmark does not show the hidden cost of constantly invalidating the global method cache.

I also modified a similar case in OpenSSL, where it previously created an SSLError and extended WaitReadable into it.


Files

eagain_readwrite.diff (5.73 KB) eagain_readwrite.diff headius (Charles Nutter), 03/16/2012 01:02 PM
eagain_readwrite.diff (6.74 KB) eagain_readwrite.diff headius (Charles Nutter), 03/23/2012 03:38 AM
eagain_readwrite.diff (10.3 KB) eagain_readwrite.diff headius (Charles Nutter), 04/03/2013 07:20 AM
eagain_readwrite.diff (10.5 KB) eagain_readwrite.diff headius (Charles Nutter), 04/03/2013 10:55 AM
Actions

Also available in: Atom PDF