Skip to content

Commit b9dc151

Browse files
authored
Work Packets (#136)
* Execute a simple work packet * Refactor * More progress * Progress to closure * Progress to the end of closures * Cleanup * Can finish one GC (and crash) * Working (with single-worker) * Refactor * Refactor: move scheduler code to a separate folder * Refactor: Remove generic type `VM: VMBinding` from scheduler types * Add scheduler tests * Support multiple worker threads for OpenJDK * WIP: Cleanup semispace * Finer granularity for root-scan works * Optimizations * Support parallel stack scanning and stack scanning before safepoints start * Update GC status correctly * Cleanup * Cleanup * Cleanup: Reduce unsafe * An implementation of GenCopy * Fix synchronization bug * Collect & report scheduler statistics * Print scheduler statistics in `scheduler` test * Only collect statistics for the timing iteration * Fix nogc build error * Fix buggy side mark-table * WIP: GenCopy barriers * GenCopy Sanity GC * Fix several bugs * Fix multi-worker synchronization error * Remove `object_reference_write` * Fix NoGC build error * Minor fix * Fix compile error * WIP: Fix errors after rebase onto PR#146 -- nogc/semispace working * Fix errors after rebase onto PR#146 -- nogc/semispace/gencopy working * Fix `ci-test` warnings and errors * WIP: Fix `ci-style` * cargo fmt * Cleanup * Support Sanity GC * Fix CI checks * Remove gencopy sanity gc (we support `feature="sanity"` now) * Optimizations * Fix * Store tls pointer to scheduler thread * Fix `SFTMap` * JikesRVM: Can finish one GC * Add a method to get the total number of worker threads * Clear references * Fix review comments * Add comments for gencopy's jikesrvm support * Move `MUTATOR_ITERATOR_LOCK` to BasePlan * Add comments to explain the use of raw pointers * Fix incorrect work-packet comparison * Fix cyclic reference: WorkerGroup -> Worker -> WorkerGroup * Reduce unsafe when accessing `coordinator_worker` * format * Add a feature to force single-threaded collection
1 parent 96855d2 commit b9dc151

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+2954
-2190
lines changed

.github/scripts/ci-style.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ cargo clippy --features nogc
99
cargo clippy --features nogc_lock_free
1010
cargo clippy --features nogc_no_zeroing
1111
cargo clippy --features semispace
12+
cargo clippy --features gencopy
1213
# check features
1314
cargo clippy --features nogc,sanity
1415
cargo clippy --features semispace,sanity
16+
cargo clippy --features gencopy,sanity
1517
cargo clippy --features nogc,vm_space,code_space,ro_space
1618
cargo clippy --features nogc,lockfreeimmortalspace
1719
cargo clippy --features semispace,vm_space,code_space,ro_space

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,19 @@ enum-map = "0.6.2"
2828
downcast-rs = "1.1.1"
2929
atomic-traits = "0.2.0"
3030
atomic = "0.4.6"
31+
spin = "0.5.2"
3132

3233
[dev-dependencies]
3334
crossbeam = "0.7.3"
35+
rand = "0.7.3"
3436

3537
[features]
3638
default = []
3739

3840
# plans
3941
nogc = ["immortalspace", "largeobjectspace"]
4042
semispace = ["immortalspace", "largeobjectspace", "copyspace"]
43+
gencopy = ["immortalspace", "largeobjectspace", "copyspace"]
4144

4245
# spaces
4346
base_spaces = []
@@ -54,3 +57,5 @@ sanity = []
5457
force_32bit_heap_layout = []
5558
nogc_lock_free = ["nogc", "lockfreeimmortalspace"]
5659
nogc_no_zeroing = ["nogc_lock_free"]
60+
61+
single_worker = []

src/lib.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(incomplete_features)]
12
#![feature(asm)]
23
#![feature(const_fn)]
34
#![feature(integer_atomics)]
@@ -6,6 +7,11 @@
67
#![feature(box_syntax)]
78
#![feature(maybe_uninit_ref)]
89
#![feature(maybe_uninit_extra)]
10+
#![feature(get_mut_unchecked)]
11+
#![feature(arbitrary_self_types)]
12+
#![feature(associated_type_defaults)]
13+
#![feature(specialization)]
14+
#![feature(trait_alias)]
915

1016
//! Memory Management ToolKit (MMTk) is a portable and high performance memory manager
1117
//! that includes various garbage collection algorithms and provides clean and efficient
@@ -51,14 +57,12 @@ mod mm;
5157
mod mmtk;
5258
mod plan;
5359
pub mod policy;
60+
pub mod scheduler;
5461
pub mod vm;
5562

5663
pub use crate::mm::memory_manager;
5764
pub use crate::mmtk::MMTK;
58-
pub use crate::plan::selected_plan::{
59-
SelectedCollector, SelectedConstraints, SelectedPlan, SelectedTraceLocal,
60-
};
65+
pub use crate::plan::selected_plan::{SelectedConstraints, SelectedPlan};
6166
pub use crate::plan::{
62-
Allocator, CollectorContext, Mutator, MutatorContext, ParallelCollector, Plan, TraceLocal,
63-
TransitiveClosure,
67+
Allocator, CopyContext, Mutator, MutatorContext, Plan, TraceLocal, TransitiveClosure,
6468
};

src/mm/memory_manager.rs

Lines changed: 21 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
use std::sync::atomic::Ordering;
22

33
use crate::plan::mutator_context::{Mutator, MutatorContext};
4-
use crate::plan::transitive_closure::TransitiveClosure;
5-
use crate::plan::CollectorContext;
64
use crate::plan::Plan;
7-
use crate::plan::TraceLocal;
5+
use crate::scheduler::GCWorker;
86

97
use crate::vm::Collection;
108

@@ -14,7 +12,6 @@ use self::selected_plan::SelectedPlan;
1412
use crate::plan::selected_plan;
1513
use crate::util::alloc::allocators::AllocatorSelector;
1614

17-
use self::selected_plan::{SelectedCollector, SelectedTraceLocal};
1815
use crate::mmtk::MMTK;
1916
use crate::plan::Allocator;
2017
use crate::util::constants::LOG_BYTES_IN_PAGE;
@@ -43,29 +40,28 @@ pub fn start_control_collector<VM: VMBinding>(mmtk: &MMTK<VM>, tls: OpaquePointe
4340
mmtk.plan.base().control_collector_context.run(tls);
4441
}
4542

46-
pub fn gc_init<VM: VMBinding>(mmtk: &MMTK<VM>, heap_size: usize) {
43+
pub fn gc_init<VM: VMBinding>(mmtk: &'static mut MMTK<VM>, heap_size: usize) {
4744
crate::util::logger::init().unwrap();
48-
mmtk.plan.gc_init(heap_size, &mmtk.vm_map);
49-
50-
// TODO: We should have an option so we know whether we should spawn the controller.
51-
// thread::spawn(|| {
52-
// SINGLETON.plan.common().control_collector_context.run(UNINITIALIZED_OPAQUE_POINTER )
53-
// });
45+
mmtk.plan.gc_init(heap_size, &mmtk.vm_map, &mmtk.scheduler);
5446
}
5547

5648
pub fn bind_mutator<VM: VMBinding>(
5749
mmtk: &'static MMTK<VM>,
5850
tls: OpaquePointer,
59-
) -> Box<Mutator<VM, SelectedPlan<VM>>> {
60-
SelectedPlan::bind_mutator(&mmtk.plan, tls)
51+
) -> Box<Mutator<SelectedPlan<VM>>> {
52+
SelectedPlan::bind_mutator(&mmtk.plan, tls, mmtk)
6153
}
6254

63-
pub fn destroy_mutator<VM: VMBinding>(mutator: Box<Mutator<VM, SelectedPlan<VM>>>) {
55+
pub fn destroy_mutator<VM: VMBinding>(mutator: Box<Mutator<SelectedPlan<VM>>>) {
6456
drop(mutator);
6557
}
6658

59+
pub fn flush_mutator<VM: VMBinding>(mutator: &mut Mutator<SelectedPlan<VM>>) {
60+
mutator.flush()
61+
}
62+
6763
pub fn alloc<VM: VMBinding>(
68-
mutator: &mut Mutator<VM, SelectedPlan<VM>>,
64+
mutator: &mut Mutator<SelectedPlan<VM>>,
6965
size: usize,
7066
align: usize,
7167
offset: isize,
@@ -75,7 +71,7 @@ pub fn alloc<VM: VMBinding>(
7571
}
7672

7773
pub fn post_alloc<VM: VMBinding>(
78-
mutator: &mut Mutator<VM, SelectedPlan<VM>>,
74+
mutator: &mut Mutator<SelectedPlan<VM>>,
7975
refer: ObjectReference,
8076
type_refer: ObjectReference,
8177
bytes: usize,
@@ -92,102 +88,19 @@ pub fn get_allocator_mapping<VM: VMBinding>(
9288
mmtk.plan.get_allocator_mapping()[allocator]
9389
}
9490

95-
// The parameter 'trace_local' could either be &mut SelectedTraceLocal or &mut SanityChecker.
96-
// Ideally we should make 'trace_local' as a trait object - &mut TraceLocal. However, this is a fat
97-
// pointer, and it would appear in our API (and possibly in native API), which imposes inconvenience
98-
// to store and pass around a fat pointer. Thus, we just assume it is &mut SelectedTraceLocal,
99-
// and use unsafe transmute when we know it is a SanityChcker ref.
100-
#[cfg(feature = "sanity")]
101-
pub fn report_delayed_root_edge<VM: VMBinding>(
102-
mmtk: &MMTK<VM>,
103-
trace_local: &mut SelectedTraceLocal<VM>,
104-
addr: Address,
105-
) {
106-
use crate::util::sanity::sanity_checker::SanityChecker;
107-
if mmtk.plan.is_in_sanity() {
108-
let sanity_checker: &mut SanityChecker<VM> =
109-
unsafe { &mut *(trace_local as *mut SelectedTraceLocal<VM> as *mut SanityChecker<VM>) };
110-
sanity_checker.report_delayed_root_edge(addr);
111-
} else {
112-
trace_local.report_delayed_root_edge(addr)
113-
}
114-
}
115-
#[cfg(not(feature = "sanity"))]
116-
pub fn report_delayed_root_edge<VM: VMBinding>(
117-
_: &MMTK<VM>,
118-
trace_local: &mut SelectedTraceLocal<VM>,
119-
addr: Address,
120-
) {
121-
trace_local.report_delayed_root_edge(addr);
122-
}
123-
124-
#[cfg(feature = "sanity")]
125-
pub fn will_not_move_in_current_collection<VM: VMBinding>(
126-
mmtk: &MMTK<VM>,
127-
trace_local: &mut SelectedTraceLocal<VM>,
128-
obj: ObjectReference,
129-
) -> bool {
130-
use crate::util::sanity::sanity_checker::SanityChecker;
131-
if mmtk.plan.is_in_sanity() {
132-
let sanity_checker: &mut SanityChecker<VM> =
133-
unsafe { &mut *(trace_local as *mut SelectedTraceLocal<VM> as *mut SanityChecker<VM>) };
134-
sanity_checker.will_not_move_in_current_collection(obj)
135-
} else {
136-
trace_local.will_not_move_in_current_collection(obj)
137-
}
138-
}
139-
#[cfg(not(feature = "sanity"))]
140-
pub fn will_not_move_in_current_collection<VM: VMBinding>(
141-
_: &MMTK<VM>,
142-
trace_local: &mut SelectedTraceLocal<VM>,
143-
obj: ObjectReference,
144-
) -> bool {
145-
trace_local.will_not_move_in_current_collection(obj)
146-
}
147-
148-
#[cfg(feature = "sanity")]
149-
pub fn process_interior_edge<VM: VMBinding>(
150-
mmtk: &MMTK<VM>,
151-
trace_local: &mut SelectedTraceLocal<VM>,
152-
target: ObjectReference,
153-
slot: Address,
154-
root: bool,
155-
) {
156-
use crate::util::sanity::sanity_checker::SanityChecker;
157-
if mmtk.plan.is_in_sanity() {
158-
let sanity_checker: &mut SanityChecker<VM> =
159-
unsafe { &mut *(trace_local as *mut SelectedTraceLocal<VM> as *mut SanityChecker<VM>) };
160-
sanity_checker.process_interior_edge(target, slot, root)
161-
} else {
162-
trace_local.process_interior_edge(target, slot, root)
163-
}
164-
}
165-
#[cfg(not(feature = "sanity"))]
166-
pub fn process_interior_edge<VM: VMBinding>(
167-
_: &MMTK<VM>,
168-
trace_local: &mut SelectedTraceLocal<VM>,
169-
target: ObjectReference,
170-
slot: Address,
171-
root: bool,
91+
pub fn start_worker<VM: VMBinding>(
92+
tls: OpaquePointer,
93+
worker: &'static mut GCWorker<VM>,
94+
mmtk: &'static MMTK<VM>,
17295
) {
173-
trace_local.process_interior_edge(target, slot, root)
174-
}
175-
176-
pub fn start_worker<VM: VMBinding>(tls: OpaquePointer, worker: &mut SelectedCollector<VM>) {
17796
worker.init(tls);
178-
worker.run(tls);
97+
worker.run(mmtk);
17998
}
18099

181100
pub fn enable_collection<VM: VMBinding>(mmtk: &'static MMTK<VM>, tls: OpaquePointer) {
182-
unsafe {
183-
{ &mut *mmtk.plan.base().control_collector_context.workers.get() }.init_group(mmtk, tls);
184-
{
185-
VM::VMCollection::spawn_worker_thread::<<SelectedPlan<VM> as Plan<VM>>::CollectorT>(
186-
tls, None,
187-
);
188-
} // spawn controller thread
189-
mmtk.plan.base().initialized.store(true, Ordering::SeqCst);
190-
}
101+
mmtk.scheduler.initialize(mmtk.options.threads, mmtk, tls);
102+
VM::VMCollection::spawn_worker_thread(tls, None); // spawn controller thread
103+
mmtk.plan.base().initialized.store(true, Ordering::SeqCst);
191104
}
192105

193106
pub fn process<VM: VMBinding>(mmtk: &'static MMTK<VM>, name: &str, value: &str) -> bool {
@@ -219,41 +132,6 @@ pub fn scan_region() {
219132
crate::util::sanity::memory_scan::scan_region();
220133
}
221134

222-
pub fn trace_get_forwarded_referent<VM: VMBinding>(
223-
trace_local: &mut SelectedTraceLocal<VM>,
224-
object: ObjectReference,
225-
) -> ObjectReference {
226-
trace_local.get_forwarded_reference(object)
227-
}
228-
229-
pub fn trace_get_forwarded_reference<VM: VMBinding>(
230-
trace_local: &mut SelectedTraceLocal<VM>,
231-
object: ObjectReference,
232-
) -> ObjectReference {
233-
trace_local.get_forwarded_reference(object)
234-
}
235-
236-
pub fn trace_root_object<VM: VMBinding>(
237-
trace_local: &mut SelectedTraceLocal<VM>,
238-
object: ObjectReference,
239-
) -> ObjectReference {
240-
trace_local.trace_object(object)
241-
}
242-
243-
pub extern "C" fn process_edge<VM: VMBinding>(
244-
trace_local: &mut SelectedTraceLocal<VM>,
245-
object: Address,
246-
) {
247-
trace_local.process_edge(object);
248-
}
249-
250-
pub fn trace_retain_referent<VM: VMBinding>(
251-
trace_local: &mut SelectedTraceLocal<VM>,
252-
object: ObjectReference,
253-
) -> ObjectReference {
254-
trace_local.retain_referent(object)
255-
}
256-
257135
pub fn handle_user_collection_request<VM: VMBinding>(mmtk: &MMTK<VM>, tls: OpaquePointer) {
258136
mmtk.plan.handle_user_collection_request(tls, false);
259137
}
@@ -305,6 +183,6 @@ pub fn harness_begin<VM: VMBinding>(mmtk: &MMTK<VM>, tls: OpaquePointer) {
305183
mmtk.harness_begin(tls);
306184
}
307185

308-
pub fn harness_end<VM: VMBinding>(mmtk: &MMTK<VM>) {
186+
pub fn harness_end<VM: VMBinding>(mmtk: &'static MMTK<VM>) {
309187
mmtk.harness_end();
310188
}

src/mmtk.rs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
1-
use crate::plan::phase::PhaseManager;
21
use crate::plan::Plan;
32
use crate::plan::SelectedPlan;
43
use crate::policy::space::SFTMap;
4+
use crate::scheduler::Scheduler;
55
use crate::util::heap::layout::heap_layout::Mmapper;
66
use crate::util::heap::layout::heap_layout::VMMap;
7-
use crate::util::OpaquePointer;
8-
7+
use crate::util::heap::layout::map::Map;
98
use crate::util::options::{Options, UnsafeOptionsWrapper};
109
use crate::util::reference_processor::ReferenceProcessors;
10+
#[cfg(feature = "sanity")]
11+
use crate::util::sanity::sanity_checker::SanityChecker;
12+
use crate::util::OpaquePointer;
13+
use crate::vm::VMBinding;
1114
use std::default::Default;
1215
use std::sync::atomic::{AtomicBool, Ordering};
13-
14-
use crate::util::heap::layout::map::Map;
15-
use crate::vm::VMBinding;
1616
use std::sync::Arc;
17+
#[cfg(feature = "sanity")]
18+
use std::sync::Mutex;
1719

1820
// TODO: remove this singleton at some point to allow multiple instances of MMTK
1921
// This helps refactoring.
@@ -32,29 +34,37 @@ lazy_static! {
3234

3335
pub struct MMTK<VM: VMBinding> {
3436
pub plan: SelectedPlan<VM>,
35-
pub phase_manager: PhaseManager,
3637
pub vm_map: &'static VMMap,
3738
pub mmapper: &'static Mmapper,
3839
pub sftmap: &'static SFTMap,
3940
pub reference_processors: ReferenceProcessors,
4041
pub options: Arc<UnsafeOptionsWrapper>,
41-
42+
pub scheduler: Arc<Scheduler<Self>>,
43+
#[cfg(feature = "sanity")]
44+
pub sanity_checker: Mutex<SanityChecker>,
4245
inside_harness: AtomicBool,
4346
}
4447

48+
unsafe impl<VM: VMBinding> Send for MMTK<VM> {}
49+
unsafe impl<VM: VMBinding> Sync for MMTK<VM> {}
50+
4551
impl<VM: VMBinding> MMTK<VM> {
4652
pub fn new() -> Self {
53+
let scheduler = Scheduler::new();
4754
let options = Arc::new(UnsafeOptionsWrapper::new(Options::default()));
48-
let plan = SelectedPlan::new(&VM_MAP, &MMAPPER, options.clone());
49-
let phase_manager = PhaseManager::new(&plan.base().stats);
55+
let plan = SelectedPlan::new(&VM_MAP, &MMAPPER, options.clone(), unsafe {
56+
&*(scheduler.as_ref() as *const Scheduler<MMTK<VM>>)
57+
});
5058
MMTK {
5159
plan,
52-
phase_manager,
5360
vm_map: &VM_MAP,
5461
mmapper: &MMAPPER,
5562
sftmap: &SFT_MAP,
5663
reference_processors: ReferenceProcessors::new(),
5764
options,
65+
scheduler,
66+
#[cfg(feature = "sanity")]
67+
sanity_checker: Mutex::new(SanityChecker::new()),
5868
inside_harness: AtomicBool::new(false),
5969
}
6070
}
@@ -64,10 +74,11 @@ impl<VM: VMBinding> MMTK<VM> {
6474
self.plan.handle_user_collection_request(tls, true);
6575
self.inside_harness.store(true, Ordering::SeqCst);
6676
self.plan.base().stats.start_all();
77+
self.scheduler.enable_stat();
6778
}
6879

69-
pub fn harness_end(&self) {
70-
self.plan.base().stats.stop_all();
80+
pub fn harness_end(&'static self) {
81+
self.plan.base().stats.stop_all(self);
7182
self.inside_harness.store(false, Ordering::SeqCst);
7283
}
7384
}

0 commit comments

Comments
 (0)