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

ruby-changes:72556

From: Takashi <ko1@a...>
Date: Fri, 15 Jul 2022 12:35:14 +0900 (JST)
Subject: [ruby-changes:72556] 439d31bc77 (master): MJIT: Merge mjit_worker.c back to mjit.c (#6138)

https://git.ruby-lang.org/ruby.git/commit/?id=439d31bc77

From 439d31bc777a6f9c9354dbe9a82495a9b4fa04ae Mon Sep 17 00:00:00 2001
From: Takashi Kokubun <takashikkbn@g...>
Date: Thu, 14 Jul 2022 20:34:46 -0700
Subject: MJIT: Merge mjit_worker.c back to mjit.c (#6138)

Since #6006, we no longer avoid executing GC on mjit_worker.c and thus
there's no need to carefully change how we write code whether you're in
mjit.c or mjit_worker.c anymore.
---
 common.mk              |    1 -
 mjit.c                 | 1269 ++++++++++++++++++++++++++++++++++++++++++++++-
 mjit_worker.c          | 1290 ------------------------------------------------
 test/ruby/test_mjit.rb |    2 +-
 4 files changed, 1265 insertions(+), 1297 deletions(-)
 delete mode 100644 mjit_worker.c

diff --git a/common.mk b/common.mk
index fa6a6e9faf..d99d52f357 100644
--- a/common.mk
+++ b/common.mk
@@ -9658,7 +9658,6 @@ mjit.$(OBJEXT): {$(VPATH)}mjit.h https://github.com/ruby/ruby/blob/trunk/common.mk#L9658
 mjit.$(OBJEXT): {$(VPATH)}mjit.rb
 mjit.$(OBJEXT): {$(VPATH)}mjit.rbinc
 mjit.$(OBJEXT): {$(VPATH)}mjit_config.h
-mjit.$(OBJEXT): {$(VPATH)}mjit_worker.c
 mjit.$(OBJEXT): {$(VPATH)}node.h
 mjit.$(OBJEXT): {$(VPATH)}onigmo.h
 mjit.$(OBJEXT): {$(VPATH)}oniguruma.h
diff --git a/mjit.c b/mjit.c
index a5c89a1ced..b52c5fad9f 100644
--- a/mjit.c
+++ b/mjit.c
@@ -6,10 +6,63 @@ https://github.com/ruby/ruby/blob/trunk/mjit.c#L6
 
 **********************************************************************/
 
-// Functions in this file are never executed on MJIT worker thread.
-// So you can safely use Ruby methods and GC in this file.
-
-// To share variables privately, include mjit_worker.c instead of linking.
+/* We utilize widely used C compilers (GCC and LLVM Clang) to
+   implement MJIT.  We feed them a C code generated from ISEQ.  The
+   industrial C compilers are slower than regular JIT engines.
+   Generated code performance of the used C compilers has a higher
+   priority over the compilation speed.
+
+   So our major goal is to minimize the ISEQ compilation time when we
+   use widely optimization level (-O2).  It is achieved by
+
+   o Using a precompiled version of the header
+   o Keeping all files in `/tmp`.  On modern Linux `/tmp` is a file
+     system in memory. So it is pretty fast
+   o Implementing MJIT as a multi-threaded code because we want to
+     compile ISEQs in parallel with iseq execution to speed up Ruby
+     code execution.  MJIT has one thread (*worker*) to do
+     parallel compilations:
+      o It prepares a precompiled code of the minimized header.
+        It starts at the MRI execution start
+      o It generates PIC object files of ISEQs
+      o It takes one JIT unit from a priority queue unless it is empty.
+      o It translates the JIT unit ISEQ into C-code using the precompiled
+        header, calls CC and load PIC code when it is ready
+      o Currently MJIT put ISEQ in the queue when ISEQ is called
+      o MJIT can reorder ISEQs in the queue if some ISEQ has been called
+        many times and its compilation did not start yet
+      o MRI reuses the machine code if it already exists for ISEQ
+      o The machine code we generate can stop and switch to the ISEQ
+        interpretation if some condition is not satisfied as the machine
+        code can be speculative or some exception raises
+      o Speculative machine code can be canceled.
+
+   Here is a diagram showing the MJIT organization:
+
+                 _______
+                |header |
+                |_______|
+                    |                         MRI building
+      --------------|----------------------------------------
+                    |                         MRI execution
+                    |
+       _____________|_____
+      |             |     |
+      |          ___V__   |  CC      ____________________
+      |         |      |----------->| precompiled header |
+      |         |      |  |         |____________________|
+      |         |      |  |              |
+      |         | MJIT |  |              |
+      |         |      |  |              |
+      |         |      |  |          ____V___  CC  __________
+      |         |______|----------->| C code |--->| .so file |
+      |                   |         |________|    |__________|
+      |                   |                              |
+      |                   |                              |
+      | MRI machine code  |<-----------------------------
+      |___________________|             loading
+
+*/
 
 #include "ruby/internal/config.h" // defines USE_MJIT
 
@@ -27,7 +80,1213 @@ https://github.com/ruby/ruby/blob/trunk/mjit.c#L80
 #include "vm_sync.h"
 #include "ractor_core.h"
 
-#include "mjit_worker.c"
+#ifdef __sun
+#define __EXTENSIONS__ 1
+#endif
+
+#include "vm_core.h"
+#include "vm_callinfo.h"
+#include "mjit.h"
+#include "gc.h"
+#include "ruby_assert.h"
+#include "ruby/debug.h"
+#include "ruby/thread.h"
+#include "ruby/version.h"
+#include "builtin.h"
+#include "insns.inc"
+#include "insns_info.inc"
+#include "internal/compile.h"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#else
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <dlfcn.h>
+#endif
+#include <errno.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+#include "dln.h"
+
+#include "ruby/util.h"
+#undef strdup // ruby_strdup may trigger GC
+
+#ifndef MAXPATHLEN
+# define MAXPATHLEN 1024
+#endif
+
+#ifdef _WIN32
+#define dlopen(name,flag) ((void*)LoadLibrary(name))
+#define dlerror() strerror(rb_w32_map_errno(GetLastError()))
+#define dlsym(handle,name) ((void*)GetProcAddress((handle),(name)))
+#define dlclose(handle) (!FreeLibrary(handle))
+#define RTLD_NOW  -1
+
+#define waitpid(pid,stat_loc,options) (WaitForSingleObject((HANDLE)(pid), INFINITE), GetExitCodeProcess((HANDLE)(pid), (LPDWORD)(stat_loc)), CloseHandle((HANDLE)pid), (pid))
+#define WIFEXITED(S) ((S) != STILL_ACTIVE)
+#define WEXITSTATUS(S) (S)
+#define WIFSIGNALED(S) (0)
+typedef intptr_t pid_t;
+#endif
+
+// Atomically set function pointer if possible.
+#define MJIT_ATOMIC_SET(var, val) (void)ATOMIC_PTR_EXCHANGE(var, val)
+
+#define MJIT_TMP_PREFIX "_ruby_mjit_"
+
+// JIT compaction requires the header transformation because linking multiple .o files
+// doesn't work without having `static` in the same function definitions. We currently
+// don't support transforming the MJIT header on Windows.
+#ifdef _WIN32
+# define USE_JIT_COMPACTION 0
+#else
+# define USE_JIT_COMPACTION 1
+#endif
+
+// The unit structure that holds metadata of ISeq for MJIT.
+struct rb_mjit_unit {
+    struct ccan_list_node unode;
+    // Unique order number of unit.
+    int id;
+    // Dlopen handle of the loaded object file.
+    void *handle;
+    rb_iseq_t *iseq;
+#if defined(_WIN32)
+    // DLL cannot be removed while loaded on Windows. If this is set, it'll be lazily deleted.
+    char *so_file;
+#endif
+    // Only used by unload_units. Flag to check this unit is currently on stack or not.
+    bool used_code_p;
+    // True if it's a unit for JIT compaction
+    bool compact_p;
+    // mjit_compile's optimization switches
+    struct rb_mjit_compile_info compile_info;
+    // captured CC values, they should be marked with iseq.
+    const struct rb_callcache **cc_entries;
+    unsigned int cc_entries_size; // ISEQ_BODY(iseq)->ci_size + ones of inlined iseqs
+};
+
+// Linked list of struct rb_mjit_unit.
+struct rb_mjit_unit_list {
+    struct ccan_list_head head;
+    int length; // the list length
+};
+
+extern void rb_native_mutex_lock(rb_nativethread_lock_t *lock);
+extern void rb_native_mutex_unlock(rb_nativethread_lock_t *lock);
+extern void rb_native_mutex_initialize(rb_nativethread_lock_t *lock);
+extern void rb_native_mutex_destroy(rb_nativethread_lock_t *lock);
+
+extern void rb_native_cond_initialize(rb_nativethread_cond_t *cond);
+extern void rb_native_cond_destroy(rb_nativethread_cond_t *cond);
+extern void rb_native_cond_signal(rb_nativethread_cond_t *cond);
+extern void rb_native_cond_broadcast(rb_nativethread_cond_t *cond);
+extern void rb_native_cond_wait(rb_nativethread_cond_t *cond, rb_nativethread_lock_t *mutex);
+
+// process.c
+extern void mjit_add_waiting_pid(rb_vm_t *vm, rb_pid_t pid);
+
+// A copy of MJIT portion of MRI options since MJIT initialization.  We
+// need them as MJIT threads still can work when the most MRI data were
+// freed.
+struct mjit_options mjit_opts;
+
+// true if MJIT is enabled.
+bool mjit_enabled = false;
+// true if JIT-ed code should be called. When `ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS`
+// and `mjit_call_p == false`, any JIT-ed code execution is cancelled as soon as possible.
+bool mjit_call_p = false;
+
+// Priority queue of iseqs waiting for JIT compilation.
+// This variable is a pointer to head unit of the queue.
+static struct rb_mjit_unit_list unit_queue = { CCAN_LIST_HEAD_INIT(unit_queue.head) };
+// List of units which are successfully compiled.
+static struct rb_mjit_unit_list active_units = { CCAN_LIST_HEAD_INIT(active_units.head) };
+// List of compacted so files which will be cleaned up by `free_list()` in `mjit_finish()`.
+static struct rb_mjit_unit_list compact_units = { CCAN_LIST_HEAD_INIT(compact_units.head) };
+// List of units before recompilation and just waiting for dlclose().
+static struct rb_mjit_unit_list stale_units = { CCAN_LIST_HEAD_INIT(stale_units.head) };
+// The number of so far processed ISEQs, used to generate unique id.
+static int current_unit_num;
+// A mutex for conitionals and critical sections.
+static rb_nativethread_lock_t mjit_engine_mutex;
+// A thread conditional to wake up `mjit_finish` at the end of PCH thread.
+static rb_nativethread_cond_t mjit_pch_wakeup;
+// A thread conditional to wake up the client if there is a change in
+// executed unit status.
+static rb_nativethread_cond_t mjit_client_wakeup;
+// A thread conditional to wake up a worker if there we have something
+// to add or we need to stop  (... truncated)

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

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