aboutsummaryrefslogtreecommitdiffstats
path: root/mjit.c
diff options
context:
space:
mode:
authork0kubun <k0kubun@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2019-04-14 04:52:02 +0000
committerk0kubun <k0kubun@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2019-04-14 04:52:02 +0000
commit9b6b4674d77da2ef3f9f15095af9e39cc966b882 (patch)
tree526581a204348af1c910fd77638328a8cadc3a9b /mjit.c
parent088df9c8c26bcd7ad4de6637d9e734c26e7b72a0 (diff)
downloadruby-9b6b4674d77da2ef3f9f15095af9e39cc966b882.tar.gz
Recompile JIT-ed code without optimization
based on inline cache when JIT cancel happens by that. This feature was in the original MJIT implementation by Vladimir, but on merging MJIT to Ruby it was removed for simplification. This commit adds the functionality again for the following benchmark: https://github.com/benchmark-driver/misc/blob/52f05781f65467baf895bf6ba79d172c9b0826fd/concurrent-map/bench.rb (shown float is duration seconds. shorter is better) * Before ``` $ INHERIT=0 ruby -v bench.rb ruby 2.7.0dev (2019-04-13 trunk 67523) [x86_64-linux] -- 1.6507579649914987 $ INHERIT=0 ruby -v --jit bench.rb ruby 2.7.0dev (2019-04-13 trunk 67523) +JIT [x86_64-linux] -- 1.5091587850474752 $ INHERIT=1 ruby -v bench.rb ruby 2.7.0dev (2019-04-13 trunk 67523) [x86_64-linux] -- 1.6124781150138006 $ INHERIT=1 ruby --jit -v bench.rb ruby 2.7.0dev (2019-04-13 trunk 67523) +JIT [x86_64-linux] -- 1.7495657080435194 # <-- this ``` * After ``` $ INHERIT=0 ruby -v bench.rb ruby 2.7.0dev (2019-04-13 trunk 67523) [x86_64-linux] last_commit=Recompile JIT-ed code without optimization -- 1.653559010999743 $ INHERIT=0 ruby --jit -v bench.rb ruby 2.7.0dev (2019-04-13 trunk 67523) +JIT [x86_64-linux] last_commit=Recompile JIT-ed code without optimization -- 1.4738391840364784 $ INHERIT=1 ruby -v bench.rb ruby 2.7.0dev (2019-04-13 trunk 67523) [x86_64-linux] last_commit=Recompile JIT-ed code without optimization -- 1.645227018976584 $ INHERIT=1 ruby --jit -v bench.rb ruby 2.7.0dev (2019-04-13 trunk 67523) +JIT [x86_64-linux] last_commit=Recompile JIT-ed code without optimization -- 1.523708809982054 # <-- this ``` git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67530 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'mjit.c')
-rw-r--r--mjit.c58
1 files changed, 50 insertions, 8 deletions
diff --git a/mjit.c b/mjit.c
index a1c8f238c2..d025ba1643 100644
--- a/mjit.c
+++ b/mjit.c
@@ -299,16 +299,16 @@ unload_units(void)
verbose(1, "Too many JIT code -- %d units unloaded", units_num - active_units.length);
}
-/* Add ISEQ to be JITed in parallel with the current thread.
- Unload some JIT codes if there are too many of them. */
-void
-mjit_add_iseq_to_process(const rb_iseq_t *iseq)
+static void
+mjit_add_iseq_to_process(const rb_iseq_t *iseq, const struct rb_mjit_compile_info *compile_info)
{
if (!mjit_enabled || pch_status == PCH_FAILED)
return;
iseq->body->jit_func = (mjit_func_t)NOT_READY_JIT_ISEQ_FUNC;
create_unit(iseq);
+ if (compile_info != NULL)
+ iseq->body->jit_unit->compile_info = *compile_info;
if (iseq->body->jit_unit == NULL)
/* Failure in creating the unit. */
return;
@@ -323,13 +323,19 @@ mjit_add_iseq_to_process(const rb_iseq_t *iseq)
CRITICAL_SECTION_FINISH(3, "in add_iseq_to_process");
}
+/* Add ISEQ to be JITed in parallel with the current thread.
+ Unload some JIT codes if there are too many of them. */
+void
+rb_mjit_add_iseq_to_process(const rb_iseq_t *iseq)
+{
+ mjit_add_iseq_to_process(iseq, NULL);
+}
+
/* For this timeout seconds, --jit-wait will wait for JIT compilation finish. */
#define MJIT_WAIT_TIMEOUT_SECONDS 60
-/* Wait for JIT compilation finish for --jit-wait, and call the function pointer
- if the compiled result is not NOT_COMPILED_JIT_ISEQ_FUNC. */
-VALUE
-mjit_wait_call(rb_execution_context_t *ec, struct rb_iseq_constant_body *body)
+static void
+mjit_wait(struct rb_iseq_constant_body *body)
{
struct timeval tv;
int tries = 0;
@@ -350,13 +356,48 @@ mjit_wait_call(rb_execution_context_t *ec, struct rb_iseq_constant_body *body)
CRITICAL_SECTION_FINISH(3, "in mjit_wait_call for a client wakeup");
rb_thread_wait_for(tv);
}
+}
+/* Wait for JIT compilation finish for --jit-wait, and call the function pointer
+ if the compiled result is not NOT_COMPILED_JIT_ISEQ_FUNC. */
+VALUE
+mjit_wait_call(rb_execution_context_t *ec, struct rb_iseq_constant_body *body)
+{
+ mjit_wait(body);
if ((uintptr_t)body->jit_func <= (uintptr_t)LAST_JIT_ISEQ_FUNC) {
return Qundef;
}
return body->jit_func(ec, ec->cfp);
}
+struct rb_mjit_compile_info*
+rb_mjit_iseq_compile_info(const struct rb_iseq_constant_body *body)
+{
+ assert(body->jit_unit != NULL);
+ return &body->jit_unit->compile_info;
+}
+
+void
+rb_mjit_recompile_iseq(const rb_iseq_t *iseq)
+{
+ if ((ptrdiff_t)iseq->body->jit_func <= (ptrdiff_t)LAST_JIT_ISEQ_FUNC)
+ return;
+
+ verbose(1, "JIT recompile: %s@%s:%d", RSTRING_PTR(iseq->body->location.label),
+ RSTRING_PTR(rb_iseq_path(iseq)), FIX2INT(iseq->body->location.first_lineno));
+
+ CRITICAL_SECTION_START(3, "in rb_mjit_recompile_iseq");
+ remove_from_list(iseq->body->jit_unit, &active_units);
+ iseq->body->jit_func = (void *)NOT_ADDED_JIT_ISEQ_FUNC;
+ add_to_list(iseq->body->jit_unit, &stale_units);
+ CRITICAL_SECTION_FINISH(3, "in rb_mjit_recompile_iseq");
+
+ mjit_add_iseq_to_process(iseq, &iseq->body->jit_unit->compile_info);
+ if (UNLIKELY(mjit_opts.wait)) {
+ mjit_wait(iseq->body);
+ }
+}
+
extern VALUE ruby_archlibdir_path, ruby_prefix_path;
// Initialize header_file, pch_file, libruby_pathflag. Return true on success.
@@ -818,6 +859,7 @@ mjit_finish(bool close_handle_p)
free_list(&unit_queue, close_handle_p);
free_list(&active_units, close_handle_p);
free_list(&compact_units, close_handle_p);
+ free_list(&stale_units, close_handle_p);
finish_conts();
mjit_enabled = false;