8130063: Refactoring tmtools jstat and jstack tests to jtreg
Summary: Some of the jstat and jstack tests refactored to be run with the jtreg
Reviewed-by: jbachorik
--- a/hotspot/test/TEST.groups Thu Jan 14 09:18:11 2016 +0100
+++ b/hotspot/test/TEST.groups Thu Jan 14 15:35:21 2016 +0300
@@ -97,7 +97,8 @@
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 @@
not_needs_nashorn = \
:jdk \
-:needs_nashorn
+
+hotspot_tmtools = \
+ serviceability/tmtools
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/DaemonThreadTest.java Thu Jan 14 15:35:21 2016 +0300
@@ -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() + "'");
+ }
+
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/JstackTool.java Thu Jan 14 15:35:21 2016 +0300
@@ -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));
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/SpreadLockTest.java Thu Jan 14 15:35:21 2016 +0300
@@ -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() + "\"");
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/ThreadNamesTest.java Thu Jan 14 15:35:21 2016 +0300
@@ -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 + "'");
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/TraveledLockTest.java Thu Jan 14 15:35:21 2016 +0300
@@ -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() + "\"");
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/WaitNotifyThreadTest.java Thu Jan 14 15:35:21 2016 +0300
@@ -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");
+ }
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/utils/Consts.java Thu Jan 14 15:35:21 2016 +0300
@@ -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";
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/utils/DefaultFormat.java Thu Jan 14 15:35:21 2016 +0300
@@ -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;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/utils/Format.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/utils/JStack.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/utils/LockInfo.java Thu Jan 14 15:35:21 2016 +0300
@@ -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;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/utils/MethodInfo.java Thu Jan 14 15:35:21 2016 +0300
@@ -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;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/utils/MonitorInfo.java Thu Jan 14 15:35:21 2016 +0300
@@ -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 + ")";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/utils/ThreadStack.java Thu Jan 14 15:35:21 2016 +0300
@@ -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;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/utils/Utils.java Thu Jan 14 15:35:21 2016 +0300
@@ -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) {
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/GcCapacityTest.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/GcCauseTest01.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/GcCauseTest02.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/GcCauseTest03.java Thu Jan 14 15:35:21 2016 +0300
@@ -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()");
+ }
+ }
+
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/GcNewTest.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ };
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/GcTest01.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/GcTest02.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ };
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/ClassLoadUtils.java Thu Jan 14 15:35:21 2016 +0300
@@ -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));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/GcProvoker.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/GcProvokerImpl.java Thu Jan 14 15:35:21 2016 +0300
@@ -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() {
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/GeneratedClassProducer.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/GeneratingClassLoader.java Thu Jan 14 15:35:21 2016 +0300
@@ -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;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCapacityResults.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCapacityTool.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCauseResults.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCauseTool.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcNewResults.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcNewTool.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcResults.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcTool.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatResults.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/Pools.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/StringOfValues.java Thu Jan 14 15:35:21 2016 +0300
@@ -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);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/TemplateClass.java Thu Jan 14 15:35:21 2016 +0300
@@ -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 {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/share/common/TmTool.java Thu Jan 14 15:35:21 2016 +0300
@@ -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();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/share/common/ToolResults.java Thu Jan 14 15:35:21 2016 +0300
@@ -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;
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/share/common/ToolRunner.java Thu Jan 14 15:35:21 2016 +0300
@@ -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;
+ }
+}