test/compiler/tiered/LevelTransitionTest.java

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

mercurial