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

Allow nursery size to be proportional to the heap size #1087

Merged
merged 13 commits into from
Apr 17, 2024
Merged
10 changes: 3 additions & 7 deletions src/plan/generational/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,7 @@ pub struct CommonGenPlan<VM: VMBinding> {
impl<VM: VMBinding> CommonGenPlan<VM> {
pub fn new(mut args: CreateSpecificPlanArgs<VM>) -> Self {
let nursery = CopySpace::new(
args.get_space_args(
"nursery",
true,
VMRequest::fixed_extent(args.global_args.options.get_max_nursery_bytes(), false),
),
args.get_space_args("nursery", true, VMRequest::discontiguous()),
true,
);
let full_heap_gc_count = args
Expand Down Expand Up @@ -102,7 +98,7 @@ impl<VM: VMBinding> CommonGenPlan<VM> {
space: Option<SpaceStats<VM>>,
) -> bool {
let cur_nursery = self.nursery.reserved_pages();
let max_nursery = self.common.base.options.get_max_nursery_pages();
let max_nursery = self.common.base.gc_trigger.get_max_nursery_pages();
let nursery_full = cur_nursery >= max_nursery;
trace!(
"nursery_full = {:?} (nursery = {}, max_nursery = {})",
Expand Down Expand Up @@ -261,7 +257,7 @@ impl<VM: VMBinding> CommonGenPlan<VM> {
/// whose value depends on which spaces have been released.
pub fn should_next_gc_be_full_heap(plan: &dyn Plan<VM = VM>) -> bool {
let available = plan.get_available_pages();
let min_nursery = plan.base().options.get_min_nursery_pages();
let min_nursery = plan.base().gc_trigger.get_min_nursery_pages();
let next_gc_full_heap = available < min_nursery;
trace!(
"next gc will be full heap? {}, available pages = {}, min nursery = {}",
Expand Down
4 changes: 1 addition & 3 deletions src/plan/generational/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,8 @@ pub const GEN_CONSTRAINTS: PlanConstraints = PlanConstraints {
barrier: ACTIVE_BARRIER,
// We may trace duplicate edges in sticky immix (or any plan that uses object remembering barrier). See https://github.com/mmtk/mmtk-core/issues/743.
may_trace_duplicate_edges: ACTIVE_BARRIER.equals(BarrierSelector::ObjectBarrier),
max_non_los_default_alloc_bytes: crate::util::rust_util::min_of_usize(
max_non_los_default_alloc_bytes:
crate::plan::plan_constraints::MAX_NON_LOS_ALLOC_BYTES_COPYING_PLAN,
crate::util::options::NURSERY_SIZE,
),
needs_prepare_mutator: false,
..PlanConstraints::default()
};
Expand Down
4 changes: 2 additions & 2 deletions src/plan/sticky/immix/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ impl<VM: VMBinding> Plan for StickyImmix<VM> {
}

fn collection_required(&self, space_full: bool, space: Option<SpaceStats<Self::VM>>) -> bool {
let nursery_full =
self.immix.immix_space.get_pages_allocated() > self.options().get_max_nursery_pages();
let nursery_full = self.immix.immix_space.get_pages_allocated()
> self.base().gc_trigger.get_max_nursery_pages();
if space_full
&& space.is_some()
&& space.as_ref().unwrap().0.name() != self.immix.immix_space.name()
Expand Down
67 changes: 63 additions & 4 deletions src/util/heap/gc_trigger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ use crate::global_state::GlobalState;
use crate::plan::gc_requester::GCRequester;
use crate::plan::Plan;
use crate::policy::space::Space;
use crate::util::constants::BYTES_IN_PAGE;
use crate::util::conversions;
use crate::util::options::{GCTriggerSelector, Options};
use crate::util::options::{GCTriggerSelector, Options, DEFAULT_MAX_NURSERY, DEFAULT_MIN_NURSERY};
use crate::vm::VMBinding;
use crate::MMTK;
use std::mem::MaybeUninit;
Expand Down Expand Up @@ -58,6 +59,10 @@ impl<VM: VMBinding> GCTrigger<VM> {
self.plan.write(plan);
}

fn plan(&self) -> &dyn Plan<VM = VM> {
unsafe { self.plan.assume_init() }
}

/// This method is called periodically by the allocation subsystem
/// (by default, each time a page is consumed), and provides the
/// collector with an opportunity to collect.
Expand Down Expand Up @@ -101,8 +106,62 @@ impl<VM: VMBinding> GCTrigger<VM> {

/// Check if the heap is full
pub fn is_heap_full(&self) -> bool {
let plan = unsafe { self.plan.assume_init() };
self.policy.is_heap_full(plan)
self.policy.is_heap_full(self.plan())
}

/// Return upper bound of the nursery size (in number of bytes)
pub fn get_max_nursery_bytes(&self) -> usize {
use crate::util::options::NurserySize;
debug_assert!(self.plan().generational().is_some());
match *self.options.nursery {
NurserySize::Bounded { min: _, max } => max,
NurserySize::ProportionalBounded { min: _, max } => {
let heap_size_bytes =
conversions::pages_to_bytes(self.policy.get_current_heap_size_in_pages());
let max_bytes = heap_size_bytes as f64 * max;
let max_bytes = conversions::raw_align_up(max_bytes as usize, BYTES_IN_PAGE);
if max_bytes > DEFAULT_MAX_NURSERY {
warn!("Proportional nursery with max size {} ({}) is larger than DEFAULT_MAX_NURSERY ({}). Use DEFAULT_MAX_NURSERY instead.", max, max_bytes, DEFAULT_MAX_NURSERY);
DEFAULT_MAX_NURSERY
} else {
max_bytes
}
}
NurserySize::Fixed(sz) => sz,
}
}

/// Return lower bound of the nursery size (in number of bytes)
pub fn get_min_nursery_bytes(&self) -> usize {
use crate::util::options::NurserySize;
debug_assert!(self.plan().generational().is_some());
match *self.options.nursery {
NurserySize::Bounded { min, max: _ } => min,
NurserySize::ProportionalBounded { min, max: _ } => {
let min_bytes =
conversions::pages_to_bytes(self.policy.get_current_heap_size_in_pages())
as f64
* min;
let min_bytes = conversions::raw_align_up(min_bytes as usize, BYTES_IN_PAGE);
if min_bytes < DEFAULT_MIN_NURSERY {
warn!("Proportional nursery with min size {} ({}) is smaller than DEFAULT_MIN_NURSERY ({}). Use DEFAULT_MIN_NURSERY instead.", min, min_bytes, DEFAULT_MIN_NURSERY);
DEFAULT_MIN_NURSERY
} else {
min_bytes
}
}
NurserySize::Fixed(sz) => sz,
}
}

/// Return upper bound of the nursery size (in number of pages)
pub fn get_max_nursery_pages(&self) -> usize {
crate::util::conversions::bytes_to_pages_up(self.get_max_nursery_bytes())
}

/// Return lower bound of the nursery size (in number of pages)
pub fn get_min_nursery_pages(&self) -> usize {
crate::util::conversions::bytes_to_pages_up(self.get_min_nursery_bytes())
}
}

Expand Down Expand Up @@ -433,7 +492,7 @@ impl<VM: VMBinding> GCTriggerPolicy<VM> for MemBalancerTrigger {
// We reserve an extra of min nursery. This ensures that we will not trigger
// a full heap GC in the next GC (if available pages is smaller than min nursery, we will force a full heap GC)
mmtk.get_plan().get_collection_reserved_pages()
+ mmtk.options.get_min_nursery_pages(),
+ mmtk.gc_trigger.get_min_nursery_pages(),
stats,
);
}
Expand Down
Loading
Loading