Skip to content

Commit e172e6a

Browse files
hgqxjjalbertnetymk
authored andcommitted
8352969: G1: Improve testability of optional collections
Reviewed-by: ayang, tschatzl
1 parent 7603e96 commit e172e6a

File tree

5 files changed

+156
-10
lines changed

5 files changed

+156
-10
lines changed

src/hotspot/share/gc/g1/g1CollectionSet.cpp

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,16 @@ static void print_finish_message(const char* reason, bool from_marking) {
385385
from_marking ? "marking" : "retained", reason);
386386
}
387387

388+
void G1CollectionSet::add_optional_group(G1CSetCandidateGroup* group,
389+
uint& num_optional_regions,
390+
double& predicted_optional_time_ms,
391+
double predicted_time_ms) {
392+
_optional_groups.append(group);
393+
prepare_optional_group(group, num_optional_regions);
394+
num_optional_regions += group->length();
395+
predicted_optional_time_ms += predicted_time_ms;
396+
}
397+
388398
double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms) {
389399
uint num_expensive_regions = 0;
390400
uint num_inital_regions = 0;
@@ -404,6 +414,8 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms)
404414

405415
G1CSetCandidateGroupList* from_marking_groups = &candidates()->from_marking_groups();
406416

417+
bool make_first_group_optional = G1ForceOptionalEvacuation;
418+
407419
log_debug(gc, ergo, cset)("Start adding marking candidates to collection set. "
408420
"Min %u regions, max %u regions, available %u regions (%u groups), "
409421
"time remaining %1.2fms, optional threshold %1.2fms",
@@ -421,6 +433,15 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms)
421433

422434
double predicted_time_ms = group->predict_group_total_time_ms();
423435

436+
if (make_first_group_optional) {
437+
make_first_group_optional = false;
438+
add_optional_group(group,
439+
num_optional_regions,
440+
predicted_optional_time_ms,
441+
predicted_time_ms);
442+
continue;
443+
}
444+
424445
time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0);
425446
// Add regions to old set until we reach the minimum amount
426447
if (num_inital_regions < min_old_cset_length) {
@@ -456,10 +477,10 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms)
456477

457478
} else if (time_remaining_ms > 0) {
458479
// Keep adding optional regions until time is up.
459-
_optional_groups.append(group);
460-
prepare_optional_group(group, num_optional_regions);
461-
num_optional_regions += group->length();
462-
predicted_optional_time_ms += predicted_time_ms;
480+
add_optional_group(group,
481+
num_optional_regions,
482+
predicted_optional_time_ms,
483+
predicted_time_ms);
463484
} else {
464485
print_finish_message("Predicted time too high", true);
465486
break;
@@ -560,10 +581,10 @@ void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms)
560581
num_initial_regions += group->length();
561582
} else if (predicted_time_ms <= optional_time_remaining_ms) {
562583
// Prepare optional collection region.
563-
_optional_groups.append(group);
564-
prepare_optional_group(group, num_optional_regions);
565-
num_optional_regions += group->length();
566-
predicted_optional_time_ms += predicted_time_ms;
584+
add_optional_group(group,
585+
num_optional_regions,
586+
predicted_optional_time_ms,
587+
predicted_time_ms);
567588
} else {
568589
// Fits neither initial nor optional time limit. Exit.
569590
break;
@@ -645,6 +666,7 @@ uint G1CollectionSet::select_optional_groups(double time_remaining_ms) {
645666

646667
log_debug(gc, ergo, cset)("Prepared %u regions out of %u for optional evacuation. Total predicted time: %.3fms",
647668
num_regions_selected, optional_regions_count, total_prediction_ms);
669+
648670
return num_regions_selected;
649671
}
650672

src/hotspot/share/gc/g1/g1CollectionSet.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,13 @@ class G1CollectionSet {
220220
size_t offset,
221221
size_t length,
222222
uint worker_id) const;
223+
224+
// Adds the given group to the optional groups list (_optional_groups)
225+
// and updates all related bookkeeping.
226+
void add_optional_group(G1CSetCandidateGroup* group,
227+
uint& num_optional_regions,
228+
double& predicted_optional_time_ms,
229+
double predicted_time_ms);
223230
public:
224231
G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy);
225232
~G1CollectionSet();

src/hotspot/share/gc/g1/g1YoungCollector.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -815,13 +815,18 @@ void G1YoungCollector::evacuate_next_optional_regions(G1ParScanThreadStateSet* p
815815

816816
void G1YoungCollector::evacuate_optional_collection_set(G1ParScanThreadStateSet* per_thread_states) {
817817
const double pause_start_time_ms = policy()->cur_pause_start_sec() * 1000.0;
818+
double target_pause_time_ms = MaxGCPauseMillis;
819+
820+
if (G1ForceOptionalEvacuation) {
821+
target_pause_time_ms = DBL_MAX;
822+
}
818823

819824
while (!evacuation_alloc_failed() && collection_set()->num_optional_regions() > 0) {
820825

821826
double time_used_ms = os::elapsedTime() * 1000.0 - pause_start_time_ms;
822-
double time_left_ms = MaxGCPauseMillis - time_used_ms;
827+
double time_left_ms = target_pause_time_ms - time_used_ms;
823828

824-
if (time_left_ms < 0 ||
829+
if (time_left_ms <= 0 ||
825830
!collection_set()->finalize_optional_for_evacuation(time_left_ms * policy()->optional_evacuation_fraction())) {
826831
log_trace(gc, ergo, cset)("Skipping evacuation of %u optional regions, no more regions can be evacuated in %.3fms",
827832
collection_set()->num_optional_regions(), time_left_ms);

src/hotspot/share/gc/g1/g1_globals.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,12 @@
370370
"scan cost related prediction samples. A sample must involve " \
371371
"the same or more than this number of code roots to be used.") \
372372
\
373+
develop(bool, G1ForceOptionalEvacuation, false, \
374+
"Force optional evacuation for all GCs where there are old gen " \
375+
"collection set candidates." \
376+
"Also schedule all available optional groups for evacuation " \
377+
"regardless of timing.") \
378+
\
373379
GC_G1_EVACUATION_FAILURE_FLAGS(develop, \
374380
develop_pd, \
375381
product, \
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/* @test
25+
* @bug 8352969
26+
* @summary Tests optional evacuation.
27+
* @requires vm.gc.G1
28+
* @requires vm.debug
29+
* @library /test/lib
30+
* @build jdk.test.whitebox.WhiteBox
31+
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
32+
* @run driver gc.g1.TestOptionalRegionGC
33+
*/
34+
35+
package gc.g1;
36+
37+
import jdk.test.lib.Asserts;
38+
import jdk.test.lib.process.OutputAnalyzer;
39+
import jdk.test.lib.process.ProcessTools;
40+
import jdk.test.whitebox.WhiteBox;
41+
42+
import java.util.ArrayList;
43+
import java.util.List;
44+
import java.util.Objects;
45+
import java.util.Random;
46+
import java.util.regex.Matcher;
47+
import java.util.regex.Pattern;
48+
49+
public class TestOptionalRegionGC {
50+
51+
private static OutputAnalyzer run() throws Exception {
52+
return ProcessTools.executeLimitedTestJava(
53+
"-XX:+WhiteBoxAPI",
54+
"-Xbootclasspath/a:.",
55+
"-Xmx300M",
56+
"-Xms300M",
57+
"-XX:G1HeapRegionSize=1M",
58+
"-XX:+UseG1GC",
59+
"-XX:MaxTenuringThreshold=1",
60+
"-Xlog:gc+ergo+cset=trace",
61+
"-XX:+G1ForceOptionalEvacuation",
62+
"-XX:+VerifyAfterGC",
63+
TestOptionalRegionGC.Action.class.getName());
64+
}
65+
66+
public static void main(String args[]) throws Exception {
67+
OutputAnalyzer out = run();
68+
out.shouldHaveExitValue(0);
69+
Pattern pattern = Pattern.compile("Prepared (\\d+) regions out of (\\d+) for optional evacuation");
70+
Matcher matcher = pattern.matcher(out.getOutput());
71+
Asserts.assertTrue(matcher.find());
72+
String selectedNum = matcher.group(1);
73+
String totalNum = matcher.group(2);
74+
Asserts.assertTrue(Objects.equals(selectedNum, totalNum), "Error info: " + selectedNum + ", " + totalNum);
75+
}
76+
77+
public static class Action {
78+
private static final WhiteBox wb = WhiteBox.getWhiteBox();
79+
private static final int MIN_OBJECT_SIZE = 64 * 1024;
80+
private static final int MAX_OBJECT_SIZE = 120 * 1024;
81+
private static final int NUM_OBJECTS = 1200;
82+
83+
public static void main(String [] args) throws Exception {
84+
// Remove garbage from VM initialization.
85+
wb.fullGC();
86+
Random rand = new Random(42);
87+
List<byte[]> objectList = new ArrayList<>();
88+
for (int i = 0; i < NUM_OBJECTS; i++) {
89+
int objSize = MIN_OBJECT_SIZE + rand.nextInt(MAX_OBJECT_SIZE - MIN_OBJECT_SIZE);
90+
byte[] obj = new byte[objSize];
91+
objectList.add(obj);
92+
}
93+
// Young GC promotes some objects to the old generation.
94+
wb.youngGC();
95+
// Clear certain references for mixed GC.
96+
for (int i = 0; i < NUM_OBJECTS; i+=2) {
97+
objectList.set(i, null);
98+
}
99+
wb.g1RunConcurrentGC();
100+
// Perform the "Prepare Mixed" GC.
101+
wb.youngGC();
102+
// Perform the "Mixed" GC.
103+
wb.youngGC();
104+
}
105+
}
106+
}

0 commit comments

Comments
 (0)