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:
Alexander Kulyakhtin 2016-01-14 15:35:21 +03:00
parent 49d61bdeb6
commit f8b5f55021
43 changed files with 3992 additions and 1 deletions

View File

@ -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

View File

@ -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() + "'");
}
}
}

View 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));
}
}

View 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() + "\"");
}
}
}

View 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.
*/
/*
* @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 + "'");
}
}
}

View 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() + "\"");
}
}
}

View File

@ -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");
}
}
}
}

View 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";
}

View File

@ -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;
}
}

View 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);
}

View 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);
}
}

View File

@ -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;
}
}

View 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;
}
}

View File

@ -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 + ")";
}
}

View File

@ -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;
}
}

View 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) {
}
}
}

View File

@ -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);
}
}

View 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);
}
}

View 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);
}
}

View 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()");
}
}
}
}

View 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);
};
}
}

View 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);
}
}

View 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);
};
}
}

View File

@ -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));
}
}

View File

@ -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);
}

View File

@ -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() {
}
}

View File

@ -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);
}
}
}

View 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.
*/
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;
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View 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);
}
}

View File

@ -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);
}
}

View File

@ -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 {
}

View 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();
}
}

View File

@ -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;
}

View 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.
*/
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;
}
}