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 /** 25 * @test LevelTransitionTest 26 * @library /testlibrary /test/lib / 27 * @modules java.base/jdk.internal.misc 28 * java.management 29 * @ignore 8067651 30 * @build TransitionsTestExecutor LevelTransitionTest 31 * @run driver ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission 32 * @run main/othervm/timeout=240 -Xmixed -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions 33 * -XX:+WhiteBoxAPI -XX:+TieredCompilation 34 * -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCaseHelper::* 35 * -XX:CompileCommand=compileonly,ExtendedTestCase$CompileMethodHolder::* 36 * TransitionsTestExecutor LevelTransitionTest 37 * @summary Test the correctness of compilation level transitions for different methods 38 */ 39 40 import java.lang.reflect.Executable; 41 import java.lang.reflect.Method; 42 import java.util.Objects; 43 import java.util.concurrent.Callable; 44 import compiler.whitebox.CompilerWhiteBoxTest; 45 import compiler.whitebox.SimpleTestCase; 46 47 public class LevelTransitionTest extends TieredLevelsTest { 48 /** Shows if method was profiled by being executed on levels 2 or 3 */ 49 protected boolean isMethodProfiled; 50 private int transitionCount; 51 52 public static void main(String[] args) throws Throwable { 53 assert (!CompilerWhiteBoxTest.skipOnTieredCompilation(false)); 54 55 CompilerWhiteBoxTest.main(LevelTransitionTest::new, args); 56 // run extended test cases 57 for (TestCase testCase : ExtendedTestCase.values()) { 58 new LevelTransitionTest(testCase).runTest(); 59 } 60 } 61 62 protected LevelTransitionTest(TestCase testCase) { 63 super(testCase); 64 isMethodProfiled = testCase.isOsr(); // OSR methods were already profiled by warmup 65 transitionCount = 0; 66 } 67 68 @Override 69 protected void test() throws Exception { 70 checkTransitions(); 71 deoptimize(); 72 printInfo(); 73 if (testCase.isOsr()) { 74 // deoptimization makes the following transitions be unstable 75 // methods go to level 3 before 4 because of uncommon_trap and reprofile 76 return; 77 } 78 checkTransitions(); 79 } 80 81 /** 82 * Makes and verifies transitions between compilation levels 83 */ 84 protected void checkTransitions() throws Exception { 85 checkNotCompiled(); 86 boolean finish = false; 87 while (!finish) { 88 System.out.printf("Level transition #%d%n", ++transitionCount); 89 int newLevel; 90 int current = getCompLevel(); 91 int expected = getNextLevel(current); 92 if (current == expected) { 93 // if we are on expected level, just execute it more 94 // to ensure that the level won't change 95 System.out.printf("Method %s is already on expected level %d%n", method, expected); 96 compile(); 97 newLevel = getCompLevel(); 98 finish = true; 99 } else { 100 newLevel = changeCompLevel(); 101 finish = false; 102 } 103 System.out.printf("Method %s is compiled on level %d. Expected level is %d%n", method, newLevel, expected); 104 checkLevel(expected, newLevel); 105 printInfo(); 106 }; 107 } 108 109 /** 110 * Gets next expected level for the test case on each transition. 111 * 112 * @param currentLevel a level the test case is compiled on 113 * @return expected compilation level 114 */ 115 protected int getNextLevel(int currentLevel) { 116 int nextLevel = currentLevel; 117 switch (currentLevel) { 118 case CompilerWhiteBoxTest.COMP_LEVEL_NONE: 119 nextLevel = isMethodProfiled ? CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION 120 : CompilerWhiteBoxTest.COMP_LEVEL_FULL_PROFILE; 121 break; 122 case CompilerWhiteBoxTest.COMP_LEVEL_LIMITED_PROFILE: 123 case CompilerWhiteBoxTest.COMP_LEVEL_FULL_PROFILE: 124 nextLevel = CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION; 125 isMethodProfiled = true; 126 break; 127 } 128 nextLevel = isTrivial() ? CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE : nextLevel; 129 return Math.min(nextLevel, CompilerWhiteBoxTest.TIERED_STOP_AT_LEVEL); 130 } 131 132 /** 133 * Determines if tested method should be handled as trivial 134 * 135 * @return {@code true} for trivial methods, {@code false} otherwise 136 */ 137 protected boolean isTrivial() { 138 return testCase == ExtendedTestCase.ACCESSOR_TEST 139 || testCase == SimpleTestCase.METHOD_TEST 140 || testCase == SimpleTestCase.STATIC_TEST 141 || (testCase == ExtendedTestCase.TRIVIAL_CODE_TEST && isMethodProfiled); 142 } 143 144 /** 145 * Invokes {@linkplain #method} until its compilation level is changed. 146 * Note that if the level won't change, it will be an endless loop 147 * 148 * @return compilation level the {@linkplain #method} was compiled on 149 */ 150 protected int changeCompLevel() { 151 int currentLevel = getCompLevel(); 152 int newLevel = currentLevel; 153 int result = 0; 154 while (currentLevel == newLevel) { 155 result = compile(1); 156 if (WHITE_BOX.isMethodCompiled(method, testCase.isOsr())) { 157 newLevel = getCompLevel(); 158 } 159 } 160 return newLevel; 161 } 162 163 protected static class Helper { 164 /** 165 * Gets method from a specified class using its name 166 * 167 * @param aClass type method belongs to 168 * @param name the name of the method 169 * @return {@link Method} that represents corresponding class method 170 */ 171 public static Method getMethod(Class<?> aClass, String name) { 172 Method method; 173 try { 174 method = aClass.getDeclaredMethod(name); 175 } catch (NoSuchMethodException e) { 176 throw new Error("TESTBUG: Unable to get method " + name, e); 177 } 178 return method; 179 } 180 181 /** 182 * Gets {@link Callable} that invokes given method from the given object 183 * 184 * @param object the object the specified method is invoked from 185 * @param name the name of the method 186 */ 187 public static Callable<Integer> getCallable(Object object, String name) { 188 Method method = getMethod(object.getClass(), name); 189 return () -> { 190 try { 191 return Objects.hashCode(method.invoke(object)); 192 } catch (ReflectiveOperationException e) { 193 throw new Error("TESTBUG: Invocation failure", e); 194 } 195 }; 196 } 197 } 198 } 199 200 enum ExtendedTestCase implements CompilerWhiteBoxTest.TestCase { 201 ACCESSOR_TEST("accessor"), 202 NONTRIVIAL_METHOD_TEST("nonTrivialMethod"), 203 TRIVIAL_CODE_TEST("trivialCode"); 204 205 private final Executable executable; 206 private final Callable<Integer> callable; 207 208 @Override 209 public Executable getExecutable() { 210 return executable; 211 } 212 213 @Override 214 public Callable<Integer> getCallable() { 215 return callable; 216 } 217 218 @Override 219 public boolean isOsr() { 220 return false; 221 } 222 223 private ExtendedTestCase(String methodName) { 224 this.executable = LevelTransitionTest.Helper.getMethod(CompileMethodHolder.class, methodName); 225 this.callable = LevelTransitionTest.Helper.getCallable(new CompileMethodHolder(), methodName); 226 } 227 228 private static class CompileMethodHolder { 229 private final int iter = 10; 230 private int field = 42; 231 232 /** Non-trivial method for threshold policy: contains loops */ 233 public int nonTrivialMethod() { 234 int acc = 0; 235 for (int i = 0; i < iter; i++) { 236 acc += i; 237 } 238 return acc; 239 } 240 241 /** Field accessor method */ 242 public int accessor() { 243 return field; 244 } 245 246 /** Method considered as trivial by amount of code */ 247 public int trivialCode() { 248 int var = 0xBAAD_C0DE; 249 var *= field; 250 return var; 251 } 252 } 253 }