test/compiler/whitebox/CompilerWhiteBoxTest.java

Thu, 17 Apr 2014 16:09:08 -0700

author
amurillo
date
Thu, 17 Apr 2014 16:09:08 -0700
changeset 6635
49b5160951dd
parent 6612
5e6f84e7a942
child 6876
710a3c8b516e
child 7318
c88a4554854c
permissions
-rw-r--r--

Added tag hs25.20-b11 for changeset b6a2ba7d3ea7

     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  */
    24 import com.sun.management.HotSpotDiagnosticMXBean;
    25 import com.sun.management.VMOption;
    26 import sun.hotspot.WhiteBox;
    27 import sun.hotspot.code.NMethod;
    28 import sun.management.ManagementFactoryHelper;
    30 import java.lang.reflect.Constructor;
    31 import java.lang.reflect.Executable;
    32 import java.lang.reflect.Method;
    33 import java.util.Objects;
    34 import java.util.concurrent.Callable;
    35 import java.util.function.Function;
    37 /**
    38  * Abstract class for WhiteBox testing of JIT.
    39  *
    40  * @author igor.ignatyev@oracle.com
    41  */
    42 public abstract class CompilerWhiteBoxTest {
    43     /** {@code CompLevel::CompLevel_none} -- Interpreter */
    44     protected static int COMP_LEVEL_NONE = 0;
    45     /** {@code CompLevel::CompLevel_any}, {@code CompLevel::CompLevel_all} */
    46     protected static int COMP_LEVEL_ANY = -1;
    47     /** {@code CompLevel::CompLevel_simple} -- C1 */
    48     protected static int COMP_LEVEL_SIMPLE = 1;
    49     /** {@code CompLevel::CompLevel_limited_profile} -- C1, invocation & backedge counters */
    50     protected static int COMP_LEVEL_LIMITED_PROFILE = 2;
    51     /** {@code CompLevel::CompLevel_full_profile} -- C1, invocation & backedge counters + mdo */
    52     protected static int COMP_LEVEL_FULL_PROFILE = 3;
    53     /** {@code CompLevel::CompLevel_full_optimization} -- C2 or Shark */
    54     protected static int COMP_LEVEL_FULL_OPTIMIZATION = 4;
    55     /** Maximal value for CompLevel */
    56     protected static int COMP_LEVEL_MAX = COMP_LEVEL_FULL_OPTIMIZATION;
    58     /** Instance of WhiteBox */
    59     protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
    60     /** Value of {@code -XX:CompileThreshold} */
    61     protected static final int COMPILE_THRESHOLD
    62             = Integer.parseInt(getVMOption("CompileThreshold", "10000"));
    63     /** Value of {@code -XX:BackgroundCompilation} */
    64     protected static final boolean BACKGROUND_COMPILATION
    65             = Boolean.valueOf(getVMOption("BackgroundCompilation", "true"));
    66     /** Value of {@code -XX:TieredCompilation} */
    67     protected static final boolean TIERED_COMPILATION
    68             = Boolean.valueOf(getVMOption("TieredCompilation", "false"));
    69     /** Value of {@code -XX:TieredStopAtLevel} */
    70     protected static final int TIERED_STOP_AT_LEVEL
    71             = Integer.parseInt(getVMOption("TieredStopAtLevel", "0"));
    72     /** Flag for verbose output, true if {@code -Dverbose} specified */
    73     protected static final boolean IS_VERBOSE
    74             = System.getProperty("verbose") != null;
    75     /** count of invocation to triger compilation */
    76     protected static final int THRESHOLD;
    77     /** count of invocation to triger OSR compilation */
    78     protected static final long BACKEDGE_THRESHOLD;
    79     /** Value of {@code java.vm.info} (interpreted|mixed|comp mode) */
    80     protected static final String MODE = System.getProperty("java.vm.info");
    82     static {
    83         if (TIERED_COMPILATION) {
    84             BACKEDGE_THRESHOLD = THRESHOLD = 150000;
    85         } else {
    86             THRESHOLD = COMPILE_THRESHOLD;
    87             BACKEDGE_THRESHOLD = COMPILE_THRESHOLD * Long.parseLong(getVMOption(
    88                     "OnStackReplacePercentage"));
    89         }
    90     }
    92     /**
    93      * Returns value of VM option.
    94      *
    95      * @param name option's name
    96      * @return value of option or {@code null}, if option doesn't exist
    97      * @throws NullPointerException if name is null
    98      */
    99     protected static String getVMOption(String name) {
   100         Objects.requireNonNull(name);
   101         HotSpotDiagnosticMXBean diagnostic
   102                 = ManagementFactoryHelper.getDiagnosticMXBean();
   103         VMOption tmp;
   104         try {
   105             tmp = diagnostic.getVMOption(name);
   106         } catch (IllegalArgumentException e) {
   107             tmp = null;
   108         }
   109         return (tmp == null ? null : tmp.getValue());
   110     }
   112     /**
   113      * Returns value of VM option or default value.
   114      *
   115      * @param name         option's name
   116      * @param defaultValue default value
   117      * @return value of option or {@code defaultValue}, if option doesn't exist
   118      * @throws NullPointerException if name is null
   119      * @see #getVMOption(String)
   120      */
   121     protected static String getVMOption(String name, String defaultValue) {
   122         String result = getVMOption(name);
   123         return result == null ? defaultValue : result;
   124     }
   126     /** copy of is_c1_compile(int) from utilities/globalDefinitions.hpp */
   127     protected static boolean isC1Compile(int compLevel) {
   128         return (compLevel > COMP_LEVEL_NONE)
   129                 && (compLevel < COMP_LEVEL_FULL_OPTIMIZATION);
   130     }
   132     /** copy of is_c2_compile(int) from utilities/globalDefinitions.hpp */
   133     protected static boolean isC2Compile(int compLevel) {
   134         return compLevel == COMP_LEVEL_FULL_OPTIMIZATION;
   135     }
   137     protected static void main(
   138             Function<TestCase, CompilerWhiteBoxTest> constructor,
   139             String[] args) {
   140         if (args.length == 0) {
   141             for (TestCase test : SimpleTestCase.values()) {
   142                 constructor.apply(test).runTest();
   143             }
   144         } else {
   145             for (String name : args) {
   146                 constructor.apply(SimpleTestCase.valueOf(name)).runTest();
   147             }
   148         }
   149     }
   151     /** tested method */
   152     protected final Executable method;
   153     protected final TestCase testCase;
   155     /**
   156      * Constructor.
   157      *
   158      * @param testCase object, that contains tested method and way to invoke it.
   159      */
   160     protected CompilerWhiteBoxTest(TestCase testCase) {
   161         Objects.requireNonNull(testCase);
   162         System.out.println("TEST CASE:" + testCase.name());
   163         method = testCase.getExecutable();
   164         this.testCase = testCase;
   165     }
   167     /**
   168      * Template method for testing. Prints tested method's info before
   169      * {@linkplain #test()} and after {@linkplain #test()} or on thrown
   170      * exception.
   171      *
   172      * @throws RuntimeException if method {@linkplain #test()} throws any
   173      *                          exception
   174      * @see #test()
   175      */
   176     protected final void runTest() {
   177         if (ManagementFactoryHelper.getCompilationMXBean() == null) {
   178             System.err.println(
   179                     "Warning: test is not applicable in interpreted mode");
   180             return;
   181         }
   182         System.out.println("at test's start:");
   183         printInfo();
   184         try {
   185             test();
   186         } catch (Exception e) {
   187             System.out.printf("on exception '%s':", e.getMessage());
   188             printInfo();
   189             e.printStackTrace();
   190             if (e instanceof RuntimeException) {
   191                 throw (RuntimeException) e;
   192             }
   193             throw new RuntimeException(e);
   194         }
   195         System.out.println("at test's end:");
   196         printInfo();
   197     }
   199     /**
   200      * Checks, that {@linkplain #method} is not compiled at the given compilation
   201      * level or above.
   202      *
   203      * @param compLevel
   204      *
   205      * @throws RuntimeException if {@linkplain #method} is in compiler queue or
   206      *                          is compiled, or if {@linkplain #method} has zero
   207      *                          compilation level.
   208      */
   210     protected final void checkNotCompiled(int compLevel) {
   211         if (WHITE_BOX.isMethodQueuedForCompilation(method)) {
   212             throw new RuntimeException(method + " must not be in queue");
   213         }
   214         if (WHITE_BOX.getMethodCompilationLevel(method, false) >= compLevel) {
   215             throw new RuntimeException(method + " comp_level must be >= maxCompLevel");
   216         }
   217         if (WHITE_BOX.getMethodCompilationLevel(method, true) >= compLevel) {
   218             throw new RuntimeException(method + " osr_comp_level must be >= maxCompLevel");
   219         }
   220     }
   222     /**
   223      * Checks, that {@linkplain #method} is not compiled.
   224      *
   225      * @throws RuntimeException if {@linkplain #method} is in compiler queue or
   226      *                          is compiled, or if {@linkplain #method} has zero
   227      *                          compilation level.
   228      */
   229     protected final void checkNotCompiled() {
   230         if (WHITE_BOX.isMethodQueuedForCompilation(method)) {
   231             throw new RuntimeException(method + " must not be in queue");
   232         }
   233         if (WHITE_BOX.isMethodCompiled(method, false)) {
   234             throw new RuntimeException(method + " must be not compiled");
   235         }
   236         if (WHITE_BOX.getMethodCompilationLevel(method, false) != 0) {
   237             throw new RuntimeException(method + " comp_level must be == 0");
   238         }
   239         if (WHITE_BOX.isMethodCompiled(method, true)) {
   240             throw new RuntimeException(method + " must be not osr_compiled");
   241         }
   242         if (WHITE_BOX.getMethodCompilationLevel(method, true) != 0) {
   243             throw new RuntimeException(method + " osr_comp_level must be == 0");
   244         }
   245     }
   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     }
   274     protected final void deoptimize() {
   275         WHITE_BOX.deoptimizeMethod(method, testCase.isOsr());
   276         if (testCase.isOsr()) {
   277             WHITE_BOX.deoptimizeMethod(method, false);
   278         }
   279     }
   281     protected final int getCompLevel() {
   282         NMethod nm = NMethod.get(method, testCase.isOsr());
   283         return nm == null ? COMP_LEVEL_NONE : nm.comp_level;
   284     }
   286     protected final boolean isCompilable() {
   287         return WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY,
   288                 testCase.isOsr());
   289     }
   291     protected final boolean isCompilable(int compLevel) {
   292         return WHITE_BOX
   293                 .isMethodCompilable(method, compLevel, testCase.isOsr());
   294     }
   296     protected final void makeNotCompilable() {
   297         WHITE_BOX.makeMethodNotCompilable(method, COMP_LEVEL_ANY,
   298                 testCase.isOsr());
   299     }
   301     protected final void makeNotCompilable(int compLevel) {
   302         WHITE_BOX.makeMethodNotCompilable(method, compLevel, testCase.isOsr());
   303     }
   305     /**
   306      * Waits for completion of background compilation of {@linkplain #method}.
   307      */
   308     protected final void waitBackgroundCompilation() {
   309         if (!BACKGROUND_COMPILATION) {
   310             return;
   311         }
   312         final Object obj = new Object();
   313         for (int i = 0; i < 10
   314                 && WHITE_BOX.isMethodQueuedForCompilation(method); ++i) {
   315             synchronized (obj) {
   316                 try {
   317                     obj.wait(1000);
   318                 } catch (InterruptedException e) {
   319                     Thread.currentThread().interrupt();
   320                 }
   321             }
   322         }
   323     }
   325     /**
   326      * Prints information about {@linkplain #method}.
   327      */
   328     protected final void printInfo() {
   329         System.out.printf("%n%s:%n", method);
   330         System.out.printf("\tcompilable:\t%b%n",
   331                 WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY, false));
   332         System.out.printf("\tcompiled:\t%b%n",
   333                 WHITE_BOX.isMethodCompiled(method, false));
   334         System.out.printf("\tcomp_level:\t%d%n",
   335                 WHITE_BOX.getMethodCompilationLevel(method, false));
   336         System.out.printf("\tosr_compilable:\t%b%n",
   337                 WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY, true));
   338         System.out.printf("\tosr_compiled:\t%b%n",
   339                 WHITE_BOX.isMethodCompiled(method, true));
   340         System.out.printf("\tosr_comp_level:\t%d%n",
   341                 WHITE_BOX.getMethodCompilationLevel(method, true));
   342         System.out.printf("\tin_queue:\t%b%n",
   343                 WHITE_BOX.isMethodQueuedForCompilation(method));
   344         System.out.printf("compile_queues_size:\t%d%n%n",
   345                 WHITE_BOX.getCompileQueuesSize());
   346     }
   348     /**
   349      * Executes testing.
   350      */
   351     protected abstract void test() throws Exception;
   353     /**
   354      * Tries to trigger compilation of {@linkplain #method} by call
   355      * {@linkplain TestCase#getCallable()} enough times.
   356      *
   357      * @return accumulated result
   358      * @see #compile(int)
   359      */
   360     protected final int compile() {
   361         if (testCase.isOsr()) {
   362             return compile(1);
   363         } else {
   364             return compile(THRESHOLD);
   365         }
   366     }
   368     /**
   369      * Tries to trigger compilation of {@linkplain #method} by call
   370      * {@linkplain TestCase#getCallable()} specified times.
   371      *
   372      * @param count invocation count
   373      * @return accumulated result
   374      */
   375     protected final int compile(int count) {
   376         int result = 0;
   377         Integer tmp;
   378         for (int i = 0; i < count; ++i) {
   379             try {
   380                 tmp = testCase.getCallable().call();
   381             } catch (Exception e) {
   382                 tmp = null;
   383             }
   384             result += tmp == null ? 0 : tmp;
   385         }
   386         if (IS_VERBOSE) {
   387             System.out.println("method was invoked " + count + " times");
   388         }
   389         return result;
   390     }
   392     /**
   393      * Utility interface provides tested method and object to invoke it.
   394      */
   395     public interface TestCase {
   396         /** the name of test case */
   397         String name();
   399         /** tested method */
   400         Executable getExecutable();
   402         /** object to invoke {@linkplain #getExecutable()} */
   403         Callable<Integer> getCallable();
   405         /** flag for OSR test case */
   406         boolean isOsr();
   407     }
   409     /**
   410      * @return {@code true} if the current test case is OSR and the mode is
   411      *          Xcomp, otherwise {@code false}
   412      */
   413     protected boolean skipXcompOSR() {
   414         boolean result =  testCase.isOsr()
   415                 && CompilerWhiteBoxTest.MODE.startsWith("compiled ");
   416         if (result && IS_VERBOSE) {
   417             System.err.printf("Warning: %s is not applicable in %s%n",
   418                     testCase.name(), CompilerWhiteBoxTest.MODE);
   419         }
   420         return result;
   421     }
   422 }
   424 enum SimpleTestCase implements CompilerWhiteBoxTest.TestCase {
   425     /** constructor test case */
   426     CONSTRUCTOR_TEST(Helper.CONSTRUCTOR, Helper.CONSTRUCTOR_CALLABLE, false),
   427     /** method test case */
   428     METOD_TEST(Helper.METHOD, Helper.METHOD_CALLABLE, false),
   429     /** static method test case */
   430     STATIC_TEST(Helper.STATIC, Helper.STATIC_CALLABLE, false),
   431     /** OSR constructor test case */
   432     OSR_CONSTRUCTOR_TEST(Helper.OSR_CONSTRUCTOR,
   433             Helper.OSR_CONSTRUCTOR_CALLABLE, true),
   434     /** OSR method test case */
   435     OSR_METOD_TEST(Helper.OSR_METHOD, Helper.OSR_METHOD_CALLABLE, true),
   436     /** OSR static method test case */
   437     OSR_STATIC_TEST(Helper.OSR_STATIC, Helper.OSR_STATIC_CALLABLE, true);
   439     private final Executable executable;
   440     private final Callable<Integer> callable;
   441     private final boolean isOsr;
   443     private SimpleTestCase(Executable executable, Callable<Integer> callable,
   444             boolean isOsr) {
   445         this.executable = executable;
   446         this.callable = callable;
   447         this.isOsr = isOsr;
   448     }
   450     @Override
   451     public Executable getExecutable() {
   452         return executable;
   453     }
   455     @Override
   456     public Callable<Integer> getCallable() {
   457         return callable;
   458     }
   460     @Override
   461     public boolean isOsr() {
   462         return isOsr;
   463     }
   465     private static class Helper {
   467         private static final Callable<Integer> CONSTRUCTOR_CALLABLE
   468                 = new Callable<Integer>() {
   469             @Override
   470             public Integer call() throws Exception {
   471                 return new Helper(1337).hashCode();
   472             }
   473         };
   475         private static final Callable<Integer> METHOD_CALLABLE
   476                 = new Callable<Integer>() {
   477             private final Helper helper = new Helper();
   479             @Override
   480             public Integer call() throws Exception {
   481                 return helper.method();
   482             }
   483         };
   485         private static final Callable<Integer> STATIC_CALLABLE
   486                 = new Callable<Integer>() {
   487             @Override
   488             public Integer call() throws Exception {
   489                 return staticMethod();
   490             }
   491         };
   493         private static final Callable<Integer> OSR_CONSTRUCTOR_CALLABLE
   494                 = new Callable<Integer>() {
   495             @Override
   496             public Integer call() throws Exception {
   497                 return new Helper(null).hashCode();
   498             }
   499         };
   501         private static final Callable<Integer> OSR_METHOD_CALLABLE
   502                 = new Callable<Integer>() {
   503             private final Helper helper = new Helper();
   505             @Override
   506             public Integer call() throws Exception {
   507                 return helper.osrMethod();
   508             }
   509         };
   511         private static final Callable<Integer> OSR_STATIC_CALLABLE
   512                 = new Callable<Integer>() {
   513             @Override
   514             public Integer call() throws Exception {
   515                 return osrStaticMethod();
   516             }
   517         };
   519         private static final Constructor CONSTRUCTOR;
   520         private static final Constructor OSR_CONSTRUCTOR;
   521         private static final Method METHOD;
   522         private static final Method STATIC;
   523         private static final Method OSR_METHOD;
   524         private static final Method OSR_STATIC;
   526         static {
   527             try {
   528                 CONSTRUCTOR = Helper.class.getDeclaredConstructor(int.class);
   529             } catch (NoSuchMethodException | SecurityException e) {
   530                 throw new RuntimeException(
   531                         "exception on getting method Helper.<init>(int)", e);
   532             }
   533             try {
   534                 OSR_CONSTRUCTOR = Helper.class.getDeclaredConstructor(
   535                         Object.class);
   536             } catch (NoSuchMethodException | SecurityException e) {
   537                 throw new RuntimeException(
   538                         "exception on getting method Helper.<init>(Object)", e);
   539             }
   540             METHOD = getMethod("method");
   541             STATIC = getMethod("staticMethod");
   542             OSR_METHOD = getMethod("osrMethod");
   543             OSR_STATIC = getMethod("osrStaticMethod");
   544         }
   546         private static Method getMethod(String name) {
   547             try {
   548                 return Helper.class.getDeclaredMethod(name);
   549             } catch (NoSuchMethodException | SecurityException e) {
   550                 throw new RuntimeException(
   551                         "exception on getting method Helper." + name, e);
   552             }
   554         }
   556         private static int staticMethod() {
   557             return 1138;
   558         }
   560         private int method() {
   561             return 42;
   562         }
   564         private static int osrStaticMethod() {
   565             int result = 0;
   566             for (long i = 0; i < CompilerWhiteBoxTest.BACKEDGE_THRESHOLD; ++i) {
   567                 result += staticMethod();
   568             }
   569             return result;
   570         }
   572         private int osrMethod() {
   573             int result = 0;
   574             for (long i = 0; i < CompilerWhiteBoxTest.BACKEDGE_THRESHOLD; ++i) {
   575                 result += method();
   576             }
   577             return result;
   578         }
   580         private final int x;
   582         // for method and OSR method test case
   583         public Helper() {
   584             x = 0;
   585         }
   587         // for OSR constructor test case
   588         private Helper(Object o) {
   589             int result = 0;
   590             for (long i = 0; i < CompilerWhiteBoxTest.BACKEDGE_THRESHOLD; ++i) {
   591                 result += method();
   592             }
   593             x = result;
   594         }
   596         // for constructor test case
   597         private Helper(int x) {
   598             this.x = x;
   599         }
   601         @Override
   602         public int hashCode() {
   603             return x;
   604         }
   605     }
   606 }

mercurial