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=<N> 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,aot=off:stdout:level,tags");
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.executeTestJava(vmOpts);
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 <ExprClassName> <iterations>
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 runUnaryIntToLongRegTest(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 runUnaryIntToLongRegTest(Expr expr, int iterations,
315 Random rng) {
316 if (!(expr.isUnaryArgumentSupported()
317 && expr.isIntToLongExprSupported())) {
318 return;
319 }
320
321 for (int value : getIntBitShifts()) {
322 log("UnaryIntToLongReg(0X%x) -> 0X%x",
323 value, expr.intToLongExpr(value));
324 }
325
326 for (int i = 0; i < iterations; i++) {
327 int value = rng.nextInt();
328 log("UnaryIntToLongReg(0X%x) -> 0X%x",
329 value, expr.intToLongExpr(value));
330 }
331 }
332
333 public static void runBinaryRegRegIntTest(Expr expr, int iterations,
334 Random rng) {
335 if (!(expr.isIntExprSupported()
336 && expr.isBinaryArgumentSupported())) {
337 return;
338 }
339
340 for (int i = 0; i < iterations; i++) {
341 int aValue = rng.nextInt();
342 int bValue = rng.nextInt();
343 log("BinaryIntRegReg(0X%x, 0X%x) -> 0X%x",
344 aValue, bValue, expr.intExpr(aValue, bValue));
345 }
346 }
347
348 public static void runBinaryRegMemIntTest(Expr expr, int iterations,
349 Random rng) {
350 if (!(expr.isIntExprSupported()
351 && expr.isBinaryArgumentSupported()
352 && expr.isMemExprSupported())) {
353 return;
354 }
355
356 for (int i = 0; i < iterations; i++) {
357 int aValue = rng.nextInt();
358 int bValue = rng.nextInt();
359 log("BinaryIntRegMem(0X%x, 0X%x) -> 0X%x", aValue, bValue,
360 expr.intExpr(aValue, new Expr.MemI(bValue)));
361 }
362 }
363
364 public static void runBinaryMemRegIntTest(Expr expr, int iterations,
365 Random rng) {
366 if (!(expr.isIntExprSupported()
367 && expr.isBinaryArgumentSupported()
368 && expr.isMemExprSupported())) {
369 return;
370 }
371
372 for (int i = 0; i < iterations; i++) {
373 int aValue = rng.nextInt();
374 int bValue = rng.nextInt();
375 log("BinaryIntMemReg(0X%x, 0X%x) -> 0X%x", aValue, bValue,
376 expr.intExpr(new Expr.MemI(aValue), bValue));
377 }
378 }
379
380 public static void runBinaryMemMemIntTest(Expr expr, int iterations,
381 Random rng) {
382 if (!(expr.isIntExprSupported()
383 && expr.isBinaryArgumentSupported()
384 && expr.isMemExprSupported())) {
385 return;
386 }
387
388 for (int i = 0; i < iterations; i++) {
389 int aValue = rng.nextInt();
390 int bValue = rng.nextInt();
391 log("BinaryIntMemMem(0X%x, 0X%x) -> 0X%x", aValue, bValue,
392 expr.intExpr(new Expr.MemI(aValue),
393 new Expr.MemI(bValue)));
394 }
395 }
396
397 public static void runBinaryRegRegLongTest(Expr expr,
398 int iterations,
399 Random rng) {
400 if (!(expr.isLongExprSupported()
401 && expr.isBinaryArgumentSupported())) {
402 return;
403 }
404
405 for (int i = 0; i < iterations; i++) {
406 long aValue = rng.nextLong();
407 long bValue = rng.nextLong();
408 log("BinaryLongRegReg(0X%x, 0X%x) -> 0X%x", aValue, bValue,
409 expr.longExpr(aValue, bValue));
410 }
411 }
412
413 public static void runBinaryRegMemLongTest(Expr expr,
414 int iterations,
415 Random rng) {
416 if (!(expr.isLongExprSupported()
417 && expr.isBinaryArgumentSupported()
418 && expr.isMemExprSupported())) {
419 return;
420 }
421
422 for (int i = 0; i < iterations; i++) {
423 long aValue = rng.nextLong();
424 long bValue = rng.nextLong();
425 log("BinaryLongRegMem(0X%x, 0X%x) -> 0X%x", aValue, bValue,
426 expr.longExpr(aValue, new Expr.MemL(bValue)));
427 }
428 }
429
430 public static void runBinaryMemRegLongTest(Expr expr,
431 int iterations,
432 Random rng) {
433 if (!(expr.isLongExprSupported()
434 && expr.isBinaryArgumentSupported()
435 && expr.isMemExprSupported())) {
436 return;
437 }
438
439 for (int i = 0; i < iterations; i++) {
440 long aValue = rng.nextLong();
441 long bValue = rng.nextLong();
442 log("BinaryLongMemReg(0X%x, 0X%x) -> 0X%x", aValue, bValue,
443 expr.longExpr(new Expr.MemL(aValue), bValue));
444 }
445 }
446
447 public static void runBinaryMemMemLongTest(Expr expr,
448 int iterations,
449 Random rng) {
450 if (!(expr.isLongExprSupported()
451 && expr.isBinaryArgumentSupported()
452 && expr.isMemExprSupported())) {
453 return;
454 }
455
456 for (int i = 0; i < iterations; i++) {
457 long aValue = rng.nextLong();
458 long bValue = rng.nextLong();
459 log("BinaryLongMemMem(0X%x, 0X%x) -> 0X%x", aValue, bValue,
460 expr.longExpr(new Expr.MemL(aValue),
461 new Expr.MemL(bValue)));
462 }
463 }
464 }
465 }
--- EOF ---