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