From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-3.9 required=3.0 tests=ALL_TRUSTED,BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS shortcircuit=no autolearn=no autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 85E4C20A1E; Thu, 13 Dec 2018 06:41:45 +0000 (UTC) From: Eric Wong To: spew@80x24.org Cc: Eric Wong Subject: [PATCH] thread_pthread.c (native_sleep): sched_yield if GVL uncontended Date: Thu, 13 Dec 2018 06:41:44 +0000 Message-Id: <20181213064144.84663-1-e@80x24.org> List-Id: [ruby-core:90417] [Bug #15398] --- thread_pthread.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/thread_pthread.c b/thread_pthread.c index c87e952750..482de64d16 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -2015,6 +2015,22 @@ ubf_ppoll_sleep(void *ignore) rb_thread_wakeup_timer_thread_fd(signal_self_pipe.ub_main[1]); } +/* + * Single CPU setups benefit from explicit sched_yield() before ppoll() + * Not sure why, but confirmed on FreeBSD 11.2 and Linux 4.19.8. + * [ruby-core:90417] [Bug #15398] + */ +#define GVL_UNLOCK_BEGIN_YIELD(th) do { \ + const native_thread_data_t *next; \ + rb_vm_t *vm = th->vm; \ + RB_GC_SAVE_MACHINE_CONTEXT(th); \ + rb_native_mutex_lock(&vm->gvl.lock); \ + next = gvl_release_common(vm); \ + rb_native_mutex_unlock(&vm->gvl.lock); \ + if (!next && vm_living_thread_num(vm) > 1) { \ + native_thread_yield(); \ + } + /* * This function does not exclusively acquire sigwait_fd, so it * cannot safely read from it. However, it can be woken up in @@ -2032,7 +2048,8 @@ native_ppoll_sleep(rb_thread_t *th, rb_hrtime_t *rel) th->unblock.func = ubf_ppoll_sleep; rb_native_mutex_unlock(&th->interrupt_lock); - GVL_UNLOCK_BEGIN(th); + GVL_UNLOCK_BEGIN_YIELD(th); + if (!RUBY_VM_INTERRUPTED(th->ec)) { struct pollfd pfd[2]; struct timespec ts; @@ -2066,7 +2083,7 @@ native_sleep(rb_thread_t *th, rb_hrtime_t *rel) th->unblock.func = ubf_sigwait; rb_native_mutex_unlock(&th->interrupt_lock); - GVL_UNLOCK_BEGIN(th); + GVL_UNLOCK_BEGIN_YIELD(th); if (!RUBY_VM_INTERRUPTED(th->ec)) { rb_sigwait_sleep(th, sigwait_fd, rel); -- EW