1 /* 2 * Copyright (c) 2014, 2015, 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 SegmentedCodeCacheDtraceTest 26 * @bug 8015774 27 * @summary testing of dtrace for segmented code cache 28 * @requires os.family=="solaris" 29 * @modules java.base/jdk.internal.misc 30 * @library /testlibrary /test/lib / 31 * 32 * @build compiler.codecache.dtrace.SegmentedCodeCacheDtraceTest 33 * @run driver ClassFileInstaller sun.hotspot.WhiteBox 34 * sun.hotspot.WhiteBox$WhiteBoxPermission 35 * @run main/othervm/timeout=600 -Xbootclasspath/a:. 36 * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 37 * compiler.codecache.dtrace.SegmentedCodeCacheDtraceTest 38 */ 39 40 package compiler.codecache.dtrace; 41 42 import compiler.testlibrary.CompilerUtils; 43 import jdk.test.lib.Asserts; 44 import jdk.test.lib.JDKToolFinder; 45 import jdk.test.lib.OutputAnalyzer; 46 import jdk.test.lib.Utils; 47 import jdk.test.lib.dtrace.DtraceResultsAnalyzer; 48 import jdk.test.lib.dtrace.DtraceRunner; 49 50 import java.io.IOException; 51 import java.lang.reflect.Executable; 52 import java.nio.file.Files; 53 import java.nio.file.Paths; 54 import java.util.Arrays; 55 import java.util.Collections; 56 import java.util.HashMap; 57 import java.util.HashSet; 58 import java.util.List; 59 import java.util.Map; 60 import java.util.Random; 61 import java.util.Set; 62 import java.util.regex.Matcher; 63 import java.util.regex.Pattern; 64 import java.util.stream.Collectors; 65 66 public class SegmentedCodeCacheDtraceTest { 67 68 private static final String WORKER_CLASS_NAME 69 = SegmentedCodeCacheDtraceTestWorker.class.getName(); 70 private static final String JAVA_OPTS = " -XX:+DTraceMethodProbes " 71 + "-Xbootclasspath/a:" + System.getProperty("test.classes") + " " 72 + "-XX:+UnlockDiagnosticVMOptions " 73 + "-XX:+WhiteBoxAPI -XX:+SegmentedCodeCache " 74 + "-XX:CompileCommand=compileonly," 75 + WORKER_CLASS_NAME + "::* " 76 + " -classpath " + System.getProperty("test.class.path") + " " 77 + String.join(" ", Utils.getTestJavaOpts()); 78 private static final String DTRACE_SCRIPT 79 = "SegmentedCodeCacheDtraceTestScript.d"; 80 private static final List<Executable> MLIST = 81 SegmentedCodeCacheDtraceTestWorker.TESTED_METHODS_LIST; 82 private static final int WORKER_METHODS_COUNT = MLIST.size(); 83 84 private void runTest(TestCombination tc) { 85 String params = MLIST.stream() 86 .map(Executable::getName) 87 .map(x -> tc.data.get(x).compileLevel + " " + tc.data.get(x).isInlined) 88 .collect(Collectors.joining(" ")); 89 DtraceRunner runner = new DtraceRunner(); 90 runner.runDtrace(JDKToolFinder.getTestJDKTool("java"), JAVA_OPTS, 91 WORKER_CLASS_NAME, params, Paths.get(System.getProperty("test.src"), 92 DTRACE_SCRIPT).toString(), 93 DtraceRunner.PERMIT_DESTRUCTIVE_ACTIONS_DTRACE_OPTION, 94 new SegmentedCodeCacheDtraceResultsAnalyzer()); 95 } 96 97 private static TestCombination generateUniqueCombination( 98 int[] availableLevels, Set<TestCombination> combinations) { 99 int len = availableLevels.length; 100 /* first, check if we're out of combinations. */ 101 int maxCombinationsCount 102 = (1 << WORKER_METHODS_COUNT) 103 * (int) Math.pow(len, WORKER_METHODS_COUNT); 104 if (combinations.size() == maxCombinationsCount) { 105 return null; 106 } 107 Random r = Utils.getRandomInstance(); 108 while (combinations.size() < maxCombinationsCount) { 109 int levels[] = new int[WORKER_METHODS_COUNT]; 110 boolean inlines[] = new boolean[WORKER_METHODS_COUNT]; 111 for (int i = 0; i < WORKER_METHODS_COUNT; i++) { 112 levels[i] = availableLevels[r.nextInt(len)]; 113 inlines[i] = r.nextBoolean(); 114 } 115 TestCombination tc = new TestCombination(levels, inlines); 116 if (combinations.add(tc)) { 117 return tc; 118 } 119 } 120 return null; 121 } 122 123 public static void main(String args[]) { 124 int iterations 125 = Integer.getInteger("jdk.test.lib.iterations", 1); 126 if (!DtraceRunner.dtraceAvailable()) { 127 System.out.println("INFO: There is no dtrace avaiable. Skipping."); 128 return; 129 } 130 int[] availableLevels = CompilerUtils.getAvailableCompilationLevels(); 131 // adding one more entry(zero) for interpeter 132 availableLevels 133 = Arrays.copyOf(availableLevels, availableLevels.length + 1); 134 Set<TestCombination> combinations = new HashSet<>(); 135 for (int i = 0; i < iterations; i++) { 136 TestCombination tc 137 = generateUniqueCombination(availableLevels, combinations); 138 if (tc == null) { 139 System.out.println("INFO: no more combinations available"); 140 return; 141 } else { 142 System.out.println("INFO: Running testcase for: " + tc); 143 new SegmentedCodeCacheDtraceTest().runTest(tc); 144 } 145 } 146 } 147 148 private static class MethodData { 149 150 public final int compileLevel; 151 public final boolean isInlined; 152 public final String name; 153 154 public MethodData(String name, int compileLevel, boolean isInlined) { 155 this.name = name; 156 this.compileLevel = compileLevel; 157 this.isInlined = isInlined; 158 } 159 160 @Override 161 public boolean equals(Object o) { 162 if (o == null || !(o instanceof MethodData)) { 163 return false; 164 } 165 MethodData md = (MethodData) o; 166 return md.compileLevel == compileLevel 167 && md.isInlined == isInlined 168 && md.name.equals(name); 169 } 170 171 @Override 172 public int hashCode() { 173 return 100 * name.hashCode() + 10 * compileLevel + (isInlined ? 1 : 0); 174 } 175 176 @Override 177 public String toString() { 178 return name + " " + compileLevel + " " + isInlined; 179 } 180 } 181 182 private static class TestCombination { 183 184 private final Map<String, MethodData> data; 185 186 public TestCombination(int compLevels[], boolean inlines[]) { 187 Map<String, MethodData> d = new HashMap<>(); 188 for (int i = 0; i < MLIST.size(); i++) { 189 d.put(MLIST.get(i).getName(), new MethodData(MLIST.get(i).getName(), 190 compLevels[i], inlines[i])); 191 } 192 data = Collections.unmodifiableMap(d); 193 } 194 195 @Override 196 public boolean equals(Object o) { 197 if (o == null || !(o instanceof TestCombination)) { 198 return false; 199 } 200 TestCombination second = (TestCombination) o; 201 return second.data.equals(data); 202 } 203 204 @Override 205 public int hashCode() { 206 int sum = 0; 207 for (MethodData md : data.values()) { 208 sum += md.hashCode(); 209 } 210 return sum; 211 } 212 213 private String getMethodDescString(MethodData md) { 214 return (md == null) 215 ? null 216 : String.format("Method %s compilation level %d and %s", 217 md.name, md.compileLevel, 218 md.isInlined ? "inlined" : "not inlined"); 219 } 220 221 @Override 222 public String toString() { 223 return data.values().stream().map(m -> getMethodDescString(m)) 224 .collect(Collectors.joining(Utils.NEW_LINE, 225 "Combination: ", "")); 226 } 227 } 228 229 private class SegmentedCodeCacheDtraceResultsAnalyzer 230 implements DtraceResultsAnalyzer { 231 232 private static final int EXPECTED_MATCH_COUNT = 2; 233 234 private final Pattern checkPattern; 235 236 public SegmentedCodeCacheDtraceResultsAnalyzer() { 237 String workerClassRegExp = "\\s*" + WORKER_CLASS_NAME + "\\."; 238 String delimeter = "\\(\\)V\\*?" + workerClassRegExp; 239 String suffix = "test\\(\\)V\\*?" + workerClassRegExp 240 + "main\\(\\[Ljava\\/lang\\/String;\\)V"; 241 StringBuilder sb = new StringBuilder(workerClassRegExp); 242 // method order is important, so, going from list tail to head, 243 // accoring to call order representation in stacktrace 244 for (int i = MLIST.size() - 1; i > -1; i--) { 245 sb.append(MLIST.get(i).getName()).append(delimeter); 246 } 247 sb.append(suffix); 248 checkPattern = Pattern.compile(sb.toString()); 249 /* such pattern match should pass on a stacktrace like 250 CPU ID FUNCTION:NAME 251 0 53573 __1cNSharedRuntimeTdtrace_method_entry6FpnKJavaThread_pnGMethod__i_:method-entry ustack: 252 253 libjvm.so`__1cNSharedRuntimeTdtrace_method_entry6FpnKJavaThread_pnGMethod__i_+0x39c 254 SegmentedCodeCacheDtraceTestWorker.baz()V* 255 SegmentedCodeCacheDtraceTestWorker.bar()V 256 SegmentedCodeCacheDtraceTestWorker.foo()V* 257 SegmentedCodeCacheDtraceTestWorker.test()V 258 SegmentedCodeCacheDtraceTestWorker.main([Ljava/lang/String;)V 259 0xffffffff6b0004b8 260 libjvm.so`__1cJJavaCallsLcall_helper6FpnJJavaValue_pnMmethodHandle_pnRJavaCallArguments_pnGThread__v_+0x94c 261 libjvm.so`__1cRjni_invoke_static6FpnHJNIEnv__pnJJavaValue_pnI_jobject_nLJNICallType_pnK_jmethodID_pnSJNI_ArgumentPusher_pnGThread__v_+0xa64 262 libjvm.so`jni_CallStaticVoidMethod+0x508 263 libjli.so`JavaMain+0x584 264 libc.so.1`_lwp_start 265 jstack: 266 267 libjvm.so`__1cNSharedRuntimeTdtrace_method_entry6FpnKJavaThread_pnGMethod__i_+0x39c 268 SegmentedCodeCacheDtraceTestWorker.baz()V* 269 SegmentedCodeCacheDtraceTestWorker.bar()V 270 SegmentedCodeCacheDtraceTestWorker.foo()V* 271 SegmentedCodeCacheDtraceTestWorker.test()V 272 SegmentedCodeCacheDtraceTestWorker.main([Ljava/lang/String;)V 273 0xffffffff6b0004b8 274 libjvm.so`__1cJJavaCallsLcall_helper6FpnJJavaValue_pnMmethodHandle_pnRJavaCallArguments_pnGThread__v_+0x94c 275 libjvm.so`__1cRjni_invoke_static6FpnHJNIEnv__pnJJavaValue_pnI_jobject_nLJNICallType_pnK_jmethodID_pnSJNI_ArgumentPusher_pnGThread__v_+0xa64 276 libjvm.so`jni_CallStaticVoidMethod+0x508 277 libjli.so`JavaMain+0x584 278 libc.so.1`_lwp_start 279 */ 280 } 281 282 protected List<String> loadLog(String dtraceOutFile) throws IOException { 283 return Files.readAllLines(Paths.get(dtraceOutFile)); 284 } 285 286 @Override 287 public void analyze(OutputAnalyzer oa, String dtraceOutFilePath) { 288 oa.shouldHaveExitValue(0); 289 List<String> dOut; 290 try { 291 dOut = loadLog(dtraceOutFilePath); 292 } catch (IOException e) { 293 throw new Error("Can't load log", e); 294 } 295 StringBuilder allDtraceOutput = new StringBuilder(); 296 for (String entry : dOut) { 297 allDtraceOutput.append(entry); 298 } 299 int matchCount = getMatchCount(allDtraceOutput.toString()); 300 Asserts.assertEQ(matchCount, EXPECTED_MATCH_COUNT, 301 "Unexpected output match amount. expected: " 302 + EXPECTED_MATCH_COUNT + " but found " + matchCount); 303 } 304 305 protected int getMatchCount(String source) { 306 Matcher m = checkPattern.matcher(source); 307 int matchCount = 0; 308 while (m.find()) { 309 matchCount++; 310 } 311 return matchCount; 312 } 313 } 314 }