# HG changeset patch # User ddmitriev # Date 1452788457 0 # Node ID 6bd011f5d96e0e10acd9bfc0a5ea42b44edce6e0 # Parent c8c0273e6b916413acf2a367ce74231a35e681ca# Parent 863fb33f99408d49d0ee097ba0c184cbc981420e Merge diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/TEST.groups --- a/hotspot/test/TEST.groups Thu Jan 14 13:26:19 2016 +0100 +++ b/hotspot/test/TEST.groups Thu Jan 14 16:20:57 2016 +0000 @@ -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 diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstack/DaemonThreadTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstack/DaemonThreadTest.java Thu Jan 14 16:20:57 2016 +0000 @@ -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() + "'"); + } + + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstack/JstackTool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstack/JstackTool.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 " and returns the results + */ +public class JstackTool extends TmTool { + + public JstackTool(long pid) { + super(ToolResults.class, "jstack", String.valueOf(pid)); + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstack/SpreadLockTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstack/SpreadLockTest.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 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() + "\""); + } + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstack/ThreadNamesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstack/ThreadNamesTest.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 + "'"); + } + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstack/TraveledLockTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstack/TraveledLockTest.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 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() + "\""); + } + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstack/WaitNotifyThreadTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstack/WaitNotifyThreadTest.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 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 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"); + } + } + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstack/utils/Consts.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstack/utils/Consts.java Thu Jan 14 16:20:57 2016 +0000 @@ -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"; + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstack/utils/DefaultFormat.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstack/utils/DefaultFormat.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 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; + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstack/utils/Format.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstack/utils/Format.java Thu Jan 14 16:20:57 2016 +0000 @@ -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); + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstack/utils/JStack.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstack/utils/JStack.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 threads = new HashMap(); + 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 getThreads() { + return threads; + } + + public void setThreads(HashMap 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); + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstack/utils/LockInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstack/utils/LockInfo.java Thu Jan 14 16:20:57 2016 +0000 @@ -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; + } +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstack/utils/MethodInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstack/utils/MethodInfo.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 locks = new LinkedList(); + + 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 getLocks() { + return locks; + } + + public void setLocks(LinkedList 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; + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstack/utils/MonitorInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstack/utils/MonitorInfo.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 + ")"; + } +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstack/utils/ThreadStack.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstack/utils/ThreadStack.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 stack = new LinkedList(); + + private LinkedList lockOSList = new LinkedList(); + + 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 getStack() { + return stack; + } + + public LinkedList getLockOSList() { + return lockOSList; + } + + public void setLockOSList(LinkedList lockOSList) { + this.lockOSList = lockOSList; + } + + public void addMethod(MethodInfo mi) { + stack.add(mi); + } + + public boolean hasEqualStack(ThreadStack another) { + boolean result = true; + + Iterator it1 = stack.iterator(); + Iterator 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; + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstack/utils/Utils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstack/utils/Utils.java Thu Jan 14 16:20:57 2016 +0000 @@ -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) { + } + } +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/GcCapacityTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/GcCapacityTest.java Thu Jan 14 16:20:57 2016 +0000 @@ -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); + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/GcCauseTest01.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/GcCauseTest01.java Thu Jan 14 16:20:57 2016 +0000 @@ -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); + } +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/GcCauseTest02.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/GcCauseTest02.java Thu Jan 14 16:20:57 2016 +0000 @@ -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); + } +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/GcCauseTest03.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/GcCauseTest03.java Thu Jan 14 16:20:57 2016 +0000 @@ -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()"); + } + } + + } +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/GcNewTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/GcNewTest.java Thu Jan 14 16:20:57 2016 +0000 @@ -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); + }; + } +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/GcTest01.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/GcTest01.java Thu Jan 14 16:20:57 2016 +0000 @@ -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); + + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/GcTest02.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/GcTest02.java Thu Jan 14 16:20:57 2016 +0000 @@ -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); + }; + } +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/utils/ClassLoadUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/utils/ClassLoadUtils.java Thu Jan 14 16:20:57 2016 +0000 @@ -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)); + } +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/utils/GcProvoker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/utils/GcProvoker.java Thu Jan 14 16:20:57 2016 +0000 @@ -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); + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/utils/GcProvokerImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/utils/GcProvokerImpl.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 eatenMetaspace; + private static List eatenMemory; + + static List eatHeapMemory(float targetUsage) { + long maxMemory = Runtime.getRuntime().maxMemory(); + // uses fixed small objects to avoid Humongous objects allocation in G1 + int memoryChunk = 2048; + List 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 eatMetaspace(float targetUsage) { + List 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() { + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/utils/GeneratedClassProducer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/utils/GeneratedClassProducer.java Thu Jan 14 16:20:57 2016 +0000 @@ -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); + } + } +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/utils/GeneratingClassLoader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/utils/GeneratingClassLoader.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 offsets = new ArrayList(); + 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; +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCapacityResults.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCapacityResults.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 ") + * + * 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 parallelGCs = Arrays.asList(new String[] { "PS MarkSweep"}); + try { + List 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); + } + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCapacityTool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCapacityTool.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 " and returns the results as + * JstatGcCapacityoolResults + */ +public class JstatGcCapacityTool extends TmTool { + + public JstatGcCapacityTool(long pid) { + super(JstatGcCapacityResults.class, "jstat", "-gccapacity " + pid); + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCauseResults.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCauseResults.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 ") + * + * 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); + } + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCauseTool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCauseTool.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 " and returns the results as + * JstatGcToolResults + */ +public class JstatGcCauseTool extends TmTool { + + public JstatGcCauseTool(long pid) { + super(JstatGcCauseResults.class, "jstat", "-gc " + pid); + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/utils/JstatGcNewResults.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcNewResults.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 ") + * + * 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); + } + } +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/utils/JstatGcNewTool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcNewTool.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 " and returns the results as + * JstatGcNewResults + */ +public class JstatGcNewTool extends TmTool { + + public JstatGcNewTool(long pid) { + super(JstatGcNewResults.class, "jstat", "-gcnew " + pid); + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/utils/JstatGcResults.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcResults.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 ") + * + * 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); + } + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/utils/JstatGcTool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcTool.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 " and returns the results as + * JstatGcToolResults + */ +public class JstatGcTool extends TmTool { + + public JstatGcTool(long pid) { + super(JstatGcResults.class, "jstat", "-gc " + pid); + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/utils/JstatResults.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatResults.java Thu Jan 14 16:20:57 2016 +0000 @@ -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); + } + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/utils/Pools.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/utils/Pools.java Thu Jan 14 16:20:57 2016 +0000 @@ -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); + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/utils/StringOfValues.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/utils/StringOfValues.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 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); + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/jstat/utils/TemplateClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/jstat/utils/TemplateClass.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 { +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/share/common/TmTool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/share/common/TmTool.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 { + + private final Class resultsClz; + private final String cmdLine; + + public TmTool(Class 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(); + } + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/share/common/ToolResults.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/share/common/ToolResults.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 getStdout() { + return stdout; + } + + public List 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 stdin, List 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 stdout; + private final List stderr; + +} diff -r c8c0273e6b91 -r 6bd011f5d96e hotspot/test/serviceability/tmtools/share/common/ToolRunner.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/tmtools/share/common/ToolRunner.java Thu Jan 14 16:20:57 2016 +0000 @@ -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 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 stringToList(String s) throws IOException { + BufferedReader reader = new BufferedReader(new StringReader(s)); + List strings = new ArrayList<>(); + for (String line = reader.readLine(); line != null; line = reader.readLine()) { + strings.add(line); + } + reader.close(); + return strings; + } +}