|
1 /* |
|
2 * Copyright (c) 2013, 2016, 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 package compiler.whitebox; |
|
25 |
|
26 import jdk.test.lib.Platform; |
|
27 import sun.hotspot.WhiteBox; |
|
28 import sun.hotspot.code.NMethod; |
|
29 |
|
30 import java.lang.reflect.Executable; |
|
31 import java.util.Objects; |
|
32 import java.util.concurrent.Callable; |
|
33 import java.util.function.Function; |
|
34 |
|
35 /** |
|
36 * Abstract class for WhiteBox testing of JIT. |
|
37 * Depends on jdk.test.lib.Platform from testlibrary. |
|
38 * |
|
39 * @author igor.ignatyev@oracle.com |
|
40 */ |
|
41 public abstract class CompilerWhiteBoxTest { |
|
42 /** {@code CompLevel::CompLevel_none} -- Interpreter */ |
|
43 public static final int COMP_LEVEL_NONE = 0; |
|
44 /** {@code CompLevel::CompLevel_any}, {@code CompLevel::CompLevel_all} */ |
|
45 public static final int COMP_LEVEL_ANY = -2; |
|
46 /** {@code CompLevel::CompLevel_aot} -- AOT */ |
|
47 public static final int COMP_LEVEL_AOT = -1; |
|
48 /** {@code CompLevel::CompLevel_simple} -- C1 */ |
|
49 public static final int COMP_LEVEL_SIMPLE = 1; |
|
50 /** {@code CompLevel::CompLevel_limited_profile} -- C1, invocation & backedge counters */ |
|
51 public static final int COMP_LEVEL_LIMITED_PROFILE = 2; |
|
52 /** {@code CompLevel::CompLevel_full_profile} -- C1, invocation & backedge counters + mdo */ |
|
53 public static final int COMP_LEVEL_FULL_PROFILE = 3; |
|
54 /** {@code CompLevel::CompLevel_full_optimization} -- C2 or Shark */ |
|
55 public static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; |
|
56 /** Maximal value for CompLevel */ |
|
57 public static final int COMP_LEVEL_MAX = COMP_LEVEL_FULL_OPTIMIZATION; |
|
58 |
|
59 /** Instance of WhiteBox */ |
|
60 protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); |
|
61 /** Value of {@code -XX:CompileThreshold} */ |
|
62 protected static final int COMPILE_THRESHOLD |
|
63 = Integer.parseInt(getVMOption("CompileThreshold", "10000")); |
|
64 /** Value of {@code -XX:BackgroundCompilation} */ |
|
65 protected static final boolean BACKGROUND_COMPILATION |
|
66 = Boolean.valueOf(getVMOption("BackgroundCompilation", "true")); |
|
67 protected static final boolean USE_COUNTER_DECAY |
|
68 = Boolean.valueOf(getVMOption("UseCounterDecay", "true")); |
|
69 /** Value of {@code -XX:TieredCompilation} */ |
|
70 protected static final boolean TIERED_COMPILATION |
|
71 = Boolean.valueOf(getVMOption("TieredCompilation", "false")); |
|
72 /** Value of {@code -XX:TieredStopAtLevel} */ |
|
73 protected static final int TIERED_STOP_AT_LEVEL |
|
74 = Integer.parseInt(getVMOption("TieredStopAtLevel", "0")); |
|
75 /** Flag for verbose output, true if {@code -Dverbose} specified */ |
|
76 protected static final boolean IS_VERBOSE |
|
77 = System.getProperty("verbose") != null; |
|
78 /** invocation count to trigger compilation */ |
|
79 public static final int THRESHOLD; |
|
80 /** invocation count to trigger OSR compilation */ |
|
81 protected static final long BACKEDGE_THRESHOLD; |
|
82 |
|
83 static { |
|
84 if (TIERED_COMPILATION) { |
|
85 BACKEDGE_THRESHOLD = THRESHOLD = 150000; |
|
86 } else { |
|
87 THRESHOLD = COMPILE_THRESHOLD; |
|
88 BACKEDGE_THRESHOLD = COMPILE_THRESHOLD * Long.parseLong(getVMOption( |
|
89 "OnStackReplacePercentage")); |
|
90 } |
|
91 } |
|
92 |
|
93 /** |
|
94 * Returns value of VM option. |
|
95 * |
|
96 * @param name option's name |
|
97 * @return value of option or {@code null}, if option doesn't exist |
|
98 * @throws NullPointerException if name is null |
|
99 */ |
|
100 protected static String getVMOption(String name) { |
|
101 Objects.requireNonNull(name); |
|
102 return Objects.toString(WHITE_BOX.getVMFlag(name), null); |
|
103 } |
|
104 |
|
105 /** |
|
106 * Returns value of VM option or default value. |
|
107 * |
|
108 * @param name option's name |
|
109 * @param defaultValue default value |
|
110 * @return value of option or {@code defaultValue}, if option doesn't exist |
|
111 * @throws NullPointerException if name is null |
|
112 * @see #getVMOption(String) |
|
113 */ |
|
114 protected static String getVMOption(String name, String defaultValue) { |
|
115 String result = getVMOption(name); |
|
116 return result == null ? defaultValue : result; |
|
117 } |
|
118 |
|
119 /** copy of is_c1_compile(int) from utilities/globalDefinitions.hpp */ |
|
120 protected static boolean isC1Compile(int compLevel) { |
|
121 return (compLevel > COMP_LEVEL_NONE) |
|
122 && (compLevel < COMP_LEVEL_FULL_OPTIMIZATION); |
|
123 } |
|
124 |
|
125 /** copy of is_c2_compile(int) from utilities/globalDefinitions.hpp */ |
|
126 protected static boolean isC2Compile(int compLevel) { |
|
127 return compLevel == COMP_LEVEL_FULL_OPTIMIZATION; |
|
128 } |
|
129 |
|
130 protected static void main( |
|
131 Function<TestCase, CompilerWhiteBoxTest> constructor, |
|
132 String[] args) { |
|
133 if (args.length == 0) { |
|
134 for (TestCase test : SimpleTestCase.values()) { |
|
135 constructor.apply(test).runTest(); |
|
136 } |
|
137 } else { |
|
138 for (String name : args) { |
|
139 constructor.apply(SimpleTestCase.valueOf(name)).runTest(); |
|
140 } |
|
141 } |
|
142 } |
|
143 |
|
144 /** tested method */ |
|
145 protected final Executable method; |
|
146 protected final TestCase testCase; |
|
147 |
|
148 /** |
|
149 * Constructor. |
|
150 * |
|
151 * @param testCase object, that contains tested method and way to invoke it. |
|
152 */ |
|
153 protected CompilerWhiteBoxTest(TestCase testCase) { |
|
154 Objects.requireNonNull(testCase); |
|
155 System.out.println("TEST CASE:" + testCase.name()); |
|
156 method = testCase.getExecutable(); |
|
157 this.testCase = testCase; |
|
158 } |
|
159 |
|
160 /** |
|
161 * Template method for testing. Prints tested method's info before |
|
162 * {@linkplain #test()} and after {@linkplain #test()} or on thrown |
|
163 * exception. |
|
164 * |
|
165 * @throws RuntimeException if method {@linkplain #test()} throws any |
|
166 * exception |
|
167 * @see #test() |
|
168 */ |
|
169 protected final void runTest() { |
|
170 if (Platform.isInt()) { |
|
171 throw new Error("TESTBUG: test can not be run in interpreter"); |
|
172 } |
|
173 System.out.println("at test's start:"); |
|
174 printInfo(); |
|
175 try { |
|
176 test(); |
|
177 } catch (Exception e) { |
|
178 System.out.printf("on exception '%s':", e.getMessage()); |
|
179 printInfo(); |
|
180 e.printStackTrace(); |
|
181 if (e instanceof RuntimeException) { |
|
182 throw (RuntimeException) e; |
|
183 } |
|
184 throw new RuntimeException(e); |
|
185 } |
|
186 System.out.println("at test's end:"); |
|
187 printInfo(); |
|
188 } |
|
189 |
|
190 /** |
|
191 * Checks, that {@linkplain #method} is not compiled at the given compilation |
|
192 * level or above. |
|
193 * |
|
194 * @param compLevel |
|
195 * |
|
196 * @throws RuntimeException if {@linkplain #method} is in compiler queue or |
|
197 * is compiled, or if {@linkplain #method} has zero |
|
198 * compilation level. |
|
199 */ |
|
200 protected final void checkNotCompiled(int compLevel) { |
|
201 if (WHITE_BOX.isMethodQueuedForCompilation(method)) { |
|
202 throw new RuntimeException(method + " must not be in queue"); |
|
203 } |
|
204 if (WHITE_BOX.getMethodCompilationLevel(method, false) >= compLevel) { |
|
205 throw new RuntimeException(method + " comp_level must be >= maxCompLevel"); |
|
206 } |
|
207 if (WHITE_BOX.getMethodCompilationLevel(method, true) >= compLevel) { |
|
208 throw new RuntimeException(method + " osr_comp_level must be >= maxCompLevel"); |
|
209 } |
|
210 } |
|
211 |
|
212 /** |
|
213 * Checks, that {@linkplain #method} is not compiled. |
|
214 * |
|
215 * @throws RuntimeException if {@linkplain #method} is in compiler queue or |
|
216 * is compiled, or if {@linkplain #method} has zero |
|
217 * compilation level. |
|
218 */ |
|
219 protected final void checkNotCompiled() { |
|
220 waitBackgroundCompilation(); |
|
221 checkNotCompiled(true); |
|
222 checkNotCompiled(false); |
|
223 } |
|
224 |
|
225 /** |
|
226 * Checks, that {@linkplain #method} is not (OSR-)compiled. |
|
227 * |
|
228 * @param isOsr Check for OSR compilation if true |
|
229 * @throws RuntimeException if {@linkplain #method} is in compiler queue or |
|
230 * is compiled, or if {@linkplain #method} has zero |
|
231 * compilation level. |
|
232 */ |
|
233 protected final void checkNotCompiled(boolean isOsr) { |
|
234 if (WHITE_BOX.isMethodQueuedForCompilation(method)) { |
|
235 throw new RuntimeException(method + " must not be in queue"); |
|
236 } |
|
237 if (WHITE_BOX.isMethodCompiled(method, isOsr)) { |
|
238 throw new RuntimeException(method + " must not be " + |
|
239 (isOsr ? "osr_" : "") + "compiled"); |
|
240 } |
|
241 if (WHITE_BOX.getMethodCompilationLevel(method, isOsr) != 0) { |
|
242 throw new RuntimeException(method + (isOsr ? " osr_" : " ") + |
|
243 "comp_level must be == 0"); |
|
244 } |
|
245 } |
|
246 |
|
247 /** |
|
248 * Checks, that {@linkplain #method} is compiled. |
|
249 * |
|
250 * @throws RuntimeException if {@linkplain #method} isn't in compiler queue |
|
251 * and isn't compiled, or if {@linkplain #method} |
|
252 * has nonzero compilation level |
|
253 */ |
|
254 protected final void checkCompiled() { |
|
255 final long start = System.currentTimeMillis(); |
|
256 waitBackgroundCompilation(); |
|
257 if (WHITE_BOX.isMethodQueuedForCompilation(method)) { |
|
258 System.err.printf("Warning: %s is still in queue after %dms%n", |
|
259 method, System.currentTimeMillis() - start); |
|
260 return; |
|
261 } |
|
262 if (!WHITE_BOX.isMethodCompiled(method, testCase.isOsr())) { |
|
263 throw new RuntimeException(method + " must be " |
|
264 + (testCase.isOsr() ? "osr_" : "") + "compiled"); |
|
265 } |
|
266 if (WHITE_BOX.getMethodCompilationLevel(method, testCase.isOsr()) |
|
267 == 0) { |
|
268 throw new RuntimeException(method |
|
269 + (testCase.isOsr() ? " osr_" : " ") |
|
270 + "comp_level must be != 0"); |
|
271 } |
|
272 } |
|
273 |
|
274 protected final void deoptimize() { |
|
275 WHITE_BOX.deoptimizeMethod(method, testCase.isOsr()); |
|
276 if (testCase.isOsr()) { |
|
277 WHITE_BOX.deoptimizeMethod(method, false); |
|
278 } |
|
279 } |
|
280 |
|
281 protected final int getCompLevel() { |
|
282 NMethod nm = NMethod.get(method, testCase.isOsr()); |
|
283 return nm == null ? COMP_LEVEL_NONE : nm.comp_level; |
|
284 } |
|
285 |
|
286 protected final boolean isCompilable() { |
|
287 return WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY, |
|
288 testCase.isOsr()); |
|
289 } |
|
290 |
|
291 protected final boolean isCompilable(int compLevel) { |
|
292 return WHITE_BOX |
|
293 .isMethodCompilable(method, compLevel, testCase.isOsr()); |
|
294 } |
|
295 |
|
296 protected final void makeNotCompilable() { |
|
297 WHITE_BOX.makeMethodNotCompilable(method, COMP_LEVEL_ANY, |
|
298 testCase.isOsr()); |
|
299 } |
|
300 |
|
301 protected final void makeNotCompilable(int compLevel) { |
|
302 WHITE_BOX.makeMethodNotCompilable(method, compLevel, testCase.isOsr()); |
|
303 } |
|
304 |
|
305 /** |
|
306 * Waits for completion of background compilation of {@linkplain #method}. |
|
307 */ |
|
308 protected final void waitBackgroundCompilation() { |
|
309 waitBackgroundCompilation(method); |
|
310 } |
|
311 |
|
312 /** |
|
313 * Waits for completion of background compilation of the given executable. |
|
314 * |
|
315 * @param executable Executable |
|
316 */ |
|
317 public static final void waitBackgroundCompilation(Executable executable) { |
|
318 if (!BACKGROUND_COMPILATION) { |
|
319 return; |
|
320 } |
|
321 final Object obj = new Object(); |
|
322 for (int i = 0; i < 100 |
|
323 && WHITE_BOX.isMethodQueuedForCompilation(executable); ++i) { |
|
324 synchronized (obj) { |
|
325 try { |
|
326 obj.wait(100); |
|
327 } catch (InterruptedException e) { |
|
328 Thread.currentThread().interrupt(); |
|
329 } |
|
330 } |
|
331 } |
|
332 } |
|
333 |
|
334 /** |
|
335 * Prints information about {@linkplain #method}. |
|
336 */ |
|
337 protected final void printInfo() { |
|
338 System.out.printf("%n%s:%n", method); |
|
339 System.out.printf("\tcompilable:\t%b%n", |
|
340 WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY, false)); |
|
341 boolean isCompiled = WHITE_BOX.isMethodCompiled(method, false); |
|
342 System.out.printf("\tcompiled:\t%b%n", isCompiled); |
|
343 if (isCompiled) { |
|
344 System.out.printf("\tcompile_id:\t%d%n", |
|
345 NMethod.get(method, false).compile_id); |
|
346 } |
|
347 System.out.printf("\tcomp_level:\t%d%n", |
|
348 WHITE_BOX.getMethodCompilationLevel(method, false)); |
|
349 System.out.printf("\tosr_compilable:\t%b%n", |
|
350 WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY, true)); |
|
351 isCompiled = WHITE_BOX.isMethodCompiled(method, true); |
|
352 System.out.printf("\tosr_compiled:\t%b%n", isCompiled); |
|
353 if (isCompiled) { |
|
354 System.out.printf("\tosr_compile_id:\t%d%n", |
|
355 NMethod.get(method, true).compile_id); |
|
356 } |
|
357 System.out.printf("\tosr_comp_level:\t%d%n", |
|
358 WHITE_BOX.getMethodCompilationLevel(method, true)); |
|
359 System.out.printf("\tin_queue:\t%b%n", |
|
360 WHITE_BOX.isMethodQueuedForCompilation(method)); |
|
361 System.out.printf("compile_queues_size:\t%d%n%n", |
|
362 WHITE_BOX.getCompileQueuesSize()); |
|
363 } |
|
364 |
|
365 /** |
|
366 * Executes testing. |
|
367 */ |
|
368 protected abstract void test() throws Exception; |
|
369 |
|
370 /** |
|
371 * Tries to trigger compilation of {@linkplain #method} by call |
|
372 * {@linkplain TestCase#getCallable()} enough times. |
|
373 * |
|
374 * @return accumulated result |
|
375 * @see #compile(int) |
|
376 */ |
|
377 protected final int compile() throws Exception { |
|
378 if (USE_COUNTER_DECAY) { |
|
379 throw new Exception("Tests using compile method must turn off counter decay for reliability"); |
|
380 } |
|
381 if (testCase.isOsr()) { |
|
382 return compile(1); |
|
383 } else { |
|
384 return compile(THRESHOLD); |
|
385 } |
|
386 } |
|
387 |
|
388 /** |
|
389 * Tries to trigger compilation of {@linkplain #method} by call |
|
390 * {@linkplain TestCase#getCallable()} specified times. |
|
391 * |
|
392 * @param count invocation count |
|
393 * @return accumulated result |
|
394 */ |
|
395 protected final int compile(int count) { |
|
396 int result = 0; |
|
397 Integer tmp; |
|
398 for (int i = 0; i < count; ++i) { |
|
399 try { |
|
400 tmp = testCase.getCallable().call(); |
|
401 } catch (Exception e) { |
|
402 tmp = null; |
|
403 } |
|
404 result += tmp == null ? 0 : tmp; |
|
405 } |
|
406 if (IS_VERBOSE) { |
|
407 System.out.println("method was invoked " + count + " times"); |
|
408 } |
|
409 return result; |
|
410 } |
|
411 |
|
412 /** |
|
413 * Utility interface provides tested method and object to invoke it. |
|
414 */ |
|
415 public interface TestCase { |
|
416 /** the name of test case */ |
|
417 String name(); |
|
418 |
|
419 /** tested method */ |
|
420 Executable getExecutable(); |
|
421 |
|
422 /** object to invoke {@linkplain #getExecutable()} */ |
|
423 Callable<Integer> getCallable(); |
|
424 |
|
425 /** flag for OSR test case */ |
|
426 boolean isOsr(); |
|
427 } |
|
428 |
|
429 /** |
|
430 * @return {@code true} if the current test case is OSR and the mode is |
|
431 * Xcomp, otherwise {@code false} |
|
432 */ |
|
433 protected boolean skipXcompOSR() { |
|
434 boolean result = testCase.isOsr() && Platform.isComp(); |
|
435 if (result && IS_VERBOSE) { |
|
436 System.err.printf("Warning: %s is not applicable in %s%n", |
|
437 testCase.name(), Platform.vmInfo); |
|
438 } |
|
439 return result; |
|
440 } |
|
441 |
|
442 /** |
|
443 * Skip the test for the specified value of Tiered Compilation |
|
444 * @param value of TieredCompilation the test should not run with |
|
445 * @return {@code true} if the test should be skipped, |
|
446 * {@code false} otherwise |
|
447 */ |
|
448 public static boolean skipOnTieredCompilation(boolean value) { |
|
449 if (value == CompilerWhiteBoxTest.TIERED_COMPILATION) { |
|
450 System.err.println("Test isn't applicable w/ " |
|
451 + (value ? "enabled" : "disabled") |
|
452 + "TieredCompilation. Skip test."); |
|
453 return true; |
|
454 } |
|
455 return false; |
|
456 } |
|
457 } |
|
458 |