mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
mjit.c: keep all .o files
and lazily delete them on termination. This will be needed to create a large so file later. The large number of .o files will be probably compacted before the large so file is created. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64077 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
e09bf11f6e
commit
ceab460fca
2 changed files with 52 additions and 28 deletions
39
mjit.c
39
mjit.c
|
@ -162,6 +162,10 @@ struct rb_mjit_unit {
|
||||||
/* Dlopen handle of the loaded object file. */
|
/* Dlopen handle of the loaded object file. */
|
||||||
void *handle;
|
void *handle;
|
||||||
const rb_iseq_t *iseq;
|
const rb_iseq_t *iseq;
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
/* This is lazily deleted so that it can be used again to create a large so file. */
|
||||||
|
char *o_file;
|
||||||
|
#endif
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
/* DLL cannot be removed while loaded on Windows */
|
/* DLL cannot be removed while loaded on Windows */
|
||||||
char *so_file;
|
char *so_file;
|
||||||
|
@ -522,12 +526,24 @@ mjit_free_iseq(const rb_iseq_t *iseq)
|
||||||
CRITICAL_SECTION_FINISH(4, "mjit_free_iseq");
|
CRITICAL_SECTION_FINISH(4, "mjit_free_iseq");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Lazily delete .o and/or .so files. */
|
||||||
static void
|
static void
|
||||||
clean_so_file(struct rb_mjit_unit *unit)
|
clean_object_files(struct rb_mjit_unit *unit)
|
||||||
{
|
{
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
if (unit->o_file) {
|
||||||
|
char *o_file = unit->o_file;
|
||||||
|
|
||||||
|
unit->o_file = NULL;
|
||||||
|
remove_file(o_file);
|
||||||
|
free(o_file);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
char *so_file = unit->so_file;
|
if (unit->so_file) {
|
||||||
if (so_file) {
|
char *so_file = unit->so_file;
|
||||||
|
|
||||||
unit->so_file = NULL;
|
unit->so_file = NULL;
|
||||||
remove_file(so_file);
|
remove_file(so_file);
|
||||||
free(so_file);
|
free(so_file);
|
||||||
|
@ -538,8 +554,9 @@ clean_so_file(struct rb_mjit_unit *unit)
|
||||||
/* This is called in the following situations:
|
/* This is called in the following situations:
|
||||||
1) On dequeue or `unload_units()`, associated ISeq is already GCed.
|
1) On dequeue or `unload_units()`, associated ISeq is already GCed.
|
||||||
2) The unit is not called often and unloaded by `unload_units()`.
|
2) The unit is not called often and unloaded by `unload_units()`.
|
||||||
|
3) Freeing lists on `mjit_finish()`.
|
||||||
|
|
||||||
`jit_func` state for 1 can be ignored because ISeq GC means it'll never be used.
|
`jit_func` value does not matter for 1 and 3 since the unit won't be used anymore.
|
||||||
For the situation 2, this sets the ISeq's JIT state to NOT_COMPILED_JIT_ISEQ_FUNC
|
For the situation 2, this sets the ISeq's JIT state to NOT_COMPILED_JIT_ISEQ_FUNC
|
||||||
to prevent the situation that the same methods are continously compiled. */
|
to prevent the situation that the same methods are continously compiled. */
|
||||||
static void
|
static void
|
||||||
|
@ -549,7 +566,7 @@ free_unit(struct rb_mjit_unit *unit)
|
||||||
unit->iseq->body->jit_func = (mjit_func_t)NOT_COMPILED_JIT_ISEQ_FUNC;
|
unit->iseq->body->jit_func = (mjit_func_t)NOT_COMPILED_JIT_ISEQ_FUNC;
|
||||||
if (unit->handle) /* handle is NULL if it's in queue */
|
if (unit->handle) /* handle is NULL if it's in queue */
|
||||||
dlclose(unit->handle);
|
dlclose(unit->handle);
|
||||||
clean_so_file(unit);
|
clean_object_files(unit);
|
||||||
xfree(unit);
|
xfree(unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1024,11 +1041,13 @@ convert_unit_to_func(struct rb_mjit_unit *unit)
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
success = compile_c_to_so(c_file, so_file);
|
success = compile_c_to_so(c_file, so_file);
|
||||||
#else
|
#else
|
||||||
/* splitting .c -> .o and .o -> .so to cache .o files in the future */
|
/* splitting .c -> .o step and .o -> .so step, to cache .o files in the future */
|
||||||
success = compile_c_to_o(c_file, o_file) && link_o_to_so(o_file, so_file);
|
if (success = compile_c_to_o(c_file, o_file)) {
|
||||||
|
success = link_o_to_so(o_file, so_file);
|
||||||
|
|
||||||
if (!mjit_opts.save_temps)
|
if (!mjit_opts.save_temps)
|
||||||
remove_file(o_file);
|
unit->o_file = strdup(o_file); /* lazily delete on `clean_object_files()` */
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
end_time = real_ms_time();
|
end_time = real_ms_time();
|
||||||
|
|
||||||
|
@ -1042,7 +1061,7 @@ convert_unit_to_func(struct rb_mjit_unit *unit)
|
||||||
func = load_func_from_so(so_file, funcname, unit);
|
func = load_func_from_so(so_file, funcname, unit);
|
||||||
if (!mjit_opts.save_temps) {
|
if (!mjit_opts.save_temps) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
unit->so_file = strdup(so_file);
|
unit->so_file = strdup(so_file); /* lazily delete on `clean_object_files()` */
|
||||||
#else
|
#else
|
||||||
remove_file(so_file);
|
remove_file(so_file);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -530,26 +530,31 @@ class TestJIT < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_unload_units
|
def test_unload_units
|
||||||
# MIN_CACHE_SIZE is 10
|
Dir.mktmpdir("jit_test_clean_so_") do |dir|
|
||||||
out, err = eval_with_jit("#{<<~"begin;"}\n#{<<~'end;'}", verbose: 1, min_calls: 1, max_cache: 10)
|
# MIN_CACHE_SIZE is 10
|
||||||
begin;
|
out, err = eval_with_jit({"TMPDIR"=>dir}, "#{<<~"begin;"}\n#{<<~'end;'}", verbose: 1, min_calls: 1, max_cache: 10)
|
||||||
10.times do |i|
|
begin;
|
||||||
eval(<<-EOS)
|
10.times do |i|
|
||||||
def mjit#{i}
|
eval(<<-EOS)
|
||||||
print #{i}
|
def mjit#{i}
|
||||||
end
|
print #{i}
|
||||||
mjit#{i}
|
end
|
||||||
EOS
|
mjit#{i}
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
assert_equal('0123456789', out)
|
||||||
|
errs = err.lines
|
||||||
|
assert_match(/\A#{JIT_SUCCESS_PREFIX}: block in <main>@-e:/, errs[0])
|
||||||
|
9.times do |i|
|
||||||
|
assert_match(/\A#{JIT_SUCCESS_PREFIX}: mjit#{i}@\(eval\):/, errs[i + 1])
|
||||||
end
|
end
|
||||||
end;
|
assert_equal("Too many JIT code -- 1 units unloaded\n", errs[10])
|
||||||
assert_equal('0123456789', out)
|
assert_match(/\A#{JIT_SUCCESS_PREFIX}: mjit9@\(eval\):/, errs[11])
|
||||||
errs = err.lines
|
|
||||||
assert_match(/\A#{JIT_SUCCESS_PREFIX}: block in <main>@-e:/, errs[0])
|
# verify .o files are deleted on unload_units
|
||||||
9.times do |i|
|
assert_send([Dir, :empty?, dir])
|
||||||
assert_match(/\A#{JIT_SUCCESS_PREFIX}: mjit#{i}@\(eval\):/, errs[i + 1])
|
|
||||||
end
|
end
|
||||||
assert_equal("Too many JIT code -- 1 units unloaded\n", errs[10])
|
|
||||||
assert_match(/\A#{JIT_SUCCESS_PREFIX}: mjit9@\(eval\):/, errs[11])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_local_stack_on_exception
|
def test_local_stack_on_exception
|
||||||
|
|
Loading…
Add table
Reference in a new issue