8026789: Update test/java/lang/instrument/Re(transform|define)BigClass.sh test to use NMT for memory leak detection
authorsla
Wed, 23 Oct 2013 15:55:31 +0200
changeset 21347 21c6a82adf04
parent 21346 793a4fec2332
child 21348 e30c5696b4c5
8026789: Update test/java/lang/instrument/Re(transform|define)BigClass.sh test to use NMT for memory leak detection Reviewed-by: dcubed
jdk/test/ProblemList.txt
jdk/test/java/lang/instrument/NMTHelper.java
jdk/test/java/lang/instrument/RedefineBigClass.sh
jdk/test/java/lang/instrument/RedefineBigClassApp.java
jdk/test/java/lang/instrument/RetransformBigClass.sh
jdk/test/java/lang/instrument/RetransformBigClassApp.java
--- a/jdk/test/ProblemList.txt	Wed Oct 23 14:38:22 2013 +0100
+++ b/jdk/test/ProblemList.txt	Wed Oct 23 15:55:31 2013 +0200
@@ -134,10 +134,6 @@
 # 8021230
 java/lang/ThreadLocal/ThreadLocalSupplierTest.java              generic-all
 
-# 8023201
-java/lang/instrument/RetransformBigClass.sh                     generic-all
-java/lang/instrument/RedefineBigClass.sh                        generic-all
-
 # 8026502
 java/lang/invoke/MethodHandleConstants.java                     generic-all
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/instrument/NMTHelper.java	Wed Oct 23 15:55:31 2013 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013 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 java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import sun.management.ManagementFactoryHelper;
+import com.sun.management.DiagnosticCommandMBean;
+
+public class NMTHelper
+{
+    public static void baseline() {
+        executeDcmd("vmNativeMemory", "baseline");
+    }
+
+    // Total:  reserved=3484685KB  +293KB, committed=266629KB +293KB
+    private static Pattern totalLine = Pattern.compile("^Total:  reserved=\\d+KB  .*KB, committed=\\d+KB (.*)KB$");
+
+    public static long committedDiff() throws Exception {
+        String res = (String) executeDcmd("vmNativeMemory", "detail.diff");
+        String[] lines = res.split("\n");
+        for (String line : lines) {
+            Matcher matcher = totalLine.matcher(line);
+            if (matcher.matches()) {
+                String committed = matcher.group(1);
+                return Long.parseLong(committed);
+            }
+        }
+        throw new Exception("Could not find the Total line in the NMT output.");
+    }
+
+    private static String executeDcmd(String cmd, String ... args) {
+        DiagnosticCommandMBean dcmd = ManagementFactoryHelper.getDiagnosticCommandMBean();
+        Object[] dcmdArgs = {args};
+        String[] signature = {String[].class.getName()};
+
+        try {
+            System.out.print("> " + cmd + " ");
+            for (String s : args) {
+                System.out.print(s + " ");
+            }
+            System.out.println(":");
+            String result = (String) dcmd.invoke(cmd, dcmdArgs, signature);
+            System.out.println(result);
+            return result;
+        } catch(Exception ex) {
+            ex.printStackTrace();
+        }
+        return null;
+    }
+}
--- a/jdk/test/java/lang/instrument/RedefineBigClass.sh	Wed Oct 23 14:38:22 2013 +0100
+++ b/jdk/test/java/lang/instrument/RedefineBigClass.sh	Wed Oct 23 15:55:31 2013 +0200
@@ -58,11 +58,19 @@
 JAVAC="${COMPILEJAVA}"/bin/javac
 JAVA="${TESTJAVA}"/bin/java
 
+# Does this VM support the 'detail' level of NMT?
+"${JAVA}" ${TESTVMOPTS} -XX:NativeMemoryTracking=detail -version
+if [ "$?" = 0 ]; then
+    NMT=-XX:NativeMemoryTracking=detail
+else
+    NMT=-XX:NativeMemoryTracking=summary
+fi
+
 "${JAVA}" ${TESTVMOPTS} \
-    -XX:TraceRedefineClasses=3 \
+    -XX:TraceRedefineClasses=3 ${NMT} \
     -javaagent:RedefineBigClassAgent.jar=BigClass.class \
     -classpath "${TESTCLASSES}" RedefineBigClassApp \
-    > output.log 2>&1
+    > output.log 2>&1 
 result=$?
 
 cat output.log
--- a/jdk/test/java/lang/instrument/RedefineBigClassApp.java	Wed Oct 23 14:38:22 2013 +0100
+++ b/jdk/test/java/lang/instrument/RedefineBigClassApp.java	Wed Oct 23 15:55:31 2013 +0200
@@ -26,16 +26,23 @@
 public class RedefineBigClassApp {
     /**
      * Memory leak is assumed, if application consumes more than specified amount of memory during its execution.
-     * The number is given in Kb.
+     * The number is given in KB.
      */
-    private static final long MEM_LEAK_THRESHOLD = 32 * 1024; // 32Mb
+    private static final long MEM_LEAK_THRESHOLD = 32 * 1024; // 32MB
 
     public static void main(String[] args) throws Exception {
         System.out.println("Creating instance of " +
             RedefineBigClassAgent.clz);
         RedefineBigClassAgent.clz.newInstance();
 
-        long vMemBefore = getVMemSize();
+        // Do a short warmup before creating the NMT baseline
+        try {
+            Thread.sleep(5 * 1000);
+        } catch (InterruptedException ie) {
+        }
+
+        NMTHelper.baseline();
+
         int count = 0;
         while (!RedefineBigClassAgent.doneRedefining) {
             System.out.println("App loop count: " + ++count);
@@ -46,39 +53,12 @@
         }
         System.out.println("App looped  " + count + " times.");
 
-        long vMemAfter = getVMemSize();
-        if (vMemBefore == 0 || vMemAfter == 0) {
-            System.err.println("WARNING: Cannot perform memory leak detection on this OS");
-        } else {
-            long vMemDelta = vMemAfter - vMemBefore;
-            if (vMemDelta > MEM_LEAK_THRESHOLD) {
-                System.err.println("FAIL: Virtual memory usage increased by " + vMemDelta + "Kb " +
-                        "(greater than " + MEM_LEAK_THRESHOLD + "Kb)");
-                System.exit(1);
-            }
-            System.err.println("PASS: Virtual memory usage increased by " + vMemDelta + "Kb " +
-                    "(not greater than " + MEM_LEAK_THRESHOLD + "Kb)");
+        long committedDiff = NMTHelper.committedDiff();
+        if (committedDiff > MEM_LEAK_THRESHOLD) {
+            throw new Exception("FAIL: Committed memory usage increased by " + committedDiff + "KB " +
+                               "(greater than " + MEM_LEAK_THRESHOLD + "KB)");
         }
-        System.exit(0);
-    }
-
-    /**
-     * Return size of virtual memory allocated to the process in Kb.
-     * Linux specific. On other platforms and in case of any errors return 0.
-     */
-    private static long getVMemSize() {
-
-        // Refer to the Linux proc(5) man page for details about /proc/self/stat file
-        //
-        // In short, this file contains status information about the current process
-        // written in one line. The fields are separated with spaces.
-        // The 23rd field is defined as 'vsize %lu   Virtual memory size in bytes'
-
-        try (FileReader fileReader = new FileReader("/proc/self/stat");
-             BufferedReader bufferedReader = new BufferedReader(fileReader)) {
-            String line = bufferedReader.readLine();
-            return Long.parseLong(line.split(" ")[22]) / 1024;
-        } catch (Exception ex) {}
-        return 0;
+        System.err.println("PASS: Committed memory usage increased by " + committedDiff + "KB " +
+                           "(not greater than " + MEM_LEAK_THRESHOLD + "KB)");
     }
 }
--- a/jdk/test/java/lang/instrument/RetransformBigClass.sh	Wed Oct 23 14:38:22 2013 +0100
+++ b/jdk/test/java/lang/instrument/RetransformBigClass.sh	Wed Oct 23 15:55:31 2013 +0200
@@ -58,8 +58,16 @@
 JAVAC="${COMPILEJAVA}"/bin/javac
 JAVA="${TESTJAVA}"/bin/java
 
+# Does this VM support the 'detail' level of NMT?
+"${JAVA}" ${TESTVMOPTS} -XX:NativeMemoryTracking=detail -version
+if [ "$?" = 0 ]; then
+    NMT=-XX:NativeMemoryTracking=detail
+else
+    NMT=-XX:NativeMemoryTracking=summary
+fi
+
 "${JAVA}" ${TESTVMOPTS} \
-    -XX:TraceRedefineClasses=3 \
+    -XX:TraceRedefineClasses=3 ${NMT} \
     -javaagent:RetransformBigClassAgent.jar=BigClass.class \
     -classpath "${TESTCLASSES}" RetransformBigClassApp \
     > output.log 2>&1
--- a/jdk/test/java/lang/instrument/RetransformBigClassApp.java	Wed Oct 23 14:38:22 2013 +0100
+++ b/jdk/test/java/lang/instrument/RetransformBigClassApp.java	Wed Oct 23 15:55:31 2013 +0200
@@ -26,16 +26,23 @@
 public class RetransformBigClassApp {
     /**
      * Memory leak is assumed, if application consumes more than specified amount of memory during its execution.
-     * The number is given in Kb.
+     * The number is given in KB.
      */
-    private static final long MEM_LEAK_THRESHOLD = 32 * 1024; // 32Mb
+    private static final long MEM_LEAK_THRESHOLD = 32 * 1024; // 32MB
 
     public static void main(String[] args) throws Exception {
         System.out.println("Creating instance of " +
             RetransformBigClassAgent.clz);
         RetransformBigClassAgent.clz.newInstance();
 
-        long vMemBefore = getVMemSize();
+        // Do a short warmup before creating the NMT baseline
+        try {
+            Thread.sleep(5 * 1000);
+        } catch (InterruptedException ie) {
+        }
+
+        NMTHelper.baseline();
+
         int count = 0;
         while (!RetransformBigClassAgent.doneRetransforming) {
             System.out.println("App loop count: " + ++count);
@@ -46,39 +53,12 @@
         }
         System.out.println("App looped  " + count + " times.");
 
-        long vMemAfter = getVMemSize();
-        if (vMemBefore == 0 || vMemAfter == 0) {
-            System.err.println("WARNING: Cannot perform memory leak detection on this OS");
-        } else {
-            long vMemDelta = vMemAfter - vMemBefore;
-            if (vMemDelta > MEM_LEAK_THRESHOLD) {
-                System.err.println("FAIL: Virtual memory usage increased by " + vMemDelta + "Kb " +
-                        "(greater than " + MEM_LEAK_THRESHOLD + "Kb)");
-                System.exit(1);
-            }
-            System.err.println("PASS: Virtual memory usage increased by " + vMemDelta + "Kb " +
-                    "(not greater than " + MEM_LEAK_THRESHOLD + "Kb)");
+        long committedDiff = NMTHelper.committedDiff();
+        if (committedDiff > MEM_LEAK_THRESHOLD) {
+            throw new Exception("FAIL: Committed memory usage increased by " + committedDiff + "KB " +
+                               "(greater than " + MEM_LEAK_THRESHOLD + "KB)");
         }
-        System.exit(0);
-    }
-
-    /**
-     * Return size of virtual memory allocated to the process in Kb.
-     * Linux specific. On other platforms and in case of any errors return 0.
-     */
-    private static long getVMemSize() {
-
-        // Refer to the Linux proc(5) man page for details about /proc/self/stat file
-        //
-        // In short, this file contains status information about the current process
-        // written in one line. The fields are separated with spaces.
-        // The 23rd field is defined as 'vsize %lu   Virtual memory size in bytes'
-
-        try (FileReader fileReader = new FileReader("/proc/self/stat");
-             BufferedReader bufferedReader = new BufferedReader(fileReader)) {
-            String line = bufferedReader.readLine();
-            return Long.parseLong(line.split(" ")[22]) / 1024;
-        } catch (Exception ex) {}
-        return 0;
+        System.err.println("PASS: Committed memory usage increased by " + committedDiff + "KB " +
+                           "(not greater than " + MEM_LEAK_THRESHOLD + "KB)");
     }
 }