1 /*
  2  * Copyright (c) 2014, 2024, 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 package compiler.intrinsics.bmi;
 25 
 26 import jdk.test.lib.Asserts;
 27 import jdk.test.lib.process.OutputAnalyzer;
 28 import jdk.test.lib.process.ProcessTools;
 29 import jdk.test.lib.Utils;
 30 
 31 import java.io.IOException;
 32 import java.nio.file.Files;
 33 import java.nio.file.Paths;
 34 import java.util.Collections;
 35 import java.util.LinkedList;
 36 import java.util.List;
 37 import 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  */
 45 public 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      * </ul>
 63      *
 64      * @param expr operation that should be tested
 65      * @param testOpts options to control test behaviour
 66      * @param additionalVMOpts additional options for VM
 67      *
 68      * @throws Throwable if test failed.
 69      */
 70     public static void runTests(Class<? extends Expr> expr,
 71                                 String testOpts[],
 72                                 String... additionalVMOpts)
 73                          throws Throwable {
 74 
 75         // ensure seed got printed out
 76         Utils.getRandomInstance();
 77         long seed = Utils.SEED;
 78         int iterations = DEFAULT_ITERATIONS_COUNT;
 79 
 80         for (String testOption : testOpts) {
 81             if (testOption.startsWith("-iterations=")) {
 82                 iterations = Integer.valueOf(testOption.
 83                                              replace("-iterations=", ""));
 84             }
 85         }
 86 
 87         OutputAnalyzer intOutput = runTest(expr, VMMode.INT,
 88                                            additionalVMOpts,
 89                                            seed, iterations);
 90         OutputAnalyzer compOutput = runTest(expr, VMMode.COMP,
 91                                             additionalVMOpts,
 92                                             seed, iterations);
 93 
 94         dumpOutput(intOutput, "int");
 95         dumpOutput(compOutput, "comp");
 96 
 97         Asserts.assertStringsEqual(intOutput.getStdout(),
 98                                    compOutput.getStdout(),
 99                                    "Results obtained in -Xint and " +
100                                    "-Xcomp should be the same.");
101     }
102 
103     /**
104      * Execute tests on methods implemented by <b>expr</b> in new VM
105      * started in <b>testVMMode</b> mode.
106      *
107      * @param expr operation that should be tested
108      * @param testVMMode VM mode for test
109      * @param additionalVMOpts additional options for VM
110      * @param seed for RNG used it tests
111      * @param iterations that will be used to invoke <b>expr</b>'s methods.
112      *
113      * @return OutputAnalyzer for executed test.
114      * @throws Throwable when something goes wrong.
115      */
116     public static OutputAnalyzer runTest(Class<? extends Expr> expr,
117                                          VMMode testVMMode,
118                                          String additionalVMOpts[],
119                                          long seed, int iterations)
120                                   throws Throwable {
121 
122         List<String> vmOpts = new LinkedList<String>();
123 
124         Collections.addAll(vmOpts, additionalVMOpts);
125         // Hide timestamps from warnings (e.g. due to potential AOT
126         // saved/runtime state mismatch), to avoid false positives when
127         // comparing output across runs.
128         vmOpts.add("-Xlog:all=warning:stdout:level,tags");
129         vmOpts.add("-Xlog:aot=off");
130 
131         //setup mode-specific options
132         switch (testVMMode) {
133         case INT:
134             Collections.addAll(vmOpts, new String[] { "-Xint" });
135             break;
136         case COMP:
137             Collections.addAll(vmOpts, new String[] {
138                     "-Xcomp",
139                     "-XX:-TieredCompilation",
140                     String.format("-XX:CompileCommand=compileonly,%s::*",
141                                   expr.getName())
142                 });
143             break;
144         }
145 
146         Collections.addAll(vmOpts, new String[] {
147                 "-XX:+DisplayVMOutputToStderr",
148                 "-D" + Utils.SEED_PROPERTY_NAME + "=" + seed,
149                 Executor.class.getName(),
150                 expr.getName(),
151                 new Integer(iterations).toString()
152             });
153 
154         OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava(vmOpts);
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             runUnaryIntToLongRegTest(expr, iterations, rng);
227             runBinaryRegRegIntTest(expr, iterations, rng);
228             runBinaryRegMemIntTest(expr, iterations, rng);
229             runBinaryMemRegIntTest(expr, iterations, rng);
230             runBinaryMemMemIntTest(expr, iterations, rng);
231             runBinaryRegRegLongTest(expr, iterations, rng);
232             runBinaryRegMemLongTest(expr, iterations, rng);
233             runBinaryMemRegLongTest(expr, iterations, rng);
234             runBinaryMemMemLongTest(expr, iterations, rng);
235         }
236 
237         public static void runUnaryIntRegTest(Expr expr, int iterations,
238                                               Random rng) {
239             if (!(expr.isUnaryArgumentSupported()
240                   && expr.isIntExprSupported())) {
241                 return;
242             }
243 
244             for (int value : getIntBitShifts()) {
245                 log("UnaryIntReg(0X%x) -> 0X%x",
246                     value, expr.intExpr(value));
247             }
248 
249             for (int i = 0; i < iterations; i++) {
250                 int value = rng.nextInt();
251                 log("UnaryIntReg(0X%x) -> 0X%x",
252                     value, expr.intExpr(value));
253             }
254         }
255 
256         public static void runUnaryIntMemTest(Expr expr, int iterations,
257                                               Random rng) {
258             if (!(expr.isUnaryArgumentSupported()
259                   && expr.isIntExprSupported()
260                   && expr.isMemExprSupported())) {
261                 return;
262             }
263 
264             for (int value : getIntBitShifts()) {
265                 log("UnaryIntMem(0X%x) -> 0X%x",
266                     value, expr.intExpr(new Expr.MemI(value)));
267             }
268 
269             for (int i = 0; i < iterations; i++) {
270                 int value = rng.nextInt();
271                 log("UnaryIntMem(0X%x) -> 0X%x",
272                     value, expr.intExpr(new Expr.MemI(value)));
273             }
274         }
275 
276         public static void runUnaryLongRegTest(Expr expr, int iterations,
277                                                Random rng) {
278             if (!(expr.isUnaryArgumentSupported()
279                   && expr.isLongExprSupported())) {
280                 return;
281             }
282 
283             for (long value : getLongBitShifts()) {
284                 log("UnaryLongReg(0X%x) -> 0X%x",
285                     value, expr.longExpr(value));
286             }
287 
288             for (int i = 0; i < iterations; i++) {
289                 long value = rng.nextLong();
290                 log("UnaryLongReg(0X%x) -> 0X%x",
291                     value, expr.longExpr(value));
292             }
293         }
294 
295         public static void runUnaryLongMemTest(Expr expr, int iterations,
296                                                Random rng) {
297             if (!(expr.isUnaryArgumentSupported()
298                   && expr.isLongExprSupported()
299                   && expr.isMemExprSupported())) {
300                 return;
301             }
302 
303             for (long value : getLongBitShifts()) {
304                 log("UnaryLongMem(0X%x) -> 0X%x",
305                     value, expr.longExpr(new Expr.MemL(value)));
306             }
307 
308             for (int i = 0; i < iterations; i++) {
309                 long value = rng.nextLong();
310                 log("UnaryLongMem(0X%x) -> 0X%x",
311                     value, expr.longExpr(new Expr.MemL(value)));
312             }
313         }
314 
315         public static void runUnaryIntToLongRegTest(Expr expr, int iterations,
316                                                     Random rng) {
317             if (!(expr.isUnaryArgumentSupported()
318                   && expr.isIntToLongExprSupported())) {
319                 return;
320             }
321 
322             for (int value : getIntBitShifts()) {
323                 log("UnaryIntToLongReg(0X%x) -> 0X%x",
324                     value, expr.intToLongExpr(value));
325             }
326 
327             for (int i = 0; i < iterations; i++) {
328                 int value = rng.nextInt();
329                 log("UnaryIntToLongReg(0X%x) -> 0X%x",
330                     value, expr.intToLongExpr(value));
331             }
332         }
333 
334         public static void runBinaryRegRegIntTest(Expr expr, int iterations,
335                                                   Random rng) {
336             if (!(expr.isIntExprSupported()
337                   && expr.isBinaryArgumentSupported())) {
338                 return;
339             }
340 
341             for (int i = 0; i < iterations; i++) {
342                 int aValue = rng.nextInt();
343                 int bValue = rng.nextInt();
344                 log("BinaryIntRegReg(0X%x, 0X%x) -> 0X%x",
345                     aValue, bValue, expr.intExpr(aValue, bValue));
346             }
347         }
348 
349         public static void runBinaryRegMemIntTest(Expr expr, int iterations,
350                                                   Random rng) {
351             if (!(expr.isIntExprSupported()
352                   && expr.isBinaryArgumentSupported()
353                   && expr.isMemExprSupported())) {
354                 return;
355             }
356 
357             for (int i = 0; i < iterations; i++) {
358                 int aValue = rng.nextInt();
359                 int bValue = rng.nextInt();
360                 log("BinaryIntRegMem(0X%x, 0X%x) -> 0X%x", aValue, bValue,
361                     expr.intExpr(aValue, new Expr.MemI(bValue)));
362             }
363         }
364 
365         public static void runBinaryMemRegIntTest(Expr expr, int iterations,
366                                                   Random rng) {
367             if (!(expr.isIntExprSupported()
368                   && expr.isBinaryArgumentSupported()
369                   && expr.isMemExprSupported())) {
370                 return;
371             }
372 
373             for (int i = 0; i < iterations; i++) {
374                 int aValue = rng.nextInt();
375                 int bValue = rng.nextInt();
376                 log("BinaryIntMemReg(0X%x, 0X%x) -> 0X%x", aValue, bValue,
377                     expr.intExpr(new Expr.MemI(aValue), bValue));
378             }
379         }
380 
381         public static void runBinaryMemMemIntTest(Expr expr, int iterations,
382                                                   Random rng) {
383             if (!(expr.isIntExprSupported()
384                   && expr.isBinaryArgumentSupported()
385                   && expr.isMemExprSupported())) {
386                 return;
387             }
388 
389             for (int i = 0; i < iterations; i++) {
390                 int aValue = rng.nextInt();
391                 int bValue = rng.nextInt();
392                 log("BinaryIntMemMem(0X%x, 0X%x) -> 0X%x", aValue, bValue,
393                     expr.intExpr(new Expr.MemI(aValue),
394                                  new Expr.MemI(bValue)));
395             }
396         }
397 
398         public static void runBinaryRegRegLongTest(Expr expr,
399                                                    int iterations,
400                                                    Random rng) {
401             if (!(expr.isLongExprSupported()
402                   && expr.isBinaryArgumentSupported())) {
403                 return;
404             }
405 
406             for (int i = 0; i < iterations; i++) {
407                 long aValue = rng.nextLong();
408                 long bValue = rng.nextLong();
409                 log("BinaryLongRegReg(0X%x, 0X%x) -> 0X%x", aValue, bValue,
410                     expr.longExpr(aValue, bValue));
411             }
412         }
413 
414         public static void runBinaryRegMemLongTest(Expr expr,
415                                                    int iterations,
416                                                    Random rng) {
417             if (!(expr.isLongExprSupported()
418                   && expr.isBinaryArgumentSupported()
419                   && expr.isMemExprSupported())) {
420                 return;
421             }
422 
423             for (int i = 0; i < iterations; i++) {
424                 long aValue = rng.nextLong();
425                 long bValue = rng.nextLong();
426                 log("BinaryLongRegMem(0X%x, 0X%x) -> 0X%x", aValue, bValue,
427                     expr.longExpr(aValue, new Expr.MemL(bValue)));
428             }
429         }
430 
431         public static void runBinaryMemRegLongTest(Expr expr,
432                                                    int iterations,
433                                                    Random rng) {
434             if (!(expr.isLongExprSupported()
435                   && expr.isBinaryArgumentSupported()
436                   && expr.isMemExprSupported())) {
437                 return;
438             }
439 
440             for (int i = 0; i < iterations; i++) {
441                 long aValue = rng.nextLong();
442                 long bValue = rng.nextLong();
443                 log("BinaryLongMemReg(0X%x, 0X%x) -> 0X%x", aValue, bValue,
444                     expr.longExpr(new Expr.MemL(aValue), bValue));
445             }
446         }
447 
448         public static void runBinaryMemMemLongTest(Expr expr,
449                                                    int iterations,
450                                                    Random rng) {
451             if (!(expr.isLongExprSupported()
452                   && expr.isBinaryArgumentSupported()
453                   && expr.isMemExprSupported())) {
454                 return;
455             }
456 
457             for (int i = 0; i < iterations; i++) {
458                 long aValue = rng.nextLong();
459                 long bValue = rng.nextLong();
460                 log("BinaryLongMemMem(0X%x, 0X%x) -> 0X%x", aValue, bValue,
461                     expr.longExpr(new Expr.MemL(aValue),
462                                   new Expr.MemL(bValue)));
463             }
464         }
465     }
466 }