Increment max_iv_count on class based on number of set_iv in initialize (#6788)

We can loosely predict the number of ivar sets on a class based on the
number of iv set instructions in the initialize method. This should give
us a more accurate estimate to use for initial size pool allocation,
which should in turn give us more cache hits.
This commit is contained in:
Jemma Issroff 2022-11-22 15:28:14 -05:00 committed by GitHub
parent 20b9d7b9fd
commit 9c5e3671eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
Notes: git 2022-11-22 20:28:39 +00:00
Merged-By: maximecb <maximecb@ruby-lang.org>
4 changed files with 46 additions and 1 deletions

2
gc.c
View File

@ -3089,7 +3089,7 @@ rb_imemo_new_debug(enum imemo_type type, VALUE v1, VALUE v2, VALUE v3, VALUE v0,
}
#endif
VALUE
MJIT_FUNC_EXPORTED VALUE
rb_class_allocate_instance(VALUE klass)
{
return rb_class_instance_allocate_internal(klass, T_OBJECT | ROBJECT_EMBED, RGENGC_WB_PROTECTED_OBJECT);

39
iseq.c
View File

@ -2490,6 +2490,45 @@ rb_iseq_disasm(const rb_iseq_t *iseq)
return str;
}
/*
* Estimates the number of instance variables that will be set on
* a given `class` with the initialize method defined in
* `initialize_iseq`
*/
attr_index_t
rb_estimate_iv_count(VALUE klass, const rb_iseq_t * initialize_iseq)
{
bool calls_super = false;
struct rb_id_table * iv_names = rb_id_table_create(0);
VALUE * code = ISEQ_BODY(initialize_iseq)->iseq_encoded;
for (unsigned int i = 0; i < ISEQ_BODY(initialize_iseq)->iseq_size; ) {
VALUE insn = code[i];
int original_insn = rb_vm_insn_addr2insn((const void *)insn);
if (BIN(setinstancevariable) == original_insn) {
ID name = (ID)code[i + 1];
rb_id_table_insert(iv_names, name, Qtrue);
}
else if (BIN(invokesuper) == original_insn) {
calls_super = true;
}
i += insn_len(original_insn);
}
attr_index_t count = (attr_index_t)rb_id_table_size(iv_names);
if (calls_super) {
VALUE superclass = rb_class_superclass(klass);
count += RCLASS_EXT(superclass)->max_iv_count;
}
return count;
}
/*
* call-seq:
* iseq.disasm -> str

View File

@ -1158,6 +1158,7 @@ rb_iseq_t *rb_iseq_new_with_callback(const struct rb_iseq_new_with_callback_call
VALUE rb_iseq_disasm(const rb_iseq_t *iseq);
int rb_iseq_disasm_insn(VALUE str, const VALUE *iseqval, size_t pos, const rb_iseq_t *iseq, VALUE child);
attr_index_t rb_estimate_iv_count(VALUE klass, const rb_iseq_t * initialize_iseq);
VALUE rb_iseq_coverage(const rb_iseq_t *iseq);

View File

@ -4946,6 +4946,11 @@ vm_define_method(const rb_execution_context_t *ec, VALUE obj, ID id, VALUE iseqv
}
rb_add_method_iseq(klass, id, (const rb_iseq_t *)iseqval, cref, visi);
// Set max_iv_count on klasses based on number of ivar sets that are in the initialize method
if (id == rb_intern("initialize") && klass != rb_cObject && RB_TYPE_P(klass, T_CLASS) && (rb_get_alloc_func(klass) == rb_class_allocate_instance)) {
RCLASS_EXT(klass)->max_iv_count = rb_estimate_iv_count(klass, (const rb_iseq_t *)iseqval);
}
if (!is_singleton && vm_scope_module_func_check(ec)) {
klass = rb_singleton_class(klass);