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