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 
  25 import java.util.*;
  26 import java.io.IOException;
  27 import java.nio.file.Files;
  28 import java.nio.file.Paths;
  29 import java.nio.charset.StandardCharsets;
  30 
  31 import com.oracle.java.testlibrary.*;
  32 
  33 /**
  34  * Test runner that invokes all methods implemented by particular Expr
  35  * with random arguments in two different JVM processes and compares output.
  36  * JVMs being started in different modes - one in int and other in comp
  37  * with C2 and disabled tiered compilation.
  38  */
  39 public class BMITestRunner {
  40 
  41     enum VMMode {
  42         COMP, INT;
  43     };
  44 
  45     public static int DEFAULT_ITERATIONS_COUNT = 4000;
  46 
  47     /**
  48      * Execute all methods implemented by <b>expr</b> in int and comp modes
  49      * and compare output.
  50      * Test pass only of output obtained with different VM modes is equal.
  51      * To control behaviour of test following options could be passed:
  52      * <ul>
  53      *   <li>-iterations=&lt;N&gt; each operation implemented by
  54      *       <b>expr</b> will be executed <i>N</i> times. Default value
  55      *       is 4000.</li>
  56      *   <li>-seed=&lt;SEED&gt; arguments for <b>expr</b>'s methods
  57      *       obtained via RNG initiated with seed <i>SEED</i>. By default
  58      *       some random seed will be used.</li>
  59      * </ul>
  60      *
  61      * @param expr operation that should be tested
  62      * @param testOpts options to control test behaviour
  63      * @param additionalVMOpts additional options for VM
  64      *
  65      * @throws Throwable if test failed.
  66      */
  67     public static void runTests(Class<? extends Expr> expr,
  68                                 String testOpts[],
  69                                 String... additionalVMOpts)
  70                          throws Throwable {
  71 
  72         int seed = new Random().nextInt();
  73         int iterations = DEFAULT_ITERATIONS_COUNT;
  74 
  75         for (String testOption : testOpts) {
  76             if (testOption.startsWith("-iterations=")) {
  77                 iterations = Integer.valueOf(testOption.
  78                                              replace("-iterations=", ""));
  79             } else if (testOption.startsWith("-seed=")) {
  80                 seed = Integer.valueOf(testOption.replace("-seed=", ""));
  81             }
  82         }
  83 
  84         System.out.println("Running test with seed: " + seed);
  85 
  86         OutputAnalyzer intOutput = runTest(expr, VMMode.INT,
  87                                            additionalVMOpts,
  88                                            seed, iterations);
  89         OutputAnalyzer compOutput = runTest(expr, VMMode.COMP,
  90                                             additionalVMOpts,
  91                                             seed, iterations);
  92 
  93         dumpOutput(intOutput, "int");
  94         dumpOutput(compOutput, "comp");
  95 
  96         Asserts.assertStringsEqual(intOutput.getStdout(),
  97                                    compOutput.getStdout(),
  98                                    "Results obtained in -Xint and " +
  99                                    "-Xcomp should be the same.");
 100     }
 101 
 102     /**
 103      * Execute tests on methods implemented by <b>expr</b> in new VM
 104      * started in <b>testVMMode</b> mode.
 105      *
 106      * @param expr operation that should be tested
 107      * @param testVMMode VM mode for test
 108      * @param additionalVMOpts additional options for VM
 109      * @param seed for RNG used it tests
 110      * @param iterations that will be used to invoke <b>expr</b>'s methods.
 111      *
 112      * @return OutputAnalyzer for executed test.
 113      * @throws Throwable when something goes wrong.
 114      */
 115     public static OutputAnalyzer runTest(Class<? extends Expr> expr,
 116                                          VMMode testVMMode,
 117                                          String additionalVMOpts[],
 118                                          int seed, int iterations)
 119                                   throws Throwable {
 120 
 121         List<String> vmOpts = new LinkedList<String>();
 122 
 123         Collections.addAll(vmOpts, additionalVMOpts);
 124 
 125         //setup mode-specific options
 126         switch (testVMMode) {
 127         case INT:
 128             Collections.addAll(vmOpts, new String[] { "-Xint" });
 129             break;
 130         case COMP:
 131             Collections.addAll(vmOpts, new String[] {
 132                     "-Xcomp",
 133                     "-XX:-TieredCompilation",
 134                     String.format("-XX:CompileCommand=compileonly,%s::*",
 135                                   expr.getName())
 136                 });
 137             break;
 138         }
 139 
 140         Collections.addAll(vmOpts, new String[] {
 141                 "-XX:+DisplayVMOutputToStderr",
 142                 Executor.class.getName(),
 143                 expr.getName(),
 144                 new Integer(seed).toString(),
 145                 new Integer(iterations).toString()
 146             });
 147 
 148         OutputAnalyzer outputAnalyzer = ProcessTools.
 149             executeTestJvm(vmOpts.toArray(new String[vmOpts.size()]));
 150 
 151         outputAnalyzer.shouldHaveExitValue(0);
 152 
 153         return outputAnalyzer;
 154     }
 155 
 156     /**
 157      * Dump stdout and stderr of test process to <i>prefix</i>.test.out
 158      * and <i>prefix</i>.test.err respectively.
 159      *
 160      * @param outputAnalyzer OutputAnalyzer whom output should be dumped
 161      * @param prefix Prefix that will be used in file names.
 162      * @throws IOException if unable to dump output to file.
 163      */
 164     protected static void dumpOutput(OutputAnalyzer outputAnalyzer,
 165                                      String prefix)
 166                               throws IOException {
 167         Files.write(Paths.get(prefix + ".test.out"),
 168                     outputAnalyzer.getStdout().getBytes());
 169 
 170         Files.write(Paths.get(prefix + ".test.err"),
 171                     outputAnalyzer.getStderr().getBytes());
 172     }
 173 
 174 
 175     /**
 176      * Executor that invoke all methods implemented by particular
 177      * Expr instance.
 178      */
 179     public static class Executor {
 180 
 181         /**
 182          * Usage: BMITestRunner$Executor <ExprClassName> <seed> <iterations>
 183          */
 184         public static void main(String args[]) throws Exception {
 185             @SuppressWarnings("unchecked")
 186             Class<? extends Expr> exprClass =
 187                 (Class<? extends Expr>)Class.forName(args[0]);
 188             Expr expr = exprClass.getConstructor().newInstance();
 189             Random rng = new Random(Integer.valueOf(args[1]));
 190             int iterations = Integer.valueOf(args[2]);
 191             runTests(expr, iterations, rng);
 192         }
 193 
 194 
 195         public static int[] getIntBitShifts() {
 196             //SIZE+1 shift is for zero.
 197             int data[] = new int[Integer.SIZE+1];
 198             for (int s = 0; s < data.length; s++) {
 199                 data[s] = 1<<s;
 200             }
 201             return data;
 202         }
 203 
 204         public static long[] getLongBitShifts() {
 205             //SIZE+1 shift is for zero.
 206             long data[] = new long[Long.SIZE+1];
 207             for (int s = 0; s < data.length; s++) {
 208                 data[s] = 1L<<s;
 209             }
 210             return data;
 211         }
 212 
 213         public static void log(String format, Object... args) {
 214             System.out.println(String.format(format, args));
 215         }
 216 
 217         public static void runTests(Expr expr, int iterations, Random rng) {
 218             runUnaryIntRegTest(expr, iterations, rng);
 219             runUnaryIntMemTest(expr, iterations, rng);
 220             runUnaryLongRegTest(expr, iterations, rng);
 221             runUnaryLongMemTest(expr, iterations, rng);
 222             runBinaryRegRegIntTest(expr, iterations, rng);
 223             runBinaryRegMemIntTest(expr, iterations, rng);
 224             runBinaryMemRegIntTest(expr, iterations, rng);
 225             runBinaryMemMemIntTest(expr, iterations, rng);
 226             runBinaryRegRegLongTest(expr, iterations, rng);
 227             runBinaryRegMemLongTest(expr, iterations, rng);
 228             runBinaryMemRegLongTest(expr, iterations, rng);
 229             runBinaryMemMemLongTest(expr, iterations, rng);
 230         }
 231 
 232         public static void runUnaryIntRegTest(Expr expr, int iterations,
 233                                               Random rng) {
 234             if (!(expr.isUnaryArgumentSupported()
 235                   && expr.isIntExprSupported())) {
 236                 return;
 237             }
 238 
 239             for (int value : getIntBitShifts()) {
 240                 log("UnaryIntReg(0X%x) -> 0X%x",
 241                     value, expr.intExpr(value));
 242             }
 243 
 244             for (int i = 0; i < iterations; i++) {
 245                 int value = rng.nextInt();
 246                 log("UnaryIntReg(0X%x) -> 0X%x",
 247                     value, expr.intExpr(value));
 248             }
 249         }
 250 
 251         public static void runUnaryIntMemTest(Expr expr, int iterations,
 252                                               Random rng) {
 253             if (!(expr.isUnaryArgumentSupported()
 254                   && expr.isIntExprSupported()
 255                   && expr.isMemExprSupported())) {
 256                 return;
 257             }
 258 
 259             for (int value : getIntBitShifts()) {
 260                 log("UnaryIntMem(0X%x) -> 0X%x",
 261                     value, expr.intExpr(new Expr.MemI(value)));
 262             }
 263 
 264             for (int i = 0; i < iterations; i++) {
 265                 int value = rng.nextInt();
 266                 log("UnaryIntMem(0X%x) -> 0X%x",
 267                     value, expr.intExpr(new Expr.MemI(value)));
 268             }
 269         }
 270 
 271         public static void runUnaryLongRegTest(Expr expr, int iterations,
 272                                                Random rng) {
 273             if (!(expr.isUnaryArgumentSupported()
 274                   && expr.isLongExprSupported())) {
 275                 return;
 276             }
 277 
 278             for (long value : getLongBitShifts()) {
 279                 log("UnaryLongReg(0X%x) -> 0X%x",
 280                     value, expr.longExpr(value));
 281             }
 282 
 283             for (int i = 0; i < iterations; i++) {
 284                 long value = rng.nextLong();
 285                 log("UnaryLongReg(0X%x) -> 0X%x",
 286                     value, expr.longExpr(value));
 287             }
 288         }
 289 
 290         public static void runUnaryLongMemTest(Expr expr, int iterations,
 291                                                Random rng) {
 292             if (!(expr.isUnaryArgumentSupported()
 293                   && expr.isLongExprSupported()
 294                   && expr.isMemExprSupported())) {
 295                 return;
 296             }
 297 
 298             for (long value : getLongBitShifts()) {
 299                 log("UnaryLongMem(0X%x) -> 0X%x",
 300                     value, expr.longExpr(new Expr.MemL(value)));
 301             }
 302 
 303             for (int i = 0; i < iterations; i++) {
 304                 long value = rng.nextLong();
 305                 log("UnaryLongMem(0X%x) -> 0X%x",
 306                     value, expr.longExpr(new Expr.MemL(value)));
 307             }
 308         }
 309 
 310         public static void runBinaryRegRegIntTest(Expr expr, int iterations,
 311                                                   Random rng) {
 312             if (!(expr.isIntExprSupported()
 313                   && expr.isBinaryArgumentSupported())) {
 314                 return;
 315             }
 316 
 317             for (int i = 0; i < iterations; i++) {
 318                 int aValue = rng.nextInt();
 319                 int bValue = rng.nextInt();
 320                 log("BinaryIntRegReg(0X%x, 0X%x) -> 0X%x",
 321                     aValue, bValue, expr.intExpr(aValue, bValue));
 322             }
 323         }
 324 
 325         public static void runBinaryRegMemIntTest(Expr expr, int iterations,
 326                                                   Random rng) {
 327             if (!(expr.isIntExprSupported()
 328                   && expr.isBinaryArgumentSupported()
 329                   && expr.isMemExprSupported())) {
 330                 return;
 331             }
 332 
 333             for (int i = 0; i < iterations; i++) {
 334                 int aValue = rng.nextInt();
 335                 int bValue = rng.nextInt();
 336                 log("BinaryIntRegMem(0X%x, 0X%x) -> 0X%x", aValue, bValue,
 337                     expr.intExpr(aValue, new Expr.MemI(bValue)));
 338             }
 339         }
 340 
 341         public static void runBinaryMemRegIntTest(Expr expr, int iterations,
 342                                                   Random rng) {
 343             if (!(expr.isIntExprSupported()
 344                   && expr.isBinaryArgumentSupported()
 345                   && expr.isMemExprSupported())) {
 346                 return;
 347             }
 348 
 349             for (int i = 0; i < iterations; i++) {
 350                 int aValue = rng.nextInt();
 351                 int bValue = rng.nextInt();
 352                 log("BinaryIntMemReg(0X%x, 0X%x) -> 0X%x", aValue, bValue,
 353                     expr.intExpr(new Expr.MemI(aValue), bValue));
 354             }
 355         }
 356 
 357         public static void runBinaryMemMemIntTest(Expr expr, int iterations,
 358                                                   Random rng) {
 359             if (!(expr.isIntExprSupported()
 360                   && expr.isBinaryArgumentSupported()
 361                   && expr.isMemExprSupported())) {
 362                 return;
 363             }
 364 
 365             for (int i = 0; i < iterations; i++) {
 366                 int aValue = rng.nextInt();
 367                 int bValue = rng.nextInt();
 368                 log("BinaryIntMemMem(0X%x, 0X%x) -> 0X%x", aValue, bValue,
 369                     expr.intExpr(new Expr.MemI(aValue),
 370                                  new Expr.MemI(bValue)));
 371             }
 372         }
 373 
 374         public static void runBinaryRegRegLongTest(Expr expr,
 375                                                    int iterations,
 376                                                    Random rng) {
 377             if (!(expr.isLongExprSupported()
 378                   && expr.isBinaryArgumentSupported())) {
 379                 return;
 380             }
 381 
 382             for (int i = 0; i < iterations; i++) {
 383                 long aValue = rng.nextLong();
 384                 long bValue = rng.nextLong();
 385                 log("BinaryLongRegReg(0X%x, 0X%x) -> 0X%x", aValue, bValue,
 386                     expr.longExpr(aValue, bValue));
 387             }
 388         }
 389 
 390         public static void runBinaryRegMemLongTest(Expr expr,
 391                                                    int iterations,
 392                                                    Random rng) {
 393             if (!(expr.isLongExprSupported()
 394                   && expr.isBinaryArgumentSupported()
 395                   && expr.isMemExprSupported())) {
 396                 return;
 397             }
 398 
 399             for (int i = 0; i < iterations; i++) {
 400                 long aValue = rng.nextLong();
 401                 long bValue = rng.nextLong();
 402                 log("BinaryLongRegMem(0X%x, 0X%x) -> 0X%x", aValue, bValue,
 403                     expr.longExpr(aValue, new Expr.MemL(bValue)));
 404             }
 405         }
 406 
 407         public static void runBinaryMemRegLongTest(Expr expr,
 408                                                    int iterations,
 409                                                    Random rng) {
 410             if (!(expr.isLongExprSupported()
 411                   && expr.isBinaryArgumentSupported()
 412                   && expr.isMemExprSupported())) {
 413                 return;
 414             }
 415 
 416             for (int i = 0; i < iterations; i++) {
 417                 long aValue = rng.nextLong();
 418                 long bValue = rng.nextLong();
 419                 log("BinaryLongMemReg(0X%x, 0X%x) -> 0X%x", aValue, bValue,
 420                     expr.longExpr(new Expr.MemL(aValue), bValue));
 421             }
 422         }
 423 
 424         public static void runBinaryMemMemLongTest(Expr expr,
 425                                                    int iterations,
 426                                                    Random rng) {
 427             if (!(expr.isLongExprSupported()
 428                   && expr.isBinaryArgumentSupported()
 429                   && expr.isMemExprSupported())) {
 430                 return;
 431             }
 432 
 433             for (int i = 0; i < iterations; i++) {
 434                 long aValue = rng.nextLong();
 435                 long bValue = rng.nextLong();
 436                 log("BinaryLongMemMem(0X%x, 0X%x) -> 0X%x", aValue, bValue,
 437                     expr.longExpr(new Expr.MemL(aValue),
 438                                   new Expr.MemL(bValue)));
 439             }
 440         }
 441     }
 442 }