8268458: Add verification type for evacuation failures

Reviewed-by: kbarrett, iwalulya
This commit is contained in:
Thomas Schatzl 2021-06-21 11:12:29 +00:00
parent a58c477c49
commit cd20c01942
6 changed files with 53 additions and 12 deletions

View File

@ -93,6 +93,8 @@ void G1Arguments::parse_verification_type(const char* type) {
G1HeapVerifier::enable_verification_type(G1HeapVerifier::G1VerifyConcurrentStart);
} else if (strcmp(type, "mixed") == 0) {
G1HeapVerifier::enable_verification_type(G1HeapVerifier::G1VerifyMixed);
} else if (strcmp(type, "young-evac-fail") == 0) {
G1HeapVerifier::enable_verification_type(G1HeapVerifier::G1VerifyYoungEvacFail);
} else if (strcmp(type, "remark") == 0) {
G1HeapVerifier::enable_verification_type(G1HeapVerifier::G1VerifyRemark);
} else if (strcmp(type, "cleanup") == 0) {
@ -101,7 +103,7 @@ void G1Arguments::parse_verification_type(const char* type) {
G1HeapVerifier::enable_verification_type(G1HeapVerifier::G1VerifyFull);
} else {
log_warning(gc, verify)("VerifyGCType: '%s' is unknown. Available types are: "
"young-normal, concurrent-start, mixed, remark, cleanup and full", type);
"young-normal, young-evac-fail, concurrent-start, mixed, remark, cleanup and full", type);
}
}

View File

@ -2851,6 +2851,9 @@ void G1CollectedHeap::verify_before_young_collection(G1HeapVerifier::G1VerifyTyp
}
void G1CollectedHeap::verify_after_young_collection(G1HeapVerifier::G1VerifyType type) {
if (evacuation_failed()) {
type = (G1HeapVerifier::G1VerifyType)(type | G1HeapVerifier::G1VerifyYoungEvacFail);
}
if (VerifyRememberedSets) {
log_info(gc, verify)("[Verifying RemSets after GC]");
VerifyRegionRemSetClosure v_cl;

View File

@ -467,7 +467,7 @@ void G1HeapVerifier::enable_verification_type(G1VerifyType type) {
}
bool G1HeapVerifier::should_verify(G1VerifyType type) {
return (_enabled_verification_types & type) == type;
return (_enabled_verification_types & type) != 0;
}
void G1HeapVerifier::verify(VerifyOption vo) {

View File

@ -45,9 +45,10 @@ public:
G1VerifyYoungNormal = 1, // -XX:VerifyGCType=young-normal
G1VerifyConcurrentStart = 2, // -XX:VerifyGCType=concurrent-start
G1VerifyMixed = 4, // -XX:VerifyGCType=mixed
G1VerifyRemark = 8, // -XX:VerifyGCType=remark
G1VerifyCleanup = 16, // -XX:VerifyGCType=cleanup
G1VerifyFull = 32, // -XX:VerifyGCType=full
G1VerifyYoungEvacFail = 8, // -XX:VerifyGCType=young-evac-fail
G1VerifyRemark = 16, // -XX:VerifyGCType=remark
G1VerifyCleanup = 32, // -XX:VerifyGCType=cleanup
G1VerifyFull = 64, // -XX:VerifyGCType=full
G1VerifyAll = -1
};

View File

@ -41,20 +41,20 @@ TEST_VM_F(G1HeapVerifierTest, parse) {
LogConfiguration::configure_stdout(LogLevel::Off, true, LOG_TAGS(gc, verify));
// Default is to verify everything.
ASSERT_TRUE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyAll));
ASSERT_TRUE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyYoungNormal));
ASSERT_TRUE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyConcurrentStart));
ASSERT_TRUE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyMixed));
ASSERT_TRUE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyYoungEvacFail));
ASSERT_TRUE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyRemark));
ASSERT_TRUE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyCleanup));
ASSERT_TRUE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyFull));
// Setting one will disable all other.
G1HeapVerifierTest::parse_verification_type("full");
ASSERT_FALSE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyAll));
ASSERT_FALSE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyYoungNormal));
ASSERT_FALSE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyConcurrentStart));
ASSERT_FALSE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyMixed));
ASSERT_FALSE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyYoungEvacFail));
ASSERT_FALSE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyRemark));
ASSERT_FALSE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyCleanup));
ASSERT_TRUE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyFull));
@ -79,7 +79,4 @@ TEST_VM_F(G1HeapVerifierTest, parse) {
G1HeapVerifierTest::parse_verification_type("cleanup");
ASSERT_TRUE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyRemark));
ASSERT_TRUE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyCleanup));
// Enabling all is not the same as G1VerifyAll
ASSERT_FALSE(G1HeapVerifier::should_verify(G1HeapVerifier::G1VerifyAll));
}

View File

@ -37,6 +37,7 @@ import java.util.ArrayList;
import java.util.Collections;
import jdk.test.lib.Asserts;
import jdk.test.lib.Platform;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import sun.hotspot.WhiteBox;
@ -52,6 +53,9 @@ public class TestVerifyGCType {
testAllExplicitlyEnabled();
testFullAndRemark();
testConcurrentMark();
if (Platform.isDebugBuild()) {
testYoungEvacFail();
}
testBadVerificationType();
}
@ -115,13 +119,33 @@ public class TestVerifyGCType {
verifyCollection("Pause Full", false, false, false, output.getStdout());
}
private static void testYoungEvacFail() throws Exception {
OutputAnalyzer output;
output = testWithVerificationType(new String[] {"young-evac-fail"},
new String[] {"-XX:+G1EvacuationFailureALot",
"-XX:G1EvacuationFailureALotCount=100",
"-XX:G1EvacuationFailureALotInterval=1",
"-XX:+UnlockDiagnosticVMOptions",
"-XX:-G1AllowPreventiveGC"});
output.shouldHaveExitValue(0);
verifyCollection("Pause Young (Normal)", false, false, true, output.getStdout());
verifyCollection("Pause Young (Concurrent Start)", false, false, true, output.getStdout());
verifyCollection("Pause Young (Mixed)", false, false, true, output.getStdout());
verifyCollection("Pause Young (Prepare Mixed)", false, false, true, output.getStdout());
verifyCollection("Pause Remark", false, false, false, output.getStdout());
verifyCollection("Pause Cleanup", false, false, false, output.getStdout());
verifyCollection("Pause Full", false, false, false, output.getStdout());
}
private static void testBadVerificationType() throws Exception {
OutputAnalyzer output;
// Test bad type
output = testWithVerificationType(new String[] {"old"});
output.shouldHaveExitValue(0);
output.shouldMatch("VerifyGCType: '.*' is unknown. Available types are: young-normal, concurrent-start, mixed, remark, cleanup and full");
output.shouldMatch("VerifyGCType: '.*' is unknown. Available types are: young-normal, young-evac-fail, concurrent-start, mixed, remark, cleanup and full");
verifyCollection("Pause Young (Normal)", true, false, true, output.getStdout());
verifyCollection("Pause Young (Concurrent Start)", true, false, true, output.getStdout());
verifyCollection("Pause Young (Mixed)", true, false, true, output.getStdout());
@ -131,7 +155,7 @@ public class TestVerifyGCType {
verifyCollection("Pause Full", true, true, true, output.getStdout());
}
private static OutputAnalyzer testWithVerificationType(String[] types) throws Exception {
private static OutputAnalyzer testWithVerificationType(String[] types, String... extraOpts) throws Exception {
ArrayList<String> basicOpts = new ArrayList<>();
Collections.addAll(basicOpts, new String[] {
"-Xbootclasspath/a:.",
@ -151,10 +175,13 @@ public class TestVerifyGCType {
basicOpts.add("-XX:VerifyGCType="+verifyType);
}
Collections.addAll(basicOpts, extraOpts);
basicOpts.add(TriggerGCs.class.getName());
ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(basicOpts);
OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start());
return analyzer;
}
@ -228,6 +255,9 @@ public class TestVerifyGCType {
}
public static class TriggerGCs {
// This class triggers GCs; we need to make sure that in all of the young gcs
// at least some objects survive so that evacuation failure can happen.
public static void main(String args[]) throws Exception {
WhiteBox wb = WhiteBox.getWhiteBox();
// Allocate some memory that can be turned into garbage.
@ -241,7 +271,10 @@ public class TestVerifyGCType {
// Memory have been promoted to old by full GC. Free
// some memory to be reclaimed by concurrent cycle.
partialFree(used);
used = alloc1M();
wb.g1StartConcMarkCycle(); // concurrent-start, remark and cleanup
partialFree(used);
// Sleep to make sure concurrent cycle is done
while (wb.g1InConcurrentMark()) {
@ -249,8 +282,13 @@ public class TestVerifyGCType {
}
// Trigger two young GCs, first will be young-prepare-mixed, second will be mixed.
used = alloc1M();
wb.youngGC(); // young-prepare-mixed
partialFree(used);
used = alloc1M();
wb.youngGC(); // mixed
partialFree(used);
}
private static Object[] alloc1M() {