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