1 /* 2 * Copyright (c) 2014, 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 SegmentedCodeCacheDtraceTest 26 * @key randomness 27 * @bug 8015774 28 * @summary testing of dtrace for segmented code cache 29 * @requires os.family=="solaris" 30 * @modules java.base/jdk.internal.misc 31 * @library /test/lib / 32 * 33 * @build sun.hotspot.WhiteBox 34 * @run driver ClassFileInstaller sun.hotspot.WhiteBox 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 import jtreg.SkippedException; 48 49 import java.io.IOException; 50 import java.lang.reflect.Executable; 51 import java.nio.file.Files; 52 import java.nio.file.Paths; 53 import java.util.Arrays; 54 import java.util.Collections; 55 import java.util.HashMap; 56 import java.util.HashSet; 57 import java.util.List; 58 import java.util.Map; 59 import java.util.Random; 60 import java.util.Set; 61 import java.util.regex.Matcher; 62 import java.util.regex.Pattern; 63 import java.util.stream.Collectors; 64 65 public class SegmentedCodeCacheDtraceTest { 66 67 private static final String WORKER_CLASS_NAME 68 = SegmentedCodeCacheDtraceTestWorker.class.getName(); 69 private static final String JAVA_OPTS = " -XX:+DTraceMethodProbes " 70 + "-Xbootclasspath/a:" + System.getProperty("test.classes") + " " 71 + "-XX:+UnlockDiagnosticVMOptions " 72 + "-XX:+WhiteBoxAPI -XX:+SegmentedCodeCache " 73 + "-XX:CompileCommand=compileonly," 74 + WORKER_CLASS_NAME + "::* " 75 + " -classpath " + System.getProperty("test.class.path") + " " 76 + String.join(" ", Utils.getTestJavaOpts()); 77 private static final String DTRACE_SCRIPT 78 = "SegmentedCodeCacheDtraceTestScript.d"; 79 private static final List<Executable> MLIST = 80 SegmentedCodeCacheDtraceTestWorker.TESTED_METHODS_LIST; 81 private static final int WORKER_METHODS_COUNT = MLIST.size(); 82 83 private void runTest(TestCombination tc) { 84 String params = MLIST.stream() 85 .map(Executable::getName) 86 .map(x -> tc.data.get(x).compileLevel + " " + tc.data.get(x).isInlined) 87 .collect(Collectors.joining(" ")); 88 DtraceRunner runner = new DtraceRunner(); 89 runner.runDtrace(JDKToolFinder.getTestJDKTool("java"), JAVA_OPTS, 90 WORKER_CLASS_NAME, params, Paths.get(System.getProperty("test.src"), 91 DTRACE_SCRIPT).toString(), 92 DtraceRunner.PERMIT_DESTRUCTIVE_ACTIONS_DTRACE_OPTION, 93 new SegmentedCodeCacheDtraceResultsAnalyzer()); 94 } 95 96 private static TestCombination generateUniqueCombination( 97 int[] availableLevels, Set<TestCombination> combinations) { 98 int len = availableLevels.length; 99 /* first, check if we're out of combinations. */ 100 int maxCombinationsCount 101 = (1 << WORKER_METHODS_COUNT) 102 * (int) Math.pow(len, WORKER_METHODS_COUNT); 103 if (combinations.size() == maxCombinationsCount) { 104 return null; 105 } 106 Random r = Utils.getRandomInstance(); 107 while (combinations.size() < maxCombinationsCount) { 108 int levels[] = new int[WORKER_METHODS_COUNT]; 109 boolean inlines[] = new boolean[WORKER_METHODS_COUNT]; 110 for (int i = 0; i < WORKER_METHODS_COUNT; i++) { 111 levels[i] = availableLevels[r.nextInt(len)]; 112 inlines[i] = r.nextBoolean(); 113 } 114 TestCombination tc = new TestCombination(levels, inlines); 115 if (combinations.add(tc)) { 116 return tc; 117 } 118 } 119 return null; 120 } 121 122 public static void main(String args[]) { 123 if (!DtraceRunner.dtraceAvailable()) { 124 throw new SkippedException("There is no dtrace avaiable."); 125 } 126 int iterations 127 = Integer.getInteger("jdk.test.lib.iterations", 1); 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 }