Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8268458: Add verification type for evacuation failures #4473

Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -90,6 +90,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) {
@@ -98,7 +100,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);
}
}

@@ -2842,6 +2842,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;
@@ -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) {
@@ -45,9 +45,10 @@ class G1HeapVerifier : public CHeapObj<mtGC> {
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
};

@@ -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));
}
@@ -37,6 +37,7 @@
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 static void main(String args[]) throws Exception {
testAllExplicitlyEnabled();
testFullAndRemark();
testConcurrentMark();
if (Platform.isDebugBuild()) {
testYoungEvacFail();
}
testBadVerificationType();
}

@@ -115,13 +119,33 @@ private static void testConcurrentMark() throws Exception {
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 @@ private static void testBadVerificationType() throws Exception {
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 @@ private static OutputAnalyzer testWithVerificationType(String[] types) throws Ex
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 @@ static CollectionInfo parseFirst(String name, String data) {
}

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,16 +271,24 @@ public static void main(String args[]) throws Exception {
// 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()) {
Thread.sleep(1000);
}

// 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() {