mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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]
This commit is contained in:
parent
175952bf07
commit
fa1250a506
Notes:
git
2020-11-23 00:11:22 +09:00
Merged-By: k0kubun <takashikkbn@gmail.com>
2 changed files with 52 additions and 58 deletions
4
mjit.c
4
mjit.c
|
@ -887,10 +887,6 @@ skip_cleaning_object_files(struct rb_mjit_unit_list *list)
|
|||
|
||||
// No mutex for list, assuming MJIT worker does not exist yet since it's immediately after fork.
|
||||
list_for_each_safe(&list->head, unit, next, unode) {
|
||||
#if USE_JIT_COMPACTION
|
||||
if (unit->c_file) unit->c_file_inherited_p = true;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) // mswin doesn't reach here either. This is for MinGW.
|
||||
if (unit->so_file) unit->so_file = NULL;
|
||||
#endif
|
||||
|
|
106
mjit_worker.c
106
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) {
|
||||
|
|
Loading…
Reference in a new issue