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 }