dumping ground for random patches and texts
 help / color / mirror / Atom feed
From: Eric Wong <e@80x24.org>
To: spew@80x24.org
Subject: [PATCH 4/2] thread_pthread (native_sleep): perform GC if idle
Date: Sun, 29 Apr 2018 10:50:29 +0000	[thread overview]
Message-ID: <20180429105029.GA23412@dcvr> (raw)
In-Reply-To: <20180429035007.6499-1-e@80x24.org>

It still makes sense to perform GC while using native_sleep for
blocked Queue (or other operations with only "local"
dependencies).  This is because some GVL release operations
can still leave other threads sleeping, as in the example
below.

The following goes from to 90MB to roughly 41MB depending
on entropy:

  require 'thread'
  q = SizedQueue.new(128)
  nr = 100_000
  th = Thread.new do
    File.open('/dev/urandom') do |rd|
      nr.times do
        q.push(rd.read(16384))
      end
    end
  end
  nr.times { q.pop }
  th.join
---
 thread_pthread.c | 81 +++++++++++++++++++++++++++++++-----------------
 1 file changed, 53 insertions(+), 28 deletions(-)

diff --git a/thread_pthread.c b/thread_pthread.c
index fccac48a44..ccc2ccb52e 100644
--- a/thread_pthread.c
+++ b/thread_pthread.c
@@ -35,6 +35,7 @@
 #include <kernel/OS.h>
 #endif
 
+static int timespec_cmp(const struct timespec *a, const struct timespec *b);
 void rb_native_mutex_lock(rb_nativethread_lock_t *lock);
 void rb_native_mutex_unlock(rb_nativethread_lock_t *lock);
 static int native_mutex_trylock(rb_nativethread_lock_t *lock);
@@ -349,17 +350,23 @@ native_cond_timedwait(rb_nativethread_cond_t *cond, pthread_mutex_t *mutex, cons
     return r;
 }
 
-static struct timespec
-native_cond_timeout(rb_nativethread_cond_t *cond, struct timespec timeout_rel)
+static void
+condattr_now(struct timespec *ts)
 {
-    struct timespec abs;
-
     if (condattr_monotonic) {
-        getclockofday(&abs);
+        getclockofday(ts);
     }
     else {
-        rb_timespec_now(&abs);
+        rb_timespec_now(ts);
     }
+}
+
+static struct timespec
+native_cond_timeout(rb_nativethread_cond_t *cond, struct timespec timeout_rel)
+{
+    struct timespec abs;
+
+    condattr_now(&abs);
     timespec_add(&abs, &timeout_rel);
 
     return abs;
@@ -1026,12 +1033,23 @@ ubf_pthread_cond_signal(void *ptr)
     rb_native_cond_signal(&th->native_thread_data.sleep_cond);
 }
 
+static int
+cond_expired_p(const struct timespec *end)
+{
+    struct timespec now;
+
+    condattr_now(&now);
+    return timespec_cmp(&now, end) >= 0;
+}
+
 static void
 native_sleep(rb_thread_t *th, struct timespec *timeout_rel)
 {
     struct timespec timeout;
     rb_nativethread_lock_t *lock = &th->interrupt_lock;
     rb_nativethread_cond_t *cond = &th->native_thread_data.sleep_cond;
+    int intr;
+    int do_gc = 1;
 
     if (timeout_rel) {
 	/* Solaris cond_timedwait() return EINVAL if an argument is greater than
@@ -1050,28 +1068,35 @@ native_sleep(rb_thread_t *th, struct timespec *timeout_rel)
 	timeout = native_cond_timeout(cond, *timeout_rel);
     }
 
-    GVL_UNLOCK_BEGIN();
-    {
-        rb_native_mutex_lock(lock);
-	th->unblock.func = ubf_pthread_cond_signal;
-	th->unblock.arg = th;
-
-	if (RUBY_VM_INTERRUPTED(th->ec)) {
-	    /* interrupted.  return immediate */
-	    thread_debug("native_sleep: interrupted before sleep\n");
-	}
-	else {
-	    if (!timeout_rel)
-		rb_native_cond_wait(cond, lock);
-	    else
-		native_cond_timedwait(cond, lock, &timeout);
-	}
-	th->unblock.func = 0;
-	th->unblock.arg = 0;
-
-	rb_native_mutex_unlock(lock);
-    }
-    GVL_UNLOCK_END();
+    do {
+        if (!do_gc || gvl_contended_p(th->vm)) {
+            GVL_UNLOCK_BEGIN();
+            {
+                rb_native_mutex_lock(lock);
+                th->unblock.func = ubf_pthread_cond_signal;
+                th->unblock.arg = th;
+
+                if ((intr = RUBY_VM_INTERRUPTED(th->ec))) {
+                    /* interrupted.  return immediate */
+                    thread_debug("native_sleep: interrupted before sleep\n");
+                }
+                else {
+                    if (!timeout_rel)
+                        rb_native_cond_wait(cond, lock);
+                    else
+                        native_cond_timedwait(cond, lock, &timeout);
+                }
+                th->unblock.func = 0;
+                th->unblock.arg = 0;
+
+                rb_native_mutex_unlock(lock);
+            }
+            GVL_UNLOCK_END();
+        }
+        else if (!(intr = RUBY_VM_INTERRUPTED(th->ec))) {
+            do_gc = rb_gc_step(th->ec);
+        }
+    } while (!intr && (!timeout_rel || !cond_expired_p(&timeout)));
 
     thread_debug("native_sleep done\n");
 }
-- 
EW

  parent reply	other threads:[~2018-04-29 10:50 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-04-29  3:50 [WIP] sleepy GC Eric Wong
2018-04-29  3:50 ` [PATCH 1/2] thread.c (timeout_prepare): common function Eric Wong
2018-04-29  3:50 ` [PATCH 2/2] gc: rb_wait_for_single_fd performs GC if idle (Linux) Eric Wong
2018-04-29  9:02   ` [PATCH 3/2] thread.c (do_select): perform GC if idle Eric Wong
2018-04-29 10:50 ` Eric Wong [this message]
2018-05-01  1:31   ` [PATCH 4/2] thread_pthread (native_sleep): " Eric Wong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180429105029.GA23412@dcvr \
    --to=e@80x24.org \
    --cc=spew@80x24.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).