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: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 <ExprClassName> <iterations> 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 }