1 /* 2 * Copyright (c) 2023, Alibaba Group Holding Limited. All Rights Reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.io.File; 25 import java.io.IOException; 26 import java.nio.file.Files; 27 import java.util.Arrays; 28 import java.util.List; 29 import java.util.stream.Collectors; 30 import java.util.stream.Stream; 31 32 import jdk.test.lib.Asserts; 33 import jdk.test.lib.JDKToolLauncher; 34 import jdk.test.lib.Utils; 35 import jdk.test.lib.apps.LingeredApp; 36 import jdk.test.lib.dcmd.PidJcmdExecutor; 37 import jdk.test.lib.process.OutputAnalyzer; 38 import jdk.test.lib.process.ProcessTools; 39 40 import jdk.test.lib.hprof.HprofParser; 41 42 /** 43 * @test 44 * @bug 8306441 8319053 45 * @summary Verify the integrity of generated heap dump and capability of parallel dump 46 * @library /test/lib 47 * @run main HeapDumpParallelTest 48 */ 49 50 public class HeapDumpParallelTest { 51 52 private static final String heapDumpFileName = "parallelHeapDump.bin"; 53 54 private static void checkAndVerify(OutputAnalyzer dcmdOut, LingeredApp app, File heapDumpFile, boolean expectSerial) throws Exception { 55 dcmdOut.shouldHaveExitValue(0); 56 dcmdOut.shouldContain("Heap dump file created"); 57 OutputAnalyzer appOut = new OutputAnalyzer(app.getProcessStdout()); 58 appOut.shouldContain("[heapdump]"); 59 String opts = Arrays.asList(Utils.getTestJavaOpts()).toString(); 60 if (opts.contains("-XX:+UseSerialGC") || opts.contains("-XX:+UseEpsilonGC")) { 61 System.out.println("UseSerialGC detected."); 62 expectSerial = true; 63 } 64 if (!expectSerial && Runtime.getRuntime().availableProcessors() > 1) { 65 appOut.shouldContain("Dump heap objects in parallel"); 66 appOut.shouldContain("Merge heap files complete"); 67 } else { 68 appOut.shouldNotContain("Dump heap objects in parallel"); 69 } 70 HprofParser.parseAndVerify(heapDumpFile); 71 72 List<String> files 73 = Stream.of(heapDumpFile.getAbsoluteFile().getParentFile().listFiles()) 74 .filter(file -> !file.isDirectory()) 75 .map(File::getName) 76 .filter(name -> name.startsWith(heapDumpFileName) && !name.equals(heapDumpFileName)) 77 .collect(Collectors.toList()); 78 if (!files.isEmpty()) { 79 throw new RuntimeException("Unexpected files left: " + files); 80 } 81 if (heapDumpFile.exists()) { 82 heapDumpFile.delete(); 83 } 84 } 85 86 private static LingeredApp launchApp() throws IOException { 87 LingeredApp theApp = new LingeredApp(); 88 LingeredApp.startApp(theApp, "-Xlog:heapdump", "-Xmx512m", 89 "-XX:-UseDynamicNumberOfGCThreads", 90 "-XX:ParallelGCThreads=2"); 91 return theApp; 92 } 93 94 public static void main(String[] args) throws Exception { 95 File heapDumpFile = new File(heapDumpFileName); 96 if (heapDumpFile.exists()) { 97 heapDumpFile.delete(); 98 } 99 100 LingeredApp theApp = launchApp(); 101 try { 102 // Expect error message 103 OutputAnalyzer out = attachJcmdHeapDump(heapDumpFile, theApp.getPid(), "-parallel=" + -1); 104 out.shouldContain("Invalid number of parallel dump threads."); 105 106 // Expect serial dump because 0 implies to disable parallel dump 107 test(heapDumpFile, "-parallel=" + 0, true); 108 109 // Expect serial dump 110 test(heapDumpFile, "-parallel=" + 1, true); 111 112 // Expect parallel dump 113 test(heapDumpFile, "-parallel=" + Integer.MAX_VALUE, false); 114 115 // Expect parallel dump 116 test(heapDumpFile, "-gz=9 -overwrite -parallel=" + Runtime.getRuntime().availableProcessors(), false); 117 } finally { 118 theApp.stopApp(); 119 } 120 } 121 122 private static void test(File heapDumpFile, String arg, boolean expectSerial) throws Exception { 123 LingeredApp theApp = launchApp(); 124 try { 125 OutputAnalyzer dcmdOut = attachJcmdHeapDump(heapDumpFile, theApp.getPid(), arg); 126 theApp.stopApp(); 127 checkAndVerify(dcmdOut, theApp, heapDumpFile, expectSerial); 128 } finally { 129 theApp.stopApp(); 130 } 131 } 132 133 private static OutputAnalyzer attachJcmdHeapDump(File heapDumpFile, long lingeredAppPid, String arg) throws Exception { 134 // e.g. jcmd <pid> GC.heap_dump -parallel=cpucount <file_path> 135 System.out.println("Testing pid " + lingeredAppPid); 136 PidJcmdExecutor executor = new PidJcmdExecutor("" + lingeredAppPid); 137 return executor.execute("GC.heap_dump " + arg + " " + heapDumpFile.getAbsolutePath()); 138 } 139 }