1 /* 2 * Copyright (c) 2016, 2021, Oracle and/or its affiliates. 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 /* 25 * @test 26 * @bug 8133747 8218458 27 * @summary Running with NMT detail should produce expected stack traces. 28 * @library /test/lib 29 * @modules java.base/jdk.internal.misc 30 * java.management 31 * @compile ../modules/CompilerUtils.java 32 * @run driver CheckForProperDetailStackTrace 33 */ 34 35 import jdk.test.lib.Platform; 36 import jdk.test.lib.process.ProcessTools; 37 import jdk.test.lib.process.OutputAnalyzer; 38 import java.nio.file.Path; 39 import java.nio.file.Paths; 40 import java.util.regex.Matcher; 41 import java.util.regex.Pattern; 42 43 /** 44 * We are checking for details that should be seen with NMT detail enabled. 45 * In particular the stack traces from os::malloc call sites should have 4 46 * (based on NMT detail stack depth setting) 'interesting' frames and skip 47 * the higher-level allocation frames and frames specific to the NMT logic. 48 * The actual stack trace is affected by the native compiler's inlining ability 49 * and the type of build, so we need to check for a number of possible stacks. 50 * This information does not change often enough that we are concerned about the 51 * stability of this test - rather we prefer to detect changes in compiler behaviour 52 * through this test and update it accordingly. 53 */ 54 public class CheckForProperDetailStackTrace { 55 private static final String TEST_SRC = System.getProperty("test.src"); 56 private static final String TEST_CLASSES = System.getProperty("test.classes"); 57 58 private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); 59 private static final Path MODS_DIR = Paths.get(TEST_CLASSES, "mods"); 60 61 /* The stack trace we look for by default. Note that :: has been replaced by .* 62 to make sure it matches even if the symbol is not unmangled. 63 */ 64 private static String stackTraceDefault = 65 ".*Hashtable.*new_entry.*\n" + 66 ".*ModuleEntryTable.*new_entry.*\n" + 67 ".*ModuleEntryTable.*locked_create_entry.*\n" + 68 ".*Modules.*define_module.*\n"; 69 70 /* Alternate stacktrace that we check if the default fails, because 71 new_entry may be inlined. 72 */ 73 private static String stackTraceAlternate = 74 ".*Hashtable.*new_entry.*\n" + 75 ".*ModuleEntryTable.*locked_create_entry.*\n" + 76 ".*Modules.*define_module.*\n" + 77 ".*JVM_DefineModule.*\n"; 78 79 /* The stack trace we look for on AIX and Windows slowdebug builds. 80 ALWAYSINLINE is only a hint and is ignored for AllocateHeap on the 81 aforementioned platforms. When that happens allocate_new_entry is 82 inlined instead. 83 */ 84 private static String stackTraceAllocateHeap = 85 ".*AllocateHeap.*\n" + 86 ".*ModuleEntryTable.*new_entry.*\n" + 87 ".*ModuleEntryTable.*locked_create_entry.*\n" + 88 ".*Modules.*define_module.*\n"; 89 90 /* A symbol that should always be present in NMT detail output. */ 91 private static String expectedSymbol = "locked_create_entry"; 92 93 public static void main(String args[]) throws Exception { 94 boolean compiled; 95 // Compile module jdk.test declaration 96 compiled = CompilerUtils.compile( 97 SRC_DIR.resolve("jdk.test"), 98 MODS_DIR.resolve("jdk.test")); 99 if (!compiled) { 100 throw new RuntimeException("Test failed to compile module jdk.test"); 101 } 102 103 // If modules in the system image have been archived in CDS, they will not be 104 // created again at run time. Explicitly use an external module to make sure 105 // we have a runtime-defined ModuleEntry 106 ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( 107 "-XX:+UnlockDiagnosticVMOptions", 108 "-XX:NativeMemoryTracking=detail", 109 "-XX:+PrintNMTStatistics", 110 "-p", MODS_DIR.toString(), 111 "-m", "jdk.test/test.Main"); 112 OutputAnalyzer output = new OutputAnalyzer(pb.start()); 113 114 output.shouldHaveExitValue(0); 115 116 // We should never see either of these frames because they are supposed to be skipped. 117 output.shouldNotContain("NativeCallStack::NativeCallStack"); 118 output.shouldNotContain("os::get_native_stack"); 119 120 // AllocateHeap shouldn't be in the output because it is supposed to always be inlined. 121 // We check for that here, but allow it for Aix and Windows slowdebug builds 122 // because the compiler ends up not inlining AllocateHeap. 123 Boolean okToHaveAllocateHeap = Platform.isSlowDebugBuild() && 124 (Platform.isAix() || Platform.isWindows()); 125 if (!okToHaveAllocateHeap) { 126 output.shouldNotContain("AllocateHeap"); 127 } 128 129 // See if we have any stack trace symbols in the output 130 boolean hasSymbols = output.getStdout().contains(expectedSymbol) || 131 output.getStderr().contains(expectedSymbol); 132 if (!hasSymbols) { 133 // It's ok for ARM not to have symbols, because it does not support NMT detail 134 // when targeting thumb2. It's also ok for Windows not to have symbols, because 135 // they are only available if the symbols file is included with the build. 136 if (Platform.isWindows() || Platform.isARM()) { 137 return; // we are done 138 } 139 output.reportDiagnosticSummary(); 140 throw new RuntimeException("Expected symbol missing from output: " + expectedSymbol); 141 } 142 143 // Make sure the expected NMT detail stack trace is found 144 System.out.println("Looking for a stack matching:"); 145 if (okToHaveAllocateHeap) { 146 System.out.print(stackTraceAllocateHeap); 147 if (stackTraceMatches(stackTraceAllocateHeap, output)) { 148 return; 149 } 150 } else { 151 System.out.print(stackTraceDefault); 152 if (!stackTraceMatches(stackTraceDefault, output)) { 153 System.out.println("Looking for alternate stack matching:"); 154 System.out.print(stackTraceAlternate); 155 if (stackTraceMatches(stackTraceAlternate, output)) { 156 return; 157 } 158 } else { 159 return; 160 } 161 } 162 // Failed to match so dump all the output 163 output.reportDiagnosticSummary(); 164 throw new RuntimeException("Expected stack trace missing from output"); 165 } 166 167 public static boolean stackTraceMatches(String stackTrace, OutputAnalyzer output) { 168 Pattern p = Pattern.compile(stackTrace, Pattern.MULTILINE); 169 Matcher stdoutMatcher = p.matcher(output.getStdout()); 170 Matcher stderrMatcher = p.matcher(output.getStderr()); 171 return (stdoutMatcher.find() || stderrMatcher.find()); 172 } 173 }