Issue #8208 has been updated by headius (Charles Nutter).


No comments?

Perf change for an implementation of this in JRuby:

Before:

$ jruby -rbenchmark -rsocket -e "s = TCPSocket.new('google.com', 80); 10.times { puts Benchmark.measure { 100_000.times { begin; s.read_nonblock(1000); rescue; end } } }"
  3.020000   0.300000   3.320000 (  1.967000)
  0.610000   0.200000   0.810000 (  0.725000)
  0.620000   0.200000   0.820000 (  0.737000)
  0.540000   0.190000   0.730000 (  0.719000)
  0.580000   0.200000   0.780000 (  0.756000)
  0.570000   0.200000   0.770000 (  0.748000)
  0.560000   0.190000   0.750000 (  0.743000)
  0.560000   0.200000   0.760000 (  0.741000)
  0.570000   0.190000   0.760000 (  0.747000)
  0.570000   0.200000   0.770000 (  0.747000)

After:

$ jruby -rbenchmark -rsocket -e "s = TCPSocket.new('google.com', 80); 10.times { puts Benchmark.measure { 100_000.times { begin; s.read_nonblock(1000); rescue; end } } }"
  1.750000   0.230000   1.980000 (  1.216000)
  0.360000   0.180000   0.540000 (  0.449000)
  0.370000   0.190000   0.560000 (  0.493000)
  0.320000   0.180000   0.500000 (  0.445000)
  0.330000   0.170000   0.500000 (  0.448000)
  0.280000   0.170000   0.450000 (  0.436000)
  0.270000   0.160000   0.430000 (  0.434000)
  0.280000   0.170000   0.450000 (  0.434000)
  0.270000   0.160000   0.430000 (  0.433000)
  0.270000   0.170000   0.440000 (  0.431000)
----------------------------------------
Bug #8208: Raise cached exceptions for nonblocking IO to avoid allocation/stack-copying costs
https://bugs.ruby-lang.org/issues/8208#change-38625

Author: headius (Charles Nutter)
Status: Open
Priority: Normal
Assignee: 
Category: 
Target version: 
ruby -v: 2.0.0


Currently, all nonblocking IO APIs raise exceptions when the IO channel cannot perform the requested read or write without blocking. This adds a tremendous performance hit to nonblocking IO, since raising an exception requires both allocating the exception object and saving off the backtrace information from the call stack.

Two changes could reduce this cost:

1. Don't provide a full backtrace for these exceptions, or only provide it in a debug or verbose modes. 99% of the rescuers of these exceptions don't ever use the backtrace, so it's wasted overhead.

2. Always raise a cached exception. This completely avoids all allocation costs for nonblocking operations that fail.

JRuby does #1 in JRuby 1.7 series, but does not do #2. I will work on a patch for MRI to do both #1 and #2.

The benefit of this change would be that nonblocking IO has zero wasted overhead. The down side would be that the exceptions raised do not have a useful backtrace unless debug or verbose.

If we did this change, we would not have to introduce a separate API for nonblocking IO that doesn't raise exceptions.

Thoughts?




-- 
http://bugs.ruby-lang.org/