Skip to content

Commit 782d959

Browse files
committed
Implement moving Immix in MMTk
This commit implements moving Immix in MMTk, which allows objects to move in the GC. The performance of this implementation is not yet amazing. It is very similar to non-moving Immix in many of them and slightly slower in others. The benchmark results is shown below. -------------- ----------------- ---------- --------- bench Moving Immix (ms) stddev (%) RSS (MiB) activerecord 241.9 0.5 86.6 chunky-png 447.8 0.8 74.9 erubi-rails 1183.9 0.8 136.1 hexapdf 1607.9 2.6 402.3 liquid-c 45.4 6.7 44.9 liquid-compile 44.1 9.3 53.0 liquid-render 105.4 4.5 55.9 lobsters 650.1 9.7 418.4 mail 115.4 2.1 64.4 psych-load 1656.8 0.8 43.6 railsbench 1653.5 1.3 149.8 rubocop 127.0 15.6 142.1 ruby-lsp 130.7 10.5 99.4 sequel 52.8 7.2 45.6 shipit 1187.0 3.9 311.0 -------------- ----------------- ---------- --------- -------------- --------------------- ---------- --------- bench Non-moving Immix (ms) stddev (%) RSS (MiB) activerecord 218.9 2.7 86.1 chunky-png 464.6 0.8 66.7 erubi-rails 1119.0 4.3 132.7 hexapdf 1539.8 1.8 425.2 liquid-c 40.6 6.9 45.2 liquid-compile 40.6 8.1 52.9 liquid-render 99.3 2.3 48.3 mail 107.4 5.3 65.4 psych-load 1535.6 1.0 39.5 railsbench 1565.6 1.1 149.6 rubocop 122.5 14.3 146.7 ruby-lsp 128.4 10.7 106.4 sequel 44.1 4.0 45.7 shipit 1154.5 2.7 358.5 -------------- --------------------- ---------- ---------
1 parent 7902ae3 commit 782d959

File tree

12 files changed

+393
-38
lines changed

12 files changed

+393
-38
lines changed

gc/mmtk/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ probe = "0.5"
2121
sysinfo = "0.32.0"
2222

2323
[dependencies.mmtk]
24-
features = ["is_mmtk_object", "object_pinning", "sticky_immix_non_moving_nursery", "immix_non_moving"]
24+
features = ["is_mmtk_object", "object_pinning", "sticky_immix_non_moving_nursery"]
2525

2626
# Uncomment the following lines to use mmtk-core from the official repository.
2727
git = "https://github.com/mmtk/mmtk-core.git"

gc/mmtk/mmtk.c

Lines changed: 90 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,18 @@ rb_mmtk_block_for_gc(MMTk_VMMutatorThread mutator)
183183
RB_GC_VM_UNLOCK(lock_lev);
184184
}
185185

186+
static void
187+
rb_mmtk_before_updating_jit_code(void)
188+
{
189+
rb_gc_before_updating_jit_code();
190+
}
191+
192+
static void
193+
rb_mmtk_after_updating_jit_code(void)
194+
{
195+
rb_gc_after_updating_jit_code();
196+
}
197+
186198
static size_t
187199
rb_mmtk_number_of_mutators(void)
188200
{
@@ -247,9 +259,19 @@ rb_mmtk_scan_objspace(void)
247259
}
248260

249261
static void
250-
rb_mmtk_scan_object_ruby_style(MMTk_ObjectReference object)
262+
rb_mmtk_move_obj_during_marking(MMTk_ObjectReference from, MMTk_ObjectReference to)
251263
{
252-
rb_gc_mark_children(rb_gc_get_objspace(), (VALUE)object);
264+
rb_gc_move_obj_during_marking((VALUE)from, (VALUE)to);
265+
}
266+
267+
static void
268+
rb_mmtk_update_object_references(MMTk_ObjectReference mmtk_object)
269+
{
270+
VALUE object = (VALUE)mmtk_object;
271+
272+
if (!RB_FL_TEST(object, RUBY_FL_WEAK_REFERENCE)) {
273+
rb_gc_update_object_references(rb_gc_get_objspace(), object);
274+
}
253275
}
254276

255277
static void
@@ -259,9 +281,15 @@ rb_mmtk_call_gc_mark_children(MMTk_ObjectReference object)
259281
}
260282

261283
static void
262-
rb_mmtk_handle_weak_references(MMTk_ObjectReference object)
284+
rb_mmtk_handle_weak_references(MMTk_ObjectReference mmtk_object, bool moving)
263285
{
264-
rb_gc_handle_weak_references((VALUE)object);
286+
VALUE object = (VALUE)mmtk_object;
287+
288+
rb_gc_handle_weak_references(object);
289+
290+
if (moving) {
291+
rb_gc_update_object_references(rb_gc_get_objspace(), object);
292+
}
265293
}
266294

267295
static void
@@ -332,27 +360,50 @@ rb_mmtk_update_finalizer_table(void)
332360
}
333361

334362
static int
335-
rb_mmtk_update_table_i(VALUE val, void *data)
363+
rb_mmtk_global_tables_count(void)
364+
{
365+
return RB_GC_VM_WEAK_TABLE_COUNT;
366+
}
367+
368+
static inline VALUE rb_mmtk_call_object_closure(VALUE obj, bool pin);
369+
370+
static int
371+
rb_mmtk_update_global_tables_i(VALUE val, void *data)
336372
{
337373
if (!mmtk_is_reachable((MMTk_ObjectReference)val)) {
338374
return ST_DELETE;
339375
}
340376

377+
// TODO: check only if in moving GC
378+
if (rb_mmtk_call_object_closure(val, false) != val) {
379+
return ST_REPLACE;
380+
}
381+
341382
return ST_CONTINUE;
342383
}
343384

344385
static int
345-
rb_mmtk_global_tables_count(void)
386+
rb_mmtk_update_global_tables_replace_i(VALUE *ptr, void *data)
346387
{
347-
return RB_GC_VM_WEAK_TABLE_COUNT;
388+
// TODO: cache the new location so we don't call rb_mmtk_call_object_closure twice
389+
*ptr = rb_mmtk_call_object_closure(*ptr, false);
390+
391+
return ST_CONTINUE;
348392
}
349393

350394
static void
351395
rb_mmtk_update_global_tables(int table)
352396
{
353397
RUBY_ASSERT(table < RB_GC_VM_WEAK_TABLE_COUNT);
354398

355-
rb_gc_vm_weak_table_foreach(rb_mmtk_update_table_i, NULL, NULL, true, (enum rb_gc_vm_weak_tables)table);
399+
// TODO: set weak_only to true for non-moving GC
400+
rb_gc_vm_weak_table_foreach(
401+
rb_mmtk_update_global_tables_i,
402+
rb_mmtk_update_global_tables_replace_i,
403+
NULL,
404+
false,
405+
(enum rb_gc_vm_weak_tables)table
406+
);
356407
}
357408

358409
static bool
@@ -376,11 +427,14 @@ MMTk_RubyUpcalls ruby_upcalls = {
376427
rb_mmtk_stop_the_world,
377428
rb_mmtk_resume_mutators,
378429
rb_mmtk_block_for_gc,
430+
rb_mmtk_before_updating_jit_code,
431+
rb_mmtk_after_updating_jit_code,
379432
rb_mmtk_number_of_mutators,
380433
rb_mmtk_get_mutators,
381434
rb_mmtk_scan_gc_roots,
382435
rb_mmtk_scan_objspace,
383-
rb_mmtk_scan_object_ruby_style,
436+
rb_mmtk_move_obj_during_marking,
437+
rb_mmtk_update_object_references,
384438
rb_mmtk_call_gc_mark_children,
385439
rb_mmtk_handle_weak_references,
386440
rb_mmtk_call_obj_free,
@@ -738,33 +792,42 @@ rb_gc_impl_free(void *objspace_ptr, void *ptr, size_t old_size)
738792
void rb_gc_impl_adjust_memory_usage(void *objspace_ptr, ssize_t diff) { }
739793

740794
// Marking
795+
static inline VALUE
796+
rb_mmtk_call_object_closure(VALUE obj, bool pin)
797+
{
798+
return (VALUE)rb_mmtk_gc_thread_tls->object_closure.c_function(
799+
rb_mmtk_gc_thread_tls->object_closure.rust_closure,
800+
rb_mmtk_gc_thread_tls->gc_context,
801+
(MMTk_ObjectReference)obj,
802+
pin
803+
);
804+
}
805+
741806
void
742807
rb_gc_impl_mark(void *objspace_ptr, VALUE obj)
743808
{
744809
if (RB_SPECIAL_CONST_P(obj)) return;
745810

746-
rb_mmtk_gc_thread_tls->object_closure.c_function(rb_mmtk_gc_thread_tls->object_closure.rust_closure,
747-
rb_mmtk_gc_thread_tls->gc_context,
748-
(MMTk_ObjectReference)obj,
749-
false);
811+
rb_mmtk_call_object_closure(obj, false);
750812
}
751813

752814
void
753815
rb_gc_impl_mark_and_move(void *objspace_ptr, VALUE *ptr)
754816
{
755817
if (RB_SPECIAL_CONST_P(*ptr)) return;
756818

757-
// TODO: make it movable
758-
rb_gc_impl_mark(objspace_ptr, *ptr);
819+
VALUE new_obj = rb_mmtk_call_object_closure(*ptr, false);
820+
if (new_obj != *ptr) {
821+
*ptr = new_obj;
822+
}
759823
}
760824

761825
void
762826
rb_gc_impl_mark_and_pin(void *objspace_ptr, VALUE obj)
763827
{
764828
if (RB_SPECIAL_CONST_P(obj)) return;
765829

766-
// TODO: also pin
767-
rb_gc_impl_mark(objspace_ptr, obj);
830+
rb_mmtk_call_object_closure(obj, true);
768831
}
769832

770833
void
@@ -775,11 +838,10 @@ rb_gc_impl_mark_maybe(void *objspace_ptr, VALUE obj)
775838
}
776839
}
777840

778-
// Weak references
779-
780841
void
781842
rb_gc_impl_declare_weak_references(void *objspace_ptr, VALUE obj)
782843
{
844+
RB_FL_SET(obj, RUBY_FL_WEAK_REFERENCE);
783845
mmtk_declare_weak_references((MMTk_ObjectReference)obj);
784846
}
785847

@@ -790,16 +852,22 @@ rb_gc_impl_handle_weak_references_alive_p(void *objspace_ptr, VALUE obj)
790852
}
791853

792854
// Compaction
855+
void
856+
rb_gc_impl_register_pinning_obj(void *objspace_ptr, VALUE obj)
857+
{
858+
mmtk_register_pinning_obj((MMTk_ObjectReference)obj);
859+
}
860+
793861
bool
794862
rb_gc_impl_object_moved_p(void *objspace_ptr, VALUE obj)
795863
{
796-
rb_bug("unimplemented");
864+
return rb_mmtk_call_object_closure(obj, false) != obj;
797865
}
798866

799867
VALUE
800-
rb_gc_impl_location(void *objspace_ptr, VALUE value)
868+
rb_gc_impl_location(void *objspace_ptr, VALUE obj)
801869
{
802-
rb_bug("unimplemented");
870+
return rb_mmtk_call_object_closure(obj, false);
803871
}
804872

805873
// Write barriers

gc/mmtk/mmtk.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,16 @@ typedef struct MMTk_RubyUpcalls {
6262
void (*stop_the_world)(void);
6363
void (*resume_mutators)(void);
6464
void (*block_for_gc)(MMTk_VMMutatorThread tls);
65+
void (*before_updating_jit_code)(void);
66+
void (*after_updating_jit_code)(void);
6567
size_t (*number_of_mutators)(void);
6668
void (*get_mutators)(void (*visit_mutator)(MMTk_Mutator*, void*), void *data);
6769
void (*scan_gc_roots)(void);
6870
void (*scan_objspace)(void);
69-
void (*scan_object_ruby_style)(MMTk_ObjectReference object);
71+
void (*move_obj_during_marking)(MMTk_ObjectReference from, MMTk_ObjectReference to);
72+
void (*update_object_references)(MMTk_ObjectReference object);
7073
void (*call_gc_mark_children)(MMTk_ObjectReference object);
71-
void (*handle_weak_references)(MMTk_ObjectReference object);
74+
void (*handle_weak_references)(MMTk_ObjectReference object, bool moving);
7275
void (*call_obj_free)(MMTk_ObjectReference object);
7376
size_t (*vm_live_bytes)(void);
7477
void (*update_global_tables)(int tbl_idx);
@@ -125,6 +128,8 @@ void mmtk_declare_weak_references(MMTk_ObjectReference object);
125128

126129
bool mmtk_weak_references_alive_p(MMTk_ObjectReference object);
127130

131+
void mmtk_register_pinning_obj(MMTk_ObjectReference obj);
132+
128133
void mmtk_object_reference_write_post(MMTk_Mutator *mutator, MMTk_ObjectReference object);
129134

130135
void mmtk_register_wb_unprotected_object(MMTk_ObjectReference object);

gc/mmtk/src/abi.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,16 +299,19 @@ pub struct RubyUpcalls {
299299
pub stop_the_world: extern "C" fn(),
300300
pub resume_mutators: extern "C" fn(),
301301
pub block_for_gc: extern "C" fn(tls: VMMutatorThread),
302+
pub before_updating_jit_code: extern "C" fn(),
303+
pub after_updating_jit_code: extern "C" fn(),
302304
pub number_of_mutators: extern "C" fn() -> usize,
303305
pub get_mutators: extern "C" fn(
304306
visit_mutator: extern "C" fn(*mut RubyMutator, *mut libc::c_void),
305307
data: *mut libc::c_void,
306308
),
307309
pub scan_gc_roots: extern "C" fn(),
308310
pub scan_objspace: extern "C" fn(),
309-
pub scan_object_ruby_style: extern "C" fn(object: ObjectReference),
311+
pub move_obj_during_marking: extern "C" fn(from: ObjectReference, to: ObjectReference),
312+
pub update_object_references: extern "C" fn(object: ObjectReference),
310313
pub call_gc_mark_children: extern "C" fn(object: ObjectReference),
311-
pub handle_weak_references: extern "C" fn(object: ObjectReference),
314+
pub handle_weak_references: extern "C" fn(object: ObjectReference, moving: bool),
312315
pub call_obj_free: extern "C" fn(object: ObjectReference),
313316
pub vm_live_bytes: extern "C" fn() -> usize,
314317
pub update_global_tables: extern "C" fn(tbl_idx: c_int),

gc/mmtk/src/api.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,13 @@ pub extern "C" fn mmtk_weak_references_alive_p(object: ObjectReference) -> bool
312312
object.is_reachable()
313313
}
314314

315+
// =============== Compaction ===============
316+
317+
#[no_mangle]
318+
pub extern "C" fn mmtk_register_pinning_obj(obj: ObjectReference) {
319+
crate::binding().pinning_registry.register(obj);
320+
}
321+
315322
// =============== Write barriers ===============
316323

317324
#[no_mangle]

gc/mmtk/src/binding.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use mmtk::MMTK;
99

1010
use crate::abi;
1111
use crate::abi::RubyBindingOptions;
12+
use crate::pinning_registry::PinningRegistry;
1213
use crate::weak_proc::WeakProcessor;
1314
use crate::Ruby;
1415

@@ -54,6 +55,7 @@ pub struct RubyBinding {
5455
pub upcalls: *const abi::RubyUpcalls,
5556
pub plan_name: Mutex<Option<CString>>,
5657
pub weak_proc: WeakProcessor,
58+
pub pinning_registry: PinningRegistry,
5759
pub gc_thread_join_handles: Mutex<Vec<JoinHandle<()>>>,
5860
pub wb_unprotected_objects: Mutex<HashSet<ObjectReference>>,
5961
}
@@ -77,6 +79,7 @@ impl RubyBinding {
7779
upcalls,
7880
plan_name: Mutex::new(None),
7981
weak_proc: WeakProcessor::new(),
82+
pinning_registry: PinningRegistry::new(),
8083
gc_thread_join_handles: Default::default(),
8184
wb_unprotected_objects: Default::default(),
8285
}

gc/mmtk/src/collection.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,45 @@ use mmtk::scheduler::*;
88
use mmtk::util::heap::GCTriggerPolicy;
99
use mmtk::util::{VMMutatorThread, VMThread, VMWorkerThread};
1010
use mmtk::vm::{Collection, GCThreadContext};
11+
use std::sync::atomic::AtomicBool;
1112
use std::sync::atomic::Ordering;
1213
use std::thread;
1314

15+
static CURRENT_GC_MAY_MOVE: AtomicBool = AtomicBool::new(false);
16+
1417
pub struct VMCollection {}
1518

1619
impl Collection<Ruby> for VMCollection {
1720
fn is_collection_enabled() -> bool {
1821
crate::CONFIGURATION.gc_enabled.load(Ordering::Relaxed)
1922
}
2023

21-
fn stop_all_mutators<F>(_tls: VMWorkerThread, mut mutator_visitor: F)
24+
fn stop_all_mutators<F>(tls: VMWorkerThread, mut mutator_visitor: F)
2225
where
2326
F: FnMut(&'static mut mmtk::Mutator<Ruby>),
2427
{
2528
(upcalls().stop_the_world)();
29+
30+
if crate::mmtk().get_plan().current_gc_may_move_object() {
31+
CURRENT_GC_MAY_MOVE.store(true, Ordering::Relaxed);
32+
(upcalls().before_updating_jit_code)();
33+
} else {
34+
CURRENT_GC_MAY_MOVE.store(false, Ordering::Relaxed);
35+
}
36+
37+
crate::binding().pinning_registry.pin_children(tls);
38+
2639
(upcalls().get_mutators)(
2740
Self::notify_mutator_ready::<F>,
2841
&mut mutator_visitor as *mut F as *mut _,
2942
);
3043
}
3144

3245
fn resume_mutators(_tls: VMWorkerThread) {
46+
if CURRENT_GC_MAY_MOVE.load(Ordering::Relaxed) {
47+
(upcalls().after_updating_jit_code)();
48+
}
49+
3350
(upcalls().resume_mutators)();
3451
}
3552

gc/mmtk/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub mod binding;
2727
pub mod collection;
2828
pub mod heap;
2929
pub mod object_model;
30+
pub mod pinning_registry;
3031
pub mod reference_glue;
3132
pub mod scanning;
3233
pub mod utils;

0 commit comments

Comments
 (0)