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