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
12 changes: 9 additions & 3 deletions src/plan/generational/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,13 @@ impl<VM: VMBinding> CommonGenPlan<VM> {
args.get_space_args(
"nursery",
true,
VMRequest::fixed_extent(args.global_args.options.get_max_nursery_bytes(), false),
VMRequest::fixed_extent(
args.global_args
.options
.nursery
.estimate_virtual_memory_in_bytes(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may make use of VMRequest::fraction if it is appropriate.

false,
),
),
true,
);
Expand Down Expand Up @@ -102,7 +108,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 +267,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
65 changes: 63 additions & 2 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 @@ -104,6 +109,62 @@ impl<VM: VMBinding> GCTrigger<VM> {
let plan = unsafe { self.plan.assume_init() };
qinsoon marked this conversation as resolved.
Show resolved Hide resolved
self.policy.is_heap_full(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 max_bytes =
conversions::pages_to_bytes(self.policy.get_current_heap_size_in_pages())
as f64
* max;
qinsoon marked this conversation as resolved.
Show resolved Hide resolved
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())
}
}

/// Provides statistics about the space. This is exposed to bindings, as it is used
Expand Down Expand Up @@ -433,7 +494,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