8059575: JEP-JDK-8043304: Test task: Tiered Compilation level transition tests
Reviewed-by: iveresov, thartmann
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/tiered/ConstantGettersTransitionsTest.java Sat Dec 13 01:24:07 2014 +0300
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.reflect.Executable;
+import java.util.concurrent.Callable;
+
+/**
+ * @test ConstantGettersTransitionsTest
+ * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @build TransitionsTestExecutor ConstantGettersTransitionsTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm/timeout=240 -Xmixed -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ * -XX:+WhiteBoxAPI -XX:+TieredCompilation
+ * -XX:CompileCommand=compileonly,ConstantGettersTestCase$TrivialMethods::*
+ * TransitionsTestExecutor ConstantGettersTransitionsTest
+ * @summary Test the correctness of compilation level transitions for constant getters methods
+ */
+public class ConstantGettersTransitionsTest extends LevelTransitionTest {
+ public static void main(String[] args) {
+ assert (!CompilerWhiteBoxTest.skipOnTieredCompilation(false));
+
+ // run test cases
+ for (TestCase testCase : ConstantGettersTestCase.values()) {
+ new ConstantGettersTransitionsTest(testCase).runTest();
+ }
+ }
+
+ @Override
+ protected boolean isTrivial() {
+ return true;
+ }
+
+ private ConstantGettersTransitionsTest(TestCase testCase) {
+ super(testCase);
+ }
+}
+
+enum ConstantGettersTestCase implements CompilerWhiteBoxTest.TestCase {
+ ICONST_M1,
+ ICONST_0,
+ ICONST_1,
+ ICONST_2,
+ ICONST_3,
+ ICONST_4,
+ ICONST_5,
+ LCONST_0,
+ LCONST_1,
+ FCONST_0,
+ FCONST_1,
+ FCONST_2,
+ DCONST_0,
+ DCONST_1,
+ DCONST_W,
+ BYTE,
+ SHORT,
+ CHAR;
+
+ private final Executable executable;
+ private final Callable<Integer> callable;
+
+ @Override
+ public Executable getExecutable() {
+ return executable;
+ }
+
+ @Override
+ public Callable<Integer> getCallable() {
+ return callable;
+ }
+
+ @Override
+ public boolean isOsr() {
+ return false;
+ }
+
+ private ConstantGettersTestCase() {
+ String name = "make" + this.name();
+ this.executable = LevelTransitionTest.Helper.getMethod(TrivialMethods.class, name);
+ this.callable = LevelTransitionTest.Helper.getCallable(new TrivialMethods(), name);
+ }
+
+ /**
+ * Contains methods that load constants with certain types of bytecodes
+ * See JVMS 2.11.2. Load and Store Instructions
+ * Note that it doesn't have a method for ldc_w instruction
+ */
+ private static class TrivialMethods {
+ public static int makeICONST_M1() {
+ return -1;
+ }
+
+ public static int makeICONST_0() {
+ return 0;
+ }
+
+ public static int makeICONST_1() {
+ return 1;
+ }
+
+ public static int makeICONST_2() {
+ return 2;
+ }
+
+ public static int makeICONST_3() {
+ return 3;
+ }
+
+ public static int makeICONST_4() {
+ return 4;
+ }
+
+ public static int makeICONST_5() {
+ return 5;
+ }
+
+ public static long makeLCONST_0() {
+ return 0L;
+ }
+
+ public static long makeLCONST_1() {
+ return 1L;
+ }
+
+ public static float makeFCONST_0() {
+ return 0F;
+ }
+
+ public static float makeFCONST_1() {
+ return 1F;
+ }
+
+ public static float makeFCONST_2() {
+ return 2F;
+ }
+
+ public static double makeDCONST_0() {
+ return 0D;
+ }
+
+ public static double makeDCONST_1() {
+ return 1D;
+ }
+
+ public static double makeDCONST_W() {
+ // ldc2_w
+ return Double.MAX_VALUE;
+ }
+
+ public static Object makeOBJECT() {
+ // aconst_null
+ return null;
+ }
+
+ public static byte makeBYTE() {
+ // bipush
+ return (byte) 0x7F;
+ }
+
+ public static short makeSHORT() {
+ // sipush
+ return (short) 0x7FFF;
+ }
+
+ public static char makeCHAR() {
+ // ldc
+ return (char) 0xFFFF;
+ }
+
+ public static boolean makeBOOLEAN() {
+ return true;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/tiered/LevelTransitionTest.java Sat Dec 13 01:24:07 2014 +0300
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.reflect.Executable;
+import java.lang.reflect.Method;
+import java.util.Objects;
+import java.util.concurrent.Callable;
+
+/**
+ * @test LevelTransitionTest
+ * @library /testlibrary /../../test/lib /compiler/whitebox
+ * @build TransitionsTestExecutor LevelTransitionTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm/timeout=240 -Xmixed -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ * -XX:+WhiteBoxAPI -XX:+TieredCompilation
+ * -XX:CompileCommand=compileonly,SimpleTestCase$Helper::*
+ * -XX:CompileCommand=compileonly,ExtendedTestCase$CompileMethodHolder::*
+ * TransitionsTestExecutor LevelTransitionTest
+ * @summary Test the correctness of compilation level transitions for different methods
+ */
+public class LevelTransitionTest extends TieredLevelsTest {
+ /** Shows if method was profiled by being executed on levels 2 or 3 */
+ protected boolean isMethodProfiled;
+ private int transitionCount;
+
+ public static void main(String[] args) throws Throwable {
+ assert (!CompilerWhiteBoxTest.skipOnTieredCompilation(false));
+
+ CompilerWhiteBoxTest.main(LevelTransitionTest::new, args);
+ // run extended test cases
+ for (TestCase testCase : ExtendedTestCase.values()) {
+ new LevelTransitionTest(testCase).runTest();
+ }
+ }
+
+ protected LevelTransitionTest(TestCase testCase) {
+ super(testCase);
+ isMethodProfiled = testCase.isOsr(); // OSR methods were already profiled by warmup
+ transitionCount = 0;
+ }
+
+ @Override
+ protected void test() throws Exception {
+ checkTransitions();
+ deoptimize();
+ printInfo();
+ if (testCase.isOsr()) {
+ // deoptimization makes the following transitions be unstable
+ // methods go to level 3 before 4 because of uncommon_trap and reprofile
+ return;
+ }
+ checkTransitions();
+ }
+
+ /**
+ * Makes and verifies transitions between compilation levels
+ */
+ protected void checkTransitions() {
+ checkNotCompiled();
+ boolean finish = false;
+ while (!finish) {
+ System.out.printf("Level transition #%d%n", ++transitionCount);
+ int newLevel;
+ int current = getCompLevel();
+ int expected = getNextLevel(current);
+ if (current == expected) {
+ // if we are on expected level, just execute it more
+ // to ensure that the level won't change
+ System.out.printf("Method %s is already on expected level %d%n", method, expected);
+ compile();
+ newLevel = getCompLevel();
+ finish = true;
+ } else {
+ newLevel = changeCompLevel();
+ finish = false;
+ }
+ System.out.printf("Method %s is compiled on level %d. Expected level is %d%n", method, newLevel, expected);
+ checkLevel(expected, newLevel);
+ printInfo();
+ };
+ }
+
+ /**
+ * Gets next expected level for the test case on each transition.
+ *
+ * @param currentLevel a level the test case is compiled on
+ * @return expected compilation level
+ */
+ protected int getNextLevel(int currentLevel) {
+ int nextLevel = currentLevel;
+ switch (currentLevel) {
+ case CompilerWhiteBoxTest.COMP_LEVEL_NONE:
+ nextLevel = isMethodProfiled ? CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION
+ : CompilerWhiteBoxTest.COMP_LEVEL_FULL_PROFILE;
+ break;
+ case CompilerWhiteBoxTest.COMP_LEVEL_LIMITED_PROFILE:
+ case CompilerWhiteBoxTest.COMP_LEVEL_FULL_PROFILE:
+ nextLevel = CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION;
+ isMethodProfiled = true;
+ break;
+ }
+ nextLevel = isTrivial() ? CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE : nextLevel;
+ return Math.min(nextLevel, CompilerWhiteBoxTest.TIERED_STOP_AT_LEVEL);
+ }
+
+ /**
+ * Determines if tested method should be handled as trivial
+ *
+ * @return {@code true} for trivial methods, {@code false} otherwise
+ */
+ protected boolean isTrivial() {
+ return testCase == ExtendedTestCase.ACCESSOR_TEST
+ || testCase == SimpleTestCase.METHOD_TEST
+ || testCase == SimpleTestCase.STATIC_TEST
+ || (testCase == ExtendedTestCase.TRIVIAL_CODE_TEST && isMethodProfiled);
+ }
+
+ /**
+ * Invokes {@linkplain #method} until its compilation level is changed.
+ * Note that if the level won't change, it will be an endless loop
+ *
+ * @return compilation level the {@linkplain #method} was compiled on
+ */
+ protected int changeCompLevel() {
+ int currentLevel = getCompLevel();
+ int newLevel = currentLevel;
+ int result = 0;
+ while (currentLevel == newLevel) {
+ result = compile(1);
+ if (WHITE_BOX.isMethodCompiled(method, testCase.isOsr())) {
+ newLevel = getCompLevel();
+ }
+ }
+ return newLevel;
+ }
+
+ protected static class Helper {
+ /**
+ * Gets method from a specified class using its name
+ *
+ * @param aClass type method belongs to
+ * @param name the name of the method
+ * @return {@link Method} that represents corresponding class method
+ */
+ public static Method getMethod(Class<?> aClass, String name) {
+ Method method;
+ try {
+ method = aClass.getDeclaredMethod(name);
+ } catch (NoSuchMethodException e) {
+ throw new Error("TESTBUG: Unable to get method " + name, e);
+ }
+ return method;
+ }
+
+ /**
+ * Gets {@link Callable} that invokes given method from the given object
+ *
+ * @param object the object the specified method is invoked from
+ * @param name the name of the method
+ */
+ public static Callable<Integer> getCallable(Object object, String name) {
+ Method method = getMethod(object.getClass(), name);
+ return () -> {
+ try {
+ return Objects.hashCode(method.invoke(object));
+ } catch (ReflectiveOperationException e) {
+ throw new Error("TESTBUG: Invocation failure", e);
+ }
+ };
+ }
+ }
+}
+
+enum ExtendedTestCase implements CompilerWhiteBoxTest.TestCase {
+ ACCESSOR_TEST("accessor"),
+ NONTRIVIAL_METHOD_TEST("nonTrivialMethod"),
+ TRIVIAL_CODE_TEST("trivialCode");
+
+ private final Executable executable;
+ private final Callable<Integer> callable;
+
+ @Override
+ public Executable getExecutable() {
+ return executable;
+ }
+
+ @Override
+ public Callable<Integer> getCallable() {
+ return callable;
+ }
+
+ @Override
+ public boolean isOsr() {
+ return false;
+ }
+
+ private ExtendedTestCase(String methodName) {
+ this.executable = LevelTransitionTest.Helper.getMethod(CompileMethodHolder.class, methodName);
+ this.callable = LevelTransitionTest.Helper.getCallable(new CompileMethodHolder(), methodName);
+ }
+
+ private static class CompileMethodHolder {
+ private final int iter = 10;
+ private int field = 42;
+
+ /** Non-trivial method for threshold policy: contains loops */
+ public int nonTrivialMethod() {
+ int acc = 0;
+ for (int i = 0; i < iter; i++) {
+ acc += i;
+ }
+ return acc;
+ }
+
+ /** Field accessor method */
+ public int accessor() {
+ return field;
+ }
+
+ /** Method considered as trivial by amount of code */
+ public int trivialCode() {
+ int var = 0xBAAD_C0DE;
+ var *= field;
+ return var;
+ }
+ }
+}
--- a/hotspot/test/compiler/tiered/NonTieredLevelsTest.java Fri Dec 12 08:40:19 2014 -0800
+++ b/hotspot/test/compiler/tiered/NonTieredLevelsTest.java Sat Dec 13 01:24:07 2014 +0300
@@ -55,9 +55,7 @@
}
public static void main(String[] args) throws Exception {
- if (TIERED_COMPILATION) {
- System.err.println("Test isn't applicable w/ enabled "
- + "TieredCompilation. Skip test.");
+ if (CompilerWhiteBoxTest.skipOnTieredCompilation(true)) {
return;
}
CompilerWhiteBoxTest.main(NonTieredLevelsTest::new, args);
--- a/hotspot/test/compiler/tiered/TieredLevelsTest.java Fri Dec 12 08:40:19 2014 -0800
+++ b/hotspot/test/compiler/tiered/TieredLevelsTest.java Sat Dec 13 01:24:07 2014 +0300
@@ -35,16 +35,14 @@
* @author igor.ignatyev@oracle.com
*/
public class TieredLevelsTest extends CompLevelsTest {
- public static void main(String[] args) throws Exception {
- if (!TIERED_COMPILATION) {
- System.err.println("Test isn't applicable w/ disabled "
- + "TieredCompilation. Skip test.");
+ public static void main(String[] args) throws Exception, Throwable {
+ if (CompilerWhiteBoxTest.skipOnTieredCompilation(false)) {
return;
}
CompilerWhiteBoxTest.main(TieredLevelsTest::new, args);
}
- private TieredLevelsTest(TestCase testCase) {
+ protected TieredLevelsTest(TestCase testCase) {
super(testCase);
// to prevent inlining of #method
WHITE_BOX.testSetDontInlineMethod(method, true);
@@ -77,14 +75,18 @@
}
}
-
@Override
protected void checkLevel(int expected, int actual) {
if (expected == COMP_LEVEL_FULL_PROFILE
&& actual == COMP_LEVEL_LIMITED_PROFILE) {
// for simple method full_profile may be replaced by limited_profile
+ if (IS_VERBOSE) {
+ System.out.printf("Level check: full profiling was replaced "
+ + "by limited profiling. Expected: %d, actual:%d",
+ expected, actual);
+ }
return;
}
super.checkLevel(expected, actual);
- }
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/tiered/TransitionsTestExecutor.java Sat Dec 13 01:24:07 2014 +0300
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.ProcessTools;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Executes given test in a separate VM with enabled Tiered Compilation for
+ * CompilationPolicyChoice 2 and 3
+ */
+public class TransitionsTestExecutor {
+ public static void main(String[] args) throws Throwable {
+ if (CompilerWhiteBoxTest.skipOnTieredCompilation(false)) {
+ return;
+ }
+ if (args.length != 1) {
+ throw new Error("TESTBUG: Test name should be specified");
+ }
+ executeTestFor(2, args[0]);
+ executeTestFor(3, args[0]);
+ }
+
+ private static void executeTestFor(int compilationPolicy, String testName) throws Throwable {
+ String policy = "-XX:CompilationPolicyChoice=" + compilationPolicy;
+
+ // Get runtime arguments including VM options given to this executor
+ RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
+ List<String> vmArgs = runtime.getInputArguments();
+
+ // Construct execution command with compilation policy choice and test name
+ List<String> args = new ArrayList<>(vmArgs);
+ Collections.addAll(args, policy, testName);
+
+ OutputAnalyzer out = ProcessTools.executeTestJvm(args.toArray(new String[args.size()]));
+ int exitCode = out.getExitValue();
+ if (exitCode != 0) {
+ throw new Error("Test execution failed with exit code " + exitCode);
+ }
+ }
+}
--- a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java Fri Dec 12 08:40:19 2014 -0800
+++ b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java Sat Dec 13 01:24:07 2014 +0300
@@ -38,19 +38,19 @@
*/
public abstract class CompilerWhiteBoxTest {
/** {@code CompLevel::CompLevel_none} -- Interpreter */
- protected static int COMP_LEVEL_NONE = 0;
+ protected static final int COMP_LEVEL_NONE = 0;
/** {@code CompLevel::CompLevel_any}, {@code CompLevel::CompLevel_all} */
- protected static int COMP_LEVEL_ANY = -1;
+ protected static final int COMP_LEVEL_ANY = -1;
/** {@code CompLevel::CompLevel_simple} -- C1 */
- protected static int COMP_LEVEL_SIMPLE = 1;
+ protected static final int COMP_LEVEL_SIMPLE = 1;
/** {@code CompLevel::CompLevel_limited_profile} -- C1, invocation & backedge counters */
- protected static int COMP_LEVEL_LIMITED_PROFILE = 2;
+ protected static final int COMP_LEVEL_LIMITED_PROFILE = 2;
/** {@code CompLevel::CompLevel_full_profile} -- C1, invocation & backedge counters + mdo */
- protected static int COMP_LEVEL_FULL_PROFILE = 3;
+ protected static final int COMP_LEVEL_FULL_PROFILE = 3;
/** {@code CompLevel::CompLevel_full_optimization} -- C2 or Shark */
- protected static int COMP_LEVEL_FULL_OPTIMIZATION = 4;
+ protected static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
/** Maximal value for CompLevel */
- protected static int COMP_LEVEL_MAX = COMP_LEVEL_FULL_OPTIMIZATION;
+ protected static final int COMP_LEVEL_MAX = COMP_LEVEL_FULL_OPTIMIZATION;
/** Instance of WhiteBox */
protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
@@ -336,14 +336,22 @@
System.out.printf("%n%s:%n", method);
System.out.printf("\tcompilable:\t%b%n",
WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY, false));
- System.out.printf("\tcompiled:\t%b%n",
- WHITE_BOX.isMethodCompiled(method, false));
+ boolean isCompiled = WHITE_BOX.isMethodCompiled(method, false);
+ System.out.printf("\tcompiled:\t%b%n", isCompiled);
+ if (isCompiled) {
+ System.out.printf("\tcompile_id:\t%d%n",
+ NMethod.get(method, false).compile_id);
+ }
System.out.printf("\tcomp_level:\t%d%n",
WHITE_BOX.getMethodCompilationLevel(method, false));
System.out.printf("\tosr_compilable:\t%b%n",
WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY, true));
- System.out.printf("\tosr_compiled:\t%b%n",
- WHITE_BOX.isMethodCompiled(method, true));
+ isCompiled = WHITE_BOX.isMethodCompiled(method, true);
+ System.out.printf("\tosr_compiled:\t%b%n", isCompiled);
+ if (isCompiled) {
+ System.out.printf("\tosr_compile_id:\t%d%n",
+ NMethod.get(method, true).compile_id);
+ }
System.out.printf("\tosr_comp_level:\t%d%n",
WHITE_BOX.getMethodCompilationLevel(method, true));
System.out.printf("\tin_queue:\t%b%n",
@@ -426,6 +434,22 @@
}
return result;
}
+
+ /**
+ * Skip the test for the specified value of Tiered Compilation
+ * @param value of TieredCompilation the test should not run with
+ * @return {@code true} if the test should be skipped,
+ * {@code false} otherwise
+ */
+ protected static boolean skipOnTieredCompilation(boolean value) {
+ if (value == CompilerWhiteBoxTest.TIERED_COMPILATION) {
+ System.err.println("Test isn't applicable w/ "
+ + (value ? "enabled" : "disabled")
+ + "TieredCompilation. Skip test.");
+ return true;
+ }
+ return false;
+ }
}
enum SimpleTestCase implements CompilerWhiteBoxTest.TestCase {