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