From: "headius (Charles Nutter)" Date: 2012-03-23T03:38:41+09:00 Subject: [ruby-core:43562] [ruby-trunk - Bug #6154] Eliminate extending WaitReadable/Writable at runtime Issue #6154 has been updated by headius (Charles Nutter). File eagain_readwrite.diff added Updated patch with the following changes: * rb_eEWOULDBLOCKReadable and rb_eEWOULDBLOCKWritable added * EWOULDBLOCK versions are set to EAGAIN versions if EAGAIN == EWOULDBLOCK * renamed function rb_readwrite_sys_fail to match error.c names better * reverted OSSL changes so nahi can do them right * fixed the one test (test/socket/test_unix.rb) that expected an exact exception Notes: * assert_raise should probably use === instead of == to better match rescue logic * more tests for this logic are needed(!!!) * I have not tested RubySpec yet * I can't test on HP/UX or other systems where EAGAIN != EWOULDBLOCK ---------------------------------------- Bug #6154: Eliminate extending WaitReadable/Writable at runtime https://bugs.ruby-lang.org/issues/6154#change-25051 Author: headius (Charles Nutter) Status: Open Priority: Normal Assignee: Category: Target version: ruby -v: 2.0.0dev 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. -- http://bugs.ruby-lang.org/