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