8130063: Refactoring tmtools jstat and jstack tests to jtreg
Some of the jstat and jstack tests refactored to be run with the jtreg Reviewed-by: jbachorik
This commit is contained in:
parent
49d61bdeb6
commit
f8b5f55021
@ -97,7 +97,8 @@ needs_jdk = \
|
||||
runtime/XCheckJniJsig/XCheckJSig.java \
|
||||
serviceability/attach/AttachWithStalePidFile.java \
|
||||
serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java \
|
||||
serviceability/dcmd/vm/DynLibsTest.java
|
||||
serviceability/dcmd/vm/DynLibsTest.java \
|
||||
serviceability/tmtools
|
||||
|
||||
|
||||
# JRE adds further tests to compact3
|
||||
@ -361,3 +362,6 @@ needs_nashorn = \
|
||||
not_needs_nashorn = \
|
||||
:jdk \
|
||||
-:needs_nashorn
|
||||
|
||||
hotspot_tmtools = \
|
||||
serviceability/tmtools
|
||||
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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
|
||||
* @summary Create daemon and non-deamon threads.
|
||||
* Check the correctness of thread's status from jstack.
|
||||
* @library /test/lib/share/classes
|
||||
* @library ../share
|
||||
* @build common.*
|
||||
*
|
||||
* @run main/othervm -XX:+UsePerfData DaemonThreadTest
|
||||
*/
|
||||
import common.ToolResults;
|
||||
import utils.*;
|
||||
|
||||
public class DaemonThreadTest {
|
||||
|
||||
static class NormalThread extends Thread {
|
||||
|
||||
NormalThread() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Utils.sleep();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class DaemonThread extends Thread {
|
||||
|
||||
DaemonThread() {
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Utils.sleep();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
testNoDaemon();
|
||||
testDaemon();
|
||||
}
|
||||
|
||||
private static void testNoDaemon() throws Exception {
|
||||
testThread(new NormalThread(), "");
|
||||
}
|
||||
|
||||
private static void testDaemon() throws Exception {
|
||||
testThread(new DaemonThread(), "daemon");
|
||||
}
|
||||
|
||||
private static void testThread(Thread thread, String expectedType) throws Exception {
|
||||
// Start the thread
|
||||
thread.start();
|
||||
|
||||
// Run jstack tool and collect the output
|
||||
JstackTool jstackTool = new JstackTool(ProcessHandle.current().getPid());
|
||||
ToolResults results = jstackTool.measure();
|
||||
|
||||
// Analyze the jstack output for the correct thread type
|
||||
JStack jstack = new DefaultFormat().parse(results.getStdoutString());
|
||||
ThreadStack ti = jstack.getThreadStack(thread.getName());
|
||||
|
||||
if (!ti.getType().trim().equals(expectedType)) {
|
||||
throw new RuntimeException("incorrect thread type '" + ti.getType() + "' for the thread '" + thread.getName() + "'");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
36
hotspot/test/serviceability/tmtools/jstack/JstackTool.java
Normal file
36
hotspot/test/serviceability/tmtools/jstack/JstackTool.java
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
import common.TmTool;
|
||||
import common.ToolResults;
|
||||
|
||||
/**
|
||||
* This tool executes "jstack <pid>" and returns the results
|
||||
*/
|
||||
public class JstackTool extends TmTool<ToolResults> {
|
||||
|
||||
public JstackTool(long pid) {
|
||||
super(ToolResults.class, "jstack", String.valueOf(pid));
|
||||
}
|
||||
|
||||
}
|
195
hotspot/test/serviceability/tmtools/jstack/SpreadLockTest.java
Normal file
195
hotspot/test/serviceability/tmtools/jstack/SpreadLockTest.java
Normal file
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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
|
||||
* @summary Create a thread which stops in methods a(), a()->b(), a()->b()->c(),
|
||||
* synchronizing on one monitor inside of each method.
|
||||
* After checking that lock info is correct invoke another method
|
||||
* and get the lock again. Repeat this action.
|
||||
* @library /test/lib/share/classes
|
||||
* @library ../share
|
||||
* @build common.*
|
||||
*
|
||||
* @run main/othervm -XX:+UsePerfData SpreadLockTest
|
||||
*/
|
||||
import common.ToolResults;
|
||||
import java.util.Iterator;
|
||||
import utils.*;
|
||||
|
||||
class SpreadLockDebuggee extends Thread {
|
||||
|
||||
static final String THREAD_NAME = "MyThread";
|
||||
|
||||
SpreadLockDebuggee() {
|
||||
setName(THREAD_NAME);
|
||||
}
|
||||
|
||||
Object monitor = new Object();
|
||||
|
||||
public void c() {
|
||||
synchronized (monitor) {
|
||||
Utils.sleep();
|
||||
}
|
||||
}
|
||||
|
||||
public void b() {
|
||||
synchronized (monitor) {
|
||||
try {
|
||||
while (true) {
|
||||
Thread.sleep(Long.MAX_VALUE);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
c();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void a() {
|
||||
synchronized (monitor) {
|
||||
try {
|
||||
while (true) {
|
||||
Thread.sleep(Long.MAX_VALUE);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
b();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
a();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class SpreadLockTest {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new SpreadLockTest().doTest();
|
||||
}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
SpreadLockDebuggee debuggee = new SpreadLockDebuggee();
|
||||
|
||||
// Start in method a()
|
||||
debuggee.start();
|
||||
|
||||
// Collect output from the jstack tool
|
||||
JstackTool jstackTool = new JstackTool(ProcessHandle.current().getPid());
|
||||
ToolResults results1 = jstackTool.measure();
|
||||
|
||||
// Go to method b()
|
||||
debuggee.interrupt();
|
||||
|
||||
// Collect output from the jstack tool
|
||||
ToolResults results2 = jstackTool.measure();
|
||||
|
||||
// Go to method c()
|
||||
debuggee.interrupt();
|
||||
|
||||
// Collect output from the jstack tool
|
||||
ToolResults results3 = jstackTool.measure();
|
||||
|
||||
analyse(results1.getStdoutString(), results2.getStdoutString(), results3.getStdoutString());
|
||||
}
|
||||
|
||||
// Analyzing the outputs from the 3 jstack runs
|
||||
public void analyse(String result1, String result2, String result3) {
|
||||
String jstackStr1 = result1;
|
||||
String jstackStr2 = result2;
|
||||
String jstackStr3 = result3;
|
||||
|
||||
if (jstackStr1 == null) {
|
||||
throw new RuntimeException("First jstack output is empty");
|
||||
}
|
||||
if (jstackStr2 == null) {
|
||||
throw new RuntimeException("Second jstack output is empty");
|
||||
}
|
||||
if (jstackStr3 == null) {
|
||||
throw new RuntimeException("Third jstack output is empty");
|
||||
}
|
||||
|
||||
Format format = new DefaultFormat();
|
||||
JStack jstack1 = format.parse(jstackStr1);
|
||||
JStack jstack2 = format.parse(jstackStr2);
|
||||
JStack jstack3 = format.parse(jstackStr3);
|
||||
|
||||
ThreadStack ts1 = jstack1.getThreadStack(SpreadLockDebuggee.THREAD_NAME);
|
||||
ThreadStack ts2 = jstack2.getThreadStack(SpreadLockDebuggee.THREAD_NAME);
|
||||
ThreadStack ts3 = jstack3.getThreadStack(SpreadLockDebuggee.THREAD_NAME);
|
||||
|
||||
if (ts1 == null || ts2 == null || ts3 == null) {
|
||||
throw new RuntimeException(
|
||||
"One of thread stack trace is null in the first jstack output : "
|
||||
+ ts1 + ", " + ts2 + ", " + ts3);
|
||||
}
|
||||
|
||||
MonitorInfo[] monitorInfo = new MonitorInfo[6];
|
||||
int counter = 0;
|
||||
|
||||
Iterator<MethodInfo> it = ts1.getStack().iterator();
|
||||
while (it.hasNext()) {
|
||||
MethodInfo mi = it.next();
|
||||
if (mi.getName().startsWith(SpreadLockDebuggee.class.getName() + ".a")) {
|
||||
monitorInfo[counter++] = haveToHaveOneLock(mi);
|
||||
}
|
||||
}
|
||||
|
||||
it = ts2.getStack().iterator();
|
||||
while (it.hasNext()) {
|
||||
MethodInfo mi = it.next();
|
||||
if (mi.getName().startsWith(SpreadLockDebuggee.class.getName() + ".a")
|
||||
|| mi.getName().startsWith(SpreadLockDebuggee.class.getName() + ".b")) {
|
||||
monitorInfo[counter++] = haveToHaveOneLock(mi);
|
||||
}
|
||||
}
|
||||
|
||||
it = ts3.getStack().iterator();
|
||||
while (it.hasNext()) {
|
||||
MethodInfo mi = it.next();
|
||||
if (mi.getName().startsWith(SpreadLockDebuggee.class.getName() + ".a")
|
||||
|| mi.getName().startsWith(SpreadLockDebuggee.class.getName() + ".b")
|
||||
|| mi.getName().startsWith(SpreadLockDebuggee.class.getName() + ".c")) {
|
||||
monitorInfo[counter++] = haveToHaveOneLock(mi);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("All monitors found - passed");
|
||||
|
||||
}
|
||||
|
||||
private MonitorInfo haveToHaveOneLock(MethodInfo mi) {
|
||||
if (mi.getLocks().size() == 1) {
|
||||
System.out.println("Method \"" + mi.getName()
|
||||
+ "\" contain 1 lock - correct");
|
||||
return mi.getLocks().getFirst();
|
||||
} else {
|
||||
throw new RuntimeException("Lock count ("
|
||||
+ mi.getLocks().size() + ") is incorrect in method \""
|
||||
+ mi.getName() + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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
|
||||
* @summary Checks that jstack correctly prints the thread names
|
||||
* @library /test/lib/share/classes
|
||||
* @library ../share
|
||||
* @build common.*
|
||||
*
|
||||
* @run main/othervm -XX:+UsePerfData ThreadNamesTest
|
||||
*/
|
||||
import common.ToolResults;
|
||||
import utils.*;
|
||||
|
||||
public class ThreadNamesTest {
|
||||
|
||||
private static final String STRANGE_NAME = "-_?+!@#$%^*()";
|
||||
private static final String LONG_NAME = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong";
|
||||
|
||||
static class NamedThread extends Thread {
|
||||
|
||||
NamedThread(String name) {
|
||||
setName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Utils.sleep();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
testWithName(STRANGE_NAME);
|
||||
testWithName("");
|
||||
testWithName(LONG_NAME);
|
||||
}
|
||||
|
||||
private static void testWithName(String name) throws Exception {
|
||||
// Start a thread with some strange name
|
||||
NamedThread thread = new NamedThread(name);
|
||||
thread.start();
|
||||
|
||||
// Run jstack tool and collect the output
|
||||
JstackTool jstackTool = new JstackTool(ProcessHandle.current().getPid());
|
||||
ToolResults results = jstackTool.measure();
|
||||
|
||||
// Analyze the jstack output for the strange thread name
|
||||
JStack jstack1 = new DefaultFormat().parse(results.getStdoutString());
|
||||
ThreadStack ti1 = jstack1.getThreadStack(name);
|
||||
|
||||
if (ti1 == null) {
|
||||
throw new RuntimeException("jstack output doesn't contain thread info for the thread '" + name + "'");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
207
hotspot/test/serviceability/tmtools/jstack/TraveledLockTest.java
Normal file
207
hotspot/test/serviceability/tmtools/jstack/TraveledLockTest.java
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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
|
||||
* @summary Create a thread which stops in methods a(), a()->b(), a()->b()->c(),
|
||||
* synchronizing on one monitor inside of each method.
|
||||
* After checking that lock info is correct free the lock and
|
||||
* invoke another method. Repeat this action.
|
||||
* @library /test/lib/share/classes
|
||||
* @library ../share
|
||||
* @build common.*
|
||||
*
|
||||
* @run main/othervm -XX:+UsePerfData TraveledLockTest
|
||||
*/
|
||||
import common.ToolResults;
|
||||
import java.util.Iterator;
|
||||
import utils.*;
|
||||
|
||||
class TraveledLockDebuggee extends Thread {
|
||||
|
||||
static final String THREAD_NAME = "MyThread";
|
||||
|
||||
TraveledLockDebuggee() {
|
||||
setName(THREAD_NAME);
|
||||
}
|
||||
|
||||
Object monitor = new Object();
|
||||
|
||||
public void c() {
|
||||
synchronized (monitor) {
|
||||
Utils.sleep();
|
||||
}
|
||||
}
|
||||
|
||||
public void b() {
|
||||
try {
|
||||
synchronized (monitor) {
|
||||
while (true) {
|
||||
Thread.sleep(Long.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
c();
|
||||
}
|
||||
}
|
||||
|
||||
public void a() {
|
||||
try {
|
||||
synchronized (monitor) {
|
||||
while (true) {
|
||||
Thread.sleep(Long.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
b();
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
a();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class TraveledLockTest {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new TraveledLockTest().doTest();
|
||||
}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
TraveledLockDebuggee debuggee = new TraveledLockDebuggee();
|
||||
|
||||
// Start in method a()
|
||||
debuggee.start();
|
||||
|
||||
// Collect output from the jstack tool
|
||||
JstackTool jstackTool = new JstackTool(ProcessHandle.current().getPid());
|
||||
ToolResults results1 = jstackTool.measure();
|
||||
|
||||
// Go to method b()
|
||||
debuggee.interrupt();
|
||||
|
||||
// Collect output from the jstack tool
|
||||
ToolResults results2 = jstackTool.measure();
|
||||
|
||||
// Go to method c()
|
||||
debuggee.interrupt();
|
||||
|
||||
// Collect output from the jstack tool
|
||||
ToolResults results3 = jstackTool.measure();
|
||||
|
||||
analyse(results1.getStdoutString(), results2.getStdoutString(), results3.getStdoutString());
|
||||
}
|
||||
|
||||
// Analyzsing the outputs from the 3 jstack runs
|
||||
public void analyse(String results1, String results2, String results3) {
|
||||
|
||||
String jstackStr1 = results1;
|
||||
String jstackStr2 = results2;
|
||||
String jstackStr3 = results3;
|
||||
|
||||
if (jstackStr1 == null) {
|
||||
throw new RuntimeException("First jstack output is empty");
|
||||
}
|
||||
if (jstackStr2 == null) {
|
||||
throw new RuntimeException("Second jstack output is empty");
|
||||
}
|
||||
if (jstackStr3 == null) {
|
||||
throw new RuntimeException("Third jstack output is empty");
|
||||
}
|
||||
|
||||
Format format = new DefaultFormat();
|
||||
JStack jstack1 = format.parse(jstackStr1);
|
||||
JStack jstack2 = format.parse(jstackStr2);
|
||||
JStack jstack3 = format.parse(jstackStr3);
|
||||
|
||||
ThreadStack ts1 = jstack1.getThreadStack(TraveledLockDebuggee.THREAD_NAME);
|
||||
ThreadStack ts2 = jstack2.getThreadStack(TraveledLockDebuggee.THREAD_NAME);
|
||||
ThreadStack ts3 = jstack3.getThreadStack(TraveledLockDebuggee.THREAD_NAME);
|
||||
|
||||
if (ts1 == null || ts2 == null || ts3 == null) {
|
||||
throw new RuntimeException(
|
||||
"One of thread stack trace is null in the first jstack output : "
|
||||
+ ts1 + ", " + ts2 + ", " + ts3);
|
||||
}
|
||||
|
||||
MonitorInfo monitorInfo1 = null;
|
||||
MonitorInfo monitorInfo2 = null;
|
||||
MonitorInfo monitorInfo3 = null;
|
||||
|
||||
Iterator<MethodInfo> it = ts1.getStack().iterator();
|
||||
while (it.hasNext()) {
|
||||
MethodInfo mi = it.next();
|
||||
if (mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".a")) {
|
||||
monitorInfo1 = haveToHaveOneLock(mi);
|
||||
}
|
||||
}
|
||||
|
||||
it = ts2.getStack().iterator();
|
||||
while (it.hasNext()) {
|
||||
MethodInfo mi = it.next();
|
||||
if (mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".a")) {
|
||||
haveToBeEmpty(mi);
|
||||
} else if (mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".b")) {
|
||||
monitorInfo2 = haveToHaveOneLock(mi);
|
||||
}
|
||||
}
|
||||
|
||||
it = ts3.getStack().iterator();
|
||||
while (it.hasNext()) {
|
||||
MethodInfo mi = it.next();
|
||||
if (mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".a")
|
||||
|| mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".b")) {
|
||||
haveToBeEmpty(mi);
|
||||
} else if (mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".c")) {
|
||||
monitorInfo3 = haveToHaveOneLock(mi);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("All monitors found - passed");
|
||||
}
|
||||
|
||||
private MonitorInfo haveToHaveOneLock(MethodInfo mi) {
|
||||
if (mi.getLocks().size() == 1) {
|
||||
System.out.println("Method \"" + mi.getName()
|
||||
+ "\" contain 1 lock - correct");
|
||||
return mi.getLocks().getFirst();
|
||||
} else {
|
||||
throw new RuntimeException("Lock count ("
|
||||
+ mi.getLocks().size() + ") is incorrect in method \""
|
||||
+ mi.getName() + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
private void haveToBeEmpty(MethodInfo mi) {
|
||||
if (mi.getLocks().size() == 0) {
|
||||
System.out.println("Method \"" + mi.getName()
|
||||
+ "\" does not lock anything - correct");
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"Unexpected lock found in method \"" + mi.getName() + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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
|
||||
* @summary Call Object.wait() method. Check that monitor information
|
||||
* presented in the stack is correct. Call notifyAll method
|
||||
* monitor info have to disappear from the stack.
|
||||
* Repeats the same scenario calling interrupt() method
|
||||
* @library /test/lib/share/classes
|
||||
* @library ../share
|
||||
* @build common.*
|
||||
*
|
||||
* @run main/othervm -XX:+UsePerfData WaitNotifyThreadTest
|
||||
*/
|
||||
import common.ToolResults;
|
||||
import java.util.Iterator;
|
||||
import utils.*;
|
||||
|
||||
public class WaitNotifyThreadTest {
|
||||
|
||||
private Object monitor = new Object();
|
||||
private final String OBJECT = "a java.lang.Object";
|
||||
private final String OBJECT_WAIT = "java.lang.Object.wait";
|
||||
|
||||
interface Action {
|
||||
|
||||
void doAction(Thread thread);
|
||||
}
|
||||
|
||||
class ActionNotify implements Action {
|
||||
|
||||
@Override
|
||||
public void doAction(Thread thread) {
|
||||
//Notify the waiting thread, so it stops waiting and sleeps
|
||||
synchronized (monitor) {
|
||||
monitor.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ActionInterrupt implements Action {
|
||||
|
||||
@Override
|
||||
public void doAction(Thread thread) {
|
||||
// Interrupt the thread
|
||||
thread.interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
class WaitThread extends Thread {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
synchronized (monitor) {
|
||||
monitor.wait();
|
||||
}
|
||||
} catch (InterruptedException x) {
|
||||
|
||||
}
|
||||
Utils.sleep();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new WaitNotifyThreadTest().doTest();
|
||||
}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
// Verify stack trace consistency when notifying the thread
|
||||
doTest(new ActionNotify());
|
||||
|
||||
// Verify stack trace consistency when interrupting the thread
|
||||
doTest(new ActionInterrupt());
|
||||
}
|
||||
|
||||
private void doTest(Action action) throws Exception {
|
||||
|
||||
final String WAITING_THREAD_NAME = "MyWaitingThread";
|
||||
|
||||
// Start athread that just waits
|
||||
WaitThread waitThread = new WaitThread();
|
||||
waitThread.setName(WAITING_THREAD_NAME);
|
||||
waitThread.start();
|
||||
|
||||
// Collect output from the jstack tool
|
||||
JstackTool jstackTool = new JstackTool(ProcessHandle.current().getPid());
|
||||
ToolResults results = jstackTool.measure();
|
||||
|
||||
// Analyze the jstack output for the patterns needed
|
||||
JStack jstack1 = new DefaultFormat().parse(results.getStdoutString());
|
||||
ThreadStack ti1 = jstack1.getThreadStack(WAITING_THREAD_NAME);
|
||||
analyzeThreadStackWaiting(ti1);
|
||||
|
||||
action.doAction(waitThread);
|
||||
|
||||
// Collect output from the jstack tool again
|
||||
results = jstackTool.measure();
|
||||
|
||||
// Analyze the output again
|
||||
JStack jstack2 = new DefaultFormat().parse(results.getStdoutString());
|
||||
ThreadStack ti2 = jstack2.getThreadStack(WAITING_THREAD_NAME);
|
||||
analyzeThreadStackNoWaiting(ti2);
|
||||
|
||||
}
|
||||
|
||||
private void analyzeThreadStackWaiting(ThreadStack ti1) {
|
||||
Iterator<MethodInfo> it = ti1.getStack().iterator();
|
||||
|
||||
String monitorAddress = null;
|
||||
while (it.hasNext()) {
|
||||
MethodInfo mi = it.next();
|
||||
if (mi.getName().startsWith(OBJECT_WAIT) && mi.getCompilationUnit() == null /*native method*/) {
|
||||
if (mi.getLocks().size() == 1) {
|
||||
MonitorInfo monInfo = mi.getLocks().getFirst();
|
||||
if (monInfo.getType().equals("waiting on")
|
||||
&& monInfo.getMonitorClass().equals(OBJECT)) {
|
||||
monitorAddress = monInfo.getMonitorAddress();
|
||||
} else {
|
||||
System.err.println("Error: incorrect monitor info: " + monInfo.getType() + ", " + monInfo.getMonitorClass());
|
||||
throw new RuntimeException("Incorrect lock record in "
|
||||
+ OBJECT_WAIT + " method");
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new RuntimeException(OBJECT_WAIT
|
||||
+ " method has to contain one lock record bu it contains " + mi.getLocks().size());
|
||||
}
|
||||
}
|
||||
|
||||
if (mi.getName().startsWith("WaitThread.run")) {
|
||||
if (monitorAddress == null) {
|
||||
throw new RuntimeException("Cannot found monitor info associated with " + OBJECT_WAIT + " method");
|
||||
}
|
||||
|
||||
int numLocks = mi.getLocks().size();
|
||||
for (int i = 0; i < numLocks - 1; ++i) {
|
||||
assertMonitorInfo("waiting to re-lock in wait()", mi.getLocks().get(i), monitorAddress);
|
||||
}
|
||||
assertMonitorInfo("locked", mi.getLocks().getLast(), monitorAddress);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void assertMonitorInfo(String expectedMessage, MonitorInfo monInfo, String monitorAddress) {
|
||||
if (monInfo.getType().equals(expectedMessage)
|
||||
&& monInfo.getMonitorClass().equals(OBJECT + "11")
|
||||
&& monInfo.getMonitorAddress().equals(
|
||||
monitorAddress)) {
|
||||
System.out.println("Correct monitor info found");
|
||||
} else {
|
||||
System.err.println("Error: incorrect monitor info: " + monInfo.getType() + ", " + monInfo.getMonitorClass() + ", " + monInfo.getMonitorAddress());
|
||||
System.err.println("Expected: " + expectedMessage + ", a java.lang.Object, " + monitorAddress);
|
||||
throw new RuntimeException("Incorrect lock record in 'run' method");
|
||||
}
|
||||
}
|
||||
|
||||
private void analyzeThreadStackNoWaiting(ThreadStack ti2) {
|
||||
Iterator<MethodInfo> it = ti2.getStack().iterator();
|
||||
|
||||
while (it.hasNext()) {
|
||||
MethodInfo mi = it.next();
|
||||
if (mi.getLocks().size() != 0) {
|
||||
throw new RuntimeException("Unexpected lock record in "
|
||||
+ mi.getName() + " method");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
47
hotspot/test/serviceability/tmtools/jstack/utils/Consts.java
Normal file
47
hotspot/test/serviceability/tmtools/jstack/utils/Consts.java
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class includes reused constants across jstack's tests
|
||||
*
|
||||
*/
|
||||
public class Consts {
|
||||
|
||||
public static final String UNKNOWN = "XXXXXX";
|
||||
public static final String JNI_GLOBAL_REF = "JNI global references: ";
|
||||
public static final String SCENARIO_NAME = "scenario";
|
||||
public static final String SEPARATOR = " ";
|
||||
|
||||
public static String REENTRANT_LOCK_NONFAIR = "a java.util.concurrent.locks.ReentrantLock$NonfairSync";
|
||||
public static String REENTRANT_LOCK_FAIR = "a java.util.concurrent.locks.ReentrantLock$FairSync";
|
||||
public static final String FFORMAT_REENTRANT_LOCK_NONFAIR = "a java/util/concurrent/locks/ReentrantLock$NonfairSync";
|
||||
public static final String FFORMAT_REENTRANT_LOCK_FAIR = "a java/util/concurrent/locks/ReentrantLock$FairSync";
|
||||
|
||||
public static String REENTRANT_RW_LOCK_NONFAIR = "a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync";
|
||||
public static String REENTRANT_RW_LOCK_FAIR = "a java.util.concurrent.locks.ReentrantReadWriteLock$FairSync";
|
||||
public static final String FFORMAT_REENTRANT_RW_LOCK_NONFAIR = "a java/util/concurrent/locks/ReentrantReadWriteLock$NonfairSync";
|
||||
public static final String FFORMAT_REENTRANT_RW_LOCK_FAIR = "a java/util/concurrent/locks/ReentrantReadWriteLock$FairSync";
|
||||
|
||||
}
|
@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
import java.util.regex.MatchResult;
|
||||
|
||||
/**
|
||||
*
|
||||
* jstack default format 2008-03-05 18:36:26 Full thread dump Java HotSpot(TM)
|
||||
* Client VM (11.0-b11 mixed mode):
|
||||
*
|
||||
* "Thread-16" #10 daemon prio=3 os_prio=0 tid=0x0814d800 nid=0x1d runnable
|
||||
* [0xf394d000..0xf394d9f0] java.lang.Thread.State: RUNNABLE at
|
||||
* java.net.SocketInputStream.socketRead0(Native Method) at
|
||||
* java.net.SocketInputStream.read(SocketInputStream.java:129) at
|
||||
* java.net.SocketInputStream.read(SocketInputStream.java:182) at
|
||||
* java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2249)
|
||||
* at
|
||||
* java.io.ObjectInputStream$BlockDataInputStream.peek(ObjectInputStream.java:2542)
|
||||
* at
|
||||
* java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2552)
|
||||
* at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1297) at
|
||||
* java.io.ObjectInputStream.readObject(ObjectInputStream.java:351) at
|
||||
* tmtools.share.debuggee.DebuggeeProtocolHandler.run(DebuggeeProtocolHandler.java:32)
|
||||
*
|
||||
* Locked ownable synchronizers: - None ....
|
||||
*
|
||||
* Note that os_prio field is optional and will be printed only if JVM was able
|
||||
* to get native thread priority.
|
||||
*/
|
||||
public class DefaultFormat implements Format {
|
||||
|
||||
protected String threadInfoPattern() {
|
||||
return "^\"(.*)\"\\s(#\\d+\\s|)(daemon\\s|)prio=(.+)\\s(os_prio=(.+)\\s|)tid=(.+)\\snid=(.+)\\s("
|
||||
+ Consts.UNKNOWN
|
||||
+ "|runnable|waiting\\son\\scondition|in\\sObject\\.wait\\(\\)|waiting\\sfor\\smonitor\\sentry)((.*))$";
|
||||
}
|
||||
|
||||
protected String methodInfoPattern() {
|
||||
return "^\\s+at\\s(.+)\\((.*?)(\\:|\\))((.*?))\\)?$";
|
||||
}
|
||||
|
||||
protected String extendedStatusPattern() {
|
||||
return "\\s+java\\.lang\\.Thread\\.State\\:\\s((.+))$";
|
||||
}
|
||||
|
||||
protected String jniGlobalRefInfoPattern() {
|
||||
return "^JNI\\sglobal\\sreferences:\\s((.+))$";
|
||||
}
|
||||
|
||||
protected String monitorInfoPattern() {
|
||||
return "^\\s+\\-\\s(locked|waiting\\son|waiting\\sto\\slock)\\s\\<(.*)\\>\\s\\(((.*))\\)$";
|
||||
}
|
||||
|
||||
protected String vmVersionInfoPattern() {
|
||||
return "Full\\sthread\\sdump\\s.*";
|
||||
}
|
||||
|
||||
protected String ownableSynchronizersPattern() {
|
||||
return "^\\s+\\-\\s(\\<.*\\>\\s\\(((.*))\\)|None)$";
|
||||
}
|
||||
|
||||
public JStack parse(String stack) {
|
||||
JStack result = new JStack();
|
||||
Scanner scanner = new Scanner(stack);
|
||||
|
||||
// parsing thread stacks
|
||||
ThreadStack currentThreadStack = null;
|
||||
MethodInfo currentMethodInfo = null;
|
||||
|
||||
try {
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine();
|
||||
if (line.matches(threadInfoPattern())) {
|
||||
currentThreadStack = parseThreadInfo(line);
|
||||
result.addThreadStack(currentThreadStack.getThreadName(), currentThreadStack);
|
||||
} else if (line.matches(methodInfoPattern())) {
|
||||
currentMethodInfo = parseMethodInfo(line);
|
||||
currentThreadStack.addMethod(currentMethodInfo);
|
||||
} else if (line.matches(monitorInfoPattern())) {
|
||||
MonitorInfo mi = parseMonitorInfo(line);
|
||||
currentMethodInfo.getLocks().add(mi);
|
||||
} else if (line.matches(extendedStatusPattern())) {
|
||||
currentThreadStack.setExtendedStatus(parseExtendedStatus(line));
|
||||
} else if (line.matches(vmVersionInfoPattern())) {
|
||||
result.setVmVersion(line);
|
||||
} else if (line.matches(ownableSynchronizersPattern())) {
|
||||
currentThreadStack.getLockOSList().add(parseLockInfo(line));
|
||||
} else if (line.matches(jniGlobalRefInfoPattern())) {
|
||||
result.setJniGlobalReferences(parseJNIGlobalRefs(line));
|
||||
} else if (line.length() != 0) {
|
||||
System.err.println("[Warning] Unknown string: " + line);
|
||||
}
|
||||
}
|
||||
|
||||
scanner.close();
|
||||
|
||||
} catch (NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("Unexpected format in jstack output");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private MonitorInfo parseMonitorInfo(String line) {
|
||||
Scanner s = new Scanner(line);
|
||||
s.findInLine(monitorInfoPattern());
|
||||
MonitorInfo mi = new MonitorInfo();
|
||||
MatchResult res = s.match();
|
||||
|
||||
mi.setType(res.group(1));
|
||||
mi.setMonitorAddress(res.group(2));
|
||||
mi.setMonitorClass(res.group(3));
|
||||
|
||||
return mi;
|
||||
}
|
||||
|
||||
protected String parseExtendedStatus(String line) {
|
||||
Scanner s = new Scanner(line);
|
||||
s.findInLine(extendedStatusPattern());
|
||||
String result = s.match().group(1);
|
||||
s.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
protected String parseJNIGlobalRefs(String line) {
|
||||
Scanner s = new Scanner(line);
|
||||
s.findInLine(jniGlobalRefInfoPattern());
|
||||
String result = s.match().group(1);
|
||||
s.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
protected ThreadStack parseThreadInfo(String threadInfo) {
|
||||
Scanner s = new Scanner(threadInfo);
|
||||
ThreadStack result = new ThreadStack();
|
||||
|
||||
// parsing thread info
|
||||
s.findInLine(threadInfoPattern());
|
||||
MatchResult res = s.match();
|
||||
|
||||
result.setThreadName(res.group(1));
|
||||
|
||||
result.setType(res.group(3));
|
||||
|
||||
result.setPriority(res.group(4));
|
||||
result.setTid(res.group(7));
|
||||
result.setNid(res.group(8));
|
||||
result.setStatus(res.group(9));
|
||||
|
||||
s.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
protected MethodInfo parseMethodInfo(String line) {
|
||||
|
||||
MethodInfo result = new MethodInfo();
|
||||
Scanner s = new Scanner(line);
|
||||
|
||||
s.findInLine(methodInfoPattern());
|
||||
MatchResult rexp = s.match();
|
||||
if (rexp.group(4) != null && rexp.group(4).length() > 0) {
|
||||
// line " at tmtools.jstack.share.utils.Utils.sleep(Utils.java:29)"
|
||||
result.setName(rexp.group(1));
|
||||
result.setCompilationUnit(rexp.group(2));
|
||||
result.setLine(rexp.group(4));
|
||||
|
||||
} else {
|
||||
// line " at java.lang.Thread.sleep(Native Method)"
|
||||
result.setName(rexp.group(1));
|
||||
}
|
||||
|
||||
s.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
public String dumpStackTraces() {
|
||||
StringBuffer result = new StringBuffer();
|
||||
Map<Thread, StackTraceElement[]> stacks = Thread.getAllStackTraces();
|
||||
|
||||
// adding data and vm version
|
||||
result.append(Consts.UNKNOWN + "\n");
|
||||
result.append(Consts.UNKNOWN + "\n\n");
|
||||
|
||||
for (Thread t : stacks.keySet()) {
|
||||
|
||||
result.append("\"" + t.getName() + "\"");
|
||||
result.append(Consts.SEPARATOR);
|
||||
|
||||
// status
|
||||
if (t.isDaemon()) {
|
||||
result.append("daemon");
|
||||
result.append(Consts.SEPARATOR);
|
||||
}
|
||||
|
||||
// priority
|
||||
result.append("prio=" + t.getPriority());
|
||||
result.append(Consts.SEPARATOR);
|
||||
|
||||
// tid
|
||||
result.append("tid=" + Consts.UNKNOWN);
|
||||
result.append(Consts.SEPARATOR);
|
||||
|
||||
// nid
|
||||
result.append("nid=" + Consts.UNKNOWN);
|
||||
result.append(Consts.SEPARATOR);
|
||||
|
||||
// status
|
||||
result.append(Consts.UNKNOWN);
|
||||
result.append(Consts.SEPARATOR);
|
||||
|
||||
result.append("\n");
|
||||
|
||||
// extended status
|
||||
result.append(" java.lang.Thread.State: "
|
||||
+ String.valueOf(Thread.currentThread().getState()));
|
||||
result.append(Consts.SEPARATOR);
|
||||
result.append("\n");
|
||||
|
||||
for (StackTraceElement st : stacks.get(t)) {
|
||||
result.append(" at " + st.toString() + "\n");
|
||||
}
|
||||
result.append("\n");
|
||||
}
|
||||
|
||||
result.append(Consts.JNI_GLOBAL_REF + Consts.UNKNOWN + "\n");
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
protected LockInfo parseLockInfo(String line) {
|
||||
LockInfo res = new LockInfo();
|
||||
|
||||
Scanner s = new Scanner(line);
|
||||
s.findInLine(ownableSynchronizersPattern());
|
||||
|
||||
MatchResult matchRes = s.match();
|
||||
String lock = matchRes.group(1).equals("None") ? matchRes.group(1) : matchRes.group(2);
|
||||
res.setLock(lock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
34
hotspot/test/serviceability/tmtools/jstack/utils/Format.java
Normal file
34
hotspot/test/serviceability/tmtools/jstack/utils/Format.java
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
/**
|
||||
*
|
||||
* Base class for all formats
|
||||
*
|
||||
*/
|
||||
public interface Format {
|
||||
|
||||
public JStack parse(String stack);
|
||||
|
||||
}
|
80
hotspot/test/serviceability/tmtools/jstack/utils/JStack.java
Normal file
80
hotspot/test/serviceability/tmtools/jstack/utils/JStack.java
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
*
|
||||
* Represents stack of all threads + some extra information
|
||||
*
|
||||
*/
|
||||
public class JStack {
|
||||
|
||||
private String date;
|
||||
private String vmVersion;
|
||||
private HashMap<String, ThreadStack> threads = new HashMap<String, ThreadStack>();
|
||||
private String jniGlobalReferences;
|
||||
|
||||
public String getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(String date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public String getVmVersion() {
|
||||
return vmVersion;
|
||||
}
|
||||
|
||||
public void setVmVersion(String vmVersion) {
|
||||
this.vmVersion = vmVersion;
|
||||
}
|
||||
|
||||
public HashMap<String, ThreadStack> getThreads() {
|
||||
return threads;
|
||||
}
|
||||
|
||||
public void setThreads(HashMap<String, ThreadStack> threads) {
|
||||
this.threads = threads;
|
||||
}
|
||||
|
||||
public void addThreadStack(String threadName, ThreadStack ts) {
|
||||
System.out.println("Adding thread stack for thread: " + threadName);
|
||||
threads.put(threadName, ts);
|
||||
}
|
||||
|
||||
public String getJniGlobalReferences() {
|
||||
return jniGlobalReferences;
|
||||
}
|
||||
|
||||
public void setJniGlobalReferences(String jniGlobalReferences) {
|
||||
this.jniGlobalReferences = jniGlobalReferences;
|
||||
}
|
||||
|
||||
public ThreadStack getThreadStack(String threadName) {
|
||||
return threads.get(threadName);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
/**
|
||||
*
|
||||
* Represents lock info string
|
||||
*
|
||||
*/
|
||||
public class LockInfo {
|
||||
|
||||
private String lock;
|
||||
|
||||
public String getLock() {
|
||||
return lock;
|
||||
}
|
||||
|
||||
public void setLock(String lock) {
|
||||
this.lock = lock;
|
||||
}
|
||||
}
|
137
hotspot/test/serviceability/tmtools/jstack/utils/MethodInfo.java
Normal file
137
hotspot/test/serviceability/tmtools/jstack/utils/MethodInfo.java
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
*
|
||||
* Represents method info string
|
||||
*
|
||||
*/
|
||||
public class MethodInfo {
|
||||
|
||||
private String name;
|
||||
private String compilationUnit;
|
||||
private String args;
|
||||
private String bci;
|
||||
private String line;
|
||||
private String frameType;
|
||||
|
||||
private LinkedList<MonitorInfo> locks = new LinkedList<MonitorInfo>();
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getCompilationUnit() {
|
||||
return compilationUnit;
|
||||
}
|
||||
|
||||
public void setCompilationUnit(String compilationUnit) {
|
||||
this.compilationUnit = compilationUnit;
|
||||
}
|
||||
|
||||
public String getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public void setArgs(String args) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public String getBci() {
|
||||
return bci;
|
||||
}
|
||||
|
||||
public void setBci(String bci) {
|
||||
this.bci = bci;
|
||||
}
|
||||
|
||||
public String getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
public void setLine(String line) {
|
||||
this.line = line;
|
||||
}
|
||||
|
||||
public String getFrameType() {
|
||||
return frameType;
|
||||
}
|
||||
|
||||
public void setFrameType(String frameType) {
|
||||
this.frameType = frameType;
|
||||
}
|
||||
|
||||
public LinkedList<MonitorInfo> getLocks() {
|
||||
return locks;
|
||||
}
|
||||
|
||||
public void setLocks(LinkedList<MonitorInfo> locks) {
|
||||
this.locks = locks;
|
||||
}
|
||||
|
||||
public boolean equals(MethodInfo another) {
|
||||
|
||||
boolean result = true;
|
||||
|
||||
if (!Utils.compareStrings(name, another.name)) {
|
||||
Utils.log("name", name, another.name);
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!Utils.compareStrings(compilationUnit, another.compilationUnit)) {
|
||||
Utils.log("compilationUnit", compilationUnit, another.compilationUnit);
|
||||
result = false;
|
||||
}
|
||||
|
||||
/*
|
||||
if (!Utils.compareStrings(args, another.args)) {
|
||||
Utils.log("args", args, another.args);
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!Utils.compareStrings(bci, another.bci)) {
|
||||
Utils.log("bci", bci, another.bci);
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!Utils.compareStrings(frameType, another.frameType)) {
|
||||
Utils.log("frameType", frameType, another.frameType);
|
||||
result = false;
|
||||
}
|
||||
*/
|
||||
if (!Utils.compareStrings(line, another.line)) {
|
||||
Utils.log("line", line, another.line);
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
/**
|
||||
*
|
||||
* Represents monitor info string
|
||||
*
|
||||
*/
|
||||
public class MonitorInfo {
|
||||
|
||||
private String type;
|
||||
private String monitorAddress;
|
||||
private String monitorClass;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getMonitorAddress() {
|
||||
return monitorAddress;
|
||||
}
|
||||
|
||||
public void setMonitorAddress(String monitorAddress) {
|
||||
this.monitorAddress = monitorAddress;
|
||||
}
|
||||
|
||||
public String getMonitorClass() {
|
||||
return monitorClass;
|
||||
}
|
||||
|
||||
public void setMonitorClass(String monitorClass) {
|
||||
this.monitorClass = monitorClass;
|
||||
}
|
||||
|
||||
public boolean equals(MonitorInfo another) {
|
||||
if (!type.equals(another.type)) {
|
||||
Utils.log("type", type, another.type);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!monitorAddress.equals(another.monitorAddress)) {
|
||||
Utils.log("monitorAddress", monitorAddress, another.monitorAddress);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!monitorClass.equals(another.monitorClass)) {
|
||||
Utils.log("monitorClass", monitorClass, another.monitorClass);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return type + " <" + monitorAddress + "> (" + monitorClass + ")";
|
||||
}
|
||||
}
|
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
*
|
||||
* Represents the stack of the thread
|
||||
*
|
||||
*/
|
||||
public class ThreadStack {
|
||||
|
||||
private String threadType; // Thread / RealtimeThread / NoHeapRealtimeThread
|
||||
private String threadName;
|
||||
private String type; //daemon or not
|
||||
private String priority;
|
||||
private String tid;
|
||||
private String nid;
|
||||
|
||||
/**
|
||||
* runnable or waiting on condition
|
||||
*/
|
||||
private String status;
|
||||
private String pointerRange;
|
||||
|
||||
/**
|
||||
* i.e. java.lang.Thread.State: WAITING (on object monitor)
|
||||
*/
|
||||
private String extendedStatus;
|
||||
|
||||
private LinkedList<MethodInfo> stack = new LinkedList<MethodInfo>();
|
||||
|
||||
private LinkedList<LockInfo> lockOSList = new LinkedList<LockInfo>();
|
||||
|
||||
public String getThreadName() {
|
||||
return threadName;
|
||||
}
|
||||
|
||||
public void setThreadName(String threadName) {
|
||||
this.threadName = threadName;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
public void setPriority(String priority) {
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public String getTid() {
|
||||
return tid;
|
||||
}
|
||||
|
||||
public void setTid(String tid) {
|
||||
this.tid = tid;
|
||||
}
|
||||
|
||||
public String getNid() {
|
||||
return nid;
|
||||
}
|
||||
|
||||
public void setNid(String nid) {
|
||||
this.nid = nid;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getPointerRange() {
|
||||
return pointerRange;
|
||||
}
|
||||
|
||||
public void setPointerRange(String pointerRange) {
|
||||
this.pointerRange = pointerRange;
|
||||
}
|
||||
|
||||
public String getExtendedStatus() {
|
||||
return extendedStatus;
|
||||
}
|
||||
|
||||
public void setExtendedStatus(String extendedStatus) {
|
||||
this.extendedStatus = extendedStatus;
|
||||
}
|
||||
|
||||
public LinkedList<MethodInfo> getStack() {
|
||||
return stack;
|
||||
}
|
||||
|
||||
public LinkedList<LockInfo> getLockOSList() {
|
||||
return lockOSList;
|
||||
}
|
||||
|
||||
public void setLockOSList(LinkedList<LockInfo> lockOSList) {
|
||||
this.lockOSList = lockOSList;
|
||||
}
|
||||
|
||||
public void addMethod(MethodInfo mi) {
|
||||
stack.add(mi);
|
||||
}
|
||||
|
||||
public boolean hasEqualStack(ThreadStack another) {
|
||||
boolean result = true;
|
||||
|
||||
Iterator<MethodInfo> it1 = stack.iterator();
|
||||
Iterator<MethodInfo> it2 = another.stack.iterator();
|
||||
|
||||
while (it1.hasNext() && it2.hasNext()) {
|
||||
|
||||
MethodInfo mi1 = it1.next();
|
||||
MethodInfo mi2 = it2.next();
|
||||
|
||||
if (mi1 == null && mi2 == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
boolean oneOfMethodInfoIsNull = mi1 == null && mi2 != null || mi1 != null && mi2 == null;
|
||||
|
||||
if (oneOfMethodInfoIsNull || !mi1.equals(mi2)) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (it1.hasNext() || it2.hasNext()) {
|
||||
Utils.log("stack sizes", String.valueOf(stack.size()), String.valueOf(another.stack.size()));
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getThreadType() {
|
||||
return threadType;
|
||||
}
|
||||
|
||||
public void setThreadType(String threadType) {
|
||||
this.threadType = threadType;
|
||||
}
|
||||
|
||||
}
|
56
hotspot/test/serviceability/tmtools/jstack/utils/Utils.java
Normal file
56
hotspot/test/serviceability/tmtools/jstack/utils/Utils.java
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
public class Utils {
|
||||
|
||||
public static void log(String field, String val1, String val2) {
|
||||
System.out.println(field + " mismatch. " + val1 + " vs " + val2);
|
||||
}
|
||||
|
||||
public static boolean compareStrings(String s1, String s2) {
|
||||
|
||||
if (s1 != null && s1.equals(Consts.UNKNOWN)
|
||||
|| s2 != null && s2.equals(Consts.UNKNOWN)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (s1 == null && s2 != null || s1 != null && s2 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s1 == null || s2 == null) {
|
||||
return true;
|
||||
}
|
||||
return s1.equals(s2);
|
||||
}
|
||||
|
||||
public static void sleep() {
|
||||
try {
|
||||
while (true) {
|
||||
Thread.sleep(Long.MAX_VALUE);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
import utils.*;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Test checks the consistency of the output
|
||||
* displayed with jstat -gccapacity.
|
||||
* @library /test/lib/share/classes
|
||||
* @library ../share
|
||||
* @build common.*
|
||||
* @build utils.*
|
||||
* @run main/othervm -XX:+UsePerfData GcCapacityTest
|
||||
*/
|
||||
public class GcCapacityTest {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
// We will be running "jstat -gc" tool
|
||||
JstatGcCapacityTool jstatGcTool = new JstatGcCapacityTool(ProcessHandle.current().getPid());
|
||||
|
||||
// Run once and get the results asserting that they are reasonable
|
||||
JstatGcCapacityResults measurement1 = jstatGcTool.measure();
|
||||
measurement1.assertConsistency();
|
||||
|
||||
// Provoke a gc and verify the changed values
|
||||
GcProvoker gcProvoker = GcProvoker.createGcProvoker();
|
||||
gcProvoker.provokeGc();
|
||||
JstatGcCapacityResults measurement2 = jstatGcTool.measure();
|
||||
measurement2.assertConsistency();
|
||||
|
||||
// Assert that the GC events count has increased
|
||||
JstatResults.assertGCEventsIncreased(measurement1, measurement2);
|
||||
|
||||
// Provoke a gc again and verify the changed values
|
||||
gcProvoker.provokeGc();
|
||||
JstatGcCapacityResults measurement3 = jstatGcTool.measure();
|
||||
measurement3.assertConsistency();
|
||||
|
||||
// Assert that the GC events count has increased
|
||||
JstatResults.assertGCEventsIncreased(measurement1, measurement2);
|
||||
}
|
||||
|
||||
}
|
72
hotspot/test/serviceability/tmtools/jstat/GcCauseTest01.java
Normal file
72
hotspot/test/serviceability/tmtools/jstat/GcCauseTest01.java
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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
|
||||
* @summary Test checks output displayed with jstat -gccause.
|
||||
* Test scenario:
|
||||
* test several times provokes garbage collection in the debuggee application and after each garbage
|
||||
* collection runs jstat. jstat should show that after garbage collection number of GC events and garbage
|
||||
* collection time increase.
|
||||
* @library /test/lib/share/classes
|
||||
* @library ../share
|
||||
* @build common.*
|
||||
* @build utils.*
|
||||
*
|
||||
* @run main/othervm -XX:+UsePerfData GcCauseTest01
|
||||
*/
|
||||
import utils.*;
|
||||
|
||||
public class GcCauseTest01 {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
// We will be running "jstat -gc" tool
|
||||
JstatGcCauseTool jstatGcTool = new JstatGcCauseTool(ProcessHandle.current().getPid());
|
||||
|
||||
// Run once and get the results asserting that they are reasonable
|
||||
JstatGcCauseResults measurement1 = jstatGcTool.measure();
|
||||
measurement1.assertConsistency();
|
||||
|
||||
GcProvoker gcProvoker = GcProvoker.createGcProvoker();
|
||||
|
||||
// Provoke GC then run the tool again and get the results asserting that they are reasonable
|
||||
gcProvoker.provokeGc();
|
||||
JstatGcCauseResults measurement2 = jstatGcTool.measure();
|
||||
measurement2.assertConsistency();
|
||||
|
||||
// Assert the increase in GC events and time between the measurements
|
||||
JstatResults.assertGCEventsIncreased(measurement1, measurement2);
|
||||
JstatResults.assertGCTimeIncreased(measurement1, measurement2);
|
||||
|
||||
// Provoke GC 3rd time then run the tool 3rd time twice and get the results
|
||||
// asserting that they are reasonable
|
||||
gcProvoker.provokeGc();
|
||||
JstatGcCauseResults measurement3 = jstatGcTool.measure();
|
||||
measurement3.assertConsistency();
|
||||
|
||||
// Assert the increase in GC events and time between the measurements
|
||||
JstatResults.assertGCEventsIncreased(measurement2, measurement3);
|
||||
JstatResults.assertGCTimeIncreased(measurement2, measurement3);
|
||||
}
|
||||
}
|
62
hotspot/test/serviceability/tmtools/jstat/GcCauseTest02.java
Normal file
62
hotspot/test/serviceability/tmtools/jstat/GcCauseTest02.java
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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
|
||||
* @summary Test checks output displayed with jstat -gccause.
|
||||
* Test scenario:
|
||||
* tests forces debuggee application eat ~70% of heap and runs jstat.
|
||||
* jstat should show that ~70% of heap (OC/OU ~= 70%).
|
||||
* @library /test/lib/share/classes
|
||||
* @library ../share
|
||||
* @build common.*
|
||||
* @build utils.*
|
||||
*
|
||||
* @run main/othervm -XX:+UsePerfData -Xms128M -XX:MaxMetaspaceSize=128M GcCauseTest02
|
||||
*/
|
||||
import utils.*;
|
||||
|
||||
public class GcCauseTest02 {
|
||||
|
||||
private final static float targetMemoryUsagePercent = 0.7f;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
// We will be running "jstat -gc" tool
|
||||
JstatGcCauseTool jstatGcTool = new JstatGcCauseTool(ProcessHandle.current().getPid());
|
||||
|
||||
// Run once and get the results asserting that they are reasonable
|
||||
JstatGcCauseResults measurement1 = jstatGcTool.measure();
|
||||
measurement1.assertConsistency();
|
||||
|
||||
GcProvoker gcProvoker = GcProvoker.createGcProvoker();
|
||||
|
||||
// Eat metaspace and heap then run the tool again and get the results asserting that they are reasonable
|
||||
gcProvoker.eatMetaspaceAndHeap(targetMemoryUsagePercent);
|
||||
JstatGcCauseResults measurement2 = jstatGcTool.measure();
|
||||
measurement2.assertConsistency();
|
||||
|
||||
// Assert that space has been utilized acordingly
|
||||
JstatResults.assertSpaceUtilization(measurement2, targetMemoryUsagePercent);
|
||||
}
|
||||
}
|
61
hotspot/test/serviceability/tmtools/jstat/GcCauseTest03.java
Normal file
61
hotspot/test/serviceability/tmtools/jstat/GcCauseTest03.java
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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
|
||||
* @summary Test checks output displayed with jstat -gccause.
|
||||
* Test scenario:
|
||||
* test forces debuggee application call System.gc(), runs jstat and checks that
|
||||
* cause of last garbage collection displayed by jstat (LGCC) is 'System.gc()'.
|
||||
* @library /test/lib/share/classes
|
||||
* @library ../share
|
||||
* @build common.*
|
||||
* @build utils.*
|
||||
*
|
||||
* @run main/othervm -XX:+UsePerfData -Xms128M -XX:MaxMetaspaceSize=128M GcCauseTest03
|
||||
*/
|
||||
import utils.*;
|
||||
|
||||
public class GcCauseTest03 {
|
||||
|
||||
private final static float targetMemoryUsagePercent = 0.7f;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
// We will be running "jstat -gc" tool
|
||||
JstatGcCauseTool jstatGcTool = new JstatGcCauseTool(ProcessHandle.current().getPid());
|
||||
|
||||
System.gc();
|
||||
|
||||
// Run once and get the results asserting that they are reasonable
|
||||
JstatGcCauseResults measurement = jstatGcTool.measure();
|
||||
measurement.assertConsistency();
|
||||
|
||||
if (measurement.valueExists("LGCC")) {
|
||||
if (!"System.gc()".equals(measurement.getStringValue("LGCC"))) {
|
||||
throw new RuntimeException("Unexpected GC cause: " + measurement.getStringValue("LGCC") + ", expected System.gc()");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
77
hotspot/test/serviceability/tmtools/jstat/GcNewTest.java
Normal file
77
hotspot/test/serviceability/tmtools/jstat/GcNewTest.java
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
import utils.*;
|
||||
/*
|
||||
* @test
|
||||
* @summary Test checks output displayed with jstat -gcnew.
|
||||
* Test scenario:
|
||||
* test several times provokes garbage collection in the debuggee application and after each garbage
|
||||
* collection runs jstat. jstat should show that after garbage collection number of GC events and garbage
|
||||
* collection time increase.
|
||||
* @library /test/lib/share/classes
|
||||
* @library ../share
|
||||
* @build common.*
|
||||
* @build utils.*
|
||||
* @run main/othervm -XX:+UsePerfData GcNewTest
|
||||
*/
|
||||
|
||||
public class GcNewTest {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
// We will be running "jstat -gc" tool
|
||||
JstatGcNewTool jstatGcTool = new JstatGcNewTool(ProcessHandle.current().getPid());
|
||||
|
||||
// Run once and get the results asserting that they are reasonable
|
||||
JstatGcNewResults measurement1 = jstatGcTool.measure();
|
||||
measurement1.assertConsistency();
|
||||
|
||||
GcProvoker gcProvoker = GcProvoker.createGcProvoker();
|
||||
|
||||
// Provoke GC and run the tool again
|
||||
gcProvoker.provokeGc();
|
||||
JstatGcNewResults measurement2 = jstatGcTool.measure();
|
||||
measurement2.assertConsistency();
|
||||
|
||||
// Assert the increase in GC events and time between the measurements
|
||||
assertThat(measurement2.getFloatValue("YGC") > measurement1.getFloatValue("YGC"), "YGC didn't increase between measurements 1 and 2");
|
||||
assertThat(measurement2.getFloatValue("YGCT") > measurement1.getFloatValue("YGCT"), "YGCT time didn't increase between measurements 1 and 2");
|
||||
|
||||
// Provoke GC and run the tool again
|
||||
gcProvoker.provokeGc();
|
||||
JstatGcNewResults measurement3 = jstatGcTool.measure();
|
||||
measurement3.assertConsistency();
|
||||
|
||||
// Assert the increase in GC events and time between the measurements
|
||||
assertThat(measurement3.getFloatValue("YGC") > measurement2.getFloatValue("YGC"), "YGC didn't increase between measurements 1 and 2");
|
||||
assertThat(measurement3.getFloatValue("YGCT") > measurement2.getFloatValue("YGCT"), "YGCT time didn't increase between measurements 1 and 2");
|
||||
|
||||
}
|
||||
|
||||
private static void assertThat(boolean result, String message) {
|
||||
if (!result) {
|
||||
throw new RuntimeException(message);
|
||||
};
|
||||
}
|
||||
}
|
78
hotspot/test/serviceability/tmtools/jstat/GcTest01.java
Normal file
78
hotspot/test/serviceability/tmtools/jstat/GcTest01.java
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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
|
||||
* @summary Test checks output displayed with jstat -gc.
|
||||
* Test scenario:
|
||||
* test several times provokes garbage collection
|
||||
* in the debuggee application
|
||||
* and after each garbage collection runs jstat.
|
||||
* jstat should show that after garbage collection
|
||||
* number of GC events and garbage
|
||||
* collection time increase.
|
||||
* @library /test/lib/share/classes
|
||||
* @library ../share
|
||||
* @build common.*
|
||||
* @build utils.*
|
||||
*
|
||||
* @run main/othervm -XX:+UsePerfData GcTest01
|
||||
*/
|
||||
import utils.*;
|
||||
|
||||
public class GcTest01 {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
// We will be running "jstat -gc" tool
|
||||
JstatGcTool jstatGcTool = new JstatGcTool(ProcessHandle.current().getPid());
|
||||
|
||||
// Run once and get the results asserting that they are reasonable
|
||||
JstatGcResults measurement1 = jstatGcTool.measure();
|
||||
measurement1.assertConsistency();
|
||||
|
||||
GcProvoker gcProvoker = GcProvoker.createGcProvoker();
|
||||
|
||||
// Provoke GC then run the tool again and get the results
|
||||
// asserting that they are reasonable
|
||||
gcProvoker.provokeGc();
|
||||
JstatGcResults measurement2 = jstatGcTool.measure();
|
||||
measurement2.assertConsistency();
|
||||
|
||||
// Assert the increase in GC events and time between the measurements
|
||||
JstatResults.assertGCEventsIncreased(measurement1, measurement2);
|
||||
JstatResults.assertGCTimeIncreased(measurement1, measurement2);
|
||||
|
||||
// Provoke GC again and get the results
|
||||
// asserting that they are reasonable
|
||||
gcProvoker.provokeGc();
|
||||
JstatGcResults measurement3 = jstatGcTool.measure();
|
||||
measurement3.assertConsistency();
|
||||
|
||||
// Assert the increase in GC events and time between the measurements
|
||||
JstatResults.assertGCEventsIncreased(measurement2, measurement3);
|
||||
JstatResults.assertGCTimeIncreased(measurement2, measurement3);
|
||||
|
||||
}
|
||||
|
||||
}
|
67
hotspot/test/serviceability/tmtools/jstat/GcTest02.java
Normal file
67
hotspot/test/serviceability/tmtools/jstat/GcTest02.java
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
import utils.*;
|
||||
/*
|
||||
* @test
|
||||
* @summary Test checks output displayed with jstat -gc.
|
||||
* Test scenario:
|
||||
* tests forces debuggee application eat ~70% of heap and runs jstat.
|
||||
* jstat should show that ~70% of heap is utilized (OC/OU ~= 70%).
|
||||
* @library /test/lib/share/classes
|
||||
* @library ../share
|
||||
* @build common.*
|
||||
* @build utils.*
|
||||
* @run main/othervm -XX:+UsePerfData -Xms128M -XX:MaxMetaspaceSize=128M GcTest02
|
||||
*/
|
||||
|
||||
public class GcTest02 {
|
||||
|
||||
private final static float targetMemoryUsagePercent = 0.7f;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
// We will be running "jstat -gc" tool
|
||||
JstatGcTool jstatGcTool = new JstatGcTool(ProcessHandle.current().getPid());
|
||||
|
||||
// Run once and get the results asserting that they are reasonable
|
||||
JstatGcResults measurement1 = jstatGcTool.measure();
|
||||
measurement1.assertConsistency();
|
||||
|
||||
GcProvoker gcProvoker = GcProvoker.createGcProvoker();
|
||||
|
||||
// Eat metaspace and heap then run the tool again and get the results asserting that they are reasonable
|
||||
gcProvoker.eatMetaspaceAndHeap(targetMemoryUsagePercent);
|
||||
JstatGcResults measurement2 = jstatGcTool.measure();
|
||||
measurement2.assertConsistency();
|
||||
|
||||
// Assert that space has been utilized acordingly
|
||||
JstatResults.assertSpaceUtilization(measurement2, targetMemoryUsagePercent);
|
||||
}
|
||||
|
||||
private static void assertThat(boolean result, String message) {
|
||||
if (!result) {
|
||||
throw new RuntimeException(message);
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.FileInputStream;
|
||||
|
||||
public class ClassLoadUtils {
|
||||
|
||||
private ClassLoadUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename of class file from classpath for given class name.
|
||||
*
|
||||
* @param className class name
|
||||
* @return filename or null if not found
|
||||
*/
|
||||
public static String getClassPath(String className) {
|
||||
String fileName = className.replace(".", File.separator) + ".class";
|
||||
String[] classPath = System.getProperty("java.class.path").split(File.pathSeparator);
|
||||
File target = null;
|
||||
int i;
|
||||
for (i = 0; i < classPath.length; ++i) {
|
||||
target = new File(classPath[i] + File.separator + fileName);
|
||||
System.out.println("Try: " + target);
|
||||
if (target.exists()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i != classPath.length) {
|
||||
return classPath[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename of class file from classpath for given class name.
|
||||
*
|
||||
* @param className class name
|
||||
* @return filename or null if not found
|
||||
*/
|
||||
public static String getClassPathFileName(String className) {
|
||||
String fileName = className.replace(".", File.separator) + ".class";
|
||||
String[] classPath = System.getProperty("java.class.path").split(File.pathSeparator);
|
||||
File target = null;
|
||||
int i;
|
||||
for (i = 0; i < classPath.length; ++i) {
|
||||
target = new File(classPath[i] + File.separator + fileName);
|
||||
System.out.println("Try: " + target);
|
||||
if (target.exists()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i != classPath.length) {
|
||||
try {
|
||||
return target.getCanonicalPath();
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getRedefineClassFileName(String dir, String className) {
|
||||
String fileName = getClassPathFileName(className);
|
||||
if (fileName == null) {
|
||||
return null;
|
||||
}
|
||||
if (fileName.contains("classes")) {
|
||||
return fileName.replace("classes", dir);
|
||||
} else {
|
||||
String classPath = getClassPath(className);
|
||||
if (classPath != null) {
|
||||
return classPath + File.separator + "newclass" + File.separator + className.replace(".", File.separator) + ".class";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename of class file which is to be redefined.
|
||||
*/
|
||||
public static String getRedefineClassFileName(String className) {
|
||||
return getRedefineClassFileName("newclass", className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read whole file.
|
||||
*
|
||||
* @param file file
|
||||
* @return contents of file as byte array
|
||||
*/
|
||||
public static byte[] readFile(File file) throws IOException {
|
||||
InputStream in = new FileInputStream(file);
|
||||
long countl = file.length();
|
||||
if (countl > Integer.MAX_VALUE) {
|
||||
throw new IOException("File is too huge");
|
||||
}
|
||||
int count = (int) countl;
|
||||
byte[] buffer = new byte[count];
|
||||
int n = 0;
|
||||
try {
|
||||
while (n < count) {
|
||||
int k = in.read(buffer, n, count - n);
|
||||
if (k < 0) {
|
||||
throw new IOException("Unexpected EOF");
|
||||
}
|
||||
n += k;
|
||||
}
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read whole file.
|
||||
*
|
||||
* @param name file name
|
||||
* @return contents of file as byte array
|
||||
*/
|
||||
public static byte[] readFile(String name) throws IOException {
|
||||
return readFile(new File(name));
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
/**
|
||||
* This is an interface used to provoke GC and perform other GC-related
|
||||
* procedures
|
||||
*
|
||||
*/
|
||||
public interface GcProvoker {
|
||||
|
||||
/**
|
||||
* The default implementation
|
||||
*
|
||||
* @return the default GC provoker
|
||||
*/
|
||||
public static GcProvoker createGcProvoker() {
|
||||
return new GcProvokerImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method provokes a GC
|
||||
*/
|
||||
public void provokeGc();
|
||||
|
||||
/**
|
||||
* Eats heap and metaspace Upon exit targetMemoryUsagePercent percents of
|
||||
* heap and metaspace is have been eaten
|
||||
*
|
||||
* @param targetMemoryUsagePercent how many percent of heap and metaspace to
|
||||
* eat
|
||||
*/
|
||||
public void eatMetaspaceAndHeap(float targetMemoryUsagePercent);
|
||||
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MemoryPoolMXBean;
|
||||
import java.lang.management.MemoryUsage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* Utilities to provoke GC in various ways
|
||||
*/
|
||||
public class GcProvokerImpl implements GcProvoker {
|
||||
|
||||
private static List<Object> eatenMetaspace;
|
||||
private static List<Object> eatenMemory;
|
||||
|
||||
static List<Object> eatHeapMemory(float targetUsage) {
|
||||
long maxMemory = Runtime.getRuntime().maxMemory();
|
||||
// uses fixed small objects to avoid Humongous objects allocation in G1
|
||||
int memoryChunk = 2048;
|
||||
List<Object> list = new ArrayList<>();
|
||||
float used = 0;
|
||||
while (used < targetUsage * maxMemory) {
|
||||
try {
|
||||
list.add(new byte[memoryChunk]);
|
||||
used += memoryChunk;
|
||||
} catch (OutOfMemoryError e) {
|
||||
list = null;
|
||||
throw new RuntimeException("Unexpected OOME while eating " + targetUsage + " of heap memory.");
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provokeGc() {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
long edenSize = Pools.getEdenCommittedSize();
|
||||
long heapSize = Pools.getHeapCommittedSize();
|
||||
float targetPercent = ((float) edenSize) / (heapSize);
|
||||
if ((targetPercent <= 0) || (targetPercent > 1.0)) {
|
||||
throw new RuntimeException("Error in the percent calculation" + " (eden size: " + edenSize + ", heap size: " + heapSize + ", calculated eden percent: " + targetPercent + ")");
|
||||
}
|
||||
eatHeapMemory(targetPercent);
|
||||
eatHeapMemory(targetPercent);
|
||||
System.gc();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eatMetaspaceAndHeap(float targetMemoryUsagePercent) {
|
||||
eatenMemory = eatHeapMemory(targetMemoryUsagePercent);
|
||||
eatenMetaspace = eatMetaspace(targetMemoryUsagePercent);
|
||||
}
|
||||
|
||||
private static List<Object> eatMetaspace(float targetUsage) {
|
||||
List<Object> list = new ArrayList<>();
|
||||
final String metaspacePoolName = "Metaspace";
|
||||
MemoryPoolMXBean metaspacePool = null;
|
||||
for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
|
||||
if (pool.getName().contains(metaspacePoolName)) {
|
||||
metaspacePool = pool;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (metaspacePool == null) {
|
||||
throw new RuntimeException("MXBean for Metaspace pool wasn't found");
|
||||
}
|
||||
float currentUsage;
|
||||
GeneratedClassProducer gp = new GeneratedClassProducer();
|
||||
do {
|
||||
try {
|
||||
list.add(gp.create(0));
|
||||
} catch (OutOfMemoryError oome) {
|
||||
list = null;
|
||||
throw new RuntimeException("Unexpected OOME while eating " + targetUsage + " of Metaspace.");
|
||||
}
|
||||
MemoryUsage memoryUsage = metaspacePool.getUsage();
|
||||
currentUsage = (((float) memoryUsage.getUsed()) / memoryUsage.getMax());
|
||||
} while (currentUsage < targetUsage);
|
||||
return list;
|
||||
}
|
||||
|
||||
public GcProvokerImpl() {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
/**
|
||||
* Garbage producer that creates classes loaded with GeneratingClassLoader.
|
||||
*
|
||||
* Note: this class is not thread-safe.
|
||||
*/
|
||||
class GeneratedClassProducer {
|
||||
|
||||
private int number;
|
||||
private String className;
|
||||
private StringBuilder sb = new StringBuilder();
|
||||
private int minPerClassLoader = 50;
|
||||
private int maxPerClassLoader = 150;
|
||||
private int count;
|
||||
private GeneratingClassLoader loader = new GeneratingClassLoader();
|
||||
|
||||
GeneratedClassProducer() {
|
||||
this(GeneratingClassLoader.DEFAULT_CLASSNAME);
|
||||
}
|
||||
|
||||
GeneratedClassProducer(String className) {
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
String getNewName() {
|
||||
sb.delete(0, sb.length());
|
||||
sb.append("Class");
|
||||
sb.append(number);
|
||||
int n = loader.getNameLength() - sb.length();
|
||||
for (int i = 0; i < n; ++i) {
|
||||
sb.append('_');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
Class create(long memory) {
|
||||
try {
|
||||
if (number++ > maxPerClassLoader || loader == null) {
|
||||
loader = new GeneratingClassLoader(className);
|
||||
count = 50;
|
||||
number = 0;
|
||||
}
|
||||
return loader.loadClass(getNewName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Classloader that generates classes on the fly.
|
||||
*
|
||||
* This classloader can load classes with name starting with 'Class'. It will
|
||||
* use TemplateClass as template and will replace class name in the bytecode of
|
||||
* template class. It can be used for example to detect memory leaks in class
|
||||
* loading or to quickly fill PermGen.
|
||||
*/
|
||||
class GeneratingClassLoader extends ClassLoader {
|
||||
|
||||
public synchronized Class loadClass(String name) throws ClassNotFoundException {
|
||||
return loadClass(name, false);
|
||||
}
|
||||
|
||||
public synchronized Class loadClass(String name, boolean resolve)
|
||||
throws ClassNotFoundException {
|
||||
Class c = findLoadedClass(name);
|
||||
if (c != null) {
|
||||
return c;
|
||||
}
|
||||
if (!name.startsWith(PREFIX)) {
|
||||
return super.loadClass(name, resolve);
|
||||
}
|
||||
if (name.length() != templateClassName.length()) {
|
||||
throw new ClassNotFoundException("Only can load classes with name.length() = " + getNameLength() + " got: '" + name + "' length: " + name.length());
|
||||
}
|
||||
byte[] bytecode = getPatchedByteCode(name);
|
||||
c = defineClass(name, bytecode, 0, bytecode.length);
|
||||
if (resolve) {
|
||||
resolveClass(c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create generating class loader that will use class file for given class
|
||||
* from classpath as template.
|
||||
*/
|
||||
GeneratingClassLoader(String templateClassName) {
|
||||
this.templateClassName = templateClassName;
|
||||
classPath = System.getProperty("java.class.path").split(File.pathSeparator);
|
||||
try {
|
||||
templateClassNameBytes = templateClassName.getBytes(encoding);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create generating class loader that will use class file for
|
||||
* nsk.share.classload.TemplateClass as template.
|
||||
*/
|
||||
GeneratingClassLoader() {
|
||||
this(TemplateClass.class.getName());
|
||||
}
|
||||
|
||||
int getNameLength() {
|
||||
return templateClassName.length();
|
||||
}
|
||||
|
||||
String getPrefix() {
|
||||
return PREFIX;
|
||||
}
|
||||
|
||||
String getClassName(int number) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(PREFIX);
|
||||
sb.append(number);
|
||||
int n = templateClassName.length() - sb.length();
|
||||
for (int i = 0; i < n; ++i) {
|
||||
sb.append("_");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private byte[] getPatchedByteCode(String name) throws ClassNotFoundException {
|
||||
try {
|
||||
byte[] bytecode = getByteCode();
|
||||
String fname = name.replace(".", File.separator);
|
||||
byte[] replaceBytes = fname.getBytes(encoding);
|
||||
for (int offset : offsets) {
|
||||
for (int i = 0; i < replaceBytes.length; ++i) {
|
||||
bytecode[offset + i] = replaceBytes[i];
|
||||
}
|
||||
}
|
||||
return bytecode;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getByteCode() throws ClassNotFoundException {
|
||||
if (bytecode == null) {
|
||||
readByteCode();
|
||||
}
|
||||
if (offsets == null) {
|
||||
getOffsets(bytecode);
|
||||
if (offsets == null) {
|
||||
throw new RuntimeException("Class name not found in template class file");
|
||||
}
|
||||
}
|
||||
return (byte[]) bytecode.clone();
|
||||
}
|
||||
|
||||
private void readByteCode() throws ClassNotFoundException {
|
||||
String fname = templateClassName.replace(".", File.separator) + ".class";
|
||||
File target = null;
|
||||
for (int i = 0; i < classPath.length; ++i) {
|
||||
target = new File(classPath[i] + File.separator + fname);
|
||||
if (target.exists()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (target == null || !target.exists()) {
|
||||
throw new ClassNotFoundException("File not found: " + target);
|
||||
}
|
||||
try {
|
||||
bytecode = ClassLoadUtils.readFile(target);
|
||||
} catch (IOException e) {
|
||||
throw new ClassNotFoundException(templateClassName, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void getOffsets(byte[] bytecode) {
|
||||
List<Integer> offsets = new ArrayList<Integer>();
|
||||
if (this.offsets == null) {
|
||||
String pname = templateClassName.replace(".", "/");
|
||||
try {
|
||||
byte[] pnameb = pname.getBytes(encoding);
|
||||
int i = 0;
|
||||
while (true) {
|
||||
while (i < bytecode.length) {
|
||||
int j = 0;
|
||||
while (j < pnameb.length && bytecode[i + j] == pnameb[j]) {
|
||||
++j;
|
||||
}
|
||||
if (j == pnameb.length) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (i == bytecode.length) {
|
||||
break;
|
||||
}
|
||||
offsets.add(new Integer(i));
|
||||
i++;
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
this.offsets = new int[offsets.size()];
|
||||
for (int i = 0; i < offsets.size(); ++i) {
|
||||
this.offsets[i] = offsets.get(i).intValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final String DEFAULT_CLASSNAME = TemplateClass.class.getName();
|
||||
static final String PREFIX = "Class";
|
||||
|
||||
private final String[] classPath;
|
||||
private byte[] bytecode;
|
||||
private int[] offsets;
|
||||
private final String encoding = "UTF8";
|
||||
private final String templateClassName;
|
||||
private final byte[] templateClassNameBytes;
|
||||
}
|
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Results of running the JstatGcTool ("jstat -gccapacity <pid>")
|
||||
*
|
||||
* Output example:
|
||||
* NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC YGC FGC
|
||||
* 41984.0 671744.0 41984.0 5248.0 5248.0 31488.0 83968.0 1343488.0 83968.0 83968.0 512.0 110592.0 4480.0 0 0
|
||||
|
||||
* Output description:
|
||||
* NGCMN Minimum new generation capacity (KB).
|
||||
* NGCMX Maximum new generation capacity (KB).
|
||||
* NGC Current new generation capacity (KB).
|
||||
* S0C Current survivor space 0 capacity (KB).
|
||||
* S1C Current survivor space 1 capacity (KB).
|
||||
* EC Current eden space capacity (KB).
|
||||
* OGCMN Minimum old generation capacity (KB).
|
||||
* OGCMX Maximum old generation capacity (KB).
|
||||
* OGC Current old generation capacity (KB).
|
||||
* OC Current old space capacity (KB).
|
||||
* MCMN Minimum metaspace capacity (KB).
|
||||
* MCMX Maximum metaspace capacity (KB).
|
||||
* MC Current metaspace capacity (KB).
|
||||
* YGC Number of Young generation GC Events.
|
||||
* FGC Number of Full GC Events.
|
||||
*/
|
||||
package utils;
|
||||
|
||||
import common.ToolResults;
|
||||
import java.lang.management.GarbageCollectorMXBean;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class JstatGcCapacityResults extends JstatResults {
|
||||
|
||||
public JstatGcCapacityResults(ToolResults rawResults) {
|
||||
super(rawResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the overall consistency of the results reported by the tool
|
||||
*/
|
||||
public void assertConsistency() {
|
||||
|
||||
// Check exit code
|
||||
assertThat(getExitCode() == 0, "Unexpected exit code: " + getExitCode());
|
||||
|
||||
// Check Young Gen consistency
|
||||
float NGCMN = getFloatValue("NGCMN");
|
||||
float NGCMX = getFloatValue("NGCMX");
|
||||
assertThat(NGCMX >= NGCMN, "NGCMN > NGCMX (min generation capacity > max generation capacity)");
|
||||
|
||||
float NGC = getFloatValue("NGC");
|
||||
assertThat(NGC >= NGCMN, "NGC < NGCMN (generation capacity < min generation capacity)");
|
||||
assertThat(NGC <= NGCMX, "NGC > NGCMX (generation capacity > max generation capacity)");
|
||||
|
||||
float S0C = getFloatValue("S0C");
|
||||
assertThat(S0C < NGC, "S0C >= NGC (survivor space 0 capacity >= new generation capacity)");
|
||||
|
||||
float S1C = getFloatValue("S1C");
|
||||
assertThat(S1C < NGC, "S1C >= NGC (survivor space 1 capacity >= new generation capacity)");
|
||||
|
||||
float EC = getFloatValue("EC");
|
||||
assertThat(EC <= NGC, "EC > NGC (eden space capacity > new generation capacity)");
|
||||
|
||||
// Verify relative size of NGC and S0C + S1C + EC.
|
||||
// The rule depends on if the tenured GC is parallel or not.
|
||||
// For parallell GC: NGC >= S0C + S1C + EC
|
||||
// For non-parallell GC: NGC == S0C + S1C + EC
|
||||
boolean isTenuredParallelGC = isTenuredParallelGC();
|
||||
String errMsg = String.format(
|
||||
"NGC %s (S0C + S1C + EC) (NGC = %.1f, S0C = %.1f, S1C = %.1f, EC = %.1f, (S0C + S1C + EC) = %.1f)",
|
||||
isTenuredParallelGC ? "<" : "!=", NGC, S0C, S1C, EC, S0C + S1C + EC);
|
||||
if (isTenuredParallelGC) {
|
||||
assertThat(NGC >= S0C + S1C + EC, errMsg);
|
||||
} else {
|
||||
assertThat(checkFloatIsSum(NGC, S0C, S1C, EC), errMsg);
|
||||
}
|
||||
|
||||
// Check Old Gen consistency
|
||||
float OGCMN = getFloatValue("OGCMN");
|
||||
float OGCMX = getFloatValue("OGCMX");
|
||||
assertThat(OGCMX >= OGCMN, "OGCMN > OGCMX (min generation capacity > max generation capacity)");
|
||||
|
||||
float OGC = getFloatValue("OGC");
|
||||
assertThat(OGC >= OGCMN, "OGC < OGCMN (generation capacity < min generation capacity)");
|
||||
assertThat(OGC <= OGCMX, "OGC > OGCMX (generation capacity > max generation capacity)");
|
||||
float OC = getFloatValue("OC");
|
||||
assertThat(OC == OGC, "OC != OGC (old generation capacity != old space capacity (these values should be equal since old space is made up only from one old generation))");
|
||||
|
||||
// Check Metaspace consistency
|
||||
float MCMN = getFloatValue("MCMN");
|
||||
float MCMX = getFloatValue("MCMX");
|
||||
assertThat(MCMX >= MCMN, "MCMN > MCMX (min generation capacity > max generation capacity)");
|
||||
float MC = getFloatValue("MC");
|
||||
assertThat(MC >= MCMN, "MC < MCMN (generation capacity < min generation capacity)");
|
||||
assertThat(MC <= MCMX, "MGC > MCMX (generation capacity > max generation capacity)");
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the tenured generation are currently using a parallel GC.
|
||||
*/
|
||||
protected static boolean isTenuredParallelGC() {
|
||||
// Currently the only parallel GC for the tenured generation is PS MarkSweep.
|
||||
List<String> parallelGCs = Arrays.asList(new String[] { "PS MarkSweep"});
|
||||
try {
|
||||
List<GarbageCollectorMXBean> beans = ManagementFactory.getGarbageCollectorMXBeans();
|
||||
for (GarbageCollectorMXBean bean : beans) {
|
||||
if (parallelGCs.contains(bean.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final float FLOAT_COMPARISON_TOLERANCE = 0.0011f;
|
||||
|
||||
private static boolean checkFloatIsSum(float sum, float... floats) {
|
||||
for (float f : floats) {
|
||||
sum -= f;
|
||||
}
|
||||
|
||||
return Math.abs(sum) <= FLOAT_COMPARISON_TOLERANCE;
|
||||
}
|
||||
|
||||
private void assertThat(boolean b, String message) {
|
||||
if (!b) {
|
||||
throw new RuntimeException(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
import common.TmTool;
|
||||
|
||||
/**
|
||||
* This tool executes "jstat -gccapacity <pid>" and returns the results as
|
||||
* JstatGcCapacityoolResults
|
||||
*/
|
||||
public class JstatGcCapacityTool extends TmTool<JstatGcCapacityResults> {
|
||||
|
||||
public JstatGcCapacityTool(long pid) {
|
||||
super(JstatGcCapacityResults.class, "jstat", "-gccapacity " + pid);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Results of running the JstatGcTool ("jstat -gccause <pid>")
|
||||
*
|
||||
* Output example:
|
||||
* S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC
|
||||
* 0.00 6.25 46.19 0.34 57.98 54.63 15305 1270.551 0 0.000 1270.551 Allocation Failure No GC
|
||||
|
||||
* Output description:
|
||||
* S0 Survivor space 0 utilization as a percentage of the space's current capacity.
|
||||
* S1 Survivor space 1 utilization as a percentage of the space's current capacity.
|
||||
* E Eden space utilization as a percentage of the space's current capacity.
|
||||
* O Old space utilization as a percentage of the space's current capacity.
|
||||
* M Metaspace utilization as a percentage of the space's current capacity.
|
||||
* CCS Compressed Class Space
|
||||
* YGC Number of young generation GC events.
|
||||
* YGCT Young generation garbage collection time.
|
||||
* FGC Number of full GC events.
|
||||
* FGCT Full garbage collection time.
|
||||
* GCT Total garbage collection time.
|
||||
* LGCC Cause of last Garbage Collection.
|
||||
* GCC Cause of current Garbage Collection.
|
||||
*/
|
||||
package utils;
|
||||
|
||||
import common.ToolResults;
|
||||
|
||||
public class JstatGcCauseResults extends JstatResults {
|
||||
|
||||
public JstatGcCauseResults(ToolResults rawResults) {
|
||||
super(rawResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the overall consistency of the results reported by the tool
|
||||
*/
|
||||
public void assertConsistency() {
|
||||
|
||||
assertThat(getExitCode() == 0, "Unexpected exit code: " + getExitCode());
|
||||
|
||||
int YGC = getIntValue("YGC");
|
||||
float YGCT = getFloatValue("YGCT");
|
||||
assertThat(YGCT >= 0, "Incorrect time value for YGCT");
|
||||
if (YGC > 0) {
|
||||
assertThat(YGCT > 0, "Number of young generation GC Events is " + YGC + ", but YGCT is 0");
|
||||
}
|
||||
|
||||
float GCT = getFloatValue("GCT");
|
||||
assertThat(GCT >= 0, "Incorrect time value for GCT");
|
||||
assertThat(GCT >= YGCT, "GCT < YGCT (total garbage collection time < young generation garbage collection time)");
|
||||
|
||||
int FGC = getIntValue("FGC");
|
||||
float FGCT = getFloatValue("FGCT");
|
||||
assertThat(FGCT >= 0, "Incorrect time value for FGCT");
|
||||
if (FGC > 0) {
|
||||
assertThat(FGCT > 0, "Number of full GC events is " + FGC + ", but FGCT is 0");
|
||||
}
|
||||
|
||||
assertThat(GCT >= FGCT, "GCT < YGCT (total garbage collection time < full generation garbage collection time)");
|
||||
|
||||
assertThat(checkFloatIsSum(GCT, YGCT, FGCT), "GCT != (YGCT + FGCT) " + "(GCT = " + GCT + ", YGCT = " + YGCT
|
||||
+ ", FGCT = " + FGCT + ", (YCGT + FGCT) = " + (YGCT + FGCT) + ")");
|
||||
}
|
||||
|
||||
private static final float FLOAT_COMPARISON_TOLERANCE = 0.0011f;
|
||||
|
||||
private static boolean checkFloatIsSum(float sum, float... floats) {
|
||||
for (float f : floats) {
|
||||
sum -= f;
|
||||
}
|
||||
|
||||
return Math.abs(sum) <= FLOAT_COMPARISON_TOLERANCE;
|
||||
}
|
||||
|
||||
private void assertThat(boolean b, String message) {
|
||||
if (!b) {
|
||||
throw new RuntimeException(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
import common.TmTool;
|
||||
|
||||
/**
|
||||
* This tool executes "jstat -gc <pid>" and returns the results as
|
||||
* JstatGcToolResults
|
||||
*/
|
||||
public class JstatGcCauseTool extends TmTool<JstatGcCauseResults> {
|
||||
|
||||
public JstatGcCauseTool(long pid) {
|
||||
super(JstatGcCauseResults.class, "jstat", "-gc " + pid);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Results of running the JstatGcTool ("jstat -gcnew <pid>")
|
||||
*
|
||||
* Output example:
|
||||
* S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT
|
||||
* 11264.0 11264.0 0.0 0.0 15 15 0.0 67584.0 1351.7 0 0.000
|
||||
|
||||
* Output description:
|
||||
* S0C Current survivor space 0 capacity (KB).
|
||||
* S1C Current survivor space 1 capacity (KB).
|
||||
* S0U Survivor space 0 utilization (KB).
|
||||
* S1U Survivor space 1 utilization (KB).
|
||||
* TT Tenuring threshold.
|
||||
* MTT Maximum tenuring threshold.
|
||||
* DSS Desired survivor size (KB).
|
||||
* EC Current eden space capacity (KB).
|
||||
* EU Eden space utilization (KB).
|
||||
* YGC Number of young generation GC events.
|
||||
* YGCT Young generation garbage collection time.
|
||||
*/
|
||||
package utils;
|
||||
|
||||
import common.ToolResults;
|
||||
|
||||
public class JstatGcNewResults extends JstatResults {
|
||||
|
||||
public JstatGcNewResults(ToolResults rawResults) {
|
||||
super(rawResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the overall consistency of the results reported by the tool
|
||||
*/
|
||||
public void assertConsistency() {
|
||||
|
||||
assertThat(getExitCode() == 0, "Unexpected exit code: " + getExitCode());
|
||||
|
||||
float S0C = getFloatValue("S0C");
|
||||
float S0U = getFloatValue("S0U");
|
||||
|
||||
assertThat(S0U <= S0C, "S0U > S0C (utilization > capacity)");
|
||||
|
||||
float S1C = getFloatValue("S1C");
|
||||
float S1U = getFloatValue("S1U");
|
||||
|
||||
assertThat(S1U <= S1C, "S1U > S1C (utilization > capacity)");
|
||||
|
||||
float EC = getFloatValue("EC");
|
||||
float EU = getFloatValue("EU");
|
||||
|
||||
assertThat(EU <= EC, "EU > EC (utilization > capacity)");
|
||||
|
||||
int YGC = getIntValue("YGC");
|
||||
float YGCT = getFloatValue("YGCT");
|
||||
|
||||
if (YGC > 0) {
|
||||
assertThat(YGCT > 0, "Number of young generation GC Events is " + YGC + ", but YGCT is 0");
|
||||
}
|
||||
|
||||
int TT = getIntValue("TT");
|
||||
int MTT = getIntValue("MTT");
|
||||
assertThat(TT <= MTT, "TT > MTT (tenuring threshold > maximum tenuring threshold)");
|
||||
}
|
||||
|
||||
private void assertThat(boolean b, String message) {
|
||||
if (!b) {
|
||||
throw new RuntimeException(message);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
import common.TmTool;
|
||||
|
||||
/**
|
||||
* This tool executes "jstat -gcnew <pid>" and returns the results as
|
||||
* JstatGcNewResults
|
||||
*/
|
||||
public class JstatGcNewTool extends TmTool<JstatGcNewResults> {
|
||||
|
||||
public JstatGcNewTool(long pid) {
|
||||
super(JstatGcNewResults.class, "jstat", "-gcnew " + pid);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Results of running the JstatGcTool ("jstat -gc <pid>")
|
||||
*
|
||||
* Output example:
|
||||
* (S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
|
||||
* 512.0 512.0 32.0 0.0 288768.0 168160.6 83968.0 288.1 4864.0 2820.3 512.0 279.7 18510 1559.208 0 0.000 1559.208
|
||||
*
|
||||
* Output description:
|
||||
* S0C Current survivor space 0 capacity (KB).
|
||||
* S1C Current survivor space 1 capacity (KB).
|
||||
* S0U Survivor space 0 utilization (KB).
|
||||
* S1U Survivor space 1 utilization (KB).
|
||||
* EC Current eden space capacity (KB).
|
||||
* EU Eden space utilization (KB).
|
||||
* OC Current old space capacity (KB).
|
||||
* OU Old space utilization (KB).
|
||||
* MC Current metaspace capacity (KB).
|
||||
* MU Metaspace utilization (KB).
|
||||
* CCSC Compressed Class Space capacity
|
||||
* CCSU Compressed Class Space utilization
|
||||
* YGC Number of young generation GC Events.
|
||||
* YGCT Young generation garbage collection time.
|
||||
* FGC Number of full GC events.
|
||||
* FGCT Full garbage collection time.
|
||||
* GCT Total garbage collection time.
|
||||
*
|
||||
*/
|
||||
package utils;
|
||||
|
||||
import common.ToolResults;
|
||||
|
||||
public class JstatGcResults extends JstatResults {
|
||||
|
||||
public JstatGcResults(ToolResults rawResults) {
|
||||
super(rawResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the overall consistency of the results reported by the tool
|
||||
*/
|
||||
public void assertConsistency() {
|
||||
|
||||
assertThat(getExitCode() == 0, "Unexpected exit code: " + getExitCode());
|
||||
|
||||
float OC = getFloatValue("OC");
|
||||
float OU = getFloatValue("OU");
|
||||
assertThat(OU <= OC, "OU > OC (utilization > capacity)");
|
||||
|
||||
float MC = getFloatValue("MC");
|
||||
float MU = getFloatValue("MU");
|
||||
assertThat(MU <= MC, "MU > MC (utilization > capacity)");
|
||||
|
||||
float CCSC = getFloatValue("CCSC");
|
||||
float CCSU = getFloatValue("CCSU");
|
||||
assertThat(CCSU <= CCSC, "CCSU > CCSC (utilization > capacity)");
|
||||
|
||||
float S0C = getFloatValue("S0C");
|
||||
float S0U = getFloatValue("S0U");
|
||||
assertThat(S0U <= S0C, "S0U > S0C (utilization > capacity)");
|
||||
|
||||
float S1C = getFloatValue("S1C");
|
||||
float S1U = getFloatValue("S1U");
|
||||
assertThat(S1U <= S1C, "S1U > S1C (utilization > capacity)");
|
||||
|
||||
float EC = getFloatValue("EC");
|
||||
float EU = getFloatValue("EU");
|
||||
assertThat(EU <= EC, "EU > EC (utilization > capacity)");
|
||||
|
||||
int YGC = getIntValue("YGC");
|
||||
float YGCT = getFloatValue("YGCT");
|
||||
assertThat(YGCT >= 0, "Incorrect time value for YGCT");
|
||||
if (YGC > 0) {
|
||||
assertThat(YGCT > 0, "Number of young generation GC Events is " + YGC + ", but YGCT is 0");
|
||||
}
|
||||
|
||||
float GCT = getFloatValue("GCT");
|
||||
assertThat(GCT >= 0, "Incorrect time value for GCT");
|
||||
assertThat(GCT >= YGCT, "GCT < YGCT (total garbage collection time < young generation garbage collection time)");
|
||||
|
||||
int FGC = getIntValue("FGC");
|
||||
float FGCT = getFloatValue("FGCT");
|
||||
assertThat(FGCT >= 0, "Incorrect time value for FGCT");
|
||||
if (FGC > 0) {
|
||||
assertThat(FGCT > 0, "Number of full GC events is " + FGC + ", but FGCT is 0");
|
||||
}
|
||||
|
||||
assertThat(GCT >= FGCT, "GCT < YGCT (total garbage collection time < full generation garbage collection time)");
|
||||
|
||||
assertThat(checkFloatIsSum(GCT, YGCT, FGCT), "GCT != (YGCT + FGCT) " + "(GCT = " + GCT + ", YGCT = " + YGCT
|
||||
+ ", FGCT = " + FGCT + ", (YCGT + FGCT) = " + (YGCT + FGCT) + ")");
|
||||
}
|
||||
|
||||
private static final float FLOAT_COMPARISON_TOLERANCE = 0.0011f;
|
||||
|
||||
private static boolean checkFloatIsSum(float sum, float... floats) {
|
||||
for (float f : floats) {
|
||||
sum -= f;
|
||||
}
|
||||
|
||||
return Math.abs(sum) <= FLOAT_COMPARISON_TOLERANCE;
|
||||
}
|
||||
|
||||
private void assertThat(boolean b, String message) {
|
||||
if (!b) {
|
||||
throw new RuntimeException(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
import common.TmTool;
|
||||
|
||||
/**
|
||||
* This tool executes "jstat -gc <pid>" and returns the results as
|
||||
* JstatGcToolResults
|
||||
*/
|
||||
public class JstatGcTool extends TmTool<JstatGcResults> {
|
||||
|
||||
public JstatGcTool(long pid) {
|
||||
super(JstatGcResults.class, "jstat", "-gc " + pid);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
import common.ToolResults;
|
||||
|
||||
/**
|
||||
* Results of running the jstat tool Concrete subclasses will detail the jstat
|
||||
* tool options
|
||||
*/
|
||||
abstract public class JstatResults extends ToolResults {
|
||||
|
||||
public JstatResults(ToolResults rawResults) {
|
||||
super(rawResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string result from the column labeled 'name'
|
||||
*
|
||||
* @param name - name of the column
|
||||
* @return the result
|
||||
*/
|
||||
public String getStringValue(String name) {
|
||||
int valueNdx = new StringOfValues(getStdoutLine(0)).getIndex(name);
|
||||
return new StringOfValues(getStdoutLine(1)).getValue(valueNdx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a float result from the column labeled 'name'
|
||||
*
|
||||
* @param name - name of the column
|
||||
* @return the result
|
||||
*/
|
||||
public float getFloatValue(String name) {
|
||||
int valueNdx = new StringOfValues(getStdoutLine(0)).getIndex(name);
|
||||
return Float.valueOf(new StringOfValues(getStdoutLine(1)).getValue(valueNdx));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an integer result from the column labeled 'name'
|
||||
*
|
||||
* @param name - name of the column
|
||||
* @return the result
|
||||
*/
|
||||
public int getIntValue(String name) {
|
||||
int valueNdx = new StringOfValues(getStdoutLine(0)).getIndex(name);
|
||||
return Integer.valueOf(new StringOfValues(getStdoutLine(1)).getValue(valueNdx));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a column with a given name exists
|
||||
*
|
||||
* @param name - name of the column
|
||||
* @return true if the column exist, false otherwise
|
||||
*/
|
||||
public boolean valueExists(String name) {
|
||||
return new StringOfValues(getStdoutLine(0)).getIndex(name) != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to assert the increase of the GC events between 2
|
||||
* measurements
|
||||
*
|
||||
* @param measurement1 -first measurement
|
||||
* @param measurement2 -first measurement
|
||||
*/
|
||||
public static void assertGCEventsIncreased(JstatResults measurement1, JstatResults measurement2) {
|
||||
assertThat(measurement2.getFloatValue("YGC") > measurement1.getFloatValue("YGC"), "YGC didn't increase between measurements 1 and 2");
|
||||
assertThat(measurement2.getFloatValue("FGC") > measurement1.getFloatValue("FGC"), "FGC didn't increase between measurements 2 and 3");
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to assert the increase of the GC time between 2
|
||||
* measurements
|
||||
*
|
||||
* @param measurement1 -first measurement
|
||||
* @param measurement2 -first measurement
|
||||
*/
|
||||
public static void assertGCTimeIncreased(JstatResults measurement1, JstatResults measurement2) {
|
||||
assertThat(measurement2.getFloatValue("YGCT") > measurement1.getFloatValue("YGCT"), "YGCT time didn't increase between measurements 1 and 2");
|
||||
assertThat(measurement2.getFloatValue("FGCT") > measurement1.getFloatValue("FGCT"), "FGCT time didn't increase between measurements 1 and 2");
|
||||
assertThat(measurement2.getFloatValue("GCT") > measurement1.getFloatValue("GCT"), "GCT time didn't increase between measurements 1 and 2");
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to assert the utilization of the space
|
||||
*
|
||||
* @param measurement - measurement results to analyze
|
||||
* @param targetMemoryUsagePercent -assert that not less than this amount of
|
||||
* space has been utilized
|
||||
*/
|
||||
public static void assertSpaceUtilization(JstatResults measurement, float targetMemoryUsagePercent) {
|
||||
|
||||
if (measurement.valueExists("OU")) {
|
||||
float OC = measurement.getFloatValue("OC");
|
||||
float OU = measurement.getFloatValue("OU");
|
||||
assertThat((OU / OC) > targetMemoryUsagePercent, "Old space utilization should be > "
|
||||
+ (targetMemoryUsagePercent * 100) + "%, actually OU / OC = " + (OU / OC));
|
||||
}
|
||||
|
||||
if (measurement.valueExists("MU")) {
|
||||
float MC = measurement.getFloatValue("MC");
|
||||
float MU = measurement.getFloatValue("MU");
|
||||
assertThat((MU / MC) > targetMemoryUsagePercent, "Metaspace utilization should be > "
|
||||
+ (targetMemoryUsagePercent * 100) + "%, actually MU / MC = " + (MU / MC));
|
||||
}
|
||||
|
||||
if (measurement.valueExists("O")) {
|
||||
float O = measurement.getFloatValue("O");
|
||||
assertThat(O > targetMemoryUsagePercent * 100, "Old space utilization should be > "
|
||||
+ (targetMemoryUsagePercent * 100) + "%, actually O = " + O);
|
||||
}
|
||||
|
||||
if (measurement.valueExists("M")) {
|
||||
float M = measurement.getFloatValue("M");
|
||||
assertThat(M > targetMemoryUsagePercent * 100, "Metaspace utilization should be > "
|
||||
+ (targetMemoryUsagePercent * 100) + "%, actually M = " + M);
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertThat(boolean result, String message) {
|
||||
if (!result) {
|
||||
throw new RuntimeException(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
105
hotspot/test/serviceability/tmtools/jstat/utils/Pools.java
Normal file
105
hotspot/test/serviceability/tmtools/jstat/utils/Pools.java
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MemoryPoolMXBean;
|
||||
|
||||
/**
|
||||
* Utility to obtain memory pools statistics
|
||||
*
|
||||
*/
|
||||
public class Pools {
|
||||
|
||||
private static final String EDEN_SPACE_POOL = "Eden Space";
|
||||
private static final String OLD_GEN_POOL = "Old Gen";
|
||||
private static final String METASPACE_POOL = "Metaspace";
|
||||
private static final String SURVIVOR_SPACE = "Survivor Space";
|
||||
|
||||
public static long getNGMaxSize() {
|
||||
// NewGen is consists of Eden and two Survivor spaces
|
||||
return getPoolMaxSize(EDEN_SPACE_POOL) + 2 * getPoolMaxSize(SURVIVOR_SPACE);
|
||||
}
|
||||
|
||||
public static long getHeapCommittedSize() {
|
||||
return ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getCommitted() / 1024;
|
||||
}
|
||||
|
||||
public static long getEdenCommittedSize() {
|
||||
return getPoolCommittedSize(EDEN_SPACE_POOL);
|
||||
}
|
||||
|
||||
public static long getOldGenCommittedSize() {
|
||||
return getPoolCommittedSize(OLD_GEN_POOL);
|
||||
}
|
||||
|
||||
public static long getMetaspaceCommittedSize() {
|
||||
return getPoolCommittedSize(METASPACE_POOL);
|
||||
}
|
||||
|
||||
private static long getPoolMaxSize(String poolName) {
|
||||
long result;
|
||||
MemoryPoolMXBean pool = findPool(poolName);
|
||||
if (pool != null) {
|
||||
if (pool.getUsage().getMax() == -1) {
|
||||
result = -1;
|
||||
} else {
|
||||
result = pool.getUsage().getCommitted() / 1024;
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Pool '" + poolName + "' wasn't found");
|
||||
}
|
||||
log("Max size of the pool '" + poolName + "' is " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static long getPoolCommittedSize(String poolName) {
|
||||
long result;
|
||||
MemoryPoolMXBean pool = findPool(poolName);
|
||||
if (pool != null) {
|
||||
if (pool.getUsage().getCommitted() == -1) {
|
||||
result = -1;
|
||||
} else {
|
||||
result = pool.getUsage().getCommitted() / 1024;
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Pool '" + poolName + "' wasn't found");
|
||||
}
|
||||
log("Committed size of the pool '" + poolName + "' is " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static MemoryPoolMXBean findPool(String poolName) {
|
||||
for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
|
||||
if (pool.getName().contains(poolName)) {
|
||||
return pool;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void log(String s) {
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Helper class to get the values from tools output
|
||||
*/
|
||||
class StringOfValues {
|
||||
|
||||
private List<String> values;
|
||||
|
||||
StringOfValues(String s) {
|
||||
this.values = new ArrayList<>();
|
||||
StringTokenizer st = new StringTokenizer(s);
|
||||
while (st.hasMoreTokens()) {
|
||||
values.add(st.nextToken());
|
||||
}
|
||||
}
|
||||
|
||||
int getIndex(String val) {
|
||||
for (int ndx = 0; ndx < values.size(); ++ndx) {
|
||||
if (values.get(ndx).equals(val)) {
|
||||
return ndx;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
String getValue(int ndx) {
|
||||
return values.get(ndx);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 utils;
|
||||
|
||||
class TemplateClass {
|
||||
}
|
67
hotspot/test/serviceability/tmtools/share/common/TmTool.java
Normal file
67
hotspot/test/serviceability/tmtools/share/common/TmTool.java
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 common;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import jdk.test.lib.Platform;
|
||||
|
||||
/**
|
||||
* A tool, such as jstat, jmap, etc Specific tools are defined as subclasses
|
||||
* parameterized by their corresponding ToolResults subclasses
|
||||
*/
|
||||
public abstract class TmTool<T extends ToolResults> {
|
||||
|
||||
private final Class<T> resultsClz;
|
||||
private final String cmdLine;
|
||||
|
||||
public TmTool(Class<T> resultsClz, String toolName, String otherArgs) {
|
||||
this.resultsClz = resultsClz;
|
||||
this.cmdLine = adjustForTestJava(toolName) + " " + otherArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the tool to completion and returns the results
|
||||
*
|
||||
* @return the tool results
|
||||
* @throws Exception if anything goes wrong
|
||||
*/
|
||||
public T measure() throws Exception {
|
||||
ToolRunner runner = new ToolRunner(cmdLine);
|
||||
ToolResults rawResults = runner.runToCompletion();
|
||||
System.out.println("Process output: " + rawResults);
|
||||
return resultsClz.getDeclaredConstructor(ToolResults.class).newInstance(rawResults);
|
||||
}
|
||||
|
||||
private String adjustForTestJava(String toolName) {
|
||||
// We need to make sure we are running the tol from the JDK under testing
|
||||
String jdkPath = System.getProperty("test.jdk");
|
||||
if (jdkPath == null || !Paths.get(jdkPath).toFile().exists()) {
|
||||
throw new RuntimeException("property test.jdk not not set");
|
||||
}
|
||||
Path toolPath = Paths.get("bin", toolName + (Platform.isWindows() ? ".exe" : ""));
|
||||
return Paths.get(jdkPath, toolPath.toString()).toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 common;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Common results of running an executable such as the saved exit code, the
|
||||
* saved stdout and stderr
|
||||
*/
|
||||
public class ToolResults {
|
||||
|
||||
public int getExitCode() {
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
public List<String> getStdout() {
|
||||
return stdout;
|
||||
}
|
||||
|
||||
public List<String> getStderr() {
|
||||
return stderr;
|
||||
}
|
||||
|
||||
public String getStdoutString() {
|
||||
return stdout.stream().collect(Collectors.joining(System.getProperty("line.separator")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to return a specified line from the saved stdout
|
||||
*
|
||||
* @return the line indexed with ndx from the saved stdout. The indexes are
|
||||
* zero-based so that getStdoutLine(0) returns the first line.
|
||||
*/
|
||||
public String getStdoutLine(int ndx) {
|
||||
return stdout.get(ndx);
|
||||
}
|
||||
|
||||
public ToolResults(int exitCode, List<String> stdin, List<String> stderr) {
|
||||
this.exitCode = exitCode;
|
||||
this.stdout = stdin;
|
||||
this.stderr = stderr;
|
||||
}
|
||||
|
||||
public ToolResults(ToolResults rawResults) {
|
||||
this(rawResults.exitCode, rawResults.stdout, rawResults.stderr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Exit code: ").append(exitCode).append("\n");
|
||||
sb.append("stdout:");
|
||||
stdout.stream().forEach((s) -> {
|
||||
sb.append(s).append("\n");
|
||||
});
|
||||
sb.append("stderr:");
|
||||
stderr.stream().forEach((s) -> {
|
||||
sb.append(s).append("\n");
|
||||
});
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private final int exitCode;
|
||||
private final List<String> stdout;
|
||||
private final List<String> stderr;
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 common;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
/**
|
||||
* This class starts a process specified by the passed command line waits till
|
||||
* the process completes and returns the process exit code and stdout and stderr
|
||||
* output as ToolResults
|
||||
*/
|
||||
class ToolRunner {
|
||||
|
||||
private final List<String> cmdArgs = new LinkedList<>();
|
||||
|
||||
ToolRunner(String cmdLine) {
|
||||
StringTokenizer st = new StringTokenizer(cmdLine);
|
||||
while (st.hasMoreTokens()) {
|
||||
cmdArgs.add(st.nextToken());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the process, waits for the process completion and returns the
|
||||
* results
|
||||
*
|
||||
* @return process results
|
||||
* @throws Exception if anything goes wrong
|
||||
*/
|
||||
ToolResults runToCompletion() throws Exception {
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder(cmdArgs);
|
||||
OutputAnalyzer oa = ProcessTools.executeProcess(pb);
|
||||
|
||||
return new ToolResults(oa.getExitValue(),
|
||||
stringToList(oa.getStdout()),
|
||||
stringToList(oa.getStderr()));
|
||||
|
||||
}
|
||||
|
||||
private static List<String> stringToList(String s) throws IOException {
|
||||
BufferedReader reader = new BufferedReader(new StringReader(s));
|
||||
List<String> strings = new ArrayList<>();
|
||||
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
|
||||
strings.add(line);
|
||||
}
|
||||
reader.close();
|
||||
return strings;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user