MJIT: Convert compact_p flag to an enum

I'm gonna add another type of unit shortly.
This commit is contained in:
Takashi Kokubun 2022-12-08 22:53:27 -08:00
parent bfc225764e
commit 0dc5c117a5
No known key found for this signature in database
GPG Key ID: 6FFC433B12EE23DD
3 changed files with 45 additions and 27 deletions

48
mjit.c
View File

@ -1104,6 +1104,24 @@ free_list(struct rb_mjit_unit_list *list, bool close_handle_p)
list->length = 0; list->length = 0;
} }
static struct rb_mjit_unit*
create_unit(enum rb_mjit_unit_type type)
{
struct rb_mjit_unit *unit = ZALLOC_N(struct rb_mjit_unit, 1);
unit->id = current_unit_num++;
unit->type = type;
return unit;
}
static struct rb_mjit_unit*
create_iseq_unit(const rb_iseq_t *iseq)
{
struct rb_mjit_unit *unit = create_unit(MJIT_UNIT_ISEQ);
unit->iseq = (rb_iseq_t *)iseq;
ISEQ_BODY(iseq)->jit_unit = unit;
return unit;
}
static void mjit_wait(struct rb_mjit_unit *unit); static void mjit_wait(struct rb_mjit_unit *unit);
// Check the unit queue and start mjit_compile if nothing is in progress. // Check the unit queue and start mjit_compile if nothing is in progress.
@ -1130,7 +1148,7 @@ check_unit_queue(void)
// Dequeue a unit // Dequeue a unit
struct rb_mjit_unit *unit = get_from_list(&unit_queue); struct rb_mjit_unit *unit = get_from_list(&unit_queue);
if (unit == NULL) return; if (unit == NULL) return;
VM_ASSERT(!unit->compact_p); VM_ASSERT(unit->type == MJIT_UNIT_ISEQ);
// Run the MJIT compiler synchronously // Run the MJIT compiler synchronously
current_cc_ms = real_ms_time(); current_cc_ms = real_ms_time();
@ -1156,22 +1174,6 @@ check_unit_queue(void)
} }
} }
// Create unit for `iseq`. This function may be called from an MJIT worker.
static struct rb_mjit_unit*
create_unit(const rb_iseq_t *iseq)
{
struct rb_mjit_unit *unit = ZALLOC_N(struct rb_mjit_unit, 1);
unit->id = current_unit_num++;
if (iseq == NULL) { // Compact unit
unit->compact_p = true;
}
else { // Normal unit
unit->iseq = (rb_iseq_t *)iseq;
ISEQ_BODY(iseq)->jit_unit = unit;
}
return unit;
}
// Check if it should compact all JIT code and start it as needed // Check if it should compact all JIT code and start it as needed
static void static void
check_compaction(void) check_compaction(void)
@ -1188,7 +1190,7 @@ check_compaction(void)
if (compact_units.length < max_compact_size if (compact_units.length < max_compact_size
&& ((!mjit_opts.wait && unit_queue.length == 0 && active_units.length > 1) && ((!mjit_opts.wait && unit_queue.length == 0 && active_units.length > 1)
|| (active_units.length == mjit_opts.max_cache_size && compact_units.length * throttle_threshold <= total_unloads))) { // throttle compaction by total_unloads || (active_units.length == mjit_opts.max_cache_size && compact_units.length * throttle_threshold <= total_unloads))) { // throttle compaction by total_unloads
struct rb_mjit_unit *unit = create_unit(NULL); struct rb_mjit_unit *unit = create_unit(MJIT_UNIT_COMPACT);
// Run the MJIT compiler synchronously // Run the MJIT compiler synchronously
current_cc_ms = real_ms_time(); current_cc_ms = real_ms_time();
@ -1225,7 +1227,7 @@ mjit_notify_waitpid(int exit_code)
// Check the result // Check the result
if (exit_code != 0) { if (exit_code != 0) {
verbose(2, "Failed to generate so"); verbose(2, "Failed to generate so");
if (!current_cc_unit->compact_p) { if (current_cc_unit->type == MJIT_UNIT_ISEQ) {
current_cc_unit->iseq->body->jit_func = (jit_func_t)MJIT_FUNC_FAILED; current_cc_unit->iseq->body->jit_func = (jit_func_t)MJIT_FUNC_FAILED;
} }
free_unit(current_cc_unit); free_unit(current_cc_unit);
@ -1236,11 +1238,11 @@ mjit_notify_waitpid(int exit_code)
// Load .so file // Load .so file
char so_file[MAXPATHLEN]; char so_file[MAXPATHLEN];
sprint_uniq_filename(so_file, (int)sizeof(so_file), current_cc_unit->id, MJIT_TMP_PREFIX, DLEXT); sprint_uniq_filename(so_file, (int)sizeof(so_file), current_cc_unit->id, MJIT_TMP_PREFIX, DLEXT);
if (current_cc_unit->compact_p) { // Compact unit if (current_cc_unit->type == MJIT_UNIT_COMPACT) {
load_compact_funcs_from_so(current_cc_unit, c_file, so_file); load_compact_funcs_from_so(current_cc_unit, c_file, so_file);
current_cc_unit = NULL; current_cc_unit = NULL;
} }
else { // Normal unit else { // MJIT_UNIT_ISEQ
// Load the function from so // Load the function from so
char funcname[MAXPATHLEN]; char funcname[MAXPATHLEN];
sprint_funcname(funcname, sizeof(funcname), current_cc_unit); sprint_funcname(funcname, sizeof(funcname), current_cc_unit);
@ -1327,7 +1329,7 @@ mjit_add_iseq_to_process(const rb_iseq_t *iseq, const struct rb_mjit_compile_inf
} }
ISEQ_BODY(iseq)->jit_func = (jit_func_t)MJIT_FUNC_COMPILING; ISEQ_BODY(iseq)->jit_func = (jit_func_t)MJIT_FUNC_COMPILING;
create_unit(iseq); create_iseq_unit(iseq);
if (compile_info != NULL) if (compile_info != NULL)
ISEQ_BODY(iseq)->jit_unit->compile_info = *compile_info; ISEQ_BODY(iseq)->jit_unit->compile_info = *compile_info;
add_to_list(ISEQ_BODY(iseq)->jit_unit, &unit_queue); add_to_list(ISEQ_BODY(iseq)->jit_unit, &unit_queue);
@ -1363,7 +1365,7 @@ mjit_wait(struct rb_mjit_unit *unit)
while (current_cc_pid == initial_pid) { while (current_cc_pid == initial_pid) {
tries++; tries++;
if (tries / 1000 > MJIT_WAIT_TIMEOUT_SECONDS) { if (tries / 1000 > MJIT_WAIT_TIMEOUT_SECONDS) {
if (!unit->compact_p) { if (unit->type == MJIT_UNIT_ISEQ) {
unit->iseq->body->jit_func = (jit_func_t)MJIT_FUNC_FAILED; // C compiler was too slow. Give up. unit->iseq->body->jit_func = (jit_func_t)MJIT_FUNC_FAILED; // C compiler was too slow. Give up.
} }
mjit_warning("timed out to wait for JIT finish"); mjit_warning("timed out to wait for JIT finish");

View File

@ -14,23 +14,35 @@
#define NOT_COMPILED_STACK_SIZE -1 #define NOT_COMPILED_STACK_SIZE -1
#define ALREADY_COMPILED_P(status, pos) (status->stack_size_for_pos[pos] != NOT_COMPILED_STACK_SIZE) #define ALREADY_COMPILED_P(status, pos) (status->stack_size_for_pos[pos] != NOT_COMPILED_STACK_SIZE)
// Type of rb_mjit_unit
enum rb_mjit_unit_type {
// Single-ISEQ unit for mjit_compile
MJIT_UNIT_ISEQ = 0,
// All-ISEQ unit for mjit_compact
MJIT_UNIT_COMPACT = 1,
};
// The unit structure that holds metadata of ISeq for MJIT. // The unit structure that holds metadata of ISeq for MJIT.
// TODO: Use different structs for ISEQ and COMPACT
struct rb_mjit_unit { struct rb_mjit_unit {
struct ccan_list_node unode; struct ccan_list_node unode;
// Unique order number of unit. // Unique order number of unit.
int id; int id;
// Dlopen handle of the loaded object file. // Dlopen handle of the loaded object file.
void *handle; void *handle;
// Type of this unit
enum rb_mjit_unit_type type;
// ISEQ for a non-batch unit
rb_iseq_t *iseq; rb_iseq_t *iseq;
// Only used by unload_units. Flag to check this unit is currently on stack or not. // Only used by unload_units. Flag to check this unit is currently on stack or not.
bool used_code_p; bool used_code_p;
// True if it's a unit for JIT compaction
bool compact_p;
// mjit_compile's optimization switches // mjit_compile's optimization switches
struct rb_mjit_compile_info compile_info; struct rb_mjit_compile_info compile_info;
// captured CC values, they should be marked with iseq. // captured CC values, they should be marked with iseq.
const struct rb_callcache **cc_entries; const struct rb_callcache **cc_entries;
unsigned int cc_entries_size; // ISEQ_BODY(iseq)->ci_size + ones of inlined iseqs // ISEQ_BODY(iseq)->ci_size + ones of inlined iseqs
unsigned int cc_entries_size;
}; };
// Storage to keep data which is consistent in each conditional branch. // Storage to keep data which is consistent in each conditional branch.

View File

@ -621,9 +621,9 @@ module RubyVM::MJIT
unode: [self.ccan_list_node, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), unode)")], unode: [self.ccan_list_node, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), unode)")],
id: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), id)")], id: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), id)")],
handle: [CType::Pointer.new { CType::Immediate.parse("void") }, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), handle)")], handle: [CType::Pointer.new { CType::Immediate.parse("void") }, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), handle)")],
type: [self.rb_mjit_unit_type, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), type)")],
iseq: [CType::Pointer.new { self.rb_iseq_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), iseq)")], iseq: [CType::Pointer.new { self.rb_iseq_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), iseq)")],
used_code_p: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), used_code_p)")], used_code_p: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), used_code_p)")],
compact_p: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), compact_p)")],
compile_info: [self.rb_mjit_compile_info, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), compile_info)")], compile_info: [self.rb_mjit_compile_info, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), compile_info)")],
cc_entries: [CType::Pointer.new { CType::Pointer.new { self.rb_callcache } }, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), cc_entries)")], cc_entries: [CType::Pointer.new { CType::Pointer.new { self.rb_callcache } }, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), cc_entries)")],
cc_entries_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), cc_entries_size)")], cc_entries_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), cc_entries_size)")],
@ -783,5 +783,9 @@ module RubyVM::MJIT
CType::Stub.new(:ccan_list_node) CType::Stub.new(:ccan_list_node)
end end
def C.rb_mjit_unit_type
CType::Stub.new(:rb_mjit_unit_type)
end
### MJIT bindgen end ### ### MJIT bindgen end ###
end if RubyVM::MJIT.enabled? && RubyVM::MJIT.const_defined?(:C) # not defined for miniruby end if RubyVM::MJIT.enabled? && RubyVM::MJIT.const_defined?(:C) # not defined for miniruby