Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a translated bitmap to enable more efficient marking #2927

Merged
merged 60 commits into from
Dec 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
954d81a
WIP: translated bitmap
ggreif Nov 22, 2021
9b76fed
fmt
ggreif Nov 22, 2021
e22bc43
WIP: try allocating the heap such that the dynamic heap is 32-bit ali…
ggreif Nov 23, 2021
b40f6b6
ruthlessly increment the static_heap_size_bytes
ggreif Nov 23, 2021
3736517
tweak assertions
ggreif Nov 23, 2021
1873a2e
cleanup
ggreif Nov 23, 2021
01a0cc8
fmt
ggreif Nov 23, 2021
a8b5310
WIP: minor refactoring
ggreif Nov 23, 2021
b5c6d82
fmt
ggreif Nov 23, 2021
922d330
WIP: remove the allocator based alignment
ggreif Nov 23, 2021
be85715
rename
ggreif Nov 23, 2021
3712928
clean up
ggreif Nov 23, 2021
20defb8
undo debugging
ggreif Nov 23, 2021
64efc2e
remove unneeded stuff
ggreif Nov 23, 2021
22611f2
these tests only make sense with no static heap portions
ggreif Nov 23, 2021
72d128d
Update rts/motoko-rts/src/gc/mark_compact/bitmap.rs
ggreif Nov 23, 2021
bf1cd6e
might be faster, but definitely shorter
ggreif Nov 24, 2021
7cc89b1
move invariant computation out of the loop
ggreif Nov 24, 2021
f670ba7
it is usafe
ggreif Nov 24, 2021
78bf047
add an explanation how this scheme works
ggreif Nov 24, 2021
aa53738
Update rts/motoko-rts/src/gc/mark_compact/bitmap.rs
ggreif Nov 24, 2021
61ae218
tweak
ggreif Nov 24, 2021
221c7c9
REVERT ME
ggreif Nov 24, 2021
1d8e3bb
REVERT ME TOO
ggreif Nov 24, 2021
394f4ce
define and use `get_bitmap_forbidden_size`
ggreif Nov 25, 2021
1f85b6b
rename to `BITMAP_FORBIDDEN_PTR`
ggreif Nov 25, 2021
0ab5d8b
get rid of `BITMAP_COMPENSATION`
ggreif Nov 25, 2021
989b6e2
tweak
ggreif Nov 25, 2021
191a144
refactor BitmapIter to keep `current_bit_idx`
ggreif Nov 25, 2021
d03b4ef
refactor to use `bits_visited`
ggreif Nov 25, 2021
7828b10
instead of counting `bits_visited`, add `current_word.leading_zeros()`
ggreif Nov 25, 2021
e20da5a
WIP: make bits iterated correspond to absolute words
ggreif Nov 25, 2021
49c0b64
Update perf-delta.nix
ggreif Nov 25, 2021
3d7c999
fix the glaring bug
ggreif Nov 26, 2021
2716eef
fmt
ggreif Nov 26, 2021
c49fc18
minor nomenclature fixes
ggreif Nov 26, 2021
a460d32
tweak graphics
ggreif Nov 26, 2021
f45e676
move comparison before the loop
ggreif Nov 26, 2021
c3b3b18
for copying collector no alignment necessary
ggreif Nov 26, 2021
af2385d
fix wording
ggreif Nov 27, 2021
c87ae9b
soup up the graphic
ggreif Nov 27, 2021
3223b36
Update rts/motoko-rts/src/gc/mark_compact/bitmap.rs
ggreif Nov 29, 2021
bf97583
update example
ggreif Nov 29, 2021
165555b
wordsmithing
ggreif Nov 29, 2021
7b24bfa
make "next word" precise
ggreif Nov 29, 2021
140e93d
undo this but be watchful
ggreif Nov 29, 2021
9872e4d
pass bool to `init` meaning mandatory alignment
ggreif Nov 29, 2021
a9bca2b
Update rts/motoko-rts/src/gc/mark_compact/bitmap.rs
ggreif Nov 30, 2021
2d9f509
Update rts/motoko-rts/src/memory/ic.rs
ggreif Nov 30, 2021
d3a2610
Update rts/motoko-rts/src/gc/mark_compact/bitmap.rs
ggreif Nov 30, 2021
a3eb0e3
Update rts/motoko-rts/src/gc/mark_compact/bitmap.rs
ggreif Nov 30, 2021
adb8c0a
Update rts/motoko-rts/src/gc/mark_compact/bitmap.rs
ggreif Nov 30, 2021
e7f6c34
fix BM start
ggreif Nov 30, 2021
c3f1147
tweak
ggreif Nov 30, 2021
cf98977
doc and code tweaks
ggreif Nov 30, 2021
b94cf22
typo
ggreif Nov 30, 2021
86fcfd4
oooops
ggreif Nov 30, 2021
f37b9af
simplify
ggreif Nov 30, 2021
aec40ce
Merge branch 'master' into gabor/translate
ggreif Nov 30, 2021
2989412
Merge branch 'master' into gabor/translate
mergify[bot] Dec 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion perf-delta.nix
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ let
do
# ignore all errors
echo -n $file
if timeout 10s moc $file -no-check-ir -ref-system-api -o $file.wasm 2>/dev/null
if timeout 10s moc $file --force-gc --compacting-gc -no-check-ir -ref-system-api -o $file.wasm 2>/dev/null
ggreif marked this conversation as resolved.
Show resolved Hide resolved
then echo " failed (ignored)"
else echo " ok"
fi
Expand Down
9 changes: 7 additions & 2 deletions rts/motoko-rts-tests/src/bitmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::memory::TestMemory;

use motoko_rts::constants::WORD_SIZE;
use motoko_rts::gc::mark_compact::bitmap::{
alloc_bitmap, get_bit, iter_bits, set_bit, BITMAP_ITER_END,
alloc_bitmap, free_bitmap, get_bit, iter_bits, set_bit, BITMAP_ITER_END,
};
use motoko_rts::memory::Memory;
use motoko_rts::types::{Bytes, Words};
Expand Down Expand Up @@ -69,6 +69,7 @@ fn test_set_get<M: Memory>(mem: &mut M, mut bits: Vec<u16>) -> Result<(), String
alloc_bitmap(
mem,
Bytes((u32::from(*bits.iter().max().unwrap()) + 1) * WORD_SIZE),
0,
);

for bit in &bits {
Expand Down Expand Up @@ -98,6 +99,8 @@ fn test_set_get<M: Memory>(mem: &mut M, mut bits: Vec<u16>) -> Result<(), String

last_bit = Some(bit);
}

free_bitmap()
ggreif marked this conversation as resolved.
Show resolved Hide resolved
}

Ok(())
Expand All @@ -111,7 +114,7 @@ fn test_bit_iter<M: Memory>(mem: &mut M, bits: HashSet<u16>) -> TestCaseResult {
.to_bytes();

unsafe {
alloc_bitmap(mem, heap_size);
alloc_bitmap(mem, heap_size, 0);

for bit in bits.iter() {
set_bit(u32::from(*bit));
Expand Down Expand Up @@ -154,6 +157,8 @@ fn test_bit_iter<M: Memory>(mem: &mut M, bits: HashSet<u16>) -> TestCaseResult {
.into(),
));
}

free_bitmap()
ggreif marked this conversation as resolved.
Show resolved Hide resolved
}

Ok(())
Expand Down
28 changes: 20 additions & 8 deletions rts/motoko-rts-tests/src/gc/heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,23 @@ impl MotokoHeapInner {
map.len(),
);

let mut heap: Vec<u8> = vec![0; heap_size];
// The Worst-case unalignment w.r.t. 32-byte alignment is 28 (assuming
// that we have general word alignment). So we over-allocate 28 bytes.
let mut heap: Vec<u8> = vec![0; heap_size + 28];
ggreif marked this conversation as resolved.
Show resolved Hide resolved

// MarkCompact assumes that the dynamic heap starts at a 32-byte multiple
let realign = match gc {
GC::Copying => 0,
GC::MarkCompact => (32 - (heap.as_ptr() as usize + static_heap_size_bytes) % 32) % 32,
};
assert_eq!(realign % 4, 0);

// Maps `ObjectIdx`s into their offsets in the heap
let object_addrs: FxHashMap<ObjectIdx, usize> =
create_dynamic_heap(map, continuation_table, &mut heap[static_heap_size_bytes..]);
let object_addrs: FxHashMap<ObjectIdx, usize> = create_dynamic_heap(
map,
continuation_table,
&mut heap[static_heap_size_bytes + realign..heap_size + realign],
);

// Closure table pointer is the last word in static heap
let continuation_table_ptr_offset = static_heap_size_bytes - WORD_SIZE;
Expand All @@ -217,15 +229,15 @@ impl MotokoHeapInner {
&object_addrs,
continuation_table_ptr_offset,
static_heap_size_bytes + dynamic_heap_size_without_continuation_table_bytes,
&mut heap[..static_heap_size_bytes],
&mut heap[realign..static_heap_size_bytes + realign],
);

MotokoHeapInner {
heap: heap.into_boxed_slice(),
heap_base_offset: static_heap_size_bytes,
heap_ptr_offset: total_heap_size_bytes,
static_root_array_offset: 0,
continuation_table_ptr_offset: continuation_table_ptr_offset,
heap_base_offset: static_heap_size_bytes + realign,
ggreif marked this conversation as resolved.
Show resolved Hide resolved
heap_ptr_offset: total_heap_size_bytes + realign,
static_root_array_offset: realign,
continuation_table_ptr_offset: continuation_table_ptr_offset + realign,
ggreif marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
10 changes: 5 additions & 5 deletions rts/motoko-rts/src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,21 @@ pub unsafe fn dump_heap(
print_heap(heap_base, hp);
}

pub(crate) unsafe fn print_continuation_table(closure_tbl_loc: *mut Value) {
pub(crate) unsafe fn print_continuation_table(continuation_tbl_loc: *mut Value) {
ggreif marked this conversation as resolved.
Show resolved Hide resolved
if !crate::continuation_table::table_initialized() {
println!(100, "Continuation table not initialized");
return;
}

let arr = (*closure_tbl_loc).as_array() as *mut Array;
let arr = (*continuation_tbl_loc).as_array();
let len = (*arr).len;

if len == 0 {
println!(50, "Closure table empty");
println!(50, "Continuation table empty");
return;
}

println!(50, "Closure table: {}", len);
println!(50, "Continuation table: {}", len);

let mut buf = [0u8; 1000];
let mut write_buf = WriteBuf::new(&mut buf);
Expand All @@ -59,7 +59,7 @@ pub(crate) unsafe fn print_continuation_table(closure_tbl_loc: *mut Value) {
write_buf.reset();
}
}
println!(50, "End of closure table");
println!(50, "End of continuation table");
}

pub(crate) unsafe fn print_static_roots(static_roots: Value) {
Expand Down
22 changes: 12 additions & 10 deletions rts/motoko-rts/src/gc/mark_compact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ unsafe fn compacting_gc<M: Memory>(mem: &mut M) {

compacting_gc_internal(
mem,
ic::get_heap_base(),
ic::get_aligned_heap_base(),
ggreif marked this conversation as resolved.
Show resolved Hide resolved
// get_hp
|| ic::HP as usize,
// set_hp
Expand Down Expand Up @@ -72,6 +72,8 @@ pub unsafe fn compacting_gc_internal<
) {
let old_hp = get_hp() as u32;

assert_eq!(heap_base % 32, 0);

mark_compact(
mem,
set_hp,
Expand All @@ -98,16 +100,16 @@ unsafe fn mark_compact<M: Memory, SetHp: Fn(u32)>(
) {
let mem_size = Bytes(heap_end - heap_base);

alloc_bitmap(mem, mem_size);
alloc_bitmap(mem, mem_size, heap_base / WORD_SIZE);
alloc_mark_stack(mem);

mark_static_roots(mem, static_roots, heap_base);

if (*continuation_table_ptr_loc).is_ptr() {
// TODO: No need to check if continuation table is already marked
mark_object(mem, *continuation_table_ptr_loc, heap_base);
mark_object(mem, *continuation_table_ptr_loc);
// Similar to `mark_root_mutbox_fields`, `continuation_table_ptr_loc` is in static heap so
// it will be readable when we unthread continuation table
// it will be readable when we unthread the continuation table
thread(continuation_table_ptr_loc);
}

Expand All @@ -125,21 +127,21 @@ unsafe fn mark_static_roots<M: Memory>(mem: &mut M, static_roots: Value, heap_ba
// Static objects are not in the dynamic heap so don't need marking.
for i in 0..root_array.len() {
let obj = root_array.get(i).as_obj();
// Root array should only has pointers to other static MutBoxes
// Root array should only have pointers to other static MutBoxes
debug_assert_eq!(obj.tag(), TAG_MUTBOX); // check tag
debug_assert!((obj as u32) < heap_base); // check that MutBox is static
mark_root_mutbox_fields(mem, obj as *mut MutBox, heap_base);
}
}

unsafe fn mark_object<M: Memory>(mem: &mut M, obj: Value, heap_base: u32) {
unsafe fn mark_object<M: Memory>(mem: &mut M, obj: Value) {
let obj_tag = obj.tag();
let obj = obj.get_ptr() as u32;

// Check object alignment to avoid undefined behavior. See also static_checks module.
debug_assert_eq!(obj % WORD_SIZE, 0);

let obj_idx = (obj - heap_base) / WORD_SIZE;
let obj_idx = obj / WORD_SIZE;

if get_bit(obj_idx) {
// Already marked
Expand All @@ -159,7 +161,7 @@ unsafe fn mark_stack<M: Memory>(mem: &mut M, heap_base: u32) {
unsafe fn mark_fields<M: Memory>(mem: &mut M, obj: *mut Obj, obj_tag: Tag, heap_base: u32) {
visit_pointer_fields(obj, obj_tag, heap_base as usize, |field_addr| {
let field_value = *field_addr;
mark_object(mem, field_value, heap_base);
mark_object(mem, field_value);

// Thread if backwards or self pointer
if field_value.get_ptr() <= obj as usize {
Expand All @@ -175,7 +177,7 @@ unsafe fn mark_root_mutbox_fields<M: Memory>(mem: &mut M, mutbox: *mut MutBox, h
if pointer_to_dynamic_heap(field_addr, heap_base as usize) {
// TODO: We should be able to omit the "already marked" check here as no two root MutBox
// can point to the same object (I think)
mark_object(mem, *field_addr, heap_base);
mark_object(mem, *field_addr);
// It's OK to thread forward pointers here as the static objects won't be moved, so we will
// be able to unthread objects pointed by these fields later.
thread(field_addr);
Expand All @@ -197,7 +199,7 @@ unsafe fn update_refs<SetHp: Fn(u32)>(set_hp: SetHp, heap_base: u32) {
let mut bitmap_iter = iter_bits();
let mut bit = bitmap_iter.next();
while bit != BITMAP_ITER_END {
let p = (heap_base + (bit * WORD_SIZE)) as *mut Obj;
let p = (bit * WORD_SIZE) as *mut Obj;
let p_new = free;

// Update backwards references to the object's new location and restore object header
Expand Down
Loading