summaryrefslogtreecommitdiff
path: root/vm_core.h
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2023-12-29 03:52:45 +0900
committerKoichi Sasada <ko1@atdot.net>2024-01-05 05:51:25 +0900
commitd65d2fb6b5c56c495f2f98f8e6ac5994ad5d93dd (patch)
tree3bf8410052a24b8da27cafe6f39ac13188a56ce1 /vm_core.h
parent6c252912af4981f016a9abdb4c1689307a4f1d2f (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.h1
1 files changed, 1 insertions, 0 deletions
diff --git a/vm_core.h b/vm_core.h
index ef770ab441..354603514e 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -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; /* $? */