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