src/hotspot/share/gc/g1/g1Policy.cpp
changeset 54465 c4f16445675a
parent 54262 1f9ad92e337b
child 54466 58751415d5f8
--- a/src/hotspot/share/gc/g1/g1Policy.cpp	Mon Apr 08 11:11:22 2019 -0700
+++ b/src/hotspot/share/gc/g1/g1Policy.cpp	Mon Apr 08 20:37:52 2019 +0200
@@ -659,7 +659,11 @@
 
     double cost_per_entry_ms = 0.0;
     if (cards_scanned > 10) {
-      cost_per_entry_ms = average_time_ms(G1GCPhaseTimes::ScanRS) / (double) cards_scanned;
+      double avg_time_scan_rs = average_time_ms(G1GCPhaseTimes::ScanRS);
+      if (this_pause_was_young_only) {
+        avg_time_scan_rs += average_time_ms(G1GCPhaseTimes::OptScanRS);
+      }
+      cost_per_entry_ms = avg_time_scan_rs / cards_scanned;
       _analytics->report_cost_per_entry_ms(cost_per_entry_ms, this_pause_was_young_only);
     }
 
@@ -694,7 +698,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 +1192,135 @@
   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::calculate_old_collection_set_regions(G1CollectionSetCandidates* candidates,
+                                                    double time_remaining_ms,
+                                                    uint& num_initial_regions,
+                                                    uint& num_optional_regions) {
+  assert(candidates != NULL, "Must be");
+
+  num_initial_regions = 0;
+  num_optional_regions = 0;
+  uint 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;
+    }
 
-  return _collection_set->region_length();
+    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::calculate_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);
+  }
+
+  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) {