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