Merge
authorddmitriev
Thu, 14 Jan 2016 16:20:57 +0000
changeset 35494 6bd011f5d96e
parent 35492 c8c0273e6b91 (current diff)
parent 35493 863fb33f9940 (diff)
child 35496 3b740753359e
Merge
--- 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	
--- /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() + "'");
+        }
+
+    }
+
+}
--- /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 <pid>" and returns the results
+ */
+public class JstackTool extends TmTool<ToolResults> {
+
+    public JstackTool(long pid) {
+        super(ToolResults.class, "jstack", String.valueOf(pid));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/SpreadLockTest.java	Thu Jan 14 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<MethodInfo> it = ts1.getStack().iterator();
+        while (it.hasNext()) {
+            MethodInfo mi = it.next();
+            if (mi.getName().startsWith(SpreadLockDebuggee.class.getName() + ".a")) {
+                monitorInfo[counter++] = haveToHaveOneLock(mi);
+            }
+        }
+
+        it = ts2.getStack().iterator();
+        while (it.hasNext()) {
+            MethodInfo mi = it.next();
+            if (mi.getName().startsWith(SpreadLockDebuggee.class.getName() + ".a")
+                    || mi.getName().startsWith(SpreadLockDebuggee.class.getName() + ".b")) {
+                monitorInfo[counter++] = haveToHaveOneLock(mi);
+            }
+        }
+
+        it = ts3.getStack().iterator();
+        while (it.hasNext()) {
+            MethodInfo mi = it.next();
+            if (mi.getName().startsWith(SpreadLockDebuggee.class.getName() + ".a")
+                    || mi.getName().startsWith(SpreadLockDebuggee.class.getName() + ".b")
+                    || mi.getName().startsWith(SpreadLockDebuggee.class.getName() + ".c")) {
+                monitorInfo[counter++] = haveToHaveOneLock(mi);
+            }
+        }
+
+        System.out.println("All monitors found - passed");
+
+    }
+
+    private MonitorInfo haveToHaveOneLock(MethodInfo mi) {
+        if (mi.getLocks().size() == 1) {
+            System.out.println("Method \"" + mi.getName()
+                    + "\" contain 1 lock - correct");
+            return mi.getLocks().getFirst();
+        } else {
+            throw new RuntimeException("Lock count ("
+                    + mi.getLocks().size() + ") is incorrect in method \""
+                    + mi.getName() + "\"");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/ThreadNamesTest.java	Thu Jan 14 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 + "'");
+        }
+    }
+
+}
--- /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<MethodInfo> it = ts1.getStack().iterator();
+        while (it.hasNext()) {
+            MethodInfo mi = it.next();
+            if (mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".a")) {
+                monitorInfo1 = haveToHaveOneLock(mi);
+            }
+        }
+
+        it = ts2.getStack().iterator();
+        while (it.hasNext()) {
+            MethodInfo mi = it.next();
+            if (mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".a")) {
+                haveToBeEmpty(mi);
+            } else if (mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".b")) {
+                monitorInfo2 = haveToHaveOneLock(mi);
+            }
+        }
+
+        it = ts3.getStack().iterator();
+        while (it.hasNext()) {
+            MethodInfo mi = it.next();
+            if (mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".a")
+                    || mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".b")) {
+                haveToBeEmpty(mi);
+            } else if (mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".c")) {
+                monitorInfo3 = haveToHaveOneLock(mi);
+            }
+        }
+
+        System.out.println("All monitors found - passed");
+    }
+
+    private MonitorInfo haveToHaveOneLock(MethodInfo mi) {
+        if (mi.getLocks().size() == 1) {
+            System.out.println("Method \"" + mi.getName()
+                    + "\" contain 1 lock - correct");
+            return mi.getLocks().getFirst();
+        } else {
+            throw new RuntimeException("Lock count ("
+                    + mi.getLocks().size() + ") is incorrect in method \""
+                    + mi.getName() + "\"");
+        }
+    }
+
+    private void haveToBeEmpty(MethodInfo mi) {
+        if (mi.getLocks().size() == 0) {
+            System.out.println("Method \"" + mi.getName()
+                    + "\" does not lock anything - correct");
+        } else {
+            throw new RuntimeException(
+                    "Unexpected lock found in method \"" + mi.getName() + "\"");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/WaitNotifyThreadTest.java	Thu Jan 14 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<MethodInfo> it = ti1.getStack().iterator();
+
+        String monitorAddress = null;
+        while (it.hasNext()) {
+            MethodInfo mi = it.next();
+            if (mi.getName().startsWith(OBJECT_WAIT) && mi.getCompilationUnit() == null /*native method*/) {
+                if (mi.getLocks().size() == 1) {
+                    MonitorInfo monInfo = mi.getLocks().getFirst();
+                    if (monInfo.getType().equals("waiting on")
+                            && monInfo.getMonitorClass().equals(OBJECT)) {
+                        monitorAddress = monInfo.getMonitorAddress();
+                    } else {
+                        System.err.println("Error: incorrect monitor info: " + monInfo.getType() + ", " + monInfo.getMonitorClass());
+                        throw new RuntimeException("Incorrect lock record in "
+                                + OBJECT_WAIT + " method");
+                    }
+
+                } else {
+                    throw new RuntimeException(OBJECT_WAIT
+                            + " method has to contain one lock record bu it contains " + mi.getLocks().size());
+                }
+            }
+
+            if (mi.getName().startsWith("WaitThread.run")) {
+                if (monitorAddress == null) {
+                    throw new RuntimeException("Cannot found monitor info associated with " + OBJECT_WAIT + " method");
+                }
+
+                int numLocks = mi.getLocks().size();
+                for (int i = 0; i < numLocks - 1; ++i) {
+                    assertMonitorInfo("waiting to re-lock in wait()", mi.getLocks().get(i), monitorAddress);
+                }
+                assertMonitorInfo("locked", mi.getLocks().getLast(), monitorAddress);
+            }
+        }
+
+    }
+
+    private void assertMonitorInfo(String expectedMessage, MonitorInfo monInfo, String monitorAddress) {
+        if (monInfo.getType().equals(expectedMessage)
+                && monInfo.getMonitorClass().equals(OBJECT + "11")
+                && monInfo.getMonitorAddress().equals(
+                        monitorAddress)) {
+            System.out.println("Correct monitor info found");
+        } else {
+            System.err.println("Error: incorrect monitor info: " + monInfo.getType() + ", " + monInfo.getMonitorClass() + ", " + monInfo.getMonitorAddress());
+            System.err.println("Expected: " + expectedMessage + ", a java.lang.Object, " + monitorAddress);
+            throw new RuntimeException("Incorrect lock record in 'run' method");
+        }
+    }
+
+    private void analyzeThreadStackNoWaiting(ThreadStack ti2) {
+        Iterator<MethodInfo> it = ti2.getStack().iterator();
+
+        while (it.hasNext()) {
+            MethodInfo mi = it.next();
+            if (mi.getLocks().size() != 0) {
+                throw new RuntimeException("Unexpected lock record in "
+                        + mi.getName() + " method");
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/utils/Consts.java	Thu Jan 14 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";
+
+}
--- /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<Thread, StackTraceElement[]> stacks = Thread.getAllStackTraces();
+
+        // adding data and vm version
+        result.append(Consts.UNKNOWN + "\n");
+        result.append(Consts.UNKNOWN + "\n\n");
+
+        for (Thread t : stacks.keySet()) {
+
+            result.append("\"" + t.getName() + "\"");
+            result.append(Consts.SEPARATOR);
+
+            // status
+            if (t.isDaemon()) {
+                result.append("daemon");
+                result.append(Consts.SEPARATOR);
+            }
+
+            // priority
+            result.append("prio=" + t.getPriority());
+            result.append(Consts.SEPARATOR);
+
+            // tid
+            result.append("tid=" + Consts.UNKNOWN);
+            result.append(Consts.SEPARATOR);
+
+            // nid
+            result.append("nid=" + Consts.UNKNOWN);
+            result.append(Consts.SEPARATOR);
+
+            // status
+            result.append(Consts.UNKNOWN);
+            result.append(Consts.SEPARATOR);
+
+            result.append("\n");
+
+            // extended status
+            result.append("   java.lang.Thread.State: "
+                    + String.valueOf(Thread.currentThread().getState()));
+            result.append(Consts.SEPARATOR);
+            result.append("\n");
+
+            for (StackTraceElement st : stacks.get(t)) {
+                result.append("  at " + st.toString() + "\n");
+            }
+            result.append("\n");
+        }
+
+        result.append(Consts.JNI_GLOBAL_REF + Consts.UNKNOWN + "\n");
+        return result.toString();
+    }
+
+    protected LockInfo parseLockInfo(String line) {
+        LockInfo res = new LockInfo();
+
+        Scanner s = new Scanner(line);
+        s.findInLine(ownableSynchronizersPattern());
+
+        MatchResult matchRes = s.match();
+        String lock = matchRes.group(1).equals("None") ? matchRes.group(1) : matchRes.group(2);
+        res.setLock(lock);
+
+        return res;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/utils/Format.java	Thu Jan 14 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);
+
+}
--- /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<String, ThreadStack> threads = new HashMap<String, ThreadStack>();
+    private String jniGlobalReferences;
+
+    public String getDate() {
+        return date;
+    }
+
+    public void setDate(String date) {
+        this.date = date;
+    }
+
+    public String getVmVersion() {
+        return vmVersion;
+    }
+
+    public void setVmVersion(String vmVersion) {
+        this.vmVersion = vmVersion;
+    }
+
+    public HashMap<String, ThreadStack> getThreads() {
+        return threads;
+    }
+
+    public void setThreads(HashMap<String, ThreadStack> threads) {
+        this.threads = threads;
+    }
+
+    public void addThreadStack(String threadName, ThreadStack ts) {
+        System.out.println("Adding thread stack for thread: " + threadName);
+        threads.put(threadName, ts);
+    }
+
+    public String getJniGlobalReferences() {
+        return jniGlobalReferences;
+    }
+
+    public void setJniGlobalReferences(String jniGlobalReferences) {
+        this.jniGlobalReferences = jniGlobalReferences;
+    }
+
+    public ThreadStack getThreadStack(String threadName) {
+        return threads.get(threadName);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/utils/LockInfo.java	Thu Jan 14 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;
+    }
+}
--- /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<MonitorInfo> locks = new LinkedList<MonitorInfo>();
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getCompilationUnit() {
+        return compilationUnit;
+    }
+
+    public void setCompilationUnit(String compilationUnit) {
+        this.compilationUnit = compilationUnit;
+    }
+
+    public String getArgs() {
+        return args;
+    }
+
+    public void setArgs(String args) {
+        this.args = args;
+    }
+
+    public String getBci() {
+        return bci;
+    }
+
+    public void setBci(String bci) {
+        this.bci = bci;
+    }
+
+    public String getLine() {
+        return line;
+    }
+
+    public void setLine(String line) {
+        this.line = line;
+    }
+
+    public String getFrameType() {
+        return frameType;
+    }
+
+    public void setFrameType(String frameType) {
+        this.frameType = frameType;
+    }
+
+    public LinkedList<MonitorInfo> getLocks() {
+        return locks;
+    }
+
+    public void setLocks(LinkedList<MonitorInfo> locks) {
+        this.locks = locks;
+    }
+
+    public boolean equals(MethodInfo another) {
+
+        boolean result = true;
+
+        if (!Utils.compareStrings(name, another.name)) {
+            Utils.log("name", name, another.name);
+            result = false;
+        }
+
+        if (!Utils.compareStrings(compilationUnit, another.compilationUnit)) {
+            Utils.log("compilationUnit", compilationUnit, another.compilationUnit);
+            result = false;
+        }
+
+        /*
+         if (!Utils.compareStrings(args, another.args)) {
+         Utils.log("args", args, another.args);
+         result = false;
+         }
+
+         if (!Utils.compareStrings(bci, another.bci)) {
+         Utils.log("bci", bci, another.bci);
+         result = false;
+         }
+
+         if (!Utils.compareStrings(frameType, another.frameType)) {
+         Utils.log("frameType", frameType, another.frameType);
+         result = false;
+         }
+         */
+        if (!Utils.compareStrings(line, another.line)) {
+            Utils.log("line", line, another.line);
+            result = false;
+        }
+
+        return result;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/utils/MonitorInfo.java	Thu Jan 14 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 + ")";
+    }
+}
--- /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<MethodInfo> stack = new LinkedList<MethodInfo>();
+
+    private LinkedList<LockInfo> lockOSList = new LinkedList<LockInfo>();
+
+    public String getThreadName() {
+        return threadName;
+    }
+
+    public void setThreadName(String threadName) {
+        this.threadName = threadName;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getPriority() {
+        return priority;
+    }
+
+    public void setPriority(String priority) {
+        this.priority = priority;
+    }
+
+    public String getTid() {
+        return tid;
+    }
+
+    public void setTid(String tid) {
+        this.tid = tid;
+    }
+
+    public String getNid() {
+        return nid;
+    }
+
+    public void setNid(String nid) {
+        this.nid = nid;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getPointerRange() {
+        return pointerRange;
+    }
+
+    public void setPointerRange(String pointerRange) {
+        this.pointerRange = pointerRange;
+    }
+
+    public String getExtendedStatus() {
+        return extendedStatus;
+    }
+
+    public void setExtendedStatus(String extendedStatus) {
+        this.extendedStatus = extendedStatus;
+    }
+
+    public LinkedList<MethodInfo> getStack() {
+        return stack;
+    }
+
+    public LinkedList<LockInfo> getLockOSList() {
+        return lockOSList;
+    }
+
+    public void setLockOSList(LinkedList<LockInfo> lockOSList) {
+        this.lockOSList = lockOSList;
+    }
+
+    public void addMethod(MethodInfo mi) {
+        stack.add(mi);
+    }
+
+    public boolean hasEqualStack(ThreadStack another) {
+        boolean result = true;
+
+        Iterator<MethodInfo> it1 = stack.iterator();
+        Iterator<MethodInfo> it2 = another.stack.iterator();
+
+        while (it1.hasNext() && it2.hasNext()) {
+
+            MethodInfo mi1 = it1.next();
+            MethodInfo mi2 = it2.next();
+
+            if (mi1 == null && mi2 == null) {
+                break;
+            }
+
+            boolean oneOfMethodInfoIsNull = mi1 == null && mi2 != null || mi1 != null && mi2 == null;
+
+            if (oneOfMethodInfoIsNull || !mi1.equals(mi2)) {
+                result = false;
+            }
+        }
+
+        if (it1.hasNext() || it2.hasNext()) {
+            Utils.log("stack sizes", String.valueOf(stack.size()), String.valueOf(another.stack.size()));
+            result = false;
+        }
+
+        return result;
+    }
+
+    public String getThreadType() {
+        return threadType;
+    }
+
+    public void setThreadType(String threadType) {
+        this.threadType = threadType;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstack/utils/Utils.java	Thu Jan 14 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) {
+        }
+    }
+}
--- /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);
+    }
+
+}
--- /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);
+    }
+}
--- /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);
+    }
+}
--- /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()");
+            }
+        }
+
+    }
+}
--- /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);
+        };
+    }
+}
--- /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);
+
+    }
+
+}
--- /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);
+        };
+    }
+}
--- /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));
+    }
+}
--- /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);
+
+}
--- /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<Object> eatenMetaspace;
+    private static List<Object> eatenMemory;
+
+    static List<Object> eatHeapMemory(float targetUsage) {
+        long maxMemory = Runtime.getRuntime().maxMemory();
+        // uses fixed small objects to avoid Humongous objects allocation in G1
+        int memoryChunk = 2048;
+        List<Object> list = new ArrayList<>();
+        float used = 0;
+        while (used < targetUsage * maxMemory) {
+            try {
+                list.add(new byte[memoryChunk]);
+                used += memoryChunk;
+            } catch (OutOfMemoryError e) {
+                list = null;
+                throw new RuntimeException("Unexpected OOME while eating " + targetUsage + " of heap memory.");
+            }
+        }
+        return list;
+    }
+
+    @Override
+    public void provokeGc() {
+        for (int i = 0; i < 3; i++) {
+            long edenSize = Pools.getEdenCommittedSize();
+            long heapSize = Pools.getHeapCommittedSize();
+            float targetPercent = ((float) edenSize) / (heapSize);
+            if ((targetPercent <= 0) || (targetPercent > 1.0)) {
+                throw new RuntimeException("Error in the percent calculation" + " (eden size: " + edenSize + ", heap size: " + heapSize + ", calculated eden percent: " + targetPercent + ")");
+            }
+            eatHeapMemory(targetPercent);
+            eatHeapMemory(targetPercent);
+            System.gc();
+        }
+    }
+
+    @Override
+    public void eatMetaspaceAndHeap(float targetMemoryUsagePercent) {
+        eatenMemory = eatHeapMemory(targetMemoryUsagePercent);
+        eatenMetaspace = eatMetaspace(targetMemoryUsagePercent);
+    }
+
+    private static List<Object> eatMetaspace(float targetUsage) {
+        List<Object> list = new ArrayList<>();
+        final String metaspacePoolName = "Metaspace";
+        MemoryPoolMXBean metaspacePool = null;
+        for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
+            if (pool.getName().contains(metaspacePoolName)) {
+                metaspacePool = pool;
+                break;
+            }
+        }
+        if (metaspacePool == null) {
+            throw new RuntimeException("MXBean for Metaspace pool wasn't found");
+        }
+        float currentUsage;
+        GeneratedClassProducer gp = new GeneratedClassProducer();
+        do {
+            try {
+                list.add(gp.create(0));
+            } catch (OutOfMemoryError oome) {
+                list = null;
+                throw new RuntimeException("Unexpected OOME while eating " + targetUsage + " of Metaspace.");
+            }
+            MemoryUsage memoryUsage = metaspacePool.getUsage();
+            currentUsage = (((float) memoryUsage.getUsed()) / memoryUsage.getMax());
+        } while (currentUsage < targetUsage);
+        return list;
+    }
+
+    public GcProvokerImpl() {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/GeneratedClassProducer.java	Thu Jan 14 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);
+        }
+    }
+}
--- /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<Integer> offsets = new ArrayList<Integer>();
+        if (this.offsets == null) {
+            String pname = templateClassName.replace(".", "/");
+            try {
+                byte[] pnameb = pname.getBytes(encoding);
+                int i = 0;
+                while (true) {
+                    while (i < bytecode.length) {
+                        int j = 0;
+                        while (j < pnameb.length && bytecode[i + j] == pnameb[j]) {
+                            ++j;
+                        }
+                        if (j == pnameb.length) {
+                            break;
+                        }
+                        i++;
+                    }
+                    if (i == bytecode.length) {
+                        break;
+                    }
+                    offsets.add(new Integer(i));
+                    i++;
+                }
+            } catch (UnsupportedEncodingException e) {
+                throw new RuntimeException(e);
+            }
+            this.offsets = new int[offsets.size()];
+            for (int i = 0; i < offsets.size(); ++i) {
+                this.offsets[i] = offsets.get(i).intValue();
+            }
+        }
+    }
+
+    static final String DEFAULT_CLASSNAME = TemplateClass.class.getName();
+    static final String PREFIX = "Class";
+
+    private final String[] classPath;
+    private byte[] bytecode;
+    private int[] offsets;
+    private final String encoding = "UTF8";
+    private final String templateClassName;
+    private final byte[] templateClassNameBytes;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCapacityResults.java	Thu Jan 14 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 <pid>")
+ *
+ * Output example:
+ * NGCMN    NGCMX     NGC     S0C   S1C       EC      OGCMN      OGCMX       OGC         OC       MCMN     MCMX      MC     YGC    FGC
+ * 41984.0 671744.0  41984.0 5248.0 5248.0  31488.0    83968.0  1343488.0    83968.0    83968.0    512.0 110592.0   4480.0      0     0
+
+ * Output description:
+ * NGCMN   Minimum new generation capacity (KB).
+ * NGCMX   Maximum new generation capacity (KB).
+ * NGC         Current new generation capacity (KB).
+ * S0C          Current survivor space 0 capacity (KB).
+ * S1C          Current survivor space 1 capacity (KB).
+ * EC            Current eden space capacity (KB).
+ * OGCMN   Minimum old generation capacity (KB).
+ * OGCMX   Maximum old generation capacity (KB).
+ * OGC         Current old generation capacity (KB).
+ * OC            Current old space capacity (KB).
+ * MCMN    Minimum metaspace capacity (KB).
+ * MCMX    Maximum metaspace capacity (KB).
+ * MC          Current metaspace capacity (KB).
+ * YGC         Number of Young generation GC Events.
+ * FGC         Number of Full GC Events.
+ */
+package utils;
+
+import common.ToolResults;
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.util.Arrays;
+import java.util.List;
+
+public class JstatGcCapacityResults extends JstatResults {
+
+    public JstatGcCapacityResults(ToolResults rawResults) {
+        super(rawResults);
+    }
+
+    /**
+     * Checks the overall consistency of the results reported by the tool
+     */
+    public void assertConsistency() {
+
+        // Check exit code
+        assertThat(getExitCode() == 0, "Unexpected exit code: " + getExitCode());
+
+        // Check Young Gen consistency
+        float NGCMN = getFloatValue("NGCMN");
+        float NGCMX = getFloatValue("NGCMX");
+        assertThat(NGCMX >= NGCMN, "NGCMN > NGCMX (min generation capacity > max generation capacity)");
+
+        float NGC = getFloatValue("NGC");
+        assertThat(NGC >= NGCMN, "NGC < NGCMN (generation capacity < min generation capacity)");
+        assertThat(NGC <= NGCMX, "NGC > NGCMX (generation capacity > max generation capacity)");
+
+        float S0C = getFloatValue("S0C");
+        assertThat(S0C < NGC, "S0C >= NGC (survivor space 0 capacity >= new generation capacity)");
+
+        float S1C = getFloatValue("S1C");
+        assertThat(S1C < NGC, "S1C >= NGC (survivor space 1 capacity >= new generation capacity)");
+
+        float EC = getFloatValue("EC");
+        assertThat(EC <= NGC, "EC > NGC (eden space capacity > new generation capacity)");
+
+        // Verify relative size of NGC and S0C + S1C + EC.
+        // The rule depends on if the tenured GC is parallel or not.
+        // For parallell GC:     NGC >= S0C + S1C + EC
+        // For non-parallell GC: NGC == S0C + S1C + EC
+        boolean isTenuredParallelGC = isTenuredParallelGC();
+        String errMsg = String.format(
+                "NGC %s (S0C + S1C + EC) (NGC = %.1f, S0C = %.1f, S1C = %.1f, EC = %.1f, (S0C + S1C + EC) = %.1f)",
+                isTenuredParallelGC ? "<" : "!=", NGC, S0C, S1C, EC, S0C + S1C + EC);
+        if (isTenuredParallelGC) {
+            assertThat(NGC >= S0C + S1C + EC, errMsg);
+        } else {
+            assertThat(checkFloatIsSum(NGC, S0C, S1C, EC), errMsg);
+        }
+
+        // Check Old Gen consistency
+        float OGCMN = getFloatValue("OGCMN");
+        float OGCMX = getFloatValue("OGCMX");
+        assertThat(OGCMX >= OGCMN, "OGCMN > OGCMX (min generation capacity > max generation capacity)");
+
+        float OGC = getFloatValue("OGC");
+        assertThat(OGC >= OGCMN, "OGC < OGCMN (generation capacity < min generation capacity)");
+        assertThat(OGC <= OGCMX, "OGC > OGCMX (generation capacity > max generation capacity)");
+        float OC = getFloatValue("OC");
+        assertThat(OC == OGC, "OC != OGC (old generation capacity != old space capacity (these values should be equal since old space is made up only from one old generation))");
+
+        // Check Metaspace consistency
+        float MCMN = getFloatValue("MCMN");
+        float MCMX = getFloatValue("MCMX");
+        assertThat(MCMX >= MCMN, "MCMN > MCMX (min generation capacity > max generation capacity)");
+        float MC = getFloatValue("MC");
+        assertThat(MC >= MCMN, "MC < MCMN (generation capacity < min generation capacity)");
+        assertThat(MC <= MCMX, "MGC > MCMX (generation capacity > max generation capacity)");
+
+
+    }
+
+    /**
+     * Check if the tenured generation are currently using a parallel GC.
+     */
+    protected static boolean isTenuredParallelGC() {
+        // Currently the only parallel GC for the tenured generation is PS MarkSweep.
+        List<String> parallelGCs = Arrays.asList(new String[] { "PS MarkSweep"});
+        try {
+            List<GarbageCollectorMXBean> beans = ManagementFactory.getGarbageCollectorMXBeans();
+            for (GarbageCollectorMXBean bean : beans) {
+                if (parallelGCs.contains(bean.getName())) {
+                    return true;
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return false;
+    }
+
+    private static final float FLOAT_COMPARISON_TOLERANCE = 0.0011f;
+
+    private static boolean checkFloatIsSum(float sum, float... floats) {
+        for (float f : floats) {
+            sum -= f;
+        }
+
+        return Math.abs(sum) <= FLOAT_COMPARISON_TOLERANCE;
+    }
+
+    private void assertThat(boolean b, String message) {
+        if (!b) {
+            throw new RuntimeException(message);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCapacityTool.java	Thu Jan 14 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 <pid>" and returns the results as
+ * JstatGcCapacityoolResults
+ */
+public class JstatGcCapacityTool extends TmTool<JstatGcCapacityResults> {
+
+    public JstatGcCapacityTool(long pid) {
+        super(JstatGcCapacityResults.class, "jstat", "-gccapacity " + pid);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCauseResults.java	Thu Jan 14 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 <pid>")
+ *
+ * Output example:
+ * S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT    LGCC                 GCC
+ * 0.00   6.25  46.19   0.34  57.98  54.63  15305 1270.551     0    0.000 1270.551 Allocation Failure   No GC
+
+ * Output description:
+ * S0         Survivor space 0 utilization as a percentage of the space's current capacity.
+ * S1         Survivor space 1 utilization as a percentage of the space's current capacity.
+ * E           Eden space utilization as a percentage of the space's current capacity.
+ * O           Old space utilization as a percentage of the space's current capacity.
+ * M          Metaspace utilization as a percentage of the space's current capacity.
+ * CCS     Compressed Class Space
+ * YGC     Number of young generation GC events.
+ * YGCT    Young generation garbage collection time.
+ * FGC      Number of full GC events.
+ * FGCT    Full garbage collection time.
+ * GCT      Total garbage collection time.
+ * LGCC    Cause of last Garbage Collection.
+ * GCC      Cause of current Garbage Collection.
+ */
+package utils;
+
+import common.ToolResults;
+
+public class JstatGcCauseResults extends JstatResults {
+
+    public JstatGcCauseResults(ToolResults rawResults) {
+        super(rawResults);
+    }
+
+    /**
+     * Checks the overall consistency of the results reported by the tool
+     */
+    public void assertConsistency() {
+
+        assertThat(getExitCode() == 0, "Unexpected exit code: " + getExitCode());
+
+        int YGC = getIntValue("YGC");
+        float YGCT = getFloatValue("YGCT");
+        assertThat(YGCT >= 0, "Incorrect time value for YGCT");
+        if (YGC > 0) {
+            assertThat(YGCT > 0, "Number of young generation GC Events is " + YGC + ", but YGCT is 0");
+        }
+
+        float GCT = getFloatValue("GCT");
+        assertThat(GCT >= 0, "Incorrect time value for GCT");
+        assertThat(GCT >= YGCT, "GCT < YGCT (total garbage collection time < young generation garbage collection time)");
+
+        int FGC = getIntValue("FGC");
+        float FGCT = getFloatValue("FGCT");
+        assertThat(FGCT >= 0, "Incorrect time value for FGCT");
+        if (FGC > 0) {
+            assertThat(FGCT > 0, "Number of full GC events is " + FGC + ", but FGCT is 0");
+        }
+
+        assertThat(GCT >= FGCT, "GCT < YGCT (total garbage collection time < full generation garbage collection time)");
+
+        assertThat(checkFloatIsSum(GCT, YGCT, FGCT), "GCT != (YGCT + FGCT) " + "(GCT = " + GCT + ", YGCT = " + YGCT
+                + ", FGCT = " + FGCT + ", (YCGT + FGCT) = " + (YGCT + FGCT) + ")");
+    }
+
+    private static final float FLOAT_COMPARISON_TOLERANCE = 0.0011f;
+
+    private static boolean checkFloatIsSum(float sum, float... floats) {
+        for (float f : floats) {
+            sum -= f;
+        }
+
+        return Math.abs(sum) <= FLOAT_COMPARISON_TOLERANCE;
+    }
+
+    private void assertThat(boolean b, String message) {
+        if (!b) {
+            throw new RuntimeException(message);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCauseTool.java	Thu Jan 14 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 <pid>" and returns the results as
+ * JstatGcToolResults
+ */
+public class JstatGcCauseTool extends TmTool<JstatGcCauseResults> {
+
+    public JstatGcCauseTool(long pid) {
+        super(JstatGcCauseResults.class, "jstat", "-gc " + pid);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcNewResults.java	Thu Jan 14 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 <pid>")
+ *
+ * Output example:
+ * S0C           S1C         S0U    S1U   TT   MTT  DSS      EC                EU       YGC     YGCT
+ * 11264.0  11264.0    0.0    0.0      15  15       0.0      67584.0   1351.7      0      0.000
+
+ * Output description:
+ * S0C     Current survivor space 0 capacity (KB).
+ * S1C     Current survivor space 1 capacity (KB).
+ * S0U     Survivor space 0 utilization (KB).
+ * S1U     Survivor space 1 utilization (KB).
+ * TT        Tenuring threshold.
+ * MTT     Maximum tenuring threshold.
+ * DSS     Desired survivor size (KB).
+ * EC        Current eden space capacity (KB).
+ * EU        Eden space utilization (KB).
+ * YGC     Number of young generation GC events.
+ * YGCT   Young generation garbage collection time.
+ */
+package utils;
+
+import common.ToolResults;
+
+public class JstatGcNewResults extends JstatResults {
+
+    public JstatGcNewResults(ToolResults rawResults) {
+        super(rawResults);
+    }
+
+    /**
+     * Checks the overall consistency of the results reported by the tool
+     */
+    public void assertConsistency() {
+
+        assertThat(getExitCode() == 0, "Unexpected exit code: " + getExitCode());
+
+        float S0C = getFloatValue("S0C");
+        float S0U = getFloatValue("S0U");
+
+        assertThat(S0U <= S0C, "S0U > S0C (utilization > capacity)");
+
+        float S1C = getFloatValue("S1C");
+        float S1U = getFloatValue("S1U");
+
+        assertThat(S1U <= S1C, "S1U > S1C (utilization > capacity)");
+
+        float EC = getFloatValue("EC");
+        float EU = getFloatValue("EU");
+
+        assertThat(EU <= EC, "EU > EC (utilization > capacity)");
+
+        int YGC = getIntValue("YGC");
+        float YGCT = getFloatValue("YGCT");
+
+        if (YGC > 0) {
+            assertThat(YGCT > 0, "Number of young generation GC Events is " + YGC + ", but YGCT is 0");
+        }
+
+        int TT = getIntValue("TT");
+        int MTT = getIntValue("MTT");
+        assertThat(TT <= MTT, "TT > MTT (tenuring threshold > maximum tenuring threshold)");
+    }
+
+    private void assertThat(boolean b, String message) {
+        if (!b) {
+            throw new RuntimeException(message);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcNewTool.java	Thu Jan 14 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 <pid>" and returns the results as
+ * JstatGcNewResults
+ */
+public class JstatGcNewTool extends TmTool<JstatGcNewResults> {
+
+    public JstatGcNewTool(long pid) {
+        super(JstatGcNewResults.class, "jstat", "-gcnew " + pid);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcResults.java	Thu Jan 14 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 <pid>")
+ *
+ * Output example:
+ * (S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
+ * 512.0  512.0   32.0   0.0   288768.0 168160.6  83968.0     288.1    4864.0 2820.3 512.0  279.7   18510 1559.208   0      0.000 1559.208
+ *
+ * Output description:
+ * S0C     Current survivor space 0 capacity (KB).
+ * S1C     Current survivor space 1 capacity (KB).
+ * S0U     Survivor space 0 utilization (KB).
+ * S1U     Survivor space 1 utilization (KB).
+ * EC      Current eden space capacity (KB).
+ * EU      Eden space utilization (KB).
+ * OC      Current old space capacity (KB).
+ * OU      Old space utilization (KB).
+ * MC      Current metaspace capacity (KB).
+ * MU      Metaspace utilization (KB).
+ * CCSC    Compressed Class Space capacity
+ * CCSU    Compressed Class Space utilization
+ * YGC     Number of young generation GC Events.
+ * YGCT    Young generation garbage collection time.
+ * FGC     Number of full GC events.
+ * FGCT    Full garbage collection time.
+ * GCT     Total garbage collection time.
+ *
+ */
+package utils;
+
+import common.ToolResults;
+
+public class JstatGcResults extends JstatResults {
+
+    public JstatGcResults(ToolResults rawResults) {
+        super(rawResults);
+    }
+
+    /**
+     * Checks the overall consistency of the results reported by the tool
+     */
+    public void assertConsistency() {
+
+        assertThat(getExitCode() == 0, "Unexpected exit code: " + getExitCode());
+
+        float OC = getFloatValue("OC");
+        float OU = getFloatValue("OU");
+        assertThat(OU <= OC, "OU > OC (utilization > capacity)");
+
+        float MC = getFloatValue("MC");
+        float MU = getFloatValue("MU");
+        assertThat(MU <= MC, "MU > MC (utilization > capacity)");
+
+        float CCSC = getFloatValue("CCSC");
+        float CCSU = getFloatValue("CCSU");
+        assertThat(CCSU <= CCSC, "CCSU > CCSC (utilization > capacity)");
+
+        float S0C = getFloatValue("S0C");
+        float S0U = getFloatValue("S0U");
+        assertThat(S0U <= S0C, "S0U > S0C (utilization > capacity)");
+
+        float S1C = getFloatValue("S1C");
+        float S1U = getFloatValue("S1U");
+        assertThat(S1U <= S1C, "S1U > S1C (utilization > capacity)");
+
+        float EC = getFloatValue("EC");
+        float EU = getFloatValue("EU");
+        assertThat(EU <= EC, "EU > EC (utilization > capacity)");
+
+        int YGC = getIntValue("YGC");
+        float YGCT = getFloatValue("YGCT");
+        assertThat(YGCT >= 0, "Incorrect time value for YGCT");
+        if (YGC > 0) {
+            assertThat(YGCT > 0, "Number of young generation GC Events is " + YGC + ", but YGCT is 0");
+        }
+
+        float GCT = getFloatValue("GCT");
+        assertThat(GCT >= 0, "Incorrect time value for GCT");
+        assertThat(GCT >= YGCT, "GCT < YGCT (total garbage collection time < young generation garbage collection time)");
+
+        int FGC = getIntValue("FGC");
+        float FGCT = getFloatValue("FGCT");
+        assertThat(FGCT >= 0, "Incorrect time value for FGCT");
+        if (FGC > 0) {
+            assertThat(FGCT > 0, "Number of full GC events is " + FGC + ", but FGCT is 0");
+        }
+
+        assertThat(GCT >= FGCT, "GCT < YGCT (total garbage collection time < full generation garbage collection time)");
+
+        assertThat(checkFloatIsSum(GCT, YGCT, FGCT), "GCT != (YGCT + FGCT) " + "(GCT = " + GCT + ", YGCT = " + YGCT
+                + ", FGCT = " + FGCT + ", (YCGT + FGCT) = " + (YGCT + FGCT) + ")");
+    }
+
+    private static final float FLOAT_COMPARISON_TOLERANCE = 0.0011f;
+
+    private static boolean checkFloatIsSum(float sum, float... floats) {
+        for (float f : floats) {
+            sum -= f;
+        }
+
+        return Math.abs(sum) <= FLOAT_COMPARISON_TOLERANCE;
+    }
+
+    private void assertThat(boolean b, String message) {
+        if (!b) {
+            throw new RuntimeException(message);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcTool.java	Thu Jan 14 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 <pid>" and returns the results as
+ * JstatGcToolResults
+ */
+public class JstatGcTool extends TmTool<JstatGcResults> {
+
+    public JstatGcTool(long pid) {
+        super(JstatGcResults.class, "jstat", "-gc " + pid);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatResults.java	Thu Jan 14 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);
+        }
+    }
+
+}
--- /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);
+    }
+
+}
--- /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<String> values;
+
+    StringOfValues(String s) {
+        this.values = new ArrayList<>();
+        StringTokenizer st = new StringTokenizer(s);
+        while (st.hasMoreTokens()) {
+            values.add(st.nextToken());
+        }
+    }
+
+    int getIndex(String val) {
+        for (int ndx = 0; ndx < values.size(); ++ndx) {
+            if (values.get(ndx).equals(val)) {
+                return ndx;
+            }
+        }
+        return -1;
+    }
+
+    String getValue(int ndx) {
+        return values.get(ndx);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/TemplateClass.java	Thu Jan 14 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 {
+}
--- /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<T extends ToolResults> {
+
+    private final Class<T> resultsClz;
+    private final String cmdLine;
+
+    public TmTool(Class<T> resultsClz, String toolName, String otherArgs) {
+        this.resultsClz = resultsClz;
+        this.cmdLine = adjustForTestJava(toolName) + " " + otherArgs;
+    }
+
+    /**
+     * Runs the tool to completion and returns the results
+     *
+     * @return the tool results
+     * @throws Exception if anything goes wrong
+     */
+    public T measure() throws Exception {
+        ToolRunner runner = new ToolRunner(cmdLine);
+        ToolResults rawResults = runner.runToCompletion();
+        System.out.println("Process output: " + rawResults);
+        return resultsClz.getDeclaredConstructor(ToolResults.class).newInstance(rawResults);
+    }
+
+    private String adjustForTestJava(String toolName) {
+        // We need to make sure we are running the tol from the JDK under testing
+        String jdkPath = System.getProperty("test.jdk");
+        if (jdkPath == null || !Paths.get(jdkPath).toFile().exists()) {
+            throw new RuntimeException("property test.jdk not not set");
+        }
+        Path toolPath = Paths.get("bin", toolName + (Platform.isWindows() ? ".exe" : ""));
+        return Paths.get(jdkPath, toolPath.toString()).toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/share/common/ToolResults.java	Thu Jan 14 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<String> getStdout() {
+        return stdout;
+    }
+
+    public List<String> getStderr() {
+        return stderr;
+    }
+
+    public String getStdoutString() {
+        return stdout.stream().collect(Collectors.joining(System.getProperty("line.separator")));
+    }
+
+    /**
+     * Helper function to return a specified line from the saved stdout
+     *
+     * @return the line indexed with ndx from the saved stdout. The indexes are
+     * zero-based so that getStdoutLine(0) returns the first line.
+     */
+    public String getStdoutLine(int ndx) {
+        return stdout.get(ndx);
+    }
+
+    public ToolResults(int exitCode, List<String> stdin, List<String> stderr) {
+        this.exitCode = exitCode;
+        this.stdout = stdin;
+        this.stderr = stderr;
+    }
+
+    public ToolResults(ToolResults rawResults) {
+        this(rawResults.exitCode, rawResults.stdout, rawResults.stderr);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Exit code: ").append(exitCode).append("\n");
+        sb.append("stdout:");
+        stdout.stream().forEach((s) -> {
+            sb.append(s).append("\n");
+        });
+        sb.append("stderr:");
+        stderr.stream().forEach((s) -> {
+            sb.append(s).append("\n");
+        });
+        return sb.toString();
+    }
+
+    private final int exitCode;
+    private final List<String> stdout;
+    private final List<String> stderr;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/tmtools/share/common/ToolRunner.java	Thu Jan 14 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<String> cmdArgs = new LinkedList<>();
+
+    ToolRunner(String cmdLine) {
+        StringTokenizer st = new StringTokenizer(cmdLine);
+        while (st.hasMoreTokens()) {
+            cmdArgs.add(st.nextToken());
+        }
+    }
+
+    /**
+     * Starts the process, waits for the process completion and returns the
+     * results
+     *
+     * @return process results
+     * @throws Exception if anything goes wrong
+     */
+    ToolResults runToCompletion() throws Exception {
+
+        ProcessBuilder pb = new ProcessBuilder(cmdArgs);
+        OutputAnalyzer oa = ProcessTools.executeProcess(pb);
+
+        return new ToolResults(oa.getExitValue(),
+                stringToList(oa.getStdout()),
+                stringToList(oa.getStderr()));
+
+    }
+
+    private static List<String> stringToList(String s) throws IOException {
+        BufferedReader reader = new BufferedReader(new StringReader(s));
+        List<String> strings = new ArrayList<>();
+        for (String line = reader.readLine(); line != null; line = reader.readLine()) {
+            strings.add(line);
+        }
+        reader.close();
+        return strings;
+    }
+}