1 /* 2 * Copyright (c) 2013, 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 package compiler.whitebox; 25 26 import sun.hotspot.WhiteBox; 27 import sun.hotspot.code.NMethod; 28 29 import java.lang.reflect.Executable; 30 import java.util.Objects; 31 import java.util.concurrent.Callable; 32 import java.util.function.Function; 33 34 /** 35 * Abstract class for WhiteBox testing of JIT. 36 * 37 * @author igor.ignatyev@oracle.com 38 */ 39 public abstract class CompilerWhiteBoxTest { 40 /** {@code CompLevel::CompLevel_none} -- Interpreter */ 41 public static final int COMP_LEVEL_NONE = 0; 42 /** {@code CompLevel::CompLevel_any}, {@code CompLevel::CompLevel_all} */ 43 public static final int COMP_LEVEL_ANY = -1; 44 /** {@code CompLevel::CompLevel_simple} -- C1 */ 45 public static final int COMP_LEVEL_SIMPLE = 1; 46 /** {@code CompLevel::CompLevel_limited_profile} -- C1, invocation & backedge counters */ 47 public static final int COMP_LEVEL_LIMITED_PROFILE = 2; 48 /** {@code CompLevel::CompLevel_full_profile} -- C1, invocation & backedge counters + mdo */ 49 public static final int COMP_LEVEL_FULL_PROFILE = 3; 50 /** {@code CompLevel::CompLevel_full_optimization} -- C2 or Shark */ 51 public static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; 52 /** Maximal value for CompLevel */ 53 public static final int COMP_LEVEL_MAX = COMP_LEVEL_FULL_OPTIMIZATION; 54 55 /** Instance of WhiteBox */ 56 protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 57 /** Value of {@code -XX:CompileThreshold} */ 58 protected static final int COMPILE_THRESHOLD 59 = Integer.parseInt(getVMOption("CompileThreshold", "10000")); 60 /** Value of {@code -XX:BackgroundCompilation} */ 61 protected static final boolean BACKGROUND_COMPILATION 62 = Boolean.valueOf(getVMOption("BackgroundCompilation", "true")); 63 protected static final boolean USE_COUNTER_DECAY 64 = Boolean.valueOf(getVMOption("UseCounterDecay", "true")); 65 /** Value of {@code -XX:TieredCompilation} */ 66 protected static final boolean TIERED_COMPILATION 67 = Boolean.valueOf(getVMOption("TieredCompilation", "false")); 68 /** Value of {@code -XX:TieredStopAtLevel} */ 69 protected static final int TIERED_STOP_AT_LEVEL 70 = Integer.parseInt(getVMOption("TieredStopAtLevel", "0")); 71 /** Flag for verbose output, true if {@code -Dverbose} specified */ 72 protected static final boolean IS_VERBOSE 73 = System.getProperty("verbose") != null; 74 /** invocation count to trigger compilation */ 75 public static final int THRESHOLD; 76 /** invocation count to trigger OSR compilation */ 77 protected static final long BACKEDGE_THRESHOLD; 78 /** Value of {@code java.vm.info} (interpreted|mixed|comp mode) */ 79 protected static final String MODE = System.getProperty("java.vm.info"); 80 81 static { 82 if (TIERED_COMPILATION) { 83 BACKEDGE_THRESHOLD = THRESHOLD = 150000; 84 } else { 85 THRESHOLD = COMPILE_THRESHOLD; 86 BACKEDGE_THRESHOLD = COMPILE_THRESHOLD * Long.parseLong(getVMOption( 87 "OnStackReplacePercentage")); 88 } 89 } 90 91 /** 92 * Returns value of VM option. 93 * 94 * @param name option's name 95 * @return value of option or {@code null}, if option doesn't exist 96 * @throws NullPointerException if name is null 97 */ 98 protected static String getVMOption(String name) { 99 Objects.requireNonNull(name); 100 return Objects.toString(WHITE_BOX.getVMFlag(name), null); 101 } 102 103 /** 104 * Returns value of VM option or default value. 105 * 106 * @param name option's name 107 * @param defaultValue default value 108 * @return value of option or {@code defaultValue}, if option doesn't exist 109 * @throws NullPointerException if name is null 110 * @see #getVMOption(String) 111 */ 112 protected static String getVMOption(String name, String defaultValue) { 113 String result = getVMOption(name); 114 return result == null ? defaultValue : result; 115 } 116 117 /** copy of is_c1_compile(int) from utilities/globalDefinitions.hpp */ 118 protected static boolean isC1Compile(int compLevel) { 119 return (compLevel > COMP_LEVEL_NONE) 120 && (compLevel < COMP_LEVEL_FULL_OPTIMIZATION); 121 } 122 123 /** copy of is_c2_compile(int) from utilities/globalDefinitions.hpp */ 124 protected static boolean isC2Compile(int compLevel) { 125 return compLevel == COMP_LEVEL_FULL_OPTIMIZATION; 126 } 127 128 protected static void main( 129 Function<TestCase, CompilerWhiteBoxTest> constructor, 130 String[] args) { 131 if (args.length == 0) { 132 for (TestCase test : SimpleTestCase.values()) { 133 constructor.apply(test).runTest(); 134 } 135 } else { 136 for (String name : args) { 137 constructor.apply(SimpleTestCase.valueOf(name)).runTest(); 138 } 139 } 140 } 141 142 /** tested method */ 143 protected final Executable method; 144 protected final TestCase testCase; 145 146 /** 147 * Constructor. 148 * 149 * @param testCase object, that contains tested method and way to invoke it. 150 */ 151 protected CompilerWhiteBoxTest(TestCase testCase) { 152 Objects.requireNonNull(testCase); 153 System.out.println("TEST CASE:" + testCase.name()); 154 method = testCase.getExecutable(); 155 this.testCase = testCase; 156 } 157 158 /** 159 * Template method for testing. Prints tested method's info before 160 * {@linkplain #test()} and after {@linkplain #test()} or on thrown 161 * exception. 162 * 163 * @throws RuntimeException if method {@linkplain #test()} throws any 164 * exception 165 * @see #test() 166 */ 167 protected final void runTest() { 168 if (CompilerWhiteBoxTest.MODE.startsWith("interpreted ")) { 169 System.err.println( 170 "Warning: test is not applicable in interpreted mode"); 171 return; 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() 435 && CompilerWhiteBoxTest.MODE.startsWith("compiled "); 436 if (result && IS_VERBOSE) { 437 System.err.printf("Warning: %s is not applicable in %s%n", 438 testCase.name(), CompilerWhiteBoxTest.MODE); 439 } 440 return result; 441 } 442 443 /** 444 * Skip the test for the specified value of Tiered Compilation 445 * @param value of TieredCompilation the test should not run with 446 * @return {@code true} if the test should be skipped, 447 * {@code false} otherwise 448 */ 449 public static boolean skipOnTieredCompilation(boolean value) { 450 if (value == CompilerWhiteBoxTest.TIERED_COMPILATION) { 451 System.err.println("Test isn't applicable w/ " 452 + (value ? "enabled" : "disabled") 453 + "TieredCompilation. Skip test."); 454 return true; 455 } 456 return false; 457 } 458 } 459