diff options
author | k0kubun <k0kubun@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2019-04-14 04:52:02 +0000 |
---|---|---|
committer | k0kubun <k0kubun@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2019-04-14 04:52:02 +0000 |
commit | 9b6b4674d77da2ef3f9f15095af9e39cc966b882 (patch) | |
tree | 526581a204348af1c910fd77638328a8cadc3a9b /mjit.c | |
parent | 088df9c8c26bcd7ad4de6637d9e734c26e7b72a0 (diff) | |
download | ruby-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.c | 58 |
1 files changed, 50 insertions, 8 deletions
@@ -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; |