1 /* 2 * Copyright (c) 2009, 2012, 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 package com.oracle.graal.compiler.hsail.test.infra; 24 25 import static org.junit.Assert.*; 26 import static org.junit.Assume.*; 27 28 import java.io.*; 29 import java.lang.annotation.*; 30 import java.lang.reflect.*; 31 import java.nio.file.*; 32 import java.util.*; 33 import java.util.concurrent.atomic.*; 34 import java.util.logging.*; 35 36 import com.amd.okra.*; 37 38 /** 39 * Abstract class on which the HSAIL unit tests are built. Executes a method or lambda on both the 40 * Java side and the Okra side and compares the results for fields that are annotated with 41 * {@link KernelTester.Result}. 42 */ 43 public abstract class KernelTester { 44 45 /** 46 * Denotes a field whose value is to be compared as part of computing the result of a test. 47 */ 48 @Retention(RetentionPolicy.RUNTIME) 49 @Target(ElementType.FIELD) 50 public @interface Result { 51 } 52 53 // Using these in case we want to compile with Java 7. 54 public interface MyIntConsumer { 55 56 void accept(int value); 57 } 58 59 public interface MyObjConsumer { 60 61 void accept(Object obj); 62 } 63 64 public enum DispatchMode { 65 SEQ, JTP, OKRA 66 } 67 68 public enum HsailMode { 69 COMPILED, INJECT_HSAIL, INJECT_OCL 70 } 71 72 private DispatchMode dispatchMode; 73 // Where the hsail comes from. 74 private HsailMode hsailMode; 75 private Method testMethod; 76 // What type of okra dispatch to use when client calls. 77 private boolean useLambdaMethod; 78 private Class<?>[] testMethodParams = null; 79 private int id = nextId.incrementAndGet(); 80 static AtomicInteger nextId = new AtomicInteger(0); 81 public static Logger logger; 82 private OkraContext okraContext; 83 private OkraKernel okraKernel; 84 private static final String propPkgName = KernelTester.class.getPackage().getName(); 85 private static Level logLevel; 86 private static ConsoleHandler consoleHandler; 87 88 static { 89 logger = Logger.getLogger(propPkgName); 90 logLevel = Level.parse(System.getProperty("kerneltester.logLevel", "SEVERE")); 91 92 // This block configure the logger with handler and formatter. 93 consoleHandler = new ConsoleHandler(); 94 logger.addHandler(consoleHandler); 95 logger.setUseParentHandlers(false); 96 SimpleFormatter formatter = new SimpleFormatter() { 97 98 @SuppressWarnings("sync-override") 99 @Override 100 public String format(LogRecord record) { 101 return (record.getMessage() + "\n"); 102 } 103 }; 104 consoleHandler.setFormatter(formatter); 105 setLogLevel(logLevel); 106 } 107 108 private static boolean gaveNoOkraWarning = false; 109 private boolean onSimulator; 110 private boolean okraLibExists; 111 112 public boolean runningOnSimulator() { 113 return onSimulator; 114 } 115 116 public KernelTester() { 117 okraLibExists = OkraUtil.okraLibExists(); 118 dispatchMode = DispatchMode.SEQ; 119 hsailMode = HsailMode.COMPILED; 120 useLambdaMethod = false; 121 } 122 123 public abstract void runTest(); 124 125 // Default comparison is to compare all things marked @Result. 126 public boolean compareResults(KernelTester base) { 127 Class<?> clazz = this.getClass(); 128 while (clazz != null && clazz != KernelTester.class) { 129 for (Field f : clazz.getDeclaredFields()) { 130 if (!Modifier.isStatic(f.getModifiers())) { 131 Result annos = f.getAnnotation(Result.class); 132 if (annos != null) { 133 logger.fine("@Result field = " + f); 134 Object myResult = getFieldFromObject(f, this); 135 Object otherResult = getFieldFromObject(f, base); 136 boolean same = compareObjects(myResult, otherResult); 137 logger.fine("comparing " + myResult + ", " + otherResult + ", match=" + same); 138 if (!same) { 139 logger.severe("mismatch comparing " + f + ", " + myResult + " vs. " + otherResult); 140 logSevere("FAILED!!! " + this.getClass()); 141 return false; 142 } 143 } 144 } 145 } 146 clazz = clazz.getSuperclass(); 147 } 148 logInfo("PASSED: " + this.getClass()); 149 return true; 150 } 151 152 private boolean compareObjects(Object first, Object second) { 153 if (first == null) { 154 return (second == null); 155 } 156 if (second == null) { 157 return (first == null); 158 } 159 Class<?> clazz = first.getClass(); 160 if (clazz != second.getClass()) { 161 return false; 162 } 163 if (!clazz.isArray()) { 164 // Non arrays. 165 if (clazz.equals(float.class) || clazz.equals(double.class)) { 166 return isEqualsFP((double) first, (double) second); 167 } else { 168 return first.equals(second); 169 } 170 } else { 171 // Handle the case where Objects are arrays. 172 ArrayComparer comparer; 173 if (clazz.equals(float[].class) || clazz.equals(double[].class)) { 174 comparer = new FPArrayComparer(); 175 } else if (clazz.equals(long[].class) || clazz.equals(int[].class) || clazz.equals(byte[].class)) { 176 comparer = new IntArrayComparer(); 177 } else if (clazz.equals(boolean[].class)) { 178 comparer = new BooleanArrayComparer(); 179 } else { 180 comparer = new ObjArrayComparer(); 181 } 182 return comparer.compareArrays(first, second); 183 } 184 } 185 186 static final int MISMATCHLIMIT = 10; 187 static final int ELEMENTDISPLAYLIMIT = 20; 188 189 public int getMisMatchLimit() { 190 return MISMATCHLIMIT; 191 } 192 193 public int getElementDisplayLimit() { 194 return ELEMENTDISPLAYLIMIT; 195 } 196 197 abstract class ArrayComparer { 198 199 abstract Object getElement(Object ary, int index); 200 201 // Equality test, can be overridden 202 boolean isEquals(Object firstElement, Object secondElement) { 203 return firstElement.equals(secondElement); 204 } 205 206 boolean compareArrays(Object first, Object second) { 207 int len = Array.getLength(first); 208 if (len != Array.getLength(second)) { 209 return false; 210 } 211 // If info logLevel, build string of first few elements from first array. 212 if (logLevel.intValue() <= Level.INFO.intValue()) { 213 StringBuilder sb = new StringBuilder(); 214 for (int i = 0; i < Math.min(len, getElementDisplayLimit()); i++) { 215 sb.append(getElement(first, i)); 216 sb.append(", "); 217 } 218 logger.info(sb.toString()); 219 } 220 boolean success = true; 221 int mismatches = 0; 222 for (int i = 0; i < len; i++) { 223 Object firstElement = getElement(first, i); 224 Object secondElement = getElement(second, i); 225 if (!isEquals(firstElement, secondElement)) { 226 logSevere("mismatch at index " + i + ", expected " + secondElement + ", saw " + firstElement); 227 success = false; 228 mismatches++; 229 if (mismatches >= getMisMatchLimit()) { 230 logSevere("...Truncated"); 231 break; 232 } 233 } 234 } 235 return success; 236 } 237 } 238 239 class FPArrayComparer extends ArrayComparer { 240 241 @Override 242 Object getElement(Object ary, int index) { 243 return Array.getDouble(ary, index); 244 } 245 246 @Override 247 boolean isEquals(Object firstElement, Object secondElement) { 248 return isEqualsFP((double) firstElement, (double) secondElement); 249 } 250 } 251 252 class IntArrayComparer extends ArrayComparer { 253 254 @Override 255 Object getElement(Object ary, int index) { 256 return Array.getLong(ary, index); 257 } 258 } 259 260 class BooleanArrayComparer extends ArrayComparer { 261 262 @Override 263 Object getElement(Object ary, int index) { 264 return Array.getBoolean(ary, index); 265 } 266 } 267 268 class ObjArrayComparer extends ArrayComparer { 269 270 @Override 271 Object getElement(Object ary, int index) { 272 return Array.get(ary, index); 273 } 274 275 @Override 276 boolean isEquals(Object firstElement, Object secondElement) { 277 return compareObjects(firstElement, secondElement); 278 } 279 } 280 281 /** 282 * This isEqualsFP method allows subclass to override what FP equality means for this particular 283 * unit test. 284 */ 285 public boolean isEqualsFP(double first, double second) { 286 return first == second; 287 } 288 289 public void setDispatchMode(DispatchMode dispatchMode) { 290 this.dispatchMode = dispatchMode; 291 } 292 293 public void setHsailMode(HsailMode hsailMode) { 294 this.hsailMode = hsailMode; 295 } 296 297 /** 298 * Return a clone of this instance unless overridden, we just call the null constructor. 299 */ 300 public KernelTester newInstance() { 301 try { 302 return this.getClass().getConstructor((Class<?>[]) null).newInstance(); 303 } catch (Throwable t) { 304 fail("Unexpected exception " + t); 305 return null; 306 } 307 } 308 309 public Method getMethodFromMethodName(String methName, Class<?> clazz) { 310 Class<?> clazz2 = clazz; 311 while (clazz2 != null) { 312 for (Method m : clazz2.getDeclaredMethods()) { 313 logger.fine(" in " + clazz2 + ", trying to match " + m); 314 if (m.getName().equals(methName)) { 315 testMethodParams = m.getParameterTypes(); 316 if (logLevel.intValue() <= Level.FINE.intValue()) { 317 logger.fine(" in " + clazz2 + ", matched " + m); 318 logger.fine("parameter types are..."); 319 int paramNum = 0; 320 for (Class<?> pclazz : testMethodParams) { 321 logger.fine(paramNum++ + ") " + pclazz.toString()); 322 } 323 } 324 return m; 325 } 326 } 327 // Didn't find it in current clazz, try superclass. 328 clazz2 = clazz2.getSuperclass(); 329 } 330 // If we got this far, no match. 331 return null; 332 } 333 334 private void setTestMethod(String methName, Class<?> inClazz) { 335 testMethod = getMethodFromMethodName(methName, inClazz); 336 if (testMethod == null) { 337 fail("cannot find method " + methName + " in class " + inClazz); 338 } else { 339 // Print info but only for first such class. 340 if (id == 1) { 341 logger.fine("testMethod to be compiled is \n " + testMethod); 342 } 343 } 344 } 345 346 // Default is method name "run", but could be overridden. 347 private final String defaultMethodName = "run"; 348 349 public String getTestMethodName() { 350 return defaultMethodName; 351 } 352 353 /** 354 * The dispatchMethodKernel dispatches a non-lambda method. All the parameters of the compiled 355 * method are supplied as parameters to this call. 356 */ 357 public void dispatchMethodKernel(int range, Object... args) { 358 if (testMethod == null) { 359 setTestMethod(getTestMethodName(), this.getClass()); 360 } 361 if (dispatchMode == DispatchMode.SEQ) { 362 dispatchMethodKernelSeq(range, args); 363 } else if (dispatchMode == DispatchMode.OKRA) { 364 dispatchMethodKernelOkra(range, args); 365 } 366 } 367 368 /** 369 * This dispatchLambdaMethodKernel dispatches the lambda version of a kernel where the "kernel" 370 * is for the lambda method itself (like lambda$0). 371 */ 372 public void dispatchLambdaMethodKernel(int range, MyIntConsumer consumer) { 373 if (testMethod == null) { 374 setTestMethod(findLambdaMethodName(), this.getClass()); 375 } 376 if (dispatchMode == DispatchMode.SEQ) { 377 dispatchLambdaKernelSeq(range, consumer); 378 } else if (dispatchMode == DispatchMode.OKRA) { 379 dispatchLambdaMethodKernelOkra(range, consumer); 380 } 381 } 382 383 public void dispatchLambdaMethodKernel(Object[] ary, MyObjConsumer consumer) { 384 if (testMethod == null) { 385 setTestMethod(findLambdaMethodName(), this.getClass()); 386 } 387 if (dispatchMode == DispatchMode.SEQ) { 388 dispatchLambdaKernelSeq(ary, consumer); 389 } else if (dispatchMode == DispatchMode.OKRA) { 390 dispatchLambdaMethodKernelOkra(ary, consumer); 391 } 392 } 393 394 /** 395 * The dispatchLambdaKernel dispatches the lambda version of a kernel where the "kernel" is for 396 * the xxx$$Lambda.accept method in the wrapper for the lambda. Note that the useLambdaMethod 397 * boolean provides a way of actually invoking dispatchLambdaMethodKernel from this API. 398 */ 399 public void dispatchLambdaKernel(int range, MyIntConsumer consumer) { 400 if (useLambdaMethod) { 401 dispatchLambdaMethodKernel(range, consumer); 402 return; 403 } 404 if (testMethod == null) { 405 setTestMethod("accept", consumer.getClass()); 406 } 407 if (dispatchMode == DispatchMode.SEQ) { 408 dispatchLambdaKernelSeq(range, consumer); 409 } else if (dispatchMode == DispatchMode.OKRA) { 410 dispatchLambdaKernelOkra(range, consumer); 411 } 412 } 413 414 public void dispatchLambdaKernel(Object[] ary, MyObjConsumer consumer) { 415 if (useLambdaMethod) { 416 dispatchLambdaMethodKernel(ary, consumer); 417 return; 418 } 419 if (testMethod == null) { 420 setTestMethod("accept", consumer.getClass()); 421 } 422 if (dispatchMode == DispatchMode.SEQ) { 423 dispatchLambdaKernelSeq(ary, consumer); 424 } else if (dispatchMode == DispatchMode.OKRA) { 425 dispatchLambdaKernelOkra(ary, consumer); 426 } 427 } 428 429 private ArrayList<String> getLambdaMethodNames() { 430 Class<?> clazz = this.getClass(); 431 ArrayList<String> lambdaNames = new ArrayList<>(); 432 while (clazz != null && (lambdaNames.size() == 0)) { 433 for (Method m : clazz.getDeclaredMethods()) { 434 logger.fine(" in " + clazz + ", trying to match " + m); 435 if (m.getName().startsWith("lambda$")) { 436 lambdaNames.add(m.getName()); 437 } 438 } 439 // Didn't find it in current clazz, try superclass. 440 clazz = clazz.getSuperclass(); 441 } 442 return lambdaNames; 443 } 444 445 /** 446 * findLambdaMethodName finds a name in the class starting with lambda$. If we find more than 447 * one, throw an error, and tell user to override explicitly 448 */ 449 private String findLambdaMethodName() { 450 // If user overrode getTestMethodName, use that name. 451 if (!getTestMethodName().equals(defaultMethodName)) { 452 return getTestMethodName(); 453 } else { 454 ArrayList<String> lambdaNames = getLambdaMethodNames(); 455 switch (lambdaNames.size()) { 456 case 1: 457 return lambdaNames.get(0); 458 case 0: 459 fail("No lambda method found in " + this.getClass()); 460 return null; 461 default: 462 // More than one lambda. 463 String msg = "Multiple lambda methods found in " + this.getClass() + "\nYou should override getTestMethodName with one of the following\n"; 464 for (String name : lambdaNames) { 465 msg = msg + name + "\n"; 466 } 467 fail(msg); 468 return null; 469 } 470 } 471 } 472 473 /** 474 * The getCompiledHSAILSource returns the string of HSAIL code for the compiled method. By 475 * default, throws an error. In graal for instance, this would be overridden in 476 * GraalKernelTester. 477 */ 478 public String getCompiledHSAILSource(Method testMethod1) { 479 fail("no compiler connected so unable to compile " + testMethod1 + "\nYou could try injecting HSAIL or OpenCL"); 480 return null; 481 } 482 483 public String getHSAILSource(Method testMethod1) { 484 switch (hsailMode) { 485 case COMPILED: 486 return getCompiledHSAILSource(testMethod1); 487 case INJECT_HSAIL: 488 return getHsailFromClassnameHsailFile(); 489 case INJECT_OCL: 490 return getHsailFromClassnameOclFile(); 491 default: 492 fail("unknown hsailMode = " + hsailMode); 493 return null; 494 } 495 } 496 497 /** 498 * The getHSAILKernelName returns the name of the hsail kernel. By default we use 'run'. unless 499 * coming from opencl injection. Could be overridden by the junit test. 500 */ 501 public String getHSAILKernelName() { 502 return (hsailMode != HsailMode.INJECT_OCL ? "&run" : "&__OpenCL_run_kernel"); 503 } 504 505 private void createOkraKernel() { 506 // Call routines in the derived class to get the hsail code and kernel name. 507 String hsailSource = getHSAILSource(testMethod); 508 if (!okraLibExists) { 509 if (!gaveNoOkraWarning) { 510 logger.severe("No Okra library detected, skipping all KernelTester tests in " + this.getClass().getPackage().getName()); 511 gaveNoOkraWarning = true; 512 } 513 } 514 // Ignore any kerneltester test if okra does not exist. 515 assumeTrue(okraLibExists); 516 // Control which okra instances can run the tests. 517 onSimulator = OkraContext.isSimulator(); 518 okraContext = new OkraContext(); 519 if (!okraContext.isValid()) { 520 fail("...unable to create context"); 521 } 522 // Control verbosity in okra from our logLevel. 523 if (logLevel.intValue() <= Level.INFO.intValue()) { 524 okraContext.setVerbose(true); 525 } 526 okraKernel = new OkraKernel(okraContext, hsailSource, getHSAILKernelName()); 527 if (!okraKernel.isValid()) { 528 fail("...unable to create kernel"); 529 } 530 } 531 532 private void dispatchKernelOkra(int range, Object... args) { 533 if (okraKernel == null) { 534 createOkraKernel(); 535 } 536 if (logLevel.intValue() <= Level.FINE.intValue()) { 537 logger.fine("Arguments passed to okra..."); 538 for (Object arg : args) { 539 logger.fine(" " + arg); 540 } 541 } 542 okraKernel.setLaunchAttributes(range); 543 okraKernel.dispatchWithArgs(args); 544 } 545 546 private void dispatchMethodKernelSeq(int range, Object... args) { 547 Object[] invokeArgs = new Object[args.length + 1]; 548 // Need space on the end for the gid parameter. 549 System.arraycopy(args, 0, invokeArgs, 0, args.length); 550 int gidArgIndex = invokeArgs.length - 1; 551 if (logLevel.intValue() <= Level.FINE.intValue()) { 552 for (Object arg : args) { 553 logger.fine(arg.toString()); 554 } 555 } 556 for (int rangeIndex = 0; rangeIndex < range; rangeIndex++) { 557 invokeArgs[gidArgIndex] = rangeIndex; 558 try { 559 testMethod.invoke(this, invokeArgs); 560 } catch (IllegalAccessException e) { 561 fail("could not invoke " + testMethod + ", make sure it is public"); 562 } catch (IllegalArgumentException e) { 563 fail("wrong arguments invoking " + testMethod + ", check number and type of args passed to dispatchMethodKernel"); 564 } catch (InvocationTargetException e) { 565 Throwable cause = e.getCause(); 566 /** 567 * We will ignore ArrayIndexOutOfBoundsException because the graal okra target 568 * doesn't really handle it yet (basically returns early if it sees one). 569 */ 570 if (cause instanceof ArrayIndexOutOfBoundsException) { 571 logger.severe("ignoring ArrayIndexOutOfBoundsException for index " + rangeIndex); 572 } else { 573 // Other exceptions. 574 String errstr = testMethod + " threw an exception on gid=" + rangeIndex + ", exception was " + cause; 575 fail(errstr); 576 } 577 } catch (Exception e) { 578 fail("Unknown exception " + e + " invoking " + testMethod); 579 } 580 } 581 } 582 583 private void dispatchMethodKernelOkra(int range, Object... args) { 584 Object[] fixedArgs = fixArgTypes(args); 585 if (Modifier.isStatic(testMethod.getModifiers())) { 586 dispatchKernelOkra(range, fixedArgs); 587 } else { 588 // If it is a non-static method we have to push "this" as the first argument. 589 Object[] newFixedArgs = new Object[fixedArgs.length + 1]; 590 System.arraycopy(fixedArgs, 0, newFixedArgs, 1, fixedArgs.length); 591 newFixedArgs[0] = this; 592 dispatchKernelOkra(range, newFixedArgs); 593 } 594 } 595 596 /** 597 * For primitive arg parameters, make sure arg types are cast to whatever the testMethod 598 * signature says they should be. 599 */ 600 private Object[] fixArgTypes(Object[] args) { 601 Object[] fixedArgs = new Object[args.length]; 602 for (int i = 0; i < args.length; i++) { 603 Class<?> paramClass = testMethodParams[i]; 604 if (paramClass.equals(Float.class) || paramClass.equals(float.class)) { 605 fixedArgs[i] = ((Number) args[i]).floatValue(); 606 } else if (paramClass.equals(Integer.class) || paramClass.equals(int.class)) { 607 fixedArgs[i] = ((Number) args[i]).intValue(); 608 } else if (paramClass.equals(Long.class) || paramClass.equals(long.class)) { 609 fixedArgs[i] = ((Number) args[i]).longValue(); 610 } else if (paramClass.equals(Double.class) || paramClass.equals(double.class)) { 611 fixedArgs[i] = ((Number) args[i]).doubleValue(); 612 } else if (paramClass.equals(Byte.class) || paramClass.equals(byte.class)) { 613 fixedArgs[i] = ((Number) args[i]).byteValue(); 614 } else if (paramClass.equals(Boolean.class) || paramClass.equals(boolean.class)) { 615 fixedArgs[i] = (boolean) args[i]; 616 } else { 617 // All others just move unchanged. 618 fixedArgs[i] = args[i]; 619 } 620 } 621 return fixedArgs; 622 } 623 624 /** 625 * Dispatching a lambda on the java side is simple. 626 */ 627 @SuppressWarnings("static-method") 628 private void dispatchLambdaKernelSeq(int range, MyIntConsumer consumer) { 629 for (int i = 0; i < range; i++) { 630 consumer.accept(i); 631 } 632 } 633 634 @SuppressWarnings("static-method") 635 private void dispatchLambdaKernelSeq(Object[] ary, MyObjConsumer consumer) { 636 for (Object obj : ary) { 637 consumer.accept(obj); 638 } 639 } 640 641 /** 642 * The dispatchLambdaMethodKernelOkra dispatches in the case where the hsail kernel implements 643 * the lambda method itself as opposed to the wrapper that calls the lambda method. From the 644 * consumer object, we need to find the fields and pass them to the kernel. 645 */ 646 private void dispatchLambdaMethodKernelOkra(int range, MyIntConsumer consumer) { 647 logger.info("To determine parameters to pass to hsail kernel, we will examine " + consumer.getClass()); 648 Field[] fields = consumer.getClass().getDeclaredFields(); 649 Object[] args = new Object[fields.length]; 650 int argIndex = 0; 651 for (Field f : fields) { 652 logger.info("... " + f); 653 args[argIndex++] = getFieldFromObject(f, consumer); 654 } 655 dispatchKernelOkra(range, args); 656 } 657 658 private void dispatchLambdaMethodKernelOkra(Object[] ary, MyObjConsumer consumer) { 659 logger.info("To determine parameters to pass to hsail kernel, we will examine " + consumer.getClass()); 660 Field[] fields = consumer.getClass().getDeclaredFields(); 661 Object[] args = new Object[fields.length]; 662 int argIndex = 0; 663 for (Field f : fields) { 664 logger.info("... " + f); 665 args[argIndex++] = getFieldFromObject(f, consumer); 666 } 667 dispatchKernelOkra(ary.length, args); 668 } 669 670 /** 671 * The dispatchLambdaKernelOkra dispatches in the case where the hsail kernel where the hsail 672 * kernel implements the accept method of the wrapper that calls the lambda method as opposed to 673 * the actual lambda method itself. 674 */ 675 private void dispatchLambdaKernelOkra(int range, MyIntConsumer consumer) { 676 // The "wrapper" method always has only one arg consisting of the consumer. 677 Object[] args = new Object[1]; 678 args[0] = consumer; 679 dispatchKernelOkra(range, args); 680 } 681 682 private void dispatchLambdaKernelOkra(Object[] ary, MyObjConsumer consumer) { 683 // The "wrapper" method always has only one arg consisting of the consumer. 684 Object[] args = new Object[1]; 685 args[0] = consumer; 686 dispatchKernelOkra(ary.length, args); 687 } 688 689 private void disposeKernelOkra() { 690 if (okraContext != null) { 691 okraContext.dispose(); 692 } 693 } 694 695 private void compareOkraToSeq(HsailMode hsailMode1) { 696 compareOkraToSeq(hsailMode1, false); 697 } 698 699 /** 700 * Runs this instance on OKRA, and as SEQ and compares the output of the two executions. 701 */ 702 private void compareOkraToSeq(HsailMode hsailMode1, boolean useLambda) { 703 // Create and run sequential instance. 704 KernelTester testerSeq = newInstance(); 705 testerSeq.setDispatchMode(DispatchMode.SEQ); 706 testerSeq.runTest(); 707 // Now do this object. 708 this.setHsailMode(hsailMode1); 709 this.setDispatchMode(DispatchMode.OKRA); 710 this.useLambdaMethod = useLambda; 711 this.runTest(); 712 this.disposeKernelOkra(); 713 assertTrue("failed comparison to SEQ", compareResults(testerSeq)); 714 } 715 716 public void testGeneratedHsail() { 717 compareOkraToSeq(HsailMode.COMPILED); 718 } 719 720 public void testGeneratedHsailUsingLambdaMethod() { 721 compareOkraToSeq(HsailMode.COMPILED, true); 722 } 723 724 public void testInjectedHsail() { 725 newInstance().compareOkraToSeq(HsailMode.INJECT_HSAIL); 726 } 727 728 public void testInjectedOpencl() { 729 newInstance().compareOkraToSeq(HsailMode.INJECT_OCL); 730 } 731 732 private static Object getFieldFromObject(Field f, Object fromObj) { 733 try { 734 f.setAccessible(true); 735 Type type = f.getType(); 736 logger.info("type = " + type); 737 if (type == double.class) { 738 return f.getDouble(fromObj); 739 } else if (type == float.class) { 740 return f.getFloat(fromObj); 741 } else if (type == long.class) { 742 return f.getLong(fromObj); 743 } else if (type == int.class) { 744 return f.getInt(fromObj); 745 } else if (type == byte.class) { 746 return f.getByte(fromObj); 747 } else if (type == boolean.class) { 748 return f.getBoolean(fromObj); 749 } else { 750 return f.get(fromObj); 751 } 752 } catch (Exception e) { 753 fail("unable to get field " + f + " from " + fromObj); 754 return null; 755 } 756 } 757 758 public static void checkFileExists(String fileName) { 759 assertTrue(fileName + " does not exist", fileExists(fileName)); 760 } 761 762 public static boolean fileExists(String fileName) { 763 return new File(fileName).exists(); 764 } 765 766 public static String getFileAsString(String sourceFileName) { 767 String source = null; 768 try { 769 checkFileExists(sourceFileName); 770 source = new String(Files.readAllBytes(FileSystems.getDefault().getPath(sourceFileName))); 771 } catch (IOException e) { 772 fail("could not open file " + sourceFileName); 773 return null; 774 } 775 return source; 776 } 777 778 public static String getHsailFromFile(String sourceFileName) { 779 logger.severe("... getting hsail from file " + sourceFileName); 780 return getFileAsString(sourceFileName); 781 } 782 783 private static void executeCmd(String... cmd) { 784 logger.info("spawning" + Arrays.toString(cmd)); 785 try { 786 ProcessBuilder pb = new ProcessBuilder(cmd); 787 Process p = pb.start(); 788 if (logLevel.intValue() <= Level.INFO.intValue()) { 789 InputStream in = p.getInputStream(); 790 BufferedInputStream buf = new BufferedInputStream(in); 791 InputStreamReader inread = new InputStreamReader(buf); 792 BufferedReader bufferedreader = new BufferedReader(inread); 793 String line; 794 while ((line = bufferedreader.readLine()) != null) { 795 logger.info(line); 796 } 797 } 798 p.waitFor(); 799 } catch (Exception e) { 800 fail("could not execute <" + Arrays.toString(cmd) + ">"); 801 } 802 } 803 804 public static String getHsailFromOpenCLFile(String openclFileName) { 805 String openclHsailFile = "opencl_out.hsail"; 806 String tmpTahitiFile = "_temp_0_Tahiti.txt"; 807 checkFileExists(openclFileName); 808 logger.severe("...converting " + openclFileName + " to HSAIL..."); 809 executeCmd("aoc2", "-m64", "-I./", "-march=hsail", openclFileName); 810 if (fileExists(tmpTahitiFile)) { 811 return getFileAsString(tmpTahitiFile); 812 } else { 813 executeCmd("HSAILasm", "-disassemble", "-o", openclHsailFile, openclFileName.replace(".cl", ".bin")); 814 checkFileExists(openclHsailFile); 815 return getFileAsString(openclHsailFile); 816 } 817 } 818 819 public String getHsailFromClassnameHsailFile() { 820 return (getHsailFromFile(this.getClass().getSimpleName() + ".hsail")); 821 } 822 823 public String getHsailFromClassnameOclFile() { 824 return (getHsailFromOpenCLFile(this.getClass().getSimpleName() + ".cl")); 825 } 826 827 public static void logInfo(String msg) { 828 logger.info(msg); 829 } 830 831 public static void logSevere(String msg) { 832 logger.severe(msg); 833 } 834 835 public static void setLogLevel(Level level) { 836 logLevel = level; 837 logger.setLevel(level); 838 consoleHandler.setLevel(level); 839 } 840 }