mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 03:58:21 +00:00
tests
This commit is contained in:
parent
43b49eb9a6
commit
9565adcda6
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package jdk.jfr.jcmd;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Test dumping with path-to-gc-roots and DFS only, excercise the array chunking path
|
||||
* @requires vm.hasJFR & vm.flagless
|
||||
* @modules jdk.jfr/jdk.jfr.internal.test
|
||||
* @library /test/lib /test/jdk
|
||||
*
|
||||
* @run main/othervm -Xmx1g jdk.jfr.jcmd.TestJcmdDumpPathToGCRootsDFSArrayChunking
|
||||
*/
|
||||
public class TestJcmdDumpPathToGCRootsDFSArrayChunking extends TestJcmdDumpPathToGCRootsDFSBase {
|
||||
|
||||
// Tests that array chunking works correctly. We create an object array; link a second object array
|
||||
// into it at its middle; link a third object array into the second at its end; fill the third array with
|
||||
// many objects. GC root search should walk successfully through the middle of the first and the end of
|
||||
// the second to the third array and sample a good portion of its objects.
|
||||
|
||||
private static final int TOTAL_OBJECTS = 10_000_000;
|
||||
private static final int arrayChunkSize = 64; // keep in sync with dfsClosure.cpp
|
||||
private Object[] leak;
|
||||
|
||||
@Override
|
||||
protected final void buildLeak() {
|
||||
final int arraySize = (arrayChunkSize * 10) + arrayChunkSize / 2;
|
||||
Object[] first = new Object[arraySize];
|
||||
Object[] second = new Object[arraySize];
|
||||
Object[] third = new Object[TOTAL_OBJECTS];
|
||||
for (int i = 0; i < third.length; i++) {
|
||||
third[i] = new Object();
|
||||
}
|
||||
second[second.length - 1] = third;
|
||||
first[first.length / 2] = second;
|
||||
leak = first;
|
||||
}
|
||||
|
||||
protected final void clearLeak() {
|
||||
leak = null;
|
||||
System.gc();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new TestJcmdDumpPathToGCRootsDFSArrayChunking().testDump("TestJcmdDumpPathToGCRootsDFSArrayChunking", 30);
|
||||
}
|
||||
|
||||
}
|
||||
98
test/jdk/jdk/jfr/jcmd/TestJcmdDumpPathToGCRootsDFSBase.java
Normal file
98
test/jdk/jdk/jfr/jcmd/TestJcmdDumpPathToGCRootsDFSBase.java
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package jdk.jfr.jcmd;
|
||||
|
||||
import jdk.jfr.Enabled;
|
||||
import jdk.jfr.Recording;
|
||||
import jdk.jfr.consumer.RecordedEvent;
|
||||
import jdk.jfr.consumer.RecordedObject;
|
||||
import jdk.jfr.consumer.RecordingFile;
|
||||
import jdk.jfr.internal.test.WhiteBox;
|
||||
import jdk.test.lib.jfr.EventNames;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public abstract class TestJcmdDumpPathToGCRootsDFSBase {
|
||||
|
||||
protected abstract void buildLeak();
|
||||
protected abstract void clearLeak();
|
||||
|
||||
protected void testDump(String jfrFileName, int minChainsExpected) throws Exception {
|
||||
WhiteBox.setWriteAllObjectSamples(true);
|
||||
WhiteBox.setSkipBFS(true);
|
||||
final String settingName = EventNames.OldObjectSample + "#" + "cutoff";
|
||||
Map<String, String> settings = Collections.singletonMap(settingName, "infinity");
|
||||
final String pathToGcRoots = "path-to-gc-roots=true";
|
||||
int numTries = 10;
|
||||
while (--numTries >= 0) {
|
||||
try (Recording r = new Recording()) {
|
||||
Map<String, String> p = new HashMap<>(settings);
|
||||
p.put(EventNames.OldObjectSample + "#" + Enabled.NAME, "true");
|
||||
r.setName("dodo");
|
||||
r.setSettings(p);
|
||||
r.setToDisk(true);
|
||||
r.start();
|
||||
clearLeak();
|
||||
System.out.println("Recording id: " + r.getId());
|
||||
System.out.println("Settings: " + settings.toString());
|
||||
System.out.println("Command: JFR.dump " + pathToGcRoots);
|
||||
buildLeak();
|
||||
System.gc();
|
||||
System.gc();
|
||||
File recording = new File(jfrFileName + r.getId() + ".jfr");
|
||||
recording.delete();
|
||||
JcmdHelper.jcmd("JFR.dump", "name=dodo", pathToGcRoots, "filename=" + recording.getAbsolutePath());
|
||||
r.setSettings(Collections.emptyMap());
|
||||
List<RecordedEvent> events = RecordingFile.readAllEvents(recording.toPath());
|
||||
if (events.isEmpty()) {
|
||||
System.out.println("No events found in recording. Retrying.");
|
||||
continue;
|
||||
}
|
||||
int chains = countChains(events);
|
||||
if (chains < minChainsExpected) {
|
||||
System.out.println(events);
|
||||
System.out.println("Not enough chains found (" + chains + "), retrying.");
|
||||
continue;
|
||||
}
|
||||
return; // Success
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Failed");
|
||||
}
|
||||
|
||||
private static int countChains(List<RecordedEvent> events) throws IOException {
|
||||
int found = 0;
|
||||
for (RecordedEvent e : events) {
|
||||
RecordedObject ro = e.getValue("object");
|
||||
if (ro.getValue("referrer") != null) {
|
||||
found++;
|
||||
}
|
||||
}
|
||||
System.out.println("Found chains: " + found);
|
||||
return found;
|
||||
}
|
||||
|
||||
}
|
||||
@ -22,19 +22,8 @@
|
||||
*/
|
||||
|
||||
package jdk.jfr.jcmd;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import jdk.jfr.Enabled;
|
||||
import jdk.jfr.Recording;
|
||||
import jdk.jfr.consumer.RecordedEvent;
|
||||
import jdk.jfr.consumer.RecordedObject;
|
||||
import jdk.jfr.consumer.RecordingFile;
|
||||
import jdk.jfr.internal.test.WhiteBox;
|
||||
import jdk.test.lib.jfr.EventNames;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Test dumping with path-to-gc-roots and DFS only with a very small stacksize for the VM thread
|
||||
@ -42,12 +31,15 @@ import jdk.test.lib.jfr.EventNames;
|
||||
* @modules jdk.jfr/jdk.jfr.internal.test
|
||||
* @library /test/lib /test/jdk
|
||||
*
|
||||
* @run main/othervm -Xmx1g -XX:VMThreadStackSize=128 jdk.jfr.jcmd.TestJcmdDumpPathToGCRootsDFSWithSmallStack dfs-only
|
||||
* @run main/othervm -Xmx1g -XX:VMThreadStackSize=128 jdk.jfr.jcmd.TestJcmdDumpPathToGCRootsDFSWithSmallStack
|
||||
*/
|
||||
public class TestJcmdDumpPathToGCRootsDFSWithSmallStack {
|
||||
public class TestJcmdDumpPathToGCRootsDFSWithSmallStack extends TestJcmdDumpPathToGCRootsDFSBase {
|
||||
|
||||
// Tests the new non-recursive implementation of the JFR leak profiler path-to-gc-roots-search.
|
||||
|
||||
// An non-zero exit code, together with a missing hs-err file or possibly a missing jfr file,
|
||||
// indicates a native stack overflow happened and is a fail condition for this test.
|
||||
|
||||
// We build up an array of linked lists, each containing enough entries for DFS search to
|
||||
// max out max_dfs_depth (but not greatly surpass it).
|
||||
// The old recursive implementation, started with such a small stack, will fail to reach
|
||||
@ -62,77 +54,10 @@ public class TestJcmdDumpPathToGCRootsDFSWithSmallStack {
|
||||
|
||||
private static final int TOTAL_OBJECTS = 10_000_000;
|
||||
private static final int OBJECTS_PER_LIST = 5_000;
|
||||
private static LinkedList[] leak;
|
||||
private LinkedList[] leak;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
WhiteBox.setWriteAllObjectSamples(true);
|
||||
String settingName = EventNames.OldObjectSample + "#" + "cutoff";
|
||||
|
||||
int leakedObjectCount = 10_000_000;
|
||||
boolean skipBFS = true;
|
||||
|
||||
WhiteBox.setSkipBFS(skipBFS);
|
||||
testDump(Collections.singletonMap(settingName, "infinity"), leakedObjectCount);
|
||||
}
|
||||
|
||||
private static void testDump(Map<String, String> settings, int leakedObjectCount) throws Exception {
|
||||
final String pathToGcRoots = "path-to-gc-roots=true";
|
||||
int numTries = 3;
|
||||
while (--numTries >= 0) {
|
||||
try (Recording r = new Recording()) {
|
||||
Map<String, String> p = new HashMap<>(settings);
|
||||
p.put(EventNames.OldObjectSample + "#" + Enabled.NAME, "true");
|
||||
r.setName("dodo");
|
||||
r.setSettings(p);
|
||||
r.setToDisk(true);
|
||||
r.start();
|
||||
clearLeak();
|
||||
System.out.println("Recording id: " + r.getId());
|
||||
System.out.println("Settings: " + settings.toString());
|
||||
System.out.println("Command: JFR.dump " + pathToGcRoots);
|
||||
buildLeak(leakedObjectCount);
|
||||
System.gc();
|
||||
System.gc();
|
||||
File recording = new File("TestJcmdDumpPathToGCRootsDFSWithSmallStack" + r.getId() + ".jfr");
|
||||
recording.delete();
|
||||
JcmdHelper.jcmd("JFR.dump", "name=dodo", pathToGcRoots, "filename=" + recording.getAbsolutePath());
|
||||
r.setSettings(Collections.emptyMap());
|
||||
List<RecordedEvent> events = RecordingFile.readAllEvents(recording.toPath());
|
||||
if (events.isEmpty()) {
|
||||
System.out.println("No events found in recording. Retrying.");
|
||||
continue;
|
||||
}
|
||||
int chains = countChains(events);
|
||||
final int minNumberOfChains = 30; // very conservative; normally ~250
|
||||
if (chains < minNumberOfChains) {
|
||||
System.out.println(events);
|
||||
System.out.println("Not enough chains found (" + chains + "), retrying.");
|
||||
continue;
|
||||
}
|
||||
return; // Success
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Failed");
|
||||
}
|
||||
|
||||
private static void clearLeak() {
|
||||
leak = null;
|
||||
System.gc();
|
||||
}
|
||||
|
||||
private static int countChains(List<RecordedEvent> events) throws IOException {
|
||||
int found = 0;
|
||||
for (RecordedEvent e : events) {
|
||||
RecordedObject ro = e.getValue("object");
|
||||
if (ro.getValue("referrer") != null) {
|
||||
found++;
|
||||
}
|
||||
}
|
||||
System.out.println("Found chains: " + found);
|
||||
return found;
|
||||
}
|
||||
|
||||
private static void buildLeak(int objectCount) {
|
||||
@Override
|
||||
protected final void buildLeak() {
|
||||
leak = new LinkedList[TOTAL_OBJECTS/OBJECTS_PER_LIST];
|
||||
for (int i = 0; i < leak.length; i++) {
|
||||
leak[i] = new LinkedList();
|
||||
@ -141,4 +66,14 @@ public class TestJcmdDumpPathToGCRootsDFSWithSmallStack {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final void clearLeak() {
|
||||
leak = null;
|
||||
System.gc();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new TestJcmdDumpPathToGCRootsDFSWithSmallStack().testDump("TestJcmdDumpPathToGCRootsDFSWithSmallStack", 30);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user