diff --git a/mmtk/Cargo.toml b/mmtk/Cargo.toml index ceca093..fd5f92b 100644 --- a/mmtk/Cargo.toml +++ b/mmtk/Cargo.toml @@ -12,7 +12,7 @@ edition = "2021" # Metadata for the Ruby repository [package.metadata.ci-repos.ruby] repo = "mmtk/ruby" # This is used by actions/checkout, so the format is "owner/repo", not URL. -rev = "db7b82e33081066233281cdfcc0b7321b29703af" +rev = "f9a0c1de19043485d1c9a26844e716a4953e693d" [lib] name = "mmtk_ruby" diff --git a/mmtk/src/abi.rs b/mmtk/src/abi.rs index 94cbe0e..e24f0d1 100644 --- a/mmtk/src/abi.rs +++ b/mmtk/src/abi.rs @@ -362,6 +362,7 @@ pub struct RubyUpcalls { pub is_no_longer_ppp: extern "C" fn(ObjectReference) -> bool, pub scan_object_ruby_style: extern "C" fn(object: ObjectReference), pub call_gc_mark_children: extern "C" fn(object: ObjectReference), + pub obj_needs_cleanup_p: extern "C" fn(object: ObjectReference) -> bool, pub call_obj_free: extern "C" fn(object: ObjectReference), pub vm_live_bytes: extern "C" fn() -> usize, pub has_exivar: extern "C" fn(object: ObjectReference) -> bool, diff --git a/mmtk/src/weak_proc.rs b/mmtk/src/weak_proc.rs index dfdd7b0..2733ca6 100644 --- a/mmtk/src/weak_proc.rs +++ b/mmtk/src/weak_proc.rs @@ -8,11 +8,18 @@ use mmtk::{ use crate::{ abi::{self, GCThreadTLS}, - extra_assert, is_mmtk_object_safe, upcalls, Ruby, + extra_assert, is_mmtk_object_safe, upcalls, + weak_proc::weak_global_tables::{ + UpdateCCRefinementTable, UpdateCiTable, UpdateFinalizerAndObjIdTables, + UpdateFrozenStringsTable, UpdateGenericFieldsTbl, UpdateGlobalSymbolsTable, + UpdateOverloadedCmeTable, + }, + Ruby, }; pub mod concurrent_set_parallel; pub mod st_table_parallel; +pub mod weak_global_tables; /// Set this to true to use chunked processing optimization for the fstring table. const SPECIALIZE_FSTRING_TABLE_PROCESSING: bool = true; @@ -154,6 +161,9 @@ impl GCWork for ProcessObjFreeCandidates { let old_cands = obj_free_candidates.len(); debug!("Total: {} candidates", old_cands); + let mut freed = 0usize; + let mut elided = 0usize; + // Process obj_free let mut new_candidates = Vec::new(); @@ -167,130 +177,27 @@ impl GCWork for ProcessObjFreeCandidates { new_object ); new_candidates.push(new_object); - } else { + } else if (upcalls().obj_needs_cleanup_p)(object) { (upcalls().call_obj_free)(object); + freed += 1; + } else { + elided += 1; } } let new_cands = new_candidates.len(); *obj_free_candidates = new_candidates; - probe!(mmtk_ruby, process_obj_free_candidates, old_cands, new_cands); - } -} - -trait GlobalTableProcessingWork { - fn process_table(&mut self); - - fn do_work(&mut self, worker: &mut GCWorker, _mmtk: &'static mmtk::MMTK) { - let gc_tls = unsafe { GCThreadTLS::from_vwt_check(worker.tls) }; - - // `hash_foreach_replace` depends on `gb_object_moved_p` which has to have the semantics - // of `trace_object` due to the way it is used in `UPDATE_IF_MOVED`. - let forward_object = |_worker, object: ObjectReference, _pin| { - extra_assert!( - is_mmtk_object_safe(object.to_raw_address()), - "{} is not an MMTk object", - object - ); - let result = object.forward(); - trace!("Forwarding reference: {} -> {}", object, result); - result - }; - - gc_tls - .object_closure - .set_temporarily_and_run_code(forward_object, || { - self.process_table(); - }); + probe!( + mmtk_ruby, + process_obj_free_candidates, + old_cands, + new_cands, + freed, + elided, + ); } } -macro_rules! define_global_table_processor { - ($name: ident, $code: expr) => { - struct $name; - impl GlobalTableProcessingWork for $name { - fn process_table(&mut self) { - $code - } - } - impl GCWork for $name { - fn do_work(&mut self, worker: &mut GCWorker, mmtk: &'static mmtk::MMTK) { - GlobalTableProcessingWork::do_work(self, worker, mmtk); - } - } - }; -} - -fn general_update_weak_table(size_getter: extern "C" fn() -> usize, cleaner: extern "C" fn()) { - let old_size = size_getter(); - cleaner(); - let new_size = size_getter(); - probe!(mmtk_ruby, weak_table_size_change, old_size, new_size); -} - -///////// BEGIN: Simple table updating work packets //////// -// Note: Follow the order of `rb_gc_vm_weak_table_foreach in `gc.c` - -define_global_table_processor!(UpdateCiTable, { - general_update_weak_table(upcalls().get_ci_table_size, upcalls().update_ci_table); -}); - -define_global_table_processor!(UpdateOverloadedCmeTable, { - general_update_weak_table( - upcalls().get_overloaded_cme_table_size, - upcalls().update_overloaded_cme_table, - ); -}); - -define_global_table_processor!(UpdateGlobalSymbolsTable, { - general_update_weak_table( - upcalls().get_global_symbols_table_size, - upcalls().update_global_symbols_table, - ); -}); - -define_global_table_processor!(UpdateFinalizerAndObjIdTables, { - let old_size_finalizer = (upcalls().get_finalizer_table_size)(); - let old_size_id_to_obj = (upcalls().get_id2ref_table_size)(); - - (upcalls().update_finalizer_and_obj_id_tables)(); - - let new_size_finalizer = (upcalls().get_finalizer_table_size)(); - let new_size_id_to_obj = (upcalls().get_id2ref_table_size)(); - - probe!( - mmtk_ruby, - update_finalizer_and_obj_id_tables, - old_size_finalizer, - new_size_finalizer, - old_size_id_to_obj, - new_size_id_to_obj, - ); -}); - -define_global_table_processor!(UpdateGenericFieldsTbl, { - general_update_weak_table( - upcalls().get_generic_fields_tbl_size, - upcalls().update_generic_fields_table, - ); -}); - -define_global_table_processor!(UpdateFrozenStringsTable, { - general_update_weak_table( - upcalls().get_frozen_strings_table_size, - upcalls().update_frozen_strings_table, - ); -}); - -define_global_table_processor!(UpdateCCRefinementTable, { - general_update_weak_table( - upcalls().get_cc_refinement_table_size, - upcalls().update_cc_refinement_table, - ); -}); - -///////// END: Simple table updating work packets //////// - struct UpdateWbUnprotectedObjectsList; impl GCWork for UpdateWbUnprotectedObjectsList { diff --git a/mmtk/src/weak_proc/weak_global_tables.rs b/mmtk/src/weak_proc/weak_global_tables.rs new file mode 100644 index 0000000..4f1d203 --- /dev/null +++ b/mmtk/src/weak_proc/weak_global_tables.rs @@ -0,0 +1,121 @@ +use mmtk::{ + scheduler::{GCWork, GCWorker}, + util::ObjectReference, +}; + +use crate::{ + abi::GCThreadTLS, extra_assert, is_mmtk_object_safe, upcalls, weak_proc::Forwardable, Ruby, +}; + +pub trait GlobalTableProcessingWork { + fn process_table(&mut self); + + fn do_work(&mut self, worker: &mut GCWorker, _mmtk: &'static mmtk::MMTK) { + let gc_tls = unsafe { GCThreadTLS::from_vwt_check(worker.tls) }; + + // `hash_foreach_replace` depends on `gb_object_moved_p` which has to have the semantics + // of `trace_object` due to the way it is used in `UPDATE_IF_MOVED`. + let forward_object = |_worker, object: ObjectReference, _pin| { + extra_assert!( + is_mmtk_object_safe(object.to_raw_address()), + "{} is not an MMTk object", + object + ); + let result = object.forward(); + trace!("Forwarding reference: {} -> {}", object, result); + result + }; + + gc_tls + .object_closure + .set_temporarily_and_run_code(forward_object, || { + self.process_table(); + }); + } +} + +macro_rules! define_global_table_processor { + ($name: ident, $code: expr) => { + pub struct $name; + impl GlobalTableProcessingWork for $name { + fn process_table(&mut self) { + $code + } + } + impl GCWork for $name { + fn do_work(&mut self, worker: &mut GCWorker, mmtk: &'static mmtk::MMTK) { + GlobalTableProcessingWork::do_work(self, worker, mmtk); + } + } + }; +} + +fn general_update_weak_table(size_getter: extern "C" fn() -> usize, cleaner: extern "C" fn()) { + let old_size = size_getter(); + cleaner(); + let new_size = size_getter(); + probe!(mmtk_ruby, weak_table_size_change, old_size, new_size); +} + +///////// BEGIN: Simple table updating work packets //////// +// Note: Follow the order of `rb_gc_vm_weak_table_foreach in `gc.c` + +define_global_table_processor!(UpdateCiTable, { + general_update_weak_table(upcalls().get_ci_table_size, upcalls().update_ci_table); +}); + +define_global_table_processor!(UpdateOverloadedCmeTable, { + general_update_weak_table( + upcalls().get_overloaded_cme_table_size, + upcalls().update_overloaded_cme_table, + ); +}); + +define_global_table_processor!(UpdateGlobalSymbolsTable, { + general_update_weak_table( + upcalls().get_global_symbols_table_size, + upcalls().update_global_symbols_table, + ); +}); + +define_global_table_processor!(UpdateFinalizerAndObjIdTables, { + let old_size_finalizer = (upcalls().get_finalizer_table_size)(); + let old_size_id_to_obj = (upcalls().get_id2ref_table_size)(); + + (upcalls().update_finalizer_and_obj_id_tables)(); + + let new_size_finalizer = (upcalls().get_finalizer_table_size)(); + let new_size_id_to_obj = (upcalls().get_id2ref_table_size)(); + + probe!( + mmtk_ruby, + update_finalizer_and_obj_id_tables, + old_size_finalizer, + new_size_finalizer, + old_size_id_to_obj, + new_size_id_to_obj, + ); +}); + +define_global_table_processor!(UpdateGenericFieldsTbl, { + general_update_weak_table( + upcalls().get_generic_fields_tbl_size, + upcalls().update_generic_fields_table, + ); +}); + +define_global_table_processor!(UpdateFrozenStringsTable, { + general_update_weak_table( + upcalls().get_frozen_strings_table_size, + upcalls().update_frozen_strings_table, + ); +}); + +define_global_table_processor!(UpdateCCRefinementTable, { + general_update_weak_table( + upcalls().get_cc_refinement_table_size, + upcalls().update_cc_refinement_table, + ); +}); + +///////// END: Simple table updating work packets //////// diff --git a/tools/tracing/timeline/capture_ruby.bt b/tools/tracing/timeline/capture_ruby.bt index 0e1472a..aa6bf51 100644 --- a/tools/tracing/timeline/capture_ruby.bt +++ b/tools/tracing/timeline/capture_ruby.bt @@ -61,36 +61,38 @@ usdt:$MMTK:mmtk_ruby:weak_cs_par_entries_end { } // Weak st table optimization - -usdt:$MMTK:mmtk_ruby:weak_st_par_init { - if (@enable_print) { - printf("weak_st_par_init,meta,%d,%lu,%lu,%lu,%lu,%lu,%s\n", tid, nsecs, arg0, arg1, arg2, arg3, str(arg4, arg5)); - } -} - -usdt:$MMTK:mmtk_ruby:weak_st_par_final { - if (@enable_print) { - printf("weak_st_par_final,meta,%d,%lu,%lu,%s\n", tid, nsecs, arg0, str(arg1, arg2)); - } -} - -usdt:$MMTK:mmtk_ruby:weak_st_par_entries { - if (@enable_print) { - printf("weak_st_par_entries,meta,%d,%lu,%lu,%lu,%lu,%s\n", tid, nsecs, arg0, arg1, arg2, str(arg3, arg4)); - } -} - -usdt:$MMTK:mmtk_ruby:weak_st_par_bins { - if (@enable_print) { - printf("weak_st_par_bins,meta,%d,%lu,%lu,%lu,%lu,%s\n", tid, nsecs, arg0, arg1, arg2, str(arg3, arg4)); - } -} +// We currently don't have weak st_tables to process in parallel. +// But if we need, we can uncomment the following probes. +// +// usdt:$MMTK:mmtk_ruby:weak_st_par_init { +// if (@enable_print) { +// printf("weak_st_par_init,meta,%d,%lu,%lu,%lu,%lu,%lu,%s\n", tid, nsecs, arg0, arg1, arg2, arg3, str(arg4, arg5)); +// } +// } +// +// usdt:$MMTK:mmtk_ruby:weak_st_par_final { +// if (@enable_print) { +// printf("weak_st_par_final,meta,%d,%lu,%lu,%s\n", tid, nsecs, arg0, str(arg1, arg2)); +// } +// } +// +// usdt:$MMTK:mmtk_ruby:weak_st_par_entries { +// if (@enable_print) { +// printf("weak_st_par_entries,meta,%d,%lu,%lu,%lu,%lu,%s\n", tid, nsecs, arg0, arg1, arg2, str(arg3, arg4)); +// } +// } +// +// usdt:$MMTK:mmtk_ruby:weak_st_par_bins { +// if (@enable_print) { +// printf("weak_st_par_bins,meta,%d,%lu,%lu,%lu,%lu,%s\n", tid, nsecs, arg0, arg1, arg2, str(arg3, arg4)); +// } +// } // Other work packets usdt:$MMTK:mmtk_ruby:process_obj_free_candidates { if (@enable_print) { - printf("process_obj_free_candidates,meta,%d,%lu,%lu,%lu\n", tid, nsecs, arg0, arg1); + printf("process_obj_free_candidates,meta,%d,%lu,%lu,%lu,%lu,%lu\n", tid, nsecs, arg0, arg1, arg2, arg3); } } @@ -100,8 +102,8 @@ usdt:$MMTK:mmtk_ruby:update_wb_unprotected_objects_list { } } -usdt:$MMTK:mmtk_ruby:update_weak_fields { +usdt:$MMTK:mmtk_ruby:process_weak_references { if (@enable_print) { - printf("update_weak_fields,meta,%d,%lu,%lu,%lu,%lu\n", tid, nsecs, arg0, arg1, arg2); + printf("process_weak_references,meta,%d,%lu,%lu,%lu\n", tid, nsecs, arg0, arg1); } } diff --git a/tools/tracing/timeline/visualize_ruby.py b/tools/tracing/timeline/visualize_ruby.py index 62eeaff..b861a53 100755 --- a/tools/tracing/timeline/visualize_ruby.py +++ b/tools/tracing/timeline/visualize_ruby.py @@ -162,13 +162,15 @@ def enrich_meta_extra(log_processor, name, tid, ts, gc, wp, args): # Other work packets case "process_obj_free_candidates": - old_candidates, new_candidates = [int(x) for x in args[0:2]] + old_candidates, new_candidates, freed, elided = [int(x) for x in args[0:4]] wp["args"] |= { "candidates": { "before": old_candidates, "after": new_candidates, "diff": new_candidates - old_candidates, }, + "freed": freed, + "elided": elided, } case "update_wb_unprotected_objects_list": @@ -181,13 +183,10 @@ def enrich_meta_extra(log_processor, name, tid, ts, gc, wp, args): }, } - case "update_weak_fields": - num_fields, live, forwarded = [int(x) for x in args[0:3]] + case "process_weak_references": + num_objects, live = [int(x) for x in args[0:2]] wp["args"] |= { - "wb_unprotected_objects": { - "num_fields": num_fields, - "live": live, - "forwarded": forwarded, - "cleared": num_fields - live, - }, + "num_objects": num_objects, + "live": live, + "dead": num_objects - live, }