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