diff options
author | Koichi Sasada <[email protected]> | 2023-12-29 03:52:45 +0900 |
---|---|---|
committer | Koichi Sasada <[email protected]> | 2024-01-05 05:51:25 +0900 |
commit | d65d2fb6b5c56c495f2f98f8e6ac5994ad5d93dd (patch) | |
tree | 3bf8410052a24b8da27cafe6f39ac13188a56ce1 /vm_core.h | |
parent | 6c252912af4981f016a9abdb4c1689307a4f1d2f (diff) |
Do not `poll` first
Before this patch, the MN scheduler waits for the IO with the
following steps:
1. `poll(fd, timeout=0)` to check fd is ready or not.
2. if fd is not ready, waits with MN thread scheduler
3. 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:
1. call `func` to issue the blocking I/O call
2. 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.
```ruby
require 'benchmark'
f = open('/dev/null', 'w')
f.sync = true
TN = 1
N = 1_000_000 / TN
Benchmark.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
```
Diffstat (limited to 'vm_core.h')
-rw-r--r-- | vm_core.h | 1 |
1 files changed, 1 insertions, 0 deletions
@@ -1076,6 +1076,7 @@ typedef struct rb_thread_struct { rb_execution_context_t *ec; struct rb_thread_sched_item sched; + bool mn_schedulable; rb_atomic_t serial; // only for RUBY_DEBUG_LOG() VALUE last_status; /* $? */ |