[前][次][番号順一覧][スレッド一覧]

ruby-changes:72171

From: Takashi <ko1@a...>
Date: Thu, 16 Jun 2022 01:41:14 +0900 (JST)
Subject: [ruby-changes:72171] 1162523bae (master): Remove MJIT worker thread (#6006)

https://git.ruby-lang.org/ruby.git/commit/?id=1162523bae

From 1162523bae926cfa6128043b635e28c14b732754 Mon Sep 17 00:00:00 2001
From: Takashi Kokubun <takashikkbn@g...>
Date: Wed, 15 Jun 2022 09:40:54 -0700
Subject: Remove MJIT worker thread (#6006)

[Misc #18830]
---
 common.mk                     |   5 +
 gc.c                          |   3 -
 mjit.c                        | 316 +++++++++++++++++++---------------
 mjit.h                        |   5 +-
 mjit_worker.c                 | 382 +++++++++++++-----------------------------
 process.c                     |  84 +++-------
 test/ruby/test_rubyvm_mjit.rb |   6 +-
 thread.c                      |  15 ++
 8 files changed, 351 insertions(+), 465 deletions(-)

diff --git a/common.mk b/common.mk
index db4a283602..56139211de 100644
--- a/common.mk
+++ b/common.mk
@@ -9657,6 +9657,8 @@ mjit.$(OBJEXT): {$(VPATH)}mjit_worker.c https://github.com/ruby/ruby/blob/trunk/common.mk#L9657
 mjit.$(OBJEXT): {$(VPATH)}node.h
 mjit.$(OBJEXT): {$(VPATH)}onigmo.h
 mjit.$(OBJEXT): {$(VPATH)}oniguruma.h
+mjit.$(OBJEXT): {$(VPATH)}ractor.h
+mjit.$(OBJEXT): {$(VPATH)}ractor_core.h
 mjit.$(OBJEXT): {$(VPATH)}ruby_assert.h
 mjit.$(OBJEXT): {$(VPATH)}ruby_atomic.h
 mjit.$(OBJEXT): {$(VPATH)}st.h
@@ -13800,6 +13802,7 @@ signal.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h https://github.com/ruby/ruby/blob/trunk/common.mk#L13802
 signal.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
 signal.$(OBJEXT): $(CCAN_DIR)/list/list.h
 signal.$(OBJEXT): $(CCAN_DIR)/str/str.h
+signal.$(OBJEXT): $(hdrdir)/ruby.h
 signal.$(OBJEXT): $(hdrdir)/ruby/ruby.h
 signal.$(OBJEXT): $(top_srcdir)/internal/array.h
 signal.$(OBJEXT): $(top_srcdir)/internal/compilers.h
@@ -13985,6 +13988,7 @@ signal.$(OBJEXT): {$(VPATH)}internal/warning_push.h https://github.com/ruby/ruby/blob/trunk/common.mk#L13988
 signal.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
 signal.$(OBJEXT): {$(VPATH)}method.h
 signal.$(OBJEXT): {$(VPATH)}missing.h
+signal.$(OBJEXT): {$(VPATH)}mjit.h
 signal.$(OBJEXT): {$(VPATH)}node.h
 signal.$(OBJEXT): {$(VPATH)}onigmo.h
 signal.$(OBJEXT): {$(VPATH)}oniguruma.h
@@ -14000,6 +14004,7 @@ signal.$(OBJEXT): {$(VPATH)}thread_native.h https://github.com/ruby/ruby/blob/trunk/common.mk#L14004
 signal.$(OBJEXT): {$(VPATH)}vm_core.h
 signal.$(OBJEXT): {$(VPATH)}vm_debug.h
 signal.$(OBJEXT): {$(VPATH)}vm_opts.h
+signal.$(OBJEXT): {$(VPATH)}yjit.h
 sprintf.$(OBJEXT): $(hdrdir)/ruby/ruby.h
 sprintf.$(OBJEXT): $(top_srcdir)/internal/bignum.h
 sprintf.$(OBJEXT): $(top_srcdir)/internal/bits.h
diff --git a/gc.c b/gc.c
index b3b44e87a1..106f7bb2b3 100644
--- a/gc.c
+++ b/gc.c
@@ -9497,8 +9497,6 @@ gc_enter(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_ https://github.com/ruby/ruby/blob/trunk/gc.c#L9497
     if (UNLIKELY(during_gc != 0)) rb_bug("during_gc != 0");
     if (RGENGC_CHECK_MODE >= 3) gc_verify_internal_consistency(objspace);
 
-    mjit_gc_start_hook();
-
     during_gc = TRUE;
     RUBY_DEBUG_LOG("%s (%s)",gc_enter_event_cstr(event), gc_current_status(objspace));
     gc_report(1, objspace, "gc_enter: %s [%s]\n", gc_enter_event_cstr(event), gc_current_status(objspace));
@@ -9517,7 +9515,6 @@ gc_exit(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_l https://github.com/ruby/ruby/blob/trunk/gc.c#L9515
     gc_report(1, objspace, "gc_exit: %s [%s]\n", gc_enter_event_cstr(event), gc_current_status(objspace));
     during_gc = FALSE;
 
-    mjit_gc_exit_hook();
     gc_exit_clock(objspace, event);
     RB_VM_LOCK_LEAVE_LEV(lock_lev);
 
diff --git a/mjit.c b/mjit.c
index b36331e72e..93e3d823e4 100644
--- a/mjit.c
+++ b/mjit.c
@@ -25,6 +25,7 @@ https://github.com/ruby/ruby/blob/trunk/mjit.c#L25
 #include "internal/hash.h"
 #include "internal/warnings.h"
 #include "vm_sync.h"
+#include "ractor_core.h"
 
 #include "mjit_worker.c"
 
@@ -50,40 +51,6 @@ get_uniq_filename(unsigned long id, const char *prefix, const char *suffix) https://github.com/ruby/ruby/blob/trunk/mjit.c#L51
     return str;
 }
 
-// Wait until workers don't compile any iseq.  It is called at the
-// start of GC.
-void
-mjit_gc_start_hook(void)
-{
-    if (!mjit_enabled)
-        return;
-    CRITICAL_SECTION_START(4, "mjit_gc_start_hook");
-    while (in_jit) {
-        verbose(4, "Waiting wakeup from a worker for GC");
-        rb_native_cond_wait(&mjit_client_wakeup, &mjit_engine_mutex);
-        verbose(4, "Getting wakeup from a worker for GC");
-    }
-    in_gc++;
-    CRITICAL_SECTION_FINISH(4, "mjit_gc_start_hook");
-}
-
-// Send a signal to workers to continue iseq compilations.  It is
-// called at the end of GC.
-void
-mjit_gc_exit_hook(void)
-{
-    if (!mjit_enabled)
-        return;
-    CRITICAL_SECTION_START(4, "mjit_gc_exit_hook");
-    in_gc--;
-    RUBY_ASSERT_ALWAYS(in_gc >= 0);
-    if (!in_gc) {
-        verbose(4, "Sending wakeup signal to workers after GC");
-        rb_native_cond_broadcast(&mjit_gc_wakeup);
-    }
-    CRITICAL_SECTION_FINISH(4, "mjit_gc_exit_hook");
-}
-
 // Prohibit calling JIT-ed code and let existing JIT-ed frames exit before the next insn.
 void
 mjit_cancel_all(const char *reason)
@@ -133,9 +100,6 @@ mjit_free_iseq(const rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/mjit.c#L100
     if (!mjit_enabled)
         return;
 
-    CRITICAL_SECTION_START(4, "mjit_free_iseq");
-    RUBY_ASSERT_ALWAYS(in_gc);
-    RUBY_ASSERT_ALWAYS(!in_jit);
     if (ISEQ_BODY(iseq)->jit_unit) {
         // jit_unit is not freed here because it may be referred by multiple
         // lists of units. `get_from_list` and `mjit_finish` do the job.
@@ -150,7 +114,6 @@ mjit_free_iseq(const rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/mjit.c#L114
             unit->iseq = NULL;
         }
     }
-    CRITICAL_SECTION_FINISH(4, "mjit_free_iseq");
 }
 
 // Free unit list. This should be called only when worker is finished
@@ -245,19 +208,169 @@ finish_conts(void) https://github.com/ruby/ruby/blob/trunk/mjit.c#L208
     }
 }
 
-// Create unit for `iseq`. This function may be called from an MJIT worker.
+static void mjit_wait(struct rb_iseq_constant_body *body);
+
+// Check the unit queue and start mjit_compile if nothing is in progress.
 static void
-create_unit(const rb_iseq_t *iseq)
+check_unit_queue(void)
 {
-    struct rb_mjit_unit *unit;
+    if (worker_stopped) return;
+    if (current_cc_pid != 0) return; // still compiling
+
+    // Run unload_units after it's requested `max_cache_size / 10` (default: 10) times.
+    // This throttles the call to mitigate locking in unload_units. It also throttles JIT compaction.
+    int throttle_threshold = mjit_opts.max_cache_size / 10;
+    if (unload_requests >= throttle_threshold) {
+        unload_units();
+        unload_requests = 0;
+        if (active_units.length == mjit_opts.max_cache_size && mjit_opts.wait) { // Sometimes all methods may be in use
+            mjit_opts.max_cache_size++; // avoid infinite loop on `rb_mjit_wait_call`. Note that --jit-wait is just for testing.
+            verbose(1, "No units can be unloaded -- incremented max-cache-size to %d for --jit-wait", mjit_opts.max_cache_size);
+        }
+    }
+    if (active_units.length >= mjit_opts.max_cache_size) return; // wait until unload_units makes a progress
 
-    unit = calloc(1, sizeof(struct rb_mjit_unit));
+    // Dequeue a unit
+    struct rb_mjit_unit *unit = get_from_list(&unit_queue);
+    if (unit == NULL) return;
+
+#ifdef _WIN32
+    // Synchronously compile methods on Windows.
+    // mswin: No SIGCHLD, MinGW: directly compiling .c to .so doesn't work
+    mjit_func_t func = convert_unit_to_func(unit);
+    if ((uintptr_t)func > (uintptr_t)LAST_JIT_ISEQ_FUNC) {
+        add_to_list(unit, &active_units);
+        MJIT_ATOMIC_SET(ISEQ_BODY(unit->iseq)->jit_func, func);
+    }
+#else
+    current_cc_ms = real_ms_time();
+    current_cc_unit = unit;
+    current_cc_pid = start_mjit_compile(unit);
+    // TODO: handle -1
+    if (mjit_opts.wait) {
+        mjit_wait(unit->iseq->body);
+    }
+#endif
+}
+
+// Create unit for `iseq`. This function may be called from an MJIT worker.
+static struct rb_mjit_unit*
+create_unit(const rb_iseq_t *iseq)
+{
+    // To prevent GC, don't use ZALLOC // TODO: just use ZALLOC
+    struct rb_mjit_unit *unit = calloc(1, sizeof(struct rb_mjit_unit));
     if (unit == NULL)
-        return;
+        return NULL;
 
     unit->id = current_unit_num++;
-    unit->iseq = (rb_iseq_t *)iseq;
-    ISEQ_BODY(iseq)->jit_unit = unit;
+    if (iseq == NULL) { // Compact unit
+        unit->compact_p = true;
+    } else { // Normal unit
+        unit->iseq = (rb_iseq_t *)iseq;
+        ISEQ_BODY(iseq)->jit_unit = unit;
+    }
+    return unit;
+}
+
+// Check if it should compact all JIT code and start it as needed
+static void
+check_compaction(void)
+{
+#if USE_JIT_COMPACTION
+    // Allow only `max_cache_size / 100` times (default: 100) of compaction.
+    // Note: GC of compacted code has not been implemented yet.
+    int max_compact_size = mjit_opts.max_cache_size / 100;
+    if (max_compact_size < 10) max_compact_size = 10;
+
+    // Run unload_units after it's requested `max_cache_size / 10` (default: 10) times.
+    // This throttles the call to mitigate locking in unload_units. It also throttles JIT compaction.
+    int throttle_threshold = mjit_opts.max_cache_size / 10;
+
+    if (compact_units.length < max_compact_size
+        && ((!mjit_opts.wait && unit_queue.length == 0 && active_units.length > 1)
+            || (active_units.length == mjit_opts.max_cache_size && compact_units.length * throttle_threshold <= total_unloads))) { // throttle compaction by total_unloads
+        struct rb_mjit_unit *unit = create_unit(NULL);
+        if (unit != NULL) {
+            // TODO: assert unit is null
+            current_cc_ms = real_ms_time();
+            current_cc_unit = unit;
+            current_cc_pid = start_mjit_compact(unit);
+            // TODO: check -1
+        }
+    }
+#endif
+}
+
+// Check the current CC process if any, and start a next C c (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]