From: "headius (Charles Nutter)" Date: 2013-04-03T10:23:08+09:00 Subject: [ruby-core:53918] [ruby-trunk - Feature #6154] Eliminate extending WaitReadable/Writable at runtime Issue #6154 has been updated by headius (Charles Nutter). normalperson (Eric Wong) wrote: > > +VALUE rb_eEAGAINWaitReadable; > > +VALUE rb_eEAGAINWaitWritable; > > +VALUE rb_eEWOULDBLOCKWaitReadable; > > +VALUE rb_eEWOULDBLOCKWaitWritable; > > +VALUE rb_eEINPROGRESSWaitWritable; > > +VALUE rb_eEINPROGRESSWaitReadable; > > New globals introduced don't appear to be used outside of io.c, > so they can be made static (unless you intend to reference them > outside of io.c in the future) Good call, will fix. ---------------------------------------- Feature #6154: Eliminate extending WaitReadable/Writable at runtime https://bugs.ruby-lang.org/issues/6154#change-38133 Author: headius (Charles Nutter) Status: Assigned Priority: Normal Assignee: headius (Charles Nutter) Category: core Target version: next minor 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/