Speed up finalizers for objects without object ID

If the object being finalized does not have an object ID, then we don't
need to insert into the object ID table, we can simply just allocate a
new object ID by bumping the next_object_id counter. This speeds up
finalization for objects that don't have an object ID. For example, the
following script now runs faster:

    1_000_000.times do
      o = Object.new
      ObjectSpace.define_finalizer(o) {}
    end

Before:

    Time (mean ± σ):      1.462 s ±  0.019 s    [User: 1.360 s, System: 0.094 s]
    Range (min … max):    1.441 s …  1.503 s    10 runs

After:

    Time (mean ± σ):      1.199 s ±  0.015 s    [User: 1.103 s, System: 0.086 s]
    Range (min … max):    1.181 s …  1.229 s    10 runs
This commit is contained in:
Peter Zhu 2024-08-15 13:22:39 -04:00
parent 703305bd03
commit bbbe07a5db

View File

@ -3045,6 +3045,19 @@ rb_gc_impl_copy_finalizer(void *objspace_ptr, VALUE dest, VALUE obj)
}
}
static VALUE
get_object_id_in_finalizer(rb_objspace_t *objspace, VALUE obj)
{
if (FL_TEST(obj, FL_SEEN_OBJ_ID)) {
return rb_gc_impl_object_id(objspace, obj);
}
else {
VALUE id = ULL2NUM(objspace->next_object_id);
objspace->next_object_id += OBJ_ID_INCREMENT;
return id;
}
}
static VALUE
get_final(long i, void *data)
{
@ -3065,7 +3078,7 @@ run_final(rb_objspace_t *objspace, VALUE zombie)
FL_UNSET(zombie, FL_FINALIZE);
st_data_t table;
if (st_delete(finalizer_table, &key, &table)) {
rb_gc_run_obj_finalizer(rb_gc_impl_object_id(objspace, zombie), RARRAY_LEN(table), get_final, (void *)table);
rb_gc_run_obj_finalizer(get_object_id_in_finalizer(objspace, zombie), RARRAY_LEN(table), get_final, (void *)table);
}
else {
rb_bug("FL_FINALIZE flag is set, but finalizers are not found");
@ -3248,7 +3261,7 @@ rb_gc_impl_shutdown_call_finalizer(void *objspace_ptr)
while (list) {
struct force_finalize_list *curr = list;
rb_gc_run_obj_finalizer(rb_gc_impl_object_id(objspace, curr->obj), RARRAY_LEN(curr->table), get_final, (void *)curr->table);
rb_gc_run_obj_finalizer(get_object_id_in_finalizer(objspace, curr->obj), RARRAY_LEN(curr->table), get_final, (void *)curr->table);
st_data_t obj = (st_data_t)curr->obj;
st_delete(finalizer_table, &obj, 0);