1
0
Fork 0
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:
Takashi Kokubun 2020-11-22 07:10:44 -08:00 committed by GitHub
parent 175952bf07
commit fa1250a506
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
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
View file

@ -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

View file

@ -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) {