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