--- old/src/hotspot/share/gc/g1/g1Policy.cpp 2019-03-13 14:03:11.084301019 +0100 +++ new/src/hotspot/share/gc/g1/g1Policy.cpp 2019-03-13 14:03:10.873295289 +0100 @@ -659,7 +659,7 @@ double cost_per_entry_ms = 0.0; if (cards_scanned > 10) { - cost_per_entry_ms = average_time_ms(G1GCPhaseTimes::ScanRS) / (double) cards_scanned; + cost_per_entry_ms = (average_time_ms(G1GCPhaseTimes::ScanRS) + average_time_ms(G1GCPhaseTimes::OptScanRS)) / (double) cards_scanned; _analytics->report_cost_per_entry_ms(cost_per_entry_ms, this_pause_was_young_only); } @@ -694,7 +694,7 @@ double cost_per_byte_ms = 0.0; if (copied_bytes > 0) { - cost_per_byte_ms = average_time_ms(G1GCPhaseTimes::ObjCopy) / (double) copied_bytes; + cost_per_byte_ms = (average_time_ms(G1GCPhaseTimes::ObjCopy) + average_time_ms(G1GCPhaseTimes::OptObjCopy)) / (double) copied_bytes; _analytics->report_cost_per_byte_ms(cost_per_byte_ms, collector_state()->mark_or_rebuild_in_progress()); } @@ -1188,11 +1188,136 @@ return (uint) result; } -uint G1Policy::finalize_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor) { - double time_remaining_ms = _collection_set->finalize_young_part(target_pause_time_ms, survivor); - _collection_set->finalize_old_part(time_remaining_ms); +void G1Policy::select_old_collection_set_regions(G1CollectionSetCandidates* candidates, + double time_remaining_ms, + uint& num_expensive_regions, + uint& num_initial_regions, + uint& num_optional_regions) { + assert(candidates != NULL, "Must be"); + + num_initial_regions = 0; + num_optional_regions = 0; + num_expensive_regions = 0; + + double predicted_old_time_ms = 0.0; + double predicted_initial_time_ms = 0.0; + double predicted_optional_time_ms = 0.0; + + double optional_threshold_ms = time_remaining_ms * optional_prediction_fraction(); + + const uint min_old_cset_length = calc_min_old_cset_length(); + const uint max_old_cset_length = MAX2(min_old_cset_length, calc_max_old_cset_length()); + const uint max_optional_regions = max_old_cset_length - min_old_cset_length; + bool check_time_remaining = adaptive_young_list_length(); + + uint candidate_idx = candidates->cur_idx(); + + log_debug(gc, ergo, cset)("Start adding old regions to collection set. Min %u regions, max %u regions, " + "time remaining %1.2fms, optional threshold %1.2fms", + min_old_cset_length, max_old_cset_length, time_remaining_ms, optional_threshold_ms); + + HeapRegion* hr = candidates->at(candidate_idx); + while (hr != NULL) { + if (num_initial_regions + num_optional_regions >= max_old_cset_length) { + // Added maximum number of old regions to the CSet. + log_debug(gc, ergo, cset)("Finish adding old regions to collection set (Maximum number of regions). " + "Initial %u regions, optional %u regions", + num_initial_regions, num_optional_regions); + break; + } + + // Stop adding regions if the remaining reclaimable space is + // not above G1HeapWastePercent. + size_t reclaimable_bytes = candidates->remaining_reclaimable_bytes(); + double reclaimable_percent = reclaimable_bytes_percent(reclaimable_bytes); + double threshold = (double) G1HeapWastePercent; + if (reclaimable_percent <= threshold) { + // We've added enough old regions that the amount of uncollected + // reclaimable space is at or below the waste threshold. Stop + // adding old regions to the CSet. + log_debug(gc, ergo, cset)("Finish adding old regions to collection set (Reclaimable percentage below threshold). " + "Reclaimable: " SIZE_FORMAT "%s (%1.2f%%) threshold: " UINTX_FORMAT "%%", + byte_size_in_proper_unit(reclaimable_bytes), proper_unit_for_byte_size(reclaimable_bytes), + reclaimable_percent, G1HeapWastePercent); + break; + } + + double predicted_time_ms = predict_region_elapsed_time_ms(hr, false); + time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0); + // Add regions to old set until we reach the minimum amount + if (num_initial_regions < min_old_cset_length) { + predicted_old_time_ms += predicted_time_ms; + num_initial_regions++; + // Record the number of regions added with no time remaining + if (time_remaining_ms == 0.0) { + num_expensive_regions++; + } + } else if (!check_time_remaining) { + // In the non-auto-tuning case, we'll finish adding regions + // to the CSet if we reach the minimum. + log_debug(gc, ergo, cset)("Finish adding old regions to collection set (Region amount reached min)."); + break; + } else { + // Keep adding regions to old set until we reach the optional threshold + if (time_remaining_ms > optional_threshold_ms) { + predicted_old_time_ms += predicted_time_ms; + num_initial_regions++; + } else if (time_remaining_ms > 0) { + // Keep adding optional regions until time is up. + assert(num_optional_regions < max_optional_regions, "Should not be possible."); + predicted_optional_time_ms += predicted_time_ms; + num_optional_regions++; + } else { + log_debug(gc, ergo, cset)("Finish adding old regions to collection set (Predicted time too high)."); + break; + } + } + hr = candidates->at(++candidate_idx); + } + if (hr == NULL) { + log_debug(gc, ergo, cset)("Old candidate collection set empty."); + } + + if (num_expensive_regions > 0) { + log_debug(gc, ergo, cset)("Added %u initial old regions to collection set although the predicted time was too high.", + num_expensive_regions); + } + + log_debug(gc, ergo, cset)("Finish choosing collection set old regions. Initial: %u, optional: %u, " + "predicted old time: %1.2fms, predicted optional time: %1.2fms, time remaining: %1.2f", + num_initial_regions, num_optional_regions, + predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms); +} + +void G1Policy::select_optional_collection_set_regions(G1CollectionSetCandidates* candidates, + uint const max_optional_regions, + double time_remaining_ms, + uint& num_optional_regions) { + assert(_g1h->collector_state()->in_mixed_phase(), "Should only be called in mixed phase"); + + num_optional_regions = 0; + double prediction_ms = 0; + uint candidate_idx = candidates->cur_idx(); + + HeapRegion* r = candidates->at(candidate_idx); + while (num_optional_regions < max_optional_regions) { + assert(r != NULL, "Region must exist"); + prediction_ms += predict_region_elapsed_time_ms(r, false); + + if (prediction_ms > time_remaining_ms) { + log_debug(gc, ergo, cset)("Prediction %.3fms for region %u does not fit remaining time: %.3fms.", + prediction_ms, r->hrm_index(), time_remaining_ms); + break; + } + // This region will be included in the next optional evacuation. + + time_remaining_ms -= prediction_ms; + num_optional_regions++; + r = candidates->at(++candidate_idx); + } - return _collection_set->region_length(); + log_debug(gc, ergo, cset)("Prepared %u regions out of %u for optional evacuation. Predicted time: %.3fms", + num_optional_regions, max_optional_regions, prediction_ms); } void G1Policy::transfer_survivors_to_cset(const G1SurvivorRegions* survivors) {