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