mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-14 18:03:44 +00:00
8352969: G1: Improve testability of optional collections
Reviewed-by: ayang, tschatzl
This commit is contained in:
parent
7603e96fa2
commit
e172e6a4e3
@ -385,6 +385,16 @@ static void print_finish_message(const char* reason, bool from_marking) {
|
||||
from_marking ? "marking" : "retained", reason);
|
||||
}
|
||||
|
||||
void G1CollectionSet::add_optional_group(G1CSetCandidateGroup* group,
|
||||
uint& num_optional_regions,
|
||||
double& predicted_optional_time_ms,
|
||||
double predicted_time_ms) {
|
||||
_optional_groups.append(group);
|
||||
prepare_optional_group(group, num_optional_regions);
|
||||
num_optional_regions += group->length();
|
||||
predicted_optional_time_ms += predicted_time_ms;
|
||||
}
|
||||
|
||||
double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms) {
|
||||
uint num_expensive_regions = 0;
|
||||
uint num_inital_regions = 0;
|
||||
@ -404,6 +414,8 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms)
|
||||
|
||||
G1CSetCandidateGroupList* from_marking_groups = &candidates()->from_marking_groups();
|
||||
|
||||
bool make_first_group_optional = G1ForceOptionalEvacuation;
|
||||
|
||||
log_debug(gc, ergo, cset)("Start adding marking candidates to collection set. "
|
||||
"Min %u regions, max %u regions, available %u regions (%u groups), "
|
||||
"time remaining %1.2fms, optional threshold %1.2fms",
|
||||
@ -421,6 +433,15 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms)
|
||||
|
||||
double predicted_time_ms = group->predict_group_total_time_ms();
|
||||
|
||||
if (make_first_group_optional) {
|
||||
make_first_group_optional = false;
|
||||
add_optional_group(group,
|
||||
num_optional_regions,
|
||||
predicted_optional_time_ms,
|
||||
predicted_time_ms);
|
||||
continue;
|
||||
}
|
||||
|
||||
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_inital_regions < min_old_cset_length) {
|
||||
@ -456,10 +477,10 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms)
|
||||
|
||||
} else if (time_remaining_ms > 0) {
|
||||
// Keep adding optional regions until time is up.
|
||||
_optional_groups.append(group);
|
||||
prepare_optional_group(group, num_optional_regions);
|
||||
num_optional_regions += group->length();
|
||||
predicted_optional_time_ms += predicted_time_ms;
|
||||
add_optional_group(group,
|
||||
num_optional_regions,
|
||||
predicted_optional_time_ms,
|
||||
predicted_time_ms);
|
||||
} else {
|
||||
print_finish_message("Predicted time too high", true);
|
||||
break;
|
||||
@ -560,10 +581,10 @@ void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms)
|
||||
num_initial_regions += group->length();
|
||||
} else if (predicted_time_ms <= optional_time_remaining_ms) {
|
||||
// Prepare optional collection region.
|
||||
_optional_groups.append(group);
|
||||
prepare_optional_group(group, num_optional_regions);
|
||||
num_optional_regions += group->length();
|
||||
predicted_optional_time_ms += predicted_time_ms;
|
||||
add_optional_group(group,
|
||||
num_optional_regions,
|
||||
predicted_optional_time_ms,
|
||||
predicted_time_ms);
|
||||
} else {
|
||||
// Fits neither initial nor optional time limit. Exit.
|
||||
break;
|
||||
@ -645,6 +666,7 @@ uint G1CollectionSet::select_optional_groups(double time_remaining_ms) {
|
||||
|
||||
log_debug(gc, ergo, cset)("Prepared %u regions out of %u for optional evacuation. Total predicted time: %.3fms",
|
||||
num_regions_selected, optional_regions_count, total_prediction_ms);
|
||||
|
||||
return num_regions_selected;
|
||||
}
|
||||
|
||||
|
||||
@ -220,6 +220,13 @@ class G1CollectionSet {
|
||||
size_t offset,
|
||||
size_t length,
|
||||
uint worker_id) const;
|
||||
|
||||
// Adds the given group to the optional groups list (_optional_groups)
|
||||
// and updates all related bookkeeping.
|
||||
void add_optional_group(G1CSetCandidateGroup* group,
|
||||
uint& num_optional_regions,
|
||||
double& predicted_optional_time_ms,
|
||||
double predicted_time_ms);
|
||||
public:
|
||||
G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy);
|
||||
~G1CollectionSet();
|
||||
|
||||
@ -815,13 +815,18 @@ void G1YoungCollector::evacuate_next_optional_regions(G1ParScanThreadStateSet* p
|
||||
|
||||
void G1YoungCollector::evacuate_optional_collection_set(G1ParScanThreadStateSet* per_thread_states) {
|
||||
const double pause_start_time_ms = policy()->cur_pause_start_sec() * 1000.0;
|
||||
double target_pause_time_ms = MaxGCPauseMillis;
|
||||
|
||||
if (G1ForceOptionalEvacuation) {
|
||||
target_pause_time_ms = DBL_MAX;
|
||||
}
|
||||
|
||||
while (!evacuation_alloc_failed() && collection_set()->num_optional_regions() > 0) {
|
||||
|
||||
double time_used_ms = os::elapsedTime() * 1000.0 - pause_start_time_ms;
|
||||
double time_left_ms = MaxGCPauseMillis - time_used_ms;
|
||||
double time_left_ms = target_pause_time_ms - time_used_ms;
|
||||
|
||||
if (time_left_ms < 0 ||
|
||||
if (time_left_ms <= 0 ||
|
||||
!collection_set()->finalize_optional_for_evacuation(time_left_ms * policy()->optional_evacuation_fraction())) {
|
||||
log_trace(gc, ergo, cset)("Skipping evacuation of %u optional regions, no more regions can be evacuated in %.3fms",
|
||||
collection_set()->num_optional_regions(), time_left_ms);
|
||||
|
||||
@ -370,6 +370,12 @@
|
||||
"scan cost related prediction samples. A sample must involve " \
|
||||
"the same or more than this number of code roots to be used.") \
|
||||
\
|
||||
develop(bool, G1ForceOptionalEvacuation, false, \
|
||||
"Force optional evacuation for all GCs where there are old gen " \
|
||||
"collection set candidates." \
|
||||
"Also schedule all available optional groups for evacuation " \
|
||||
"regardless of timing.") \
|
||||
\
|
||||
GC_G1_EVACUATION_FAILURE_FLAGS(develop, \
|
||||
develop_pd, \
|
||||
product, \
|
||||
|
||||
106
test/hotspot/jtreg/gc/g1/TestOptionalRegionGC.java
Normal file
106
test/hotspot/jtreg/gc/g1/TestOptionalRegionGC.java
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 8352969
|
||||
* @summary Tests optional evacuation.
|
||||
* @requires vm.gc.G1
|
||||
* @requires vm.debug
|
||||
* @library /test/lib
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run driver gc.g1.TestOptionalRegionGC
|
||||
*/
|
||||
|
||||
package gc.g1;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.whitebox.WhiteBox;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class TestOptionalRegionGC {
|
||||
|
||||
private static OutputAnalyzer run() throws Exception {
|
||||
return ProcessTools.executeLimitedTestJava(
|
||||
"-XX:+WhiteBoxAPI",
|
||||
"-Xbootclasspath/a:.",
|
||||
"-Xmx300M",
|
||||
"-Xms300M",
|
||||
"-XX:G1HeapRegionSize=1M",
|
||||
"-XX:+UseG1GC",
|
||||
"-XX:MaxTenuringThreshold=1",
|
||||
"-Xlog:gc+ergo+cset=trace",
|
||||
"-XX:+G1ForceOptionalEvacuation",
|
||||
"-XX:+VerifyAfterGC",
|
||||
TestOptionalRegionGC.Action.class.getName());
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
OutputAnalyzer out = run();
|
||||
out.shouldHaveExitValue(0);
|
||||
Pattern pattern = Pattern.compile("Prepared (\\d+) regions out of (\\d+) for optional evacuation");
|
||||
Matcher matcher = pattern.matcher(out.getOutput());
|
||||
Asserts.assertTrue(matcher.find());
|
||||
String selectedNum = matcher.group(1);
|
||||
String totalNum = matcher.group(2);
|
||||
Asserts.assertTrue(Objects.equals(selectedNum, totalNum), "Error info: " + selectedNum + ", " + totalNum);
|
||||
}
|
||||
|
||||
public static class Action {
|
||||
private static final WhiteBox wb = WhiteBox.getWhiteBox();
|
||||
private static final int MIN_OBJECT_SIZE = 64 * 1024;
|
||||
private static final int MAX_OBJECT_SIZE = 120 * 1024;
|
||||
private static final int NUM_OBJECTS = 1200;
|
||||
|
||||
public static void main(String [] args) throws Exception {
|
||||
// Remove garbage from VM initialization.
|
||||
wb.fullGC();
|
||||
Random rand = new Random(42);
|
||||
List<byte[]> objectList = new ArrayList<>();
|
||||
for (int i = 0; i < NUM_OBJECTS; i++) {
|
||||
int objSize = MIN_OBJECT_SIZE + rand.nextInt(MAX_OBJECT_SIZE - MIN_OBJECT_SIZE);
|
||||
byte[] obj = new byte[objSize];
|
||||
objectList.add(obj);
|
||||
}
|
||||
// Young GC promotes some objects to the old generation.
|
||||
wb.youngGC();
|
||||
// Clear certain references for mixed GC.
|
||||
for (int i = 0; i < NUM_OBJECTS; i+=2) {
|
||||
objectList.set(i, null);
|
||||
}
|
||||
wb.g1RunConcurrentGC();
|
||||
// Perform the "Prepare Mixed" GC.
|
||||
wb.youngGC();
|
||||
// Perform the "Mixed" GC.
|
||||
wb.youngGC();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user