6313383: SA: Update jmap to support HPROF binary format "JAVA PROFILE 1.0.2"

Fri, 04 Oct 2013 13:44:49 +0200

author
sla
date
Fri, 04 Oct 2013 13:44:49 +0200
changeset 5845
8ef918538e22
parent 5843
763705f0fec3
child 5846
9c63ad02c0a4

6313383: SA: Update jmap to support HPROF binary format "JAVA PROFILE 1.0.2"
Summary: Adds support for large(>4G) heap dumps in hprof format. Adds tests and updates testlibrary.
Reviewed-by: sla, allwin
Contributed-by: fredrik.arvidsson@oracle.com

agent/src/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java file | annotate | diff | comparison | revisions
agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java file | annotate | diff | comparison | revisions
test/TEST.groups file | annotate | diff | comparison | revisions
test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java file | annotate | diff | comparison | revisions
test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java file | annotate | diff | comparison | revisions
test/testlibrary/com/oracle/java/testlibrary/JDKToolLauncher.java file | annotate | diff | comparison | revisions
     1.1 --- a/agent/src/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java	Fri Oct 04 13:01:07 2013 +0200
     1.2 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java	Fri Oct 04 13:44:49 2013 +0200
     1.3 @@ -59,6 +59,7 @@
     1.4  
     1.5                      public boolean doObj(Oop oop) {
     1.6                          try {
     1.7 +                            writeHeapRecordPrologue();
     1.8                              if (oop instanceof TypeArray) {
     1.9                                  writePrimitiveArray((TypeArray)oop);
    1.10                              } else if (oop instanceof ObjArray) {
    1.11 @@ -97,6 +98,7 @@
    1.12                                  // not-a-Java-visible oop
    1.13                                  writeInternalObject(oop);
    1.14                              }
    1.15 +                            writeHeapRecordEpilogue();
    1.16                          } catch (IOException exp) {
    1.17                              throw new RuntimeException(exp);
    1.18                          }
    1.19 @@ -416,6 +418,12 @@
    1.20      protected void writeHeapFooter() throws IOException {
    1.21      }
    1.22  
    1.23 +    protected void writeHeapRecordPrologue() throws IOException {
    1.24 +    }
    1.25 +
    1.26 +    protected void writeHeapRecordEpilogue() throws IOException {
    1.27 +    }
    1.28 +
    1.29      // HeapVisitor, OopVisitor methods can't throw any non-runtime
    1.30      // exception. But, derived class write methods (which are called
    1.31      // from visitor callbacks) may throw IOException. Hence, we throw
     2.1 --- a/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java	Fri Oct 04 13:01:07 2013 +0200
     2.2 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java	Fri Oct 04 13:44:49 2013 +0200
     2.3 @@ -44,7 +44,7 @@
     2.4   * WARNING: This format is still under development, and is subject to
     2.5   * change without notice.
     2.6   *
     2.7 - * header    "JAVA PROFILE 1.0.1" (0-terminated)
     2.8 + * header    "JAVA PROFILE 1.0.1" or "JAVA PROFILE 1.0.2" (0-terminated)
     2.9   * u4        size of identifiers. Identifiers are used to represent
    2.10   *            UTF8 strings, objects, stack traces, etc. They usually
    2.11   *            have the same size as host pointers. For example, on
    2.12 @@ -292,11 +292,34 @@
    2.13   *                          0x00000002: cpu sampling on/off
    2.14   *                u2        stack trace depth
    2.15   *
    2.16 + *
    2.17 + * When the header is "JAVA PROFILE 1.0.2" a heap dump can optionally
    2.18 + * be generated as a sequence of heap dump segments. This sequence is
    2.19 + * terminated by an end record. The additional tags allowed by format
    2.20 + * "JAVA PROFILE 1.0.2" are:
    2.21 + *
    2.22 + * HPROF_HEAP_DUMP_SEGMENT  denote a heap dump segment
    2.23 + *
    2.24 + *               [heap dump sub-records]*
    2.25 + *               The same sub-record types allowed by HPROF_HEAP_DUMP
    2.26 + *
    2.27 + * HPROF_HEAP_DUMP_END      denotes the end of a heap dump
    2.28 + *
    2.29   */
    2.30  
    2.31  public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
    2.32 +
    2.33 +    // The heap size threshold used to determine if segmented format
    2.34 +    // ("JAVA PROFILE 1.0.2") should be used.
    2.35 +    private static final long HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD = 2L * 0x40000000;
    2.36 +
    2.37 +    // The approximate size of a heap segment. Used to calculate when to create
    2.38 +    // a new segment.
    2.39 +    private static final long HPROF_SEGMENTED_HEAP_DUMP_SEGMENT_SIZE = 1L * 0x40000000;
    2.40 +
    2.41      // hprof binary file header
    2.42 -    private static final String HPROF_HEADER = "JAVA PROFILE 1.0.1";
    2.43 +    private static final String HPROF_HEADER_1_0_1 = "JAVA PROFILE 1.0.1";
    2.44 +    private static final String HPROF_HEADER_1_0_2 = "JAVA PROFILE 1.0.2";
    2.45  
    2.46      // constants in enum HprofTag
    2.47      private static final int HPROF_UTF8             = 0x01;
    2.48 @@ -312,6 +335,10 @@
    2.49      private static final int HPROF_CPU_SAMPLES      = 0x0D;
    2.50      private static final int HPROF_CONTROL_SETTINGS = 0x0E;
    2.51  
    2.52 +    // 1.0.2 record types
    2.53 +    private static final int HPROF_HEAP_DUMP_SEGMENT = 0x1C;
    2.54 +    private static final int HPROF_HEAP_DUMP_END     = 0x2C;
    2.55 +
    2.56      // Heap dump constants
    2.57      // constants in enum HprofGcTag
    2.58      private static final int HPROF_GC_ROOT_UNKNOWN       = 0xFF;
    2.59 @@ -352,11 +379,9 @@
    2.60      private static final int JVM_SIGNATURE_ARRAY   = '[';
    2.61      private static final int JVM_SIGNATURE_CLASS   = 'L';
    2.62  
    2.63 -
    2.64      public synchronized void write(String fileName) throws IOException {
    2.65          // open file stream and create buffered data output stream
    2.66 -        FileOutputStream fos = new FileOutputStream(fileName);
    2.67 -        FileChannel chn = fos.getChannel();
    2.68 +        fos = new FileOutputStream(fileName);
    2.69          out = new DataOutputStream(new BufferedOutputStream(fos));
    2.70  
    2.71          VM vm = VM.getVM();
    2.72 @@ -385,6 +410,9 @@
    2.73          FLOAT_SIZE = objectHeap.getFloatSize();
    2.74          DOUBLE_SIZE = objectHeap.getDoubleSize();
    2.75  
    2.76 +        // Check weather we should dump the heap as segments
    2.77 +        useSegmentedHeapDump = vm.getUniverse().heap().used() > HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD;
    2.78 +
    2.79          // hprof bin format header
    2.80          writeFileHeader();
    2.81  
    2.82 @@ -394,38 +422,87 @@
    2.83  
    2.84          // hprof UTF-8 symbols section
    2.85          writeSymbols();
    2.86 +
    2.87          // HPROF_LOAD_CLASS records for all classes
    2.88          writeClasses();
    2.89  
    2.90 -        // write heap data now
    2.91 -        out.writeByte((byte)HPROF_HEAP_DUMP);
    2.92 -        out.writeInt(0); // relative timestamp
    2.93 -
    2.94 -        // remember position of dump length, we will fixup
    2.95 -        // length later - hprof format requires length.
    2.96 -        out.flush();
    2.97 -        long dumpStart = chn.position();
    2.98 -
    2.99 -        // write dummy length of 0 and we'll fix it later.
   2.100 -        out.writeInt(0);
   2.101 -
   2.102          // write CLASS_DUMP records
   2.103          writeClassDumpRecords();
   2.104  
   2.105          // this will write heap data into the buffer stream
   2.106          super.write();
   2.107  
   2.108 +        // flush buffer stream.
   2.109 +        out.flush();
   2.110 +
   2.111 +        // Fill in final length
   2.112 +        fillInHeapRecordLength();
   2.113 +
   2.114 +        if (useSegmentedHeapDump) {
   2.115 +            // Write heap segment-end record
   2.116 +            out.writeByte((byte) HPROF_HEAP_DUMP_END);
   2.117 +            out.writeInt(0);
   2.118 +            out.writeInt(0);
   2.119 +        }
   2.120 +
   2.121          // flush buffer stream and throw it.
   2.122          out.flush();
   2.123          out = null;
   2.124  
   2.125 +        // close the file stream
   2.126 +        fos.close();
   2.127 +    }
   2.128 +
   2.129 +    @Override
   2.130 +    protected void writeHeapRecordPrologue() throws IOException {
   2.131 +        if (currentSegmentStart == 0) {
   2.132 +            // write heap data header, depending on heap size use segmented heap
   2.133 +            // format
   2.134 +            out.writeByte((byte) (useSegmentedHeapDump ? HPROF_HEAP_DUMP_SEGMENT
   2.135 +                    : HPROF_HEAP_DUMP));
   2.136 +            out.writeInt(0);
   2.137 +
   2.138 +            // remember position of dump length, we will fixup
   2.139 +            // length later - hprof format requires length.
   2.140 +            out.flush();
   2.141 +            currentSegmentStart = fos.getChannel().position();
   2.142 +
   2.143 +            // write dummy length of 0 and we'll fix it later.
   2.144 +            out.writeInt(0);
   2.145 +        }
   2.146 +    }
   2.147 +
   2.148 +    @Override
   2.149 +    protected void writeHeapRecordEpilogue() throws IOException {
   2.150 +        if (useSegmentedHeapDump) {
   2.151 +            out.flush();
   2.152 +            if ((fos.getChannel().position() - currentSegmentStart - 4) >= HPROF_SEGMENTED_HEAP_DUMP_SEGMENT_SIZE) {
   2.153 +                fillInHeapRecordLength();
   2.154 +                currentSegmentStart = 0;
   2.155 +            }
   2.156 +        }
   2.157 +    }
   2.158 +
   2.159 +    private void fillInHeapRecordLength() throws IOException {
   2.160 +
   2.161          // now get current position to calculate length
   2.162 -        long dumpEnd = chn.position();
   2.163 +        long dumpEnd = fos.getChannel().position();
   2.164 +
   2.165          // calculate length of heap data
   2.166 -        int dumpLen = (int) (dumpEnd - dumpStart - 4);
   2.167 +        long dumpLenLong = (dumpEnd - currentSegmentStart - 4L);
   2.168 +
   2.169 +        // Check length boundary, overflow could happen but is _very_ unlikely
   2.170 +        if(dumpLenLong >= (4L * 0x40000000)){
   2.171 +            throw new RuntimeException("Heap segment size overflow.");
   2.172 +        }
   2.173 +
   2.174 +        // Save the current position
   2.175 +        long currentPosition = fos.getChannel().position();
   2.176  
   2.177          // seek the position to write length
   2.178 -        chn.position(dumpStart);
   2.179 +        fos.getChannel().position(currentSegmentStart);
   2.180 +
   2.181 +        int dumpLen = (int) dumpLenLong;
   2.182  
   2.183          // write length as integer
   2.184          fos.write((dumpLen >>> 24) & 0xFF);
   2.185 @@ -433,8 +510,8 @@
   2.186          fos.write((dumpLen >>> 8) & 0xFF);
   2.187          fos.write((dumpLen >>> 0) & 0xFF);
   2.188  
   2.189 -        // close the file stream
   2.190 -        fos.close();
   2.191 +        //Reset to previous current position
   2.192 +        fos.getChannel().position(currentPosition);
   2.193      }
   2.194  
   2.195      private void writeClassDumpRecords() throws IOException {
   2.196 @@ -443,7 +520,9 @@
   2.197              sysDict.allClassesDo(new SystemDictionary.ClassVisitor() {
   2.198                              public void visit(Klass k) {
   2.199                                  try {
   2.200 +                                    writeHeapRecordPrologue();
   2.201                                      writeClassDumpRecord(k);
   2.202 +                                    writeHeapRecordEpilogue();
   2.203                                  } catch (IOException e) {
   2.204                                      throw new RuntimeException(e);
   2.205                                  }
   2.206 @@ -884,7 +963,12 @@
   2.207      // writes hprof binary file header
   2.208      private void writeFileHeader() throws IOException {
   2.209          // version string
   2.210 -        out.writeBytes(HPROF_HEADER);
   2.211 +        if(useSegmentedHeapDump) {
   2.212 +            out.writeBytes(HPROF_HEADER_1_0_2);
   2.213 +        }
   2.214 +        else {
   2.215 +            out.writeBytes(HPROF_HEADER_1_0_1);
   2.216 +        }
   2.217          out.writeByte((byte)'\0');
   2.218  
   2.219          // write identifier size. we use pointers as identifiers.
   2.220 @@ -976,6 +1060,7 @@
   2.221      private static final int EMPTY_FRAME_DEPTH = -1;
   2.222  
   2.223      private DataOutputStream out;
   2.224 +    private FileOutputStream fos;
   2.225      private Debugger dbg;
   2.226      private ObjectHeap objectHeap;
   2.227      private SymbolTable symTbl;
   2.228 @@ -983,6 +1068,10 @@
   2.229      // oopSize of the debuggee
   2.230      private int OBJ_ID_SIZE;
   2.231  
   2.232 +    // Added for hprof file format 1.0.2 support
   2.233 +    private boolean useSegmentedHeapDump;
   2.234 +    private long currentSegmentStart;
   2.235 +
   2.236      private long BOOLEAN_BASE_OFFSET;
   2.237      private long BYTE_BASE_OFFSET;
   2.238      private long CHAR_BASE_OFFSET;
   2.239 @@ -1005,6 +1094,7 @@
   2.240      private static class ClassData {
   2.241          int instSize;
   2.242          List fields;
   2.243 +
   2.244          ClassData(int instSize, List fields) {
   2.245              this.instSize = instSize;
   2.246              this.fields = fields;
     3.1 --- a/test/TEST.groups	Fri Oct 04 13:01:07 2013 +0200
     3.2 +++ b/test/TEST.groups	Fri Oct 04 13:44:49 2013 +0200
     3.3 @@ -84,7 +84,9 @@
     3.4    runtime/NMT/VirtualAllocTestType.java \
     3.5    runtime/RedefineObject/TestRedefineObject.java \
     3.6    runtime/XCheckJniJsig/XCheckJSig.java \
     3.7 -  serviceability/attach/AttachWithStalePidFile.java
     3.8 +  serviceability/attach/AttachWithStalePidFile.java \
     3.9 +  serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java
    3.10 +
    3.11  
    3.12  # JRE adds further tests to compact3
    3.13  #
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java	Fri Oct 04 13:44:49 2013 +0200
     4.3 @@ -0,0 +1,71 @@
     4.4 +/*
     4.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4.7 + *
     4.8 + * This code is free software; you can redistribute it and/or modify it
     4.9 + * under the terms of the GNU General Public License version 2 only, as
    4.10 + * published by the Free Software Foundation.
    4.11 + *
    4.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    4.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    4.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    4.15 + * version 2 for more details (a copy is included in the LICENSE file that
    4.16 + * accompanied this code).
    4.17 + *
    4.18 + * You should have received a copy of the GNU General Public License version
    4.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    4.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    4.21 + *
    4.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    4.23 + * or visit www.oracle.com if you need additional information or have any
    4.24 + * questions.
    4.25 + */
    4.26 +
    4.27 +import java.lang.management.ManagementFactory;
    4.28 +import java.lang.management.RuntimeMXBean;
    4.29 +import java.lang.reflect.Field;
    4.30 +import java.lang.reflect.Method;
    4.31 +import java.util.ArrayList;
    4.32 +import java.util.List;
    4.33 +
    4.34 +import sun.management.VMManagement;
    4.35 +
    4.36 +public class JMapHProfLargeHeapProc {
    4.37 +    private static final List<byte[]> heapGarbage = new ArrayList<>();
    4.38 +
    4.39 +    public static void main(String[] args) throws Exception {
    4.40 +
    4.41 +        buildLargeHeap(args);
    4.42 +
    4.43 +        // Print our pid on stdout
    4.44 +        System.out.println("PID[" + getProcessId() + "]");
    4.45 +
    4.46 +        // Wait for input before termination
    4.47 +        System.in.read();
    4.48 +    }
    4.49 +
    4.50 +    private static void buildLargeHeap(String[] args) {
    4.51 +        for (long i = 0; i < Integer.parseInt(args[0]); i++) {
    4.52 +            heapGarbage.add(new byte[1024]);
    4.53 +        }
    4.54 +    }
    4.55 +
    4.56 +    public static int getProcessId() throws Exception {
    4.57 +
    4.58 +        // Get the current process id using a reflection hack
    4.59 +        RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
    4.60 +        Field jvm = runtime.getClass().getDeclaredField("jvm");
    4.61 +
    4.62 +        jvm.setAccessible(true);
    4.63 +        VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime);
    4.64 +
    4.65 +        Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId");
    4.66 +
    4.67 +        pid_method.setAccessible(true);
    4.68 +
    4.69 +        int pid = (Integer) pid_method.invoke(mgmt);
    4.70 +
    4.71 +        return pid;
    4.72 +    }
    4.73 +
    4.74 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java	Fri Oct 04 13:44:49 2013 +0200
     5.3 @@ -0,0 +1,146 @@
     5.4 +/*
     5.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5.7 + *
     5.8 + * This code is free software; you can redistribute it and/or modify it
     5.9 + * under the terms of the GNU General Public License version 2 only, as
    5.10 + * published by the Free Software Foundation.
    5.11 + *
    5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    5.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    5.15 + * version 2 for more details (a copy is included in the LICENSE file that
    5.16 + * accompanied this code).
    5.17 + *
    5.18 + * You should have received a copy of the GNU General Public License version
    5.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    5.21 + *
    5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    5.23 + * or visit www.oracle.com if you need additional information or have any
    5.24 + * questions.
    5.25 + */
    5.26 +
    5.27 +import java.io.BufferedReader;
    5.28 +import java.io.File;
    5.29 +import java.io.FileNotFoundException;
    5.30 +import java.io.FileReader;
    5.31 +import java.io.IOException;
    5.32 +import java.io.Reader;
    5.33 +import java.nio.CharBuffer;
    5.34 +import java.util.Arrays;
    5.35 +import java.util.Scanner;
    5.36 +
    5.37 +import com.oracle.java.testlibrary.Asserts;
    5.38 +import com.oracle.java.testlibrary.JDKToolFinder;
    5.39 +import com.oracle.java.testlibrary.JDKToolLauncher;
    5.40 +import com.oracle.java.testlibrary.OutputAnalyzer;
    5.41 +import com.oracle.java.testlibrary.Platform;
    5.42 +import com.oracle.java.testlibrary.ProcessTools;
    5.43 +
    5.44 +/*
    5.45 + * @test
    5.46 + * @bug 6313383
    5.47 + * @key regression
    5.48 + * @summary Regression test for hprof export issue due to large heaps (>2G)
    5.49 + * @library /testlibrary
    5.50 + * @compile JMapHProfLargeHeapProc.java
    5.51 + * @run main JMapHProfLargeHeapTest
    5.52 + */
    5.53 +
    5.54 +public class JMapHProfLargeHeapTest {
    5.55 +    private static final String HEAP_DUMP_FILE_NAME = "heap.hprof";
    5.56 +    private static final String HPROF_HEADER_1_0_1 = "JAVA PROFILE 1.0.1";
    5.57 +    private static final String HPROF_HEADER_1_0_2 = "JAVA PROFILE 1.0.2";
    5.58 +    private static final long M = 1024L;
    5.59 +    private static final long G = 1024L * M;
    5.60 +
    5.61 +    public static void main(String[] args) throws Exception {
    5.62 +        // If we are on MacOSX, test if JMap tool is signed, otherwise return
    5.63 +        // since test will fail with privilege error.
    5.64 +        if (Platform.isOSX()) {
    5.65 +            String jmapToolPath = JDKToolFinder.getCurrentJDKTool("jmap");
    5.66 +            ProcessBuilder codesignProcessBuilder = new ProcessBuilder(
    5.67 +                    "codesign", "-v", jmapToolPath);
    5.68 +            Process codesignProcess = codesignProcessBuilder.start();
    5.69 +            OutputAnalyzer analyser = new OutputAnalyzer(codesignProcess);
    5.70 +            try {
    5.71 +                analyser.shouldNotContain("code object is not signed at all");
    5.72 +                System.out.println("Signed jmap found at: " + jmapToolPath);
    5.73 +            } catch (Exception e) {
    5.74 +                // Abort since we can't know if the test will work
    5.75 +                System.out
    5.76 +                        .println("Test aborted since we are on MacOSX and the jmap tool is not signed.");
    5.77 +                return;
    5.78 +            }
    5.79 +        }
    5.80 +
    5.81 +        // Small heap 22 megabytes, should create 1.0.1 file format
    5.82 +        testHProfFileFormat("-Xmx1g", 22 * M, HPROF_HEADER_1_0_1);
    5.83 +
    5.84 +        /**
    5.85 +         * This test was deliberately commented out since the test system lacks
    5.86 +         * support to handle the requirements for this kind of heap size in a
    5.87 +         * good way. If or when it becomes possible to run this kind of tests in
    5.88 +         * the test environment the test should be enabled again.
    5.89 +         * */
    5.90 +        // Large heap 2,2 gigabytes, should create 1.0.2 file format
    5.91 +        // testHProfFileFormat("-Xmx4g", 2 * G + 2 * M, HPROF_HEADER_1_0_2);
    5.92 +    }
    5.93 +
    5.94 +    private static void testHProfFileFormat(String vmArgs, long heapSize,
    5.95 +            String expectedFormat) throws Exception, IOException,
    5.96 +            InterruptedException, FileNotFoundException {
    5.97 +        ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(
    5.98 +                vmArgs, "JMapHProfLargeHeapProc", String.valueOf(heapSize));
    5.99 +        procBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);
   5.100 +        Process largeHeapProc = procBuilder.start();
   5.101 +
   5.102 +        try (Scanner largeHeapScanner = new Scanner(
   5.103 +                largeHeapProc.getInputStream());) {
   5.104 +            String pidstring = null;
   5.105 +            while ((pidstring = largeHeapScanner.findInLine("PID\\[[0-9].*\\]")) == null) {
   5.106 +                Thread.sleep(500);
   5.107 +            }
   5.108 +            int pid = Integer.parseInt(pidstring.substring(4,
   5.109 +                    pidstring.length() - 1));
   5.110 +            System.out.println("Extracted pid: " + pid);
   5.111 +
   5.112 +            JDKToolLauncher jMapLauncher = JDKToolLauncher
   5.113 +                    .create("jmap", false);
   5.114 +            jMapLauncher.addToolArg("-dump:format=b,file=" + pid + "-"
   5.115 +                    + HEAP_DUMP_FILE_NAME);
   5.116 +            jMapLauncher.addToolArg(String.valueOf(pid));
   5.117 +
   5.118 +            ProcessBuilder jMapProcessBuilder = new ProcessBuilder(
   5.119 +                    jMapLauncher.getCommand());
   5.120 +            System.out.println("jmap command: "
   5.121 +                    + Arrays.toString(jMapLauncher.getCommand()));
   5.122 +
   5.123 +            Process jMapProcess = jMapProcessBuilder.start();
   5.124 +            OutputAnalyzer analyzer = new OutputAnalyzer(jMapProcess);
   5.125 +            analyzer.shouldHaveExitValue(0);
   5.126 +            analyzer.shouldContain(pid + "-" + HEAP_DUMP_FILE_NAME);
   5.127 +            analyzer.shouldContain("Heap dump file created");
   5.128 +
   5.129 +            largeHeapProc.getOutputStream().write('\n');
   5.130 +
   5.131 +            File dumpFile = new File(pid + "-" + HEAP_DUMP_FILE_NAME);
   5.132 +            Asserts.assertTrue(dumpFile.exists(), "Heap dump file not found.");
   5.133 +
   5.134 +            try (Reader reader = new BufferedReader(new FileReader(dumpFile))) {
   5.135 +                CharBuffer buf = CharBuffer.allocate(expectedFormat.length());
   5.136 +                reader.read(buf);
   5.137 +                buf.clear();
   5.138 +                Asserts.assertEQ(buf.toString(), expectedFormat,
   5.139 +                        "Wrong file format. Expected '" + expectedFormat
   5.140 +                                + "', but found '" + buf.toString() + "'");
   5.141 +            }
   5.142 +
   5.143 +            System.out.println("Success!");
   5.144 +
   5.145 +        } finally {
   5.146 +            largeHeapProc.destroyForcibly();
   5.147 +        }
   5.148 +    }
   5.149 +}
     6.1 --- a/test/testlibrary/com/oracle/java/testlibrary/JDKToolLauncher.java	Fri Oct 04 13:01:07 2013 +0200
     6.2 +++ b/test/testlibrary/com/oracle/java/testlibrary/JDKToolLauncher.java	Fri Oct 04 13:44:49 2013 +0200
     6.3 @@ -23,20 +23,17 @@
     6.4  
     6.5  package com.oracle.java.testlibrary;
     6.6  
     6.7 -import java.util.List;
     6.8  import java.util.ArrayList;
     6.9  import java.util.Arrays;
    6.10 -
    6.11 -import com.oracle.java.testlibrary.JDKToolFinder;
    6.12 -import com.oracle.java.testlibrary.ProcessTools;
    6.13 +import java.util.List;
    6.14  
    6.15  /**
    6.16   * A utility for constructing command lines for starting JDK tool processes.
    6.17   *
    6.18   * The JDKToolLauncher can in particular be combined with a
    6.19 - * java.lang.ProcessBuilder to easily run a JDK tool. For example, the
    6.20 - * following code run {@code jmap -heap} against a process with GC logging
    6.21 - * turned on for the {@code jmap} process:
    6.22 + * java.lang.ProcessBuilder to easily run a JDK tool. For example, the following
    6.23 + * code run {@code jmap -heap} against a process with GC logging turned on for
    6.24 + * the {@code jmap} process:
    6.25   *
    6.26   * <pre>
    6.27   * {@code
    6.28 @@ -55,19 +52,39 @@
    6.29      private final List<String> vmArgs = new ArrayList<String>();
    6.30      private final List<String> toolArgs = new ArrayList<String>();
    6.31  
    6.32 -    private JDKToolLauncher(String tool) {
    6.33 -        executable = JDKToolFinder.getJDKTool(tool);
    6.34 +    private JDKToolLauncher(String tool, boolean useCompilerJDK) {
    6.35 +        if (useCompilerJDK) {
    6.36 +            executable = JDKToolFinder.getJDKTool(tool);
    6.37 +        } else {
    6.38 +            executable = JDKToolFinder.getCurrentJDKTool(tool);
    6.39 +        }
    6.40          vmArgs.addAll(Arrays.asList(ProcessTools.getPlatformSpecificVMArgs()));
    6.41      }
    6.42  
    6.43      /**
    6.44 +     * Creates a new JDKToolLauncher for the specified tool. Using tools path
    6.45 +     * from the compiler JDK.
    6.46 +     *
    6.47 +     * @param tool
    6.48 +     *            The name of the tool
    6.49 +     * @return A new JDKToolLauncher
    6.50 +     */
    6.51 +    public static JDKToolLauncher create(String tool) {
    6.52 +        return new JDKToolLauncher(tool, true);
    6.53 +    }
    6.54 +
    6.55 +    /**
    6.56       * Creates a new JDKToolLauncher for the specified tool.
    6.57       *
    6.58 -     * @param tool The name of the tool
    6.59 +     * @param tool
    6.60 +     *            The name of the tool
    6.61 +     * @param useCompilerPath
    6.62 +     *            If true use the compiler JDK path, otherwise use the tested
    6.63 +     *            JDK path.
    6.64       * @return A new JDKToolLauncher
    6.65       */
    6.66 -    public static JDKToolLauncher create(String tool) {
    6.67 -        return new JDKToolLauncher(tool);
    6.68 +    public static JDKToolLauncher create(String tool, boolean useCompilerJDK) {
    6.69 +        return new JDKToolLauncher(tool, useCompilerJDK);
    6.70      }
    6.71  
    6.72      /**
    6.73 @@ -80,7 +97,8 @@
    6.74       * automatically added.
    6.75       *
    6.76       *
    6.77 -     * @param arg The argument to VM running the tool
    6.78 +     * @param arg
    6.79 +     *            The argument to VM running the tool
    6.80       * @return The JDKToolLauncher instance
    6.81       */
    6.82      public JDKToolLauncher addVMArg(String arg) {
    6.83 @@ -91,7 +109,8 @@
    6.84      /**
    6.85       * Adds an argument to the tool.
    6.86       *
    6.87 -     * @param arg The argument to the tool
    6.88 +     * @param arg
    6.89 +     *            The argument to the tool
    6.90       * @return The JDKToolLauncher instance
    6.91       */
    6.92      public JDKToolLauncher addToolArg(String arg) {

mercurial