Skip to content

Commit 038b158

Browse files
committed
[ruby/mmtk] Implement fast path for bump pointer allocator
Adding a fast path for bump pointer allocator can improve allocation performance. For the following microbenchmark with MMTK_HEAP_MIN=100MiB: 10_000_000.times { String.new } Before: 810.7 ms ± 8.3 ms [User: 790.9 ms, System: 40.3 ms] After: 777.9 ms ± 10.4 ms [User: 759.0 ms, System: 37.9 ms] ruby/mmtk@0ff5c9f579
1 parent 1bc2a91 commit 038b158

File tree

4 files changed

+63
-3
lines changed

4 files changed

+63
-3
lines changed

gc/mmtk/cbindgen.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ typedef void *MMTk_Address;
2020
typedef void *MMTk_ObjectReference;
2121
typedef void *MMTk_NullableObjectReference;
2222
typedef uint32_t MMTk_AllocationSemantics;
23+
24+
typedef struct MMTk_BumpPointer {
25+
uintptr_t cursor;
26+
uintptr_t limit;
27+
} MMTk_BumpPointer;
2328
"""
2429

2530
[export]

gc/mmtk/mmtk.c

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ struct MMTk_ractor_cache {
4848

4949
MMTk_Mutator *mutator;
5050
bool gc_mutator_p;
51+
52+
MMTk_BumpPointer *bump_pointer;
5153
};
5254

5355
struct MMTk_final_job {
@@ -447,6 +449,7 @@ rb_gc_impl_ractor_cache_alloc(void *objspace_ptr, void *ractor)
447449
ccan_list_add(&objspace->ractor_caches, &cache->list_node);
448450

449451
cache->mutator = mmtk_bind_mutator(cache);
452+
cache->bump_pointer = mmtk_get_bump_pointer_allocator(cache->mutator);
450453

451454
return cache;
452455
}
@@ -612,6 +615,24 @@ rb_gc_impl_config_set(void *objspace_ptr, VALUE hash)
612615

613616
// Object allocation
614617

618+
static VALUE
619+
rb_mmtk_alloc_fast_path(struct objspace *objspace, struct MMTk_ractor_cache *ractor_cache, size_t size)
620+
{
621+
MMTk_BumpPointer *bump_pointer = ractor_cache->bump_pointer;
622+
if (bump_pointer == NULL) return 0;
623+
624+
uintptr_t new_cursor = bump_pointer->cursor + size;
625+
626+
if (new_cursor > bump_pointer->limit) {
627+
return 0;
628+
}
629+
else {
630+
VALUE obj = (VALUE)bump_pointer->cursor;
631+
bump_pointer->cursor = new_cursor;
632+
return obj;
633+
}
634+
}
635+
615636
VALUE
616637
rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, bool wb_protected, size_t alloc_size)
617638
{
@@ -632,13 +653,20 @@ rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags
632653
mmtk_handle_user_collection_request(ractor_cache, false, false);
633654
}
634655

635-
VALUE *alloc_obj = mmtk_alloc(ractor_cache->mutator, alloc_size + 8, MMTk_MIN_OBJ_ALIGN, 0, MMTK_ALLOCATION_SEMANTICS_DEFAULT);
656+
alloc_size += sizeof(VALUE);
657+
658+
VALUE *alloc_obj = (VALUE *)rb_mmtk_alloc_fast_path(objspace, ractor_cache, alloc_size);
659+
if (!alloc_obj) {
660+
alloc_obj = mmtk_alloc(ractor_cache->mutator, alloc_size, MMTk_MIN_OBJ_ALIGN, 0, MMTK_ALLOCATION_SEMANTICS_DEFAULT);
661+
}
662+
636663
alloc_obj++;
637-
alloc_obj[-1] = alloc_size;
664+
alloc_obj[-1] = alloc_size - sizeof(VALUE);
638665
alloc_obj[0] = flags;
639666
alloc_obj[1] = klass;
640667

641-
mmtk_post_alloc(ractor_cache->mutator, (void*)alloc_obj, alloc_size + 8, MMTK_ALLOCATION_SEMANTICS_DEFAULT);
668+
// TODO: implement fast path for mmtk_post_alloc
669+
mmtk_post_alloc(ractor_cache->mutator, (void*)alloc_obj, alloc_size, MMTK_ALLOCATION_SEMANTICS_DEFAULT);
642670

643671
// TODO: only add when object needs obj_free to be called
644672
mmtk_add_obj_free_candidate(alloc_obj);

gc/mmtk/mmtk.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ typedef void *MMTk_ObjectReference;
2020
typedef void *MMTk_NullableObjectReference;
2121
typedef uint32_t MMTk_AllocationSemantics;
2222

23+
typedef struct MMTk_BumpPointer {
24+
uintptr_t cursor;
25+
uintptr_t limit;
26+
} MMTk_BumpPointer;
27+
2328

2429
#define MMTk_OBJREF_OFFSET 8
2530

@@ -93,6 +98,8 @@ void mmtk_initialize_collection(MMTk_VMThread tls);
9398

9499
MMTk_Mutator *mmtk_bind_mutator(MMTk_VMMutatorThread tls);
95100

101+
MMTk_BumpPointer *mmtk_get_bump_pointer_allocator(MMTk_Mutator *m);
102+
96103
void mmtk_destroy_mutator(MMTk_Mutator *mutator);
97104

98105
void mmtk_handle_user_collection_request(MMTk_VMMutatorThread tls, bool force, bool exhaustive);

gc/mmtk/src/api.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// They are called by C functions and they need to pass raw pointers to Rust.
33
#![allow(clippy::missing_safety_doc)]
44

5+
use mmtk::util::alloc::BumpPointer;
6+
use mmtk::util::alloc::ImmixAllocator;
57
use mmtk::util::options::PlanSelector;
68
use std::str::FromStr;
79
use std::sync::atomic::Ordering;
@@ -174,6 +176,24 @@ pub extern "C" fn mmtk_bind_mutator(tls: VMMutatorThread) -> *mut RubyMutator {
174176
Box::into_raw(memory_manager::bind_mutator(mmtk(), tls))
175177
}
176178

179+
#[no_mangle]
180+
pub unsafe extern "C" fn mmtk_get_bump_pointer_allocator(m: *mut RubyMutator) -> *mut BumpPointer {
181+
match *crate::BINDING.get().unwrap().mmtk.get_options().plan {
182+
PlanSelector::Immix => {
183+
let mutator: &mut Mutator<Ruby> = unsafe { &mut *m };
184+
let allocator =
185+
unsafe { mutator.allocator_mut(mmtk::util::alloc::AllocatorSelector::Immix(0)) };
186+
187+
if let Some(immix_allocator) = allocator.downcast_mut::<ImmixAllocator<Ruby>>() {
188+
&mut immix_allocator.bump_pointer as *mut BumpPointer
189+
} else {
190+
panic!("Failed to get bump pointer allocator");
191+
}
192+
}
193+
_ => std::ptr::null_mut(),
194+
}
195+
}
196+
177197
#[no_mangle]
178198
pub unsafe extern "C" fn mmtk_destroy_mutator(mutator: *mut RubyMutator) {
179199
// notify mmtk-core about destroyed mutator

0 commit comments

Comments
 (0)