diff options
author | Takashi Kokubun <[email protected]> | 2020-11-22 07:10:44 -0800 |
---|---|---|
committer | GitHub <[email protected]> | 2020-11-22 07:10:44 -0800 |
commit | fa1250a506e9b6a1bcbf664f6b7b9c06e045d9b9 (patch) | |
tree | 794ba06e9a6ddee9d7cf07e2759d189684657c33 /mjit_worker.c | |
parent | 175952bf0779f236be643880f8a04b9d46dcd083 (diff) |
Stop leaving .c files for JIT compaction in /tmp (#3802)
* Re-generate C files for JIT compaction every time
* Refactor in_jit return logic
* Just write code in a single file
* Add a TODO comment [ci skip]
Notes
Notes:
Merged-By: k0kubun <[email protected]>
Diffstat (limited to 'mjit_worker.c')
-rw-r--r-- | mjit_worker.c | 106 |
1 files changed, 52 insertions, 54 deletions
diff --git a/mjit_worker.c b/mjit_worker.c index d37613434e..2271bbe46d 100644 --- a/mjit_worker.c +++ b/mjit_worker.c @@ -153,14 +153,6 @@ struct rb_mjit_unit { // Dlopen handle of the loaded object file. void *handle; rb_iseq_t *iseq; -#if USE_JIT_COMPACTION - // This value is always set for `compact_all_jit_code`. Also used for lazy deletion. - char *c_file; - // true if it's inherited from parent Ruby process and lazy deletion should be skipped. - // `c_file = NULL` can't be used to skip lazy deletion because `c_file` could be used - // by child for `compact_all_jit_code`. - bool c_file_inherited_p; -#endif #if defined(_WIN32) // DLL cannot be removed while loaded on Windows. If this is set, it'll be lazily deleted. char *so_file; @@ -397,23 +389,10 @@ remove_file(const char *filename) } } -// Lazily delete .c and/or .so files. +// Lazily delete .so files. static void clean_temp_files(struct rb_mjit_unit *unit) { -#if USE_JIT_COMPACTION - if (unit->c_file) { - char *c_file = unit->c_file; - - unit->c_file = NULL; - // For compaction, unit->c_file is always set when compilation succeeds. - // So save_temps needs to be checked here. - if (!mjit_opts.save_temps && !unit->c_file_inherited_p) - remove_file(c_file); - free(c_file); - } -#endif - #if defined(_WIN32) if (unit->so_file) { char *so_file = unit->so_file; @@ -921,13 +900,57 @@ compile_compact_jit_code(char* c_file) compile_prelude(f); - struct rb_mjit_unit *cur = 0; - list_for_each(&active_units.head, cur, unode) { - fprintf(f, "#include \"%s\"\n", cur->c_file); + // wait until mjit_gc_exit_hook is called + CRITICAL_SECTION_START(3, "before mjit_compile to wait GC finish"); + while (in_gc) { + verbose(3, "Waiting wakeup from GC"); + rb_native_cond_wait(&mjit_gc_wakeup, &mjit_engine_mutex); + } + // We need to check again here because we could've waited on GC above + bool iseq_gced = false; + struct rb_mjit_unit *child_unit = 0; + list_for_each(&active_units.head, child_unit, unode) { + if (child_unit->iseq == NULL) iseq_gced = true; + } + in_jit = !iseq_gced; + CRITICAL_SECTION_FINISH(3, "before mjit_compile to wait GC finish"); + if (!in_jit) { + fclose(f); + if (!mjit_opts.save_temps) + remove_file(c_file); + return false; + } + + // This entire loop lock GC so that we do not need to consider a case that + // ISeq is GC-ed in a middle of re-compilation. It takes 3~4ms with 100 methods + // on my machine. It's not too bad compared to compilation time of C (7200~8000ms), + // but it might be larger if we use a larger --jit-max-cache. + // + // TODO: Consider using a more granular lock after we implement inlining across + // compacted functions (not done yet). + bool success = true; + list_for_each(&active_units.head, child_unit, unode) { + char funcname[MAXPATHLEN]; + sprint_funcname(funcname, child_unit); + + long iseq_lineno = 0; + if (FIXNUM_P(child_unit->iseq->body->location.first_lineno)) + // FIX2INT may fallback to rb_num2long(), which is a method call and dangerous in MJIT worker. So using only FIX2LONG. + iseq_lineno = FIX2LONG(child_unit->iseq->body->location.first_lineno); + fprintf(f, "\n/* %s@%s:%ld */\n", RSTRING_PTR(child_unit->iseq->body->location.label), + RSTRING_PTR(rb_iseq_path(child_unit->iseq)), iseq_lineno); + success &= mjit_compile(f, child_unit->iseq, funcname, child_unit->id); } + // release blocking mjit_gc_start_hook + CRITICAL_SECTION_START(3, "after mjit_compile to wakeup client for GC"); + in_jit = false; + verbose(3, "Sending wakeup signal to client in a mjit-worker for GC"); + rb_native_cond_signal(&mjit_client_wakeup); + CRITICAL_SECTION_FINISH(3, "in worker to wakeup client for GC"); + fclose(f); - return true; + return success; } // Compile all cached .c files and build a single .so file. Reload all JIT func from it. @@ -1046,10 +1069,6 @@ compile_prelude(FILE *f) const char *s = pch_file; const char *e = header_name_end(s); -# if USE_JIT_COMPACTION - fprintf(f, "#ifndef MJIT_PCH\n"); - fprintf(f, "#define MJIT_PCH\n"); -# endif fprintf(f, "#include \""); // print pch_file except .gch for gcc, but keep .pch for mswin for (; s < e; s++) { @@ -1060,9 +1079,6 @@ compile_prelude(FILE *f) fputc(*s, f); } fprintf(f, "\"\n"); -# if USE_JIT_COMPACTION - fprintf(f, "#endif\n"); -# endif #endif #ifdef _WIN32 @@ -1102,19 +1118,13 @@ convert_unit_to_func(struct rb_mjit_unit *unit) verbose(3, "Waiting wakeup from GC"); rb_native_cond_wait(&mjit_gc_wakeup, &mjit_engine_mutex); } - // We need to check again here because we could've waited on GC above - if (unit->iseq == NULL) { + in_jit = (unit->iseq != NULL); + CRITICAL_SECTION_FINISH(3, "before mjit_compile to wait GC finish"); + if (!in_jit) { fclose(f); if (!mjit_opts.save_temps) remove_file(c_file); - in_jit = false; // just being explicit for return - } - else { - in_jit = true; - } - CRITICAL_SECTION_FINISH(3, "before mjit_compile to wait GC finish"); - if (!in_jit) { return (mjit_func_t)NOT_COMPILED_JIT_ISEQ_FUNC; } @@ -1149,20 +1159,8 @@ convert_unit_to_func(struct rb_mjit_unit *unit) double start_time = real_ms_time(); success = compile_c_to_so(c_file, so_file); -#if USE_JIT_COMPACTION - if (success) { - // Always set c_file for compaction. The value is also used for lazy deletion. - unit->c_file = strdup(c_file); - if (unit->c_file == NULL) { - mjit_warning("failed to allocate memory to remember '%s' (%s), removing it...", c_file, strerror(errno)); - } - } - if (!mjit_opts.save_temps && unit->c_file == NULL) - remove_file(c_file); -#else if (!mjit_opts.save_temps) remove_file(c_file); -#endif double end_time = real_ms_time(); if (!success) { |