< prev index next >
src/hotspot/share/gc/g1/g1Policy.cpp
Print this page
rev 60060 : [mq]: 8210462-lkorinth-review
@@ -72,11 +72,11 @@
_free_regions_at_end_of_collection(0),
_rs_length(0),
_rs_length_prediction(0),
_pending_cards_at_gc_start(0),
_old_gen_alloc_tracker(),
- _initial_mark_to_mixed(),
+ _concurrent_start_to_mixed(),
_collection_set(NULL),
_g1h(NULL),
_phase_times(new G1GCPhaseTimes(gc_timer, ParallelGCThreads)),
_mark_remark_start_sec(0),
_mark_cleanup_start_sec(0),
@@ -446,11 +446,11 @@
// "Nuke" the heuristics that control the young/mixed GC
// transitions and make sure we start with young GCs after the Full GC.
collector_state()->set_in_young_only_phase(true);
collector_state()->set_in_young_gc_before_mixed(false);
collector_state()->set_initiate_conc_mark_if_possible(need_to_start_conc_mark("end of Full GC", 0));
- collector_state()->set_in_initial_mark_gc(false);
+ collector_state()->set_in_concurrent_start_gc(false);
collector_state()->set_mark_or_rebuild_in_progress(false);
collector_state()->set_clearing_next_bitmap(false);
_eden_surv_rate_group->start_adding_regions();
// also call this on any additional surv rate groups
@@ -542,11 +542,11 @@
assert(_g1h->collection_set()->verify_young_ages(), "region age verification failed");
}
void G1Policy::record_concurrent_mark_init_end(double mark_init_elapsed_time_ms) {
assert(!collector_state()->initiate_conc_mark_if_possible(), "we should have cleared it by now");
- collector_state()->set_in_initial_mark_gc(false);
+ collector_state()->set_in_concurrent_start_gc(false);
}
void G1Policy::record_concurrent_mark_remark_start() {
_mark_remark_start_sec = os::elapsedTime();
}
@@ -630,21 +630,19 @@
void G1Policy::record_collection_pause_end(double pause_time_ms) {
G1GCPhaseTimes* p = phase_times();
double end_time_sec = os::elapsedTime();
- bool this_pause_included_initial_mark = false;
- bool this_pause_was_young_only = collector_state()->in_young_only_phase();
+ PauseKind this_pause = young_gc_pause_kind();
bool update_stats = !_g1h->evacuation_failed();
- record_pause(young_gc_pause_kind(), end_time_sec - pause_time_ms / 1000.0, end_time_sec);
+ record_pause(this_pause, end_time_sec - pause_time_ms / 1000.0, end_time_sec);
_collection_pause_end_millis = os::javaTimeNanos() / NANOSECS_PER_MILLISEC;
- this_pause_included_initial_mark = collector_state()->in_initial_mark_gc();
- if (this_pause_included_initial_mark) {
+ if (is_concurrent_start_pause(this_pause)) {
record_concurrent_mark_init_end(0.0);
} else {
maybe_start_marking();
}
@@ -671,18 +669,19 @@
_analytics->compute_pause_time_ratios(end_time_sec, pause_time_ms);
_analytics->update_recent_gc_times(end_time_sec, pause_time_ms);
}
- if (collector_state()->in_young_gc_before_mixed()) {
- assert(!this_pause_included_initial_mark, "The young GC before mixed is not allowed to be an initial mark GC");
+ if (is_last_young_pause(this_pause)) {
+ assert(!is_concurrent_start_pause(this_pause),
+ "The young GC before mixed is not allowed to be concurrent start GC");
// This has been the young GC before we start doing mixed GCs. We already
// decided to start mixed GCs much earlier, so there is nothing to do except
// advancing the state.
collector_state()->set_in_young_only_phase(false);
collector_state()->set_in_young_gc_before_mixed(false);
- } else if (!this_pause_was_young_only) {
+ } else if (!is_young_only_pause(this_pause)) {
// This is a mixed GC. Here we decide whether to continue doing more
// mixed GCs or not.
if (!next_gc_should_be_mixed("continue mixed GCs",
"do not continue mixed GCs")) {
collector_state()->set_in_young_only_phase(true);
@@ -711,22 +710,24 @@
double avg_time_merge_cards = average_time_ms(G1GCPhaseTimes::MergeER) +
average_time_ms(G1GCPhaseTimes::MergeRS) +
average_time_ms(G1GCPhaseTimes::MergeHCC) +
average_time_ms(G1GCPhaseTimes::MergeLB) +
average_time_ms(G1GCPhaseTimes::OptMergeRS);
- _analytics->report_cost_per_card_merge_ms(avg_time_merge_cards / total_cards_merged, this_pause_was_young_only);
+ _analytics->report_cost_per_card_merge_ms(avg_time_merge_cards / total_cards_merged,
+ is_young_only_pause(this_pause));
}
// Update prediction for card scan
size_t const total_cards_scanned = p->sum_thread_work_items(G1GCPhaseTimes::ScanHR, G1GCPhaseTimes::ScanHRScannedCards) +
p->sum_thread_work_items(G1GCPhaseTimes::OptScanHR, G1GCPhaseTimes::ScanHRScannedCards);
if (total_cards_scanned > CardsNumSamplingThreshold) {
double avg_time_dirty_card_scan = average_time_ms(G1GCPhaseTimes::ScanHR) +
average_time_ms(G1GCPhaseTimes::OptScanHR);
- _analytics->report_cost_per_card_scan_ms(avg_time_dirty_card_scan / total_cards_scanned, this_pause_was_young_only);
+ _analytics->report_cost_per_card_scan_ms(avg_time_dirty_card_scan / total_cards_scanned,
+ is_young_only_pause(this_pause));
}
// Update prediction for the ratio between cards from the remembered
// sets and actually scanned cards from the remembered sets.
// Cards from the remembered sets are all cards not duplicated by cards from
@@ -736,11 +737,12 @@
const size_t from_rs_length_cards = (total_cards_scanned > total_log_buffer_cards) ? total_cards_scanned - total_log_buffer_cards : 0;
double merge_to_scan_ratio = 0.0;
if (total_cards_scanned > 0) {
merge_to_scan_ratio = (double) from_rs_length_cards / total_cards_scanned;
}
- _analytics->report_card_merge_to_scan_ratio(merge_to_scan_ratio, this_pause_was_young_only);
+ _analytics->report_card_merge_to_scan_ratio(merge_to_scan_ratio,
+ is_young_only_pause(this_pause));
const size_t recorded_rs_length = _collection_set->recorded_rs_length();
const size_t rs_length_diff = _rs_length > recorded_rs_length ? _rs_length - recorded_rs_length : 0;
_analytics->report_rs_length_diff(rs_length_diff);
@@ -766,19 +768,19 @@
// Do not update RS lengths and the number of pending cards with information from mixed gc:
// these are is wildly different to during young only gc and mess up young gen sizing right
// after the mixed gc phase.
// During mixed gc we do not use them for young gen sizing.
- if (this_pause_was_young_only) {
+ if (is_young_only_pause(this_pause)) {
_analytics->report_pending_cards((double) _pending_cards_at_gc_start);
_analytics->report_rs_length((double) _rs_length);
}
}
- assert(!(this_pause_included_initial_mark && collector_state()->mark_or_rebuild_in_progress()),
- "If the last pause has been an initial mark, we should not have been in the marking window");
- if (this_pause_included_initial_mark) {
+ assert(!(is_concurrent_start_pause(this_pause) && collector_state()->mark_or_rebuild_in_progress()),
+ "If the last pause has been concurrent start, we should not have been in the marking window");
+ if (is_concurrent_start_pause(this_pause)) {
collector_state()->set_mark_or_rebuild_in_progress(true);
}
_free_regions_at_end_of_collection = _g1h->num_free_regions();
@@ -795,21 +797,21 @@
_old_gen_alloc_tracker.reset_after_young_gc(app_time_ms / 1000.0);
update_ihop_prediction(_old_gen_alloc_tracker.last_cycle_duration(),
_old_gen_alloc_tracker.last_cycle_old_bytes(),
last_unrestrained_young_length * HeapRegion::GrainBytes,
- this_pause_was_young_only);
+ is_young_only_pause(this_pause));
_ihop_control->send_trace_event(_g1h->gc_tracer_stw());
} else {
// Any garbage collection triggered as periodic collection resets the time-to-mixed
// measurement. Periodic collection typically means that the application is "inactive", i.e.
// the marking threads may have received an uncharacterisic amount of cpu time
// for completing the marking, i.e. are faster than expected.
// This skews the predicted marking length towards smaller values which might cause
// the mark start being too late.
- _initial_mark_to_mixed.reset();
+ _concurrent_start_to_mixed.reset();
}
// Note that _mmu_tracker->max_gc_time() returns the time in seconds.
double scan_logged_cards_time_goal_ms = _mmu_tracker->max_gc_time() * MILLIUNITS * G1RSetUpdatingPauseTimePercent / 100.0;
@@ -856,14 +858,14 @@
double const min_valid_time = 1e-6;
bool report = false;
double marking_to_mixed_time = -1.0;
- if (!this_gc_was_young_only && _initial_mark_to_mixed.has_result()) {
- marking_to_mixed_time = _initial_mark_to_mixed.last_marking_time();
+ if (!this_gc_was_young_only && _concurrent_start_to_mixed.has_result()) {
+ marking_to_mixed_time = _concurrent_start_to_mixed.last_marking_time();
assert(marking_to_mixed_time > 0.0,
- "Initial mark to mixed time must be larger than zero but is %.3f",
+ "Concurrent start to mixed time must be larger than zero but is %.3f",
marking_to_mixed_time);
if (marking_to_mixed_time > min_valid_time) {
_ihop_control->update_marking_length(marking_to_mixed_time);
report = true;
}
@@ -1015,39 +1017,43 @@
// be allocated into.
_max_survivor_regions = MIN2(desired_max_survivor_regions,
_g1h->num_free_or_available_regions());
}
-bool G1Policy::force_initial_mark_if_outside_cycle(GCCause::Cause gc_cause) {
+bool G1Policy::force_concurrent_start_if_outside_cycle(GCCause::Cause gc_cause) {
// We actually check whether we are marking here and not if we are in a
// reclamation phase. This means that we will schedule a concurrent mark
// even while we are still in the process of reclaiming memory.
bool during_cycle = _g1h->concurrent_mark()->cm_thread()->during_cycle();
if (!during_cycle) {
- log_debug(gc, ergo)("Request concurrent cycle initiation (requested by GC cause). GC cause: %s", GCCause::to_string(gc_cause));
+ log_debug(gc, ergo)("Request concurrent cycle initiation (requested by GC cause). "
+ "GC cause: %s",
+ GCCause::to_string(gc_cause));
collector_state()->set_initiate_conc_mark_if_possible(true);
return true;
} else {
- log_debug(gc, ergo)("Do not request concurrent cycle initiation (concurrent cycle already in progress). GC cause: %s", GCCause::to_string(gc_cause));
+ log_debug(gc, ergo)("Do not request concurrent cycle initiation "
+ "(concurrent cycle already in progress). GC cause: %s",
+ GCCause::to_string(gc_cause));
return false;
}
}
void G1Policy::initiate_conc_mark() {
- collector_state()->set_in_initial_mark_gc(true);
+ collector_state()->set_in_concurrent_start_gc(true);
collector_state()->set_initiate_conc_mark_if_possible(false);
}
void G1Policy::decide_on_conc_mark_initiation() {
- // We are about to decide on whether this pause will be an
- // initial-mark pause.
+ // We are about to decide on whether this pause will be a
+ // concurrent start pause.
- // First, collector_state()->in_initial_mark_gc() should not be already set. We
+ // First, collector_state()->in_concurrent_start_gc() should not be already set. We
// will set it here if we have to. However, it should be cleared by
- // the end of the pause (it's only set for the duration of an
- // initial-mark pause).
- assert(!collector_state()->in_initial_mark_gc(), "pre-condition");
+ // the end of the pause (it's only set for the duration of a
+ // concurrent start pause).
+ assert(!collector_state()->in_concurrent_start_gc(), "pre-condition");
if (collector_state()->initiate_conc_mark_if_possible()) {
// We had noticed on a previous pause that the heap occupancy has
// gone over the initiating threshold and we should start a
// concurrent marking cycle. Or we've been explicitly requested
@@ -1057,17 +1063,17 @@
GCCause::Cause cause = _g1h->gc_cause();
if ((cause != GCCause::_wb_breakpoint) &&
ConcurrentGCBreakpoints::is_controlled()) {
log_debug(gc, ergo)("Do not initiate concurrent cycle (whitebox controlled)");
} else if (!about_to_start_mixed_phase() && collector_state()->in_young_only_phase()) {
- // Initiate a new initial mark if there is no marking or reclamation going on.
+ // Initiate a new concurrent start if there is no marking or reclamation going on.
initiate_conc_mark();
log_debug(gc, ergo)("Initiate concurrent cycle (concurrent cycle initiation requested)");
} else if (_g1h->is_user_requested_concurrent_full_gc(cause) ||
(cause == GCCause::_wb_breakpoint)) {
- // Initiate a user requested initial mark or run_to a breakpoint.
- // An initial mark must be young only GC, so the collector state
+ // Initiate a user requested concurrent start or run to a breakpoint.
+ // A concurrent start must be young only GC, so the collector state
// must be updated to reflect this.
collector_state()->set_in_young_only_phase(true);
collector_state()->set_in_young_gc_before_mixed(false);
// We might have ended up coming here about to start a mixed phase with a collection set
@@ -1143,60 +1149,75 @@
// this pause we decided to postpone it. That's OK.
collector_state()->set_initiate_conc_mark_if_possible(true);
}
}
+bool G1Policy::is_young_only_pause(PauseKind kind) {
+ assert(kind != FullGC, "must be");
+ assert(kind != Remark, "must be");
+ assert(kind != Cleanup, "must be");
+ return kind == ConcurrentStartGC || kind == LastYoungGC || kind == YoungOnlyGC;
+}
+
+bool G1Policy::is_last_young_pause(PauseKind kind) {
+ return kind == LastYoungGC;
+}
+
+bool G1Policy::is_concurrent_start_pause(PauseKind kind) {
+ return kind == ConcurrentStartGC;
+}
+
G1Policy::PauseKind G1Policy::young_gc_pause_kind() const {
assert(!collector_state()->in_full_gc(), "must be");
- if (collector_state()->in_initial_mark_gc()) {
+ if (collector_state()->in_concurrent_start_gc()) {
assert(!collector_state()->in_young_gc_before_mixed(), "must be");
- return InitialMarkGC;
+ return ConcurrentStartGC;
} else if (collector_state()->in_young_gc_before_mixed()) {
- assert(!collector_state()->in_initial_mark_gc(), "must be");
+ assert(!collector_state()->in_concurrent_start_gc(), "must be");
return LastYoungGC;
} else if (collector_state()->in_mixed_phase()) {
- assert(!collector_state()->in_initial_mark_gc(), "must be");
+ assert(!collector_state()->in_concurrent_start_gc(), "must be");
assert(!collector_state()->in_young_gc_before_mixed(), "must be");
return MixedGC;
} else {
- assert(!collector_state()->in_initial_mark_gc(), "must be");
+ assert(!collector_state()->in_concurrent_start_gc(), "must be");
assert(!collector_state()->in_young_gc_before_mixed(), "must be");
return YoungOnlyGC;
}
}
void G1Policy::record_pause(PauseKind kind, double start, double end) {
// Manage the MMU tracker. For some reason it ignores Full GCs.
if (kind != FullGC) {
_mmu_tracker->add_pause(start, end);
}
- // Manage the mutator time tracking from initial mark to first mixed gc.
+ // Manage the mutator time tracking from concurrent start to first mixed gc.
switch (kind) {
case FullGC:
abort_time_to_mixed_tracking();
break;
case Cleanup:
case Remark:
case YoungOnlyGC:
case LastYoungGC:
- _initial_mark_to_mixed.add_pause(end - start);
+ _concurrent_start_to_mixed.add_pause(end - start);
break;
- case InitialMarkGC:
+ case ConcurrentStartGC:
if (_g1h->gc_cause() != GCCause::_g1_periodic_collection) {
- _initial_mark_to_mixed.record_initial_mark_end(end);
+ _concurrent_start_to_mixed.record_concurrent_start_end(end);
}
break;
case MixedGC:
- _initial_mark_to_mixed.record_mixed_gc_start(start);
+ _concurrent_start_to_mixed.record_mixed_gc_start(start);
break;
default:
ShouldNotReachHere();
}
}
void G1Policy::abort_time_to_mixed_tracking() {
- _initial_mark_to_mixed.reset();
+ _concurrent_start_to_mixed.reset();
}
bool G1Policy::next_gc_should_be_mixed(const char* true_action_str,
const char* false_action_str) const {
G1CollectionSetCandidates* candidates = _collection_set->candidates();
< prev index next >