Before this patch, the MN scheduler waits for the IO with the following steps:
poll(fd, timeout=0) to check fd is ready or not.
if fd is not ready, waits with MN thread scheduler
call func to issue the blocking I/O call
The advantage of advanced poll() is we can wait for the IO ready for any fds. However poll() becomes overhead for already ready fds.
This patch changes the steps like:
call func to issue the blocking I/O call
if the func returns EWOULDBLOCK the fd is O_NONBLOCK and we need to wait for fd is ready so that waits with MN thread scheduler.
In this case, we can wait only for O_NONBLOCK fds. Otherwise it waits with blocking operations such as read() system call. However we don't need to call poll() to check fd is ready in advance.
With this patch we can observe performance improvement on microbenchmark which repeats blocking I/O (not O_NONBLOCK fd) with and without MN thread scheduler.
require'benchmark'f=open('/dev/null','w')f.sync=trueTN=1N=1_000_000/TNBenchmark.bm{|x|x.report{TN.times.map{Thread.new{N.times{f.print'.'}}}.each(&:join)}}__END__ TN = 1 user system total real ruby32 0.393966 0.101122 0.495088 ( 0.495235) ruby33 0.493963 0.089521 0.583484 ( 0.584091) ruby33+MN 0.639333 0.200843 0.840176 ( 0.840291) <- Slow this+MN 0.512231 0.099091 0.611322 ( 0.611074) <- Good
Do not
pollfirstBefore this patch, the MN scheduler waits for the IO with the
following steps:
poll(fd, timeout=0)to check fd is ready or not.functo issue the blocking I/O callThe advantage of advanced
poll()is we can wait for theIO ready for any fds. However
poll()becomes overheadfor already ready fds.
This patch changes the steps like:
functo issue the blocking I/O callfuncreturnsEWOULDBLOCKthe fd isO_NONBLOCKand we need to wait for fd is ready so that waits with MN
thread scheduler.
In this case, we can wait only for
O_NONBLOCKfds. Otherwiseit waits with blocking operations such as
read()system call.However we don't need to call
poll()to check fd is readyin advance.
With this patch we can observe performance improvement
on microbenchmark which repeats blocking I/O (not
O_NONBLOCKfd) with and without MN thread scheduler.