1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17/* UT_reduce_backward.java is a much simpler version of this test 18 * case that exercises pragmas after the functions (backward 19 * reference), whereas this test case exercises the pragmas before 20 * the functions (forward reference). 21 */ 22 23package com.android.rs.test; 24 25import android.content.Context; 26import android.renderscript.Allocation; 27import android.renderscript.Element; 28import android.renderscript.Float2; 29import android.renderscript.Int2; 30import android.renderscript.Int3; 31import android.renderscript.RenderScript; 32import android.renderscript.ScriptIntrinsicHistogram; 33import android.renderscript.Type; 34import android.util.Log; 35 36import java.util.ArrayList; 37import java.util.Arrays; 38import java.util.Random; 39 40import static junit.framework.Assert.assertEquals; 41import static junit.framework.Assert.assertTrue; 42 43public class UT_reduce extends UnitTest { 44 private static final String TAG = "reduce"; 45 46 protected UT_reduce(RSTestCore rstc, Context ctx) { 47 super(rstc, "reduce", ctx); 48 } 49 50 private static class timing { 51 timing(long myJavaStart, long myJavaEnd, long myRsStart, 52 long myCopyStart, long myKernelStart, long myRsEnd, 53 Allocation... myInputs) { 54 javaStart = myJavaStart; 55 javaEnd = myJavaEnd; 56 rsStart = myRsStart; 57 copyStart = myCopyStart; 58 kernelStart = myKernelStart; 59 rsEnd = myRsEnd; 60 61 inputBytes = 0; 62 for (Allocation input : myInputs) 63 inputBytes += input.getBytesSize(); 64 65 inputCells = (myInputs.length > 0) ? myInputs[0].getType().getCount() : 0; 66 } 67 68 timing(long myInputCells) { 69 inputCells = myInputCells; 70 } 71 72 private long javaStart = -1; 73 private long javaEnd = -1; 74 private long rsStart = -1; 75 private long copyStart = -1; 76 private long kernelStart = -1; 77 private long rsEnd = -1; 78 private long inputBytes = -1; 79 private long inputCells = -1; 80 81 public long javaTime() { 82 return javaEnd - javaStart; 83 } 84 85 public long rsTime() { 86 return rsEnd - rsStart; 87 } 88 89 public long kernelTime() { 90 return rsEnd - kernelStart; 91 } 92 93 public long overheadTime() { 94 return kernelStart - rsStart; 95 } 96 97 public long allocationTime() { 98 return copyStart - rsStart; 99 } 100 101 public long copyTime() { 102 return kernelStart - copyStart; 103 } 104 105 public static String string(long myJavaStart, long myJavaEnd, long myRsStart, 106 long myCopyStart, long myKernelStart, long myRsEnd, 107 Allocation... myInputs) { 108 return (new timing(myJavaStart, myJavaEnd, myRsStart, 109 myCopyStart, myKernelStart, myRsEnd, myInputs)).string(); 110 } 111 112 public static String string(long myInputCells) { 113 return (new timing(myInputCells)).string(); 114 } 115 116 public String string() { 117 String result; 118 if (javaStart >= 0) { 119 result = "(java " + javaTime() + "ms, rs " + rsTime() + "ms = overhead " + 120 overheadTime() + "ms (alloc " + allocationTime() + "ms + copy " + 121 copyTime() + "ms) + kernel+get() " + kernelTime() + "ms)"; 122 if (inputCells > 0) 123 result += " "; 124 } else { 125 result = ""; 126 } 127 if (inputCells > 0) { 128 result += "(" + fmt.format(inputCells) + " cells"; 129 if (inputBytes > 0) 130 result += ", " + fmt.format(inputBytes) + " bytes"; 131 result += ")"; 132 } 133 return result; 134 } 135 136 private static java.text.DecimalFormat fmt; 137 138 static { 139 fmt = new java.text.DecimalFormat("###,###"); 140 } 141 } 142 143 private byte[] createInputArrayByte(int len, int seed) { 144 byte[] array = new byte[len]; 145 (new Random(seed)).nextBytes(array); 146 return array; 147 } 148 149 private float[] createInputArrayFloat(int len, Random rand) { 150 float[] array = new float[len]; 151 for (int i = 0; i < len; ++i) { 152 final float val = rand.nextFloat(); 153 array[i] = rand.nextBoolean() ? val : -val; 154 } 155 return array; 156 } 157 158 private float[] createInputArrayFloat(int len, int seed) { 159 return createInputArrayFloat(len, new Random(seed)); 160 } 161 162 private float[] createInputArrayFloatWithInfs(int len, int infs, int seed) { 163 Random rand = new Random(seed); 164 float[] array = createInputArrayFloat(len, rand); 165 for (int i = 0; i < infs; ++i) 166 array[rand.nextInt(len)] = (rand.nextBoolean() ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY); 167 return array; 168 } 169 170 private int[] createInputArrayInt(int len, int seed) { 171 Random rand = new Random(seed); 172 int[] array = new int[len]; 173 for (int i = 0; i < len; ++i) 174 array[i] = rand.nextInt(); 175 return array; 176 } 177 178 private int[] createInputArrayInt(int len, int seed, int eltRange) { 179 Random rand = new Random(seed); 180 int[] array = new int[len]; 181 for (int i = 0; i < len; ++i) 182 array[i] = rand.nextInt(eltRange); 183 return array; 184 } 185 186 private long[] intArrayToLong(final int[] input) { 187 final long[] output = new long[input.length]; 188 189 for (int i = 0; i < input.length; ++i) 190 output[i] = input[i]; 191 192 return output; 193 } 194 195 private <T extends Number> boolean result(String testName, final timing t, 196 T javaResult, T rsResult) { 197 final boolean success = javaResult.equals(rsResult); 198 String status = (success ? "PASSED" : "FAILED"); 199 if (success && (t != null)) 200 status += " " + t.string(); 201 Log.i(TAG, testName + ": java " + javaResult + ", rs " + rsResult + ": " + status); 202 return success; 203 } 204 205 private boolean result(String testName, final timing t, 206 final float[] javaResult, final float[] rsResult) { 207 if (javaResult.length != rsResult.length) { 208 Log.i(TAG, testName + ": java length " + javaResult.length + 209 ", rs length " + rsResult.length + ": FAILED"); 210 return false; 211 } 212 for (int i = 0; i < javaResult.length; ++i) { 213 if (javaResult[i] != rsResult[i]) { 214 Log.i(TAG, testName + "[" + i + "]: java " + javaResult[i] + 215 ", rs " + rsResult[i] + ": FAILED"); 216 return false; 217 } 218 } 219 String status = "PASSED"; 220 if (t != null) 221 status += " " + t.string(); 222 Log.i(TAG, testName + ": " + status); 223 return true; 224 } 225 226 private boolean result(String testName, final timing t, 227 final long[] javaResult, final long[] rsResult) { 228 if (javaResult.length != rsResult.length) { 229 Log.i(TAG, testName + ": java length " + javaResult.length + 230 ", rs length " + rsResult.length + ": FAILED"); 231 return false; 232 } 233 for (int i = 0; i < javaResult.length; ++i) { 234 if (javaResult[i] != rsResult[i]) { 235 Log.i(TAG, testName + "[" + i + "]: java " + javaResult[i] + 236 ", rs " + rsResult[i] + ": FAILED"); 237 return false; 238 } 239 } 240 String status = "PASSED"; 241 if (t != null) 242 status += " " + t.string(); 243 Log.i(TAG, testName + ": " + status); 244 return true; 245 } 246 247 private boolean result(String testName, final timing t, 248 final int[] javaResult, final int[] rsResult) { 249 return result(testName, t, intArrayToLong(javaResult), intArrayToLong(rsResult)); 250 } 251 252 private boolean result(String testName, final timing t, Int2 javaResult, Int2 rsResult) { 253 final boolean success = (javaResult.x == rsResult.x) && (javaResult.y == rsResult.y); 254 String status = (success ? "PASSED" : "FAILED"); 255 if (success && (t != null)) 256 status += " " + t.string(); 257 Log.i(TAG, 258 testName + 259 ": java (" + javaResult.x + ", " + javaResult.y + ")" + 260 ", rs (" + rsResult.x + ", " + rsResult.y + ")" + 261 ": " + status); 262 return success; 263 } 264 265 private boolean result(String testName, final timing t, Float2 javaResult, Float2 rsResult) { 266 final boolean success = (javaResult.x == rsResult.x) && (javaResult.y == rsResult.y); 267 String status = (success ? "PASSED" : "FAILED"); 268 if (success && (t != null)) 269 status += " " + t.string(); 270 Log.i(TAG, 271 testName + 272 ": java (" + javaResult.x + ", " + javaResult.y + ")" + 273 ", rs (" + rsResult.x + ", " + rsResult.y + ")" + 274 ": " + status); 275 return success; 276 } 277 278 /////////////////////////////////////////////////////////////////// 279 280 private int addint(int[] input) { 281 int result = 0; 282 for (int idx = 0; idx < input.length; ++idx) 283 result += input[idx]; 284 return result; 285 } 286 287 private boolean addint1D_array(RenderScript RS, ScriptC_reduce s, int seed, int[] size) { 288 final int[] input = createInputArrayInt(size[0], seed, Integer.MAX_VALUE / size[0]); 289 290 final int javaResult = addint(input); 291 final int rsResult = s.reduce_addint(input).get(); 292 293 return result("addint1D_array", new timing(size[0]), javaResult, rsResult); 294 } 295 296 private boolean addint1D(RenderScript RS, ScriptC_reduce s, int seed, int[] size) { 297 final int[] inputArray = createInputArrayInt(size[0], seed, Integer.MAX_VALUE / size[0]); 298 299 final long javaTimeStart = java.lang.System.currentTimeMillis(); 300 final int javaResult = addint(inputArray); 301 final long javaTimeEnd = java.lang.System.currentTimeMillis(); 302 303 final long rsTimeStart = java.lang.System.currentTimeMillis(); 304 305 Allocation inputAllocation = Allocation.createSized(RS, Element.I32(RS), inputArray.length); 306 307 final long copyTimeStart = java.lang.System.currentTimeMillis(); 308 309 inputAllocation.copyFrom(inputArray); 310 311 final long kernelTimeStart = java.lang.System.currentTimeMillis(); 312 final int rsResult = s.reduce_addint(inputAllocation).get(); 313 final long rsTimeEnd = java.lang.System.currentTimeMillis(); 314 315 final boolean success = 316 result("addint1D", 317 new timing(javaTimeStart, javaTimeEnd, rsTimeStart, 318 copyTimeStart, kernelTimeStart, rsTimeEnd, inputAllocation), 319 javaResult, rsResult); 320 inputAllocation.destroy(); 321 return success; 322 } 323 324 private boolean addint2D(RenderScript RS, ScriptC_reduce s, int seed, int[] size) { 325 final int dimX = size[0]; 326 final int dimY = size[1]; 327 328 final int[] inputArray = createInputArrayInt(dimX * dimY, seed, Integer.MAX_VALUE / (dimX * dimY)); 329 330 final long javaTimeStart = java.lang.System.currentTimeMillis(); 331 final int javaResult = addint(inputArray); 332 final long javaTimeEnd = java.lang.System.currentTimeMillis(); 333 334 final long rsTimeStart = java.lang.System.currentTimeMillis(); 335 336 Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS)); 337 typeBuilder.setX(dimX).setY(dimY); 338 Allocation inputAllocation = Allocation.createTyped(RS, typeBuilder.create()); 339 340 final long copyTimeStart = java.lang.System.currentTimeMillis(); 341 342 inputAllocation.copy2DRangeFrom(0, 0, dimX, dimY, inputArray); 343 344 final long kernelTimeStart = java.lang.System.currentTimeMillis(); 345 final int rsResult = s.reduce_addint(inputAllocation).get(); 346 final long rsTimeEnd = java.lang.System.currentTimeMillis(); 347 348 final boolean success = 349 result("addint2D", 350 new timing(javaTimeStart, javaTimeEnd, rsTimeStart, 351 copyTimeStart, kernelTimeStart, rsTimeEnd, inputAllocation), 352 javaResult, rsResult); 353 inputAllocation.destroy(); 354 return success; 355 } 356 357 private boolean addint3D(RenderScript RS, ScriptC_reduce s, int seed, int[] size) { 358 final int dimX = size[0]; 359 final int dimY = size[1]; 360 final int dimZ = size[2]; 361 362 final int[] inputArray = createInputArrayInt(dimX * dimY * dimZ, seed, Integer.MAX_VALUE / (dimX * dimY * dimZ)); 363 364 final long javaTimeStart = java.lang.System.currentTimeMillis(); 365 final int javaResult = addint(inputArray); 366 final long javaTimeEnd = java.lang.System.currentTimeMillis(); 367 368 final long rsTimeStart = java.lang.System.currentTimeMillis(); 369 370 Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS)); 371 typeBuilder.setX(dimX).setY(dimY).setZ(dimZ); 372 Allocation inputAllocation = Allocation.createTyped(RS, typeBuilder.create()); 373 374 final long copyTimeStart = java.lang.System.currentTimeMillis(); 375 376 inputAllocation.copy3DRangeFrom(0, 0, 0, dimX, dimY, dimZ, inputArray); 377 378 final long kernelTimeStart = java.lang.System.currentTimeMillis(); 379 final int rsResult = s.reduce_addint(inputAllocation).get(); 380 final long rsTimeEnd = java.lang.System.currentTimeMillis(); 381 382 final boolean success = 383 result("addint3D", 384 new timing(javaTimeStart, javaTimeEnd, rsTimeStart, 385 copyTimeStart, kernelTimeStart, rsTimeEnd, inputAllocation), 386 javaResult, rsResult); 387 inputAllocation.destroy(); 388 return success; 389 } 390 391 //----------------------------------------------------------------- 392 393 private boolean patternInterleavedReduce(RenderScript RS, ScriptC_reduce s) { 394 // Run two reduce operations without forcing completion between them. 395 // We want to ensure that the driver can handle this, and that 396 // temporary Allocations created to run the reduce operations survive 397 // until get(). 398 399 boolean pass = true; 400 401 final int inputSize = (1 << 18); 402 403 final int[] input1 = createInputArrayInt(123, Integer.MAX_VALUE / inputSize); 404 final int[] input2 = createInputArrayInt(456, Integer.MAX_VALUE / inputSize); 405 406 final int javaResult1 = addint(input1); 407 final int javaResult2 = addint(input2); 408 409 final ScriptC_reduce.result_int rsResultFuture1 = s.reduce_addint(input1); 410 final ScriptC_reduce.result_int rsResultFuture2 = s.reduce_addint(input2); 411 412 pass &= result("patternInterleavedReduce (1)", new timing(inputSize), 413 javaResult1, rsResultFuture1.get()); 414 pass &= result("patternInterleavedReduce (2)", new timing(inputSize), 415 javaResult2, rsResultFuture2.get()); 416 417 return pass; 418 } 419 420 //----------------------------------------------------------------- 421 422 private int[] sillySumIntoDecArray(final int[] input) { 423 final int resultScalar = addint(input); 424 final int[] result = new int[4]; 425 for (int i = 0; i < 4; ++i) 426 result[i] = resultScalar / (i + 1); 427 return result; 428 } 429 430 private int[] sillySumIntoIncArray(final int[] input) { 431 final int resultScalar = addint(input); 432 final int[] result = new int[4]; 433 for (int i = 0; i < 4; ++i) 434 result[i] = resultScalar / (4 - i); 435 return result; 436 } 437 438 private boolean patternDuplicateAnonymousResult(RenderScript RS, ScriptC_reduce s) { 439 // Ensure that we can have two kernels with the same anonymous result type. 440 441 boolean pass = true; 442 443 final int inputSize = 1000; 444 final int[] input = createInputArrayInt(149, Integer.MAX_VALUE / inputSize); 445 446 final int[] javaResultDec = sillySumIntoDecArray(input); 447 final int[] rsResultDec = s.reduce_sillySumIntoDecArray(input).get(); 448 pass &= result("patternDuplicateAnonymousResult (Dec)", new timing(inputSize), 449 javaResultDec, rsResultDec); 450 451 final int[] javaResultInc = sillySumIntoIncArray(input); 452 final int[] rsResultInc = s.reduce_sillySumIntoIncArray(input).get(); 453 pass &= result("patternDuplicateAnonymousResult (Inc)", new timing(inputSize), 454 javaResultInc, rsResultInc); 455 456 return pass; 457 } 458 459 /////////////////////////////////////////////////////////////////// 460 461 private float findMinAbs(float[] input) { 462 float accum = input[0]; 463 for (int idx = 1; idx < input.length; ++idx) { 464 final float val = input[idx]; 465 if (Math.abs(val) < Math.abs(accum)) 466 accum = val; 467 } 468 return accum; 469 } 470 471 static interface ReduceFindMinAbs { 472 float run(Allocation input); 473 } 474 475 private boolean findMinAbs(RenderScript RS, float[] inputArray, String testName, ReduceFindMinAbs reduction) { 476 final long javaTimeStart = java.lang.System.currentTimeMillis(); 477 final float javaResult = findMinAbs(inputArray); 478 final long javaTimeEnd = java.lang.System.currentTimeMillis(); 479 480 final long rsTimeStart = java.lang.System.currentTimeMillis(); 481 482 Allocation inputAllocation = Allocation.createSized(RS, Element.F32(RS), inputArray.length); 483 484 final long copyTimeStart = java.lang.System.currentTimeMillis(); 485 486 inputAllocation.copyFrom(inputArray); 487 488 final long kernelTimeStart = java.lang.System.currentTimeMillis(); 489 final float rsResult = reduction.run(inputAllocation); 490 final long rsTimeEnd = java.lang.System.currentTimeMillis(); 491 492 // Note that the Java and RenderScript algorithms are not 493 // guaranteed to find the same results -- but the results 494 // should have the same absolute value. 495 496 final boolean success = 497 result(testName, 498 new timing(javaTimeStart, javaTimeEnd, rsTimeStart, 499 copyTimeStart, kernelTimeStart, rsTimeEnd, inputAllocation), 500 Math.abs(javaResult), Math.abs(rsResult)); 501 inputAllocation.destroy(); 502 return success; 503 } 504 505 private boolean findMinAbsBool(RenderScript RS, ScriptC_reduce s, int seed, int[] size) { 506 return findMinAbs(RS, createInputArrayFloat(size[0], seed), "findMinAbsBool", 507 (Allocation input) -> s.reduce_findMinAbsBool(input).get()); 508 } 509 510 private boolean findMinAbsBoolInf(RenderScript RS, ScriptC_reduce s, int seed, int[] size) { 511 return findMinAbs(RS, createInputArrayFloatWithInfs(size[0], 1 + size[0] / 1000, seed), "findMinAbsBoolInf", 512 (Allocation input) -> s.reduce_findMinAbsBool(input).get()); 513 } 514 515 private boolean findMinAbsNaN(RenderScript RS, ScriptC_reduce s, int seed, int[] size) { 516 return findMinAbs(RS, createInputArrayFloat(size[0], seed), "findMinAbsNaN", 517 (Allocation input) -> s.reduce_findMinAbsNaN(input).get()); 518 } 519 520 private boolean findMinAbsNaNInf(RenderScript RS, ScriptC_reduce s, int seed, int[] size) { 521 return findMinAbs(RS, createInputArrayFloatWithInfs(size[0], 1 + size[0] / 1000, seed), "findMinAbsNaNInf", 522 (Allocation input) -> s.reduce_findMinAbsNaN(input).get()); 523 } 524 525 /////////////////////////////////////////////////////////////////// 526 527 private Int2 findMinAndMax(float[] input) { 528 float minVal = Float.POSITIVE_INFINITY; 529 int minIdx = -1; 530 float maxVal = Float.NEGATIVE_INFINITY; 531 int maxIdx = -1; 532 533 for (int idx = 0; idx < input.length; ++idx) { 534 if ((minIdx < 0) || (input[idx] < minVal)) { 535 minVal = input[idx]; 536 minIdx = idx; 537 } 538 if ((maxIdx < 0) || (input[idx] > maxVal)) { 539 maxVal = input[idx]; 540 maxIdx = idx; 541 } 542 } 543 544 return new Int2(minIdx, maxIdx); 545 } 546 547 private boolean findMinAndMax_array(RenderScript RS, ScriptC_reduce s, int seed, int[] size) { 548 final float[] input = createInputArrayFloat(size[0], seed); 549 550 final Int2 javaResult = findMinAndMax(input); 551 final Int2 rsResult = s.reduce_findMinAndMax(input).get(); 552 553 // Note that the Java and RenderScript algorithms are not 554 // guaranteed to find the same cells -- but they should 555 // find cells of the same value. 556 final Float2 javaVal = new Float2(input[javaResult.x], input[javaResult.y]); 557 final Float2 rsVal = new Float2(input[rsResult.x], input[rsResult.y]); 558 559 return result("findMinAndMax_array", new timing(size[0]), javaVal, rsVal); 560 } 561 562 private boolean findMinAndMax(RenderScript RS, ScriptC_reduce s, int seed, int[] size) { 563 final float[] inputArray = createInputArrayFloat(size[0], seed); 564 565 final long javaTimeStart = java.lang.System.currentTimeMillis(); 566 final Int2 javaResult = findMinAndMax(inputArray); 567 final long javaTimeEnd = java.lang.System.currentTimeMillis(); 568 569 final long rsTimeStart = java.lang.System.currentTimeMillis(); 570 571 Allocation inputAllocation = Allocation.createSized(RS, Element.F32(RS), inputArray.length); 572 573 final long copyTimeStart = java.lang.System.currentTimeMillis(); 574 575 inputAllocation.copyFrom(inputArray); 576 577 final long kernelTimeStart = java.lang.System.currentTimeMillis(); 578 final Int2 rsResult = s.reduce_findMinAndMax(inputAllocation).get(); 579 final long rsTimeEnd = java.lang.System.currentTimeMillis(); 580 581 // Note that the Java and RenderScript algorithms are not 582 // guaranteed to find the same cells -- but they should 583 // find cells of the same value. 584 final Float2 javaVal = new Float2(inputArray[javaResult.x], inputArray[javaResult.y]); 585 final Float2 rsVal = new Float2(inputArray[rsResult.x], inputArray[rsResult.y]); 586 587 final boolean success = 588 result("findMinAndMax", 589 new timing(javaTimeStart, javaTimeEnd, rsTimeStart, 590 copyTimeStart, kernelTimeStart, rsTimeEnd, inputAllocation), 591 javaVal, rsVal); 592 inputAllocation.destroy(); 593 return success; 594 } 595 596 //----------------------------------------------------------------- 597 598 private boolean patternFindMinAndMaxInf(RenderScript RS, ScriptC_reduce s) { 599 // Run this kernel on an input consisting solely of a single infinity. 600 601 final float[] input = new float[1]; 602 input[0] = Float.POSITIVE_INFINITY; 603 604 final Int2 javaResult = findMinAndMax(input); 605 final Int2 rsResult = s.reduce_findMinAndMax(input).get(); 606 607 // Note that the Java and RenderScript algorithms are not 608 // guaranteed to find the same cells -- but they should 609 // find cells of the same value. 610 final Float2 javaVal = new Float2(input[javaResult.x], input[javaResult.y]); 611 final Float2 rsVal = new Float2(input[rsResult.x], input[rsResult.y]); 612 613 return result("patternFindMinAndMaxInf", new timing(1), javaVal, rsVal); 614 } 615 616 /////////////////////////////////////////////////////////////////// 617 618 // Both the input and the result are linearized representations of matSize*matSize matrices. 619 private float[] findMinMat(final float[] inputArray, final int matSize) { 620 final int matSizeSquared = matSize * matSize; 621 622 float[] result = new float[matSizeSquared]; 623 for (int i = 0; i < matSizeSquared; ++i) 624 result[i] = Float.POSITIVE_INFINITY; 625 626 for (int i = 0; i < inputArray.length; ++i) 627 result[i % matSizeSquared] = Math.min(result[i % matSizeSquared], inputArray[i]); 628 629 return result; 630 } 631 632 static interface ReduceFindMinMat { 633 float[] run(Allocation input); 634 } 635 636 private boolean findMinMat(RenderScript RS, int seed, int[] inputSize, 637 int matSize, Element matElement, ReduceFindMinMat reduction) { 638 final int length = inputSize[0]; 639 final int matSizeSquared = matSize * matSize; 640 641 final float[] inputArray = createInputArrayFloat(matSizeSquared * length, seed); 642 643 final long javaTimeStart = java.lang.System.currentTimeMillis(); 644 final float[] javaResult = findMinMat(inputArray, matSize); 645 final long javaTimeEnd = java.lang.System.currentTimeMillis(); 646 647 final long rsTimeStart = java.lang.System.currentTimeMillis(); 648 649 Allocation inputAllocation = Allocation.createSized(RS, matElement, length); 650 651 final long copyTimeStart = java.lang.System.currentTimeMillis(); 652 653 inputAllocation.copyFromUnchecked(inputArray); 654 655 final long kernelTimeStart = java.lang.System.currentTimeMillis(); 656 final float[] rsResult = reduction.run(inputAllocation); 657 final long rsTimeEnd = java.lang.System.currentTimeMillis(); 658 659 final boolean success = 660 result("findMinMat" + matSize, 661 new timing(javaTimeStart, javaTimeEnd, rsTimeStart, 662 copyTimeStart, kernelTimeStart, rsTimeEnd, inputAllocation), 663 javaResult, rsResult); 664 inputAllocation.destroy(); 665 return success; 666 } 667 668 private boolean findMinMat2(RenderScript RS, ScriptC_reduce s, int seed, int[] size) { 669 return findMinMat(RS, seed, size, 2, Element.MATRIX_2X2(RS), 670 (Allocation input) -> s.reduce_findMinMat2(input).get()); 671 } 672 673 private boolean findMinMat4(RenderScript RS, ScriptC_reduce s, int seed, int[] size) { 674 return findMinMat(RS, seed, size, 4, Element.MATRIX_4X4(RS), 675 (Allocation input) -> s.reduce_findMinMat4(input).get()); 676 } 677 678 /////////////////////////////////////////////////////////////////// 679 680 private int fz(final int[] input) { 681 for (int i = 0; i < input.length; ++i) 682 if (input[i] == 0) 683 return i; 684 return -1; 685 } 686 687 private boolean fz_array(RenderScript RS, ScriptC_reduce s, int seed, int size[]) { 688 final int inputLen = size[0]; 689 int[] input = createInputArrayInt(inputLen, seed + 0); 690 // just in case we got unlucky 691 input[(new Random(seed + 1)).nextInt(inputLen)] = 0; 692 693 final int rsResult = s.reduce_fz(input).get(); 694 695 final boolean success = (input[rsResult] == 0); 696 Log.i(TAG, 697 "fz_array: input[" + rsResult + "] == " + input[rsResult] + ": " + 698 (success ? "PASSED " + timing.string(size[0]) : "FAILED")); 699 return success; 700 } 701 702 private boolean fz(RenderScript RS, ScriptC_reduce s, int seed, int size[]) { 703 final int inputLen = size[0]; 704 int[] inputArray = createInputArrayInt(inputLen, seed + 0); 705 // just in case we got unlucky 706 inputArray[(new Random(seed + 1)).nextInt(inputLen)] = 0; 707 708 final long javaTimeStart = java.lang.System.currentTimeMillis(); 709 final int javaResult = fz(inputArray); 710 final long javaTimeEnd = java.lang.System.currentTimeMillis(); 711 712 final long rsTimeStart = java.lang.System.currentTimeMillis(); 713 714 Allocation inputAllocation = Allocation.createSized(RS, Element.I32(RS), inputArray.length); 715 716 final long copyTimeStart = java.lang.System.currentTimeMillis(); 717 718 inputAllocation.copyFrom(inputArray); 719 720 final long kernelTimeStart = java.lang.System.currentTimeMillis(); 721 final int rsResult = s.reduce_fz(inputAllocation).get(); 722 final long rsTimeEnd = java.lang.System.currentTimeMillis(); 723 724 final boolean success = (inputArray[rsResult] == 0); 725 String status = (success ? "PASSED" : "FAILED"); 726 if (success) 727 status += " " + timing.string(javaTimeStart, javaTimeEnd, rsTimeStart, 728 copyTimeStart, kernelTimeStart, rsTimeEnd, inputAllocation); 729 Log.i(TAG, 730 "fz: java input[" + javaResult + "] == " + inputArray[javaResult] + 731 ", rs input[" + rsResult + "] == " + inputArray[javaResult] + ": " + status); 732 inputAllocation.destroy(); 733 return success; 734 } 735 736 /////////////////////////////////////////////////////////////////// 737 738 private boolean fz2(RenderScript RS, ScriptC_reduce s, int seed, int size[]) { 739 final int dimX = size[0], dimY = size[1]; 740 final int inputLen = dimX * dimY; 741 742 int[] inputArray = createInputArrayInt(inputLen, seed + 0); 743 // just in case we got unlucky 744 inputArray[(new Random(seed + 1)).nextInt(inputLen)] = 0; 745 746 final long javaTimeStart = java.lang.System.currentTimeMillis(); 747 final int javaResultLinear = fz(inputArray); 748 final long javaTimeEnd = java.lang.System.currentTimeMillis(); 749 750 final Int2 javaResult = new Int2(javaResultLinear % dimX, javaResultLinear / dimX); 751 final int javaCellVal = inputArray[javaResult.x + dimX * javaResult.y]; 752 753 final long rsTimeStart = java.lang.System.currentTimeMillis(); 754 755 Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS)); 756 typeBuilder.setX(dimX).setY(dimY); 757 Allocation inputAllocation = Allocation.createTyped(RS, typeBuilder.create()); 758 759 final long copyTimeStart = java.lang.System.currentTimeMillis(); 760 761 inputAllocation.copy2DRangeFrom(0, 0, dimX, dimY, inputArray); 762 763 final long kernelTimeStart = java.lang.System.currentTimeMillis(); 764 final Int2 rsResult = s.reduce_fz2(inputAllocation).get(); 765 final long rsTimeEnd = java.lang.System.currentTimeMillis(); 766 767 final int rsCellVal = inputArray[rsResult.x + dimX * rsResult.y]; 768 final boolean success = (rsCellVal == 0); 769 String status = (success ? "PASSED" : "FAILED"); 770 if (success) 771 status += " " + timing.string(javaTimeStart, javaTimeEnd, rsTimeStart, 772 copyTimeStart, kernelTimeStart, rsTimeEnd, inputAllocation); 773 Log.i(TAG, 774 "fz2: java input[" + javaResult.x + ", " + javaResult.y + "] == " + javaCellVal + 775 ", rs input[" + rsResult.x + ", " + rsResult.y + "] == " + rsCellVal + ": " + status); 776 inputAllocation.destroy(); 777 return success; 778 } 779 780 /////////////////////////////////////////////////////////////////// 781 782 private boolean fz3(RenderScript RS, ScriptC_reduce s, int seed, int[] size) { 783 final int dimX = size[0], dimY = size[1], dimZ = size[2]; 784 final int inputLen = dimX * dimY * dimZ; 785 786 int[] inputArray = createInputArrayInt(inputLen, seed + 0); 787 // just in case we got unlucky 788 inputArray[(new Random(seed + 1)).nextInt(inputLen)] = 0; 789 790 final long javaTimeStart = java.lang.System.currentTimeMillis(); 791 final int javaResultLinear = fz(inputArray); 792 final long javaTimeEnd = java.lang.System.currentTimeMillis(); 793 794 final Int3 javaResult = new Int3( 795 javaResultLinear % dimX, 796 (javaResultLinear / dimX) % dimY, 797 javaResultLinear / (dimX * dimY)); 798 final int javaCellVal = inputArray[javaResult.x + dimX * javaResult.y + dimX * dimY * javaResult.z]; 799 800 final long rsTimeStart = java.lang.System.currentTimeMillis(); 801 802 Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS)); 803 typeBuilder.setX(dimX).setY(dimY).setZ(dimZ); 804 Allocation inputAllocation = Allocation.createTyped(RS, typeBuilder.create()); 805 806 final long copyTimeStart = java.lang.System.currentTimeMillis(); 807 808 inputAllocation.copy3DRangeFrom(0, 0, 0, dimX, dimY, dimZ, inputArray); 809 810 final long kernelTimeStart = java.lang.System.currentTimeMillis(); 811 final Int3 rsResult = s.reduce_fz3(inputAllocation).get(); 812 final long rsTimeEnd = java.lang.System.currentTimeMillis(); 813 814 final int rsCellVal = inputArray[rsResult.x + dimX * rsResult.y + dimX * dimY * rsResult.z]; 815 final boolean success = (rsCellVal == 0); 816 String status = (success ? "PASSED" : "FAILED"); 817 if (success) 818 status += " " + timing.string(javaTimeStart, javaTimeEnd, rsTimeStart, 819 copyTimeStart, kernelTimeStart, rsTimeEnd, inputAllocation); 820 Log.i(TAG, 821 "fz3: java input[" + javaResult.x + ", " + javaResult.y + ", " + javaResult.z + "] == " + javaCellVal + 822 ", rs input[" + rsResult.x + ", " + rsResult.y + ", " + rsResult.z + "] == " + rsCellVal + ": " + status); 823 inputAllocation.destroy(); 824 return success; 825 } 826 827 /////////////////////////////////////////////////////////////////// 828 829 private static final int histogramBucketCount = 256; 830 831 private long[] histogram(RenderScript RS, final byte[] inputArray) { 832 Allocation inputAllocation = Allocation.createSized(RS, Element.U8(RS), inputArray.length); 833 inputAllocation.copyFrom(inputArray); 834 835 Allocation outputAllocation = Allocation.createSized(RS, Element.U32(RS), histogramBucketCount); 836 837 ScriptIntrinsicHistogram scriptHsg = ScriptIntrinsicHistogram.create(RS, Element.U8(RS)); 838 scriptHsg.setOutput(outputAllocation); 839 scriptHsg.forEach(inputAllocation); 840 841 int[] outputArrayMistyped = new int[histogramBucketCount]; 842 outputAllocation.copyTo(outputArrayMistyped); 843 844 long[] outputArray = new long[histogramBucketCount]; 845 for (int i = 0; i < histogramBucketCount; ++i) 846 outputArray[i] = outputArrayMistyped[i] & (long) 0xffffffff; 847 848 inputAllocation.destroy(); 849 outputAllocation.destroy(); 850 851 scriptHsg.destroy(); 852 return outputArray; 853 } 854 855 private boolean histogram_array(RenderScript RS, ScriptC_reduce s, int seed, int size[]) { 856 final byte[] inputArray = createInputArrayByte(size[0], seed); 857 858 final long[] javaResult = histogram(RS, inputArray); 859 assertEquals("javaResult length", histogramBucketCount, javaResult.length); 860 final long[] rsResult = s.reduce_histogram(inputArray).get(); 861 assertEquals("rsResult length", histogramBucketCount, rsResult.length); 862 863 return result("histogram_array", new timing(size[0]), javaResult, rsResult); 864 } 865 866 private boolean histogram(RenderScript RS, ScriptC_reduce s, int seed, int size[]) { 867 final byte[] inputArray = createInputArrayByte(size[0], seed); 868 869 final long javaTimeStart = java.lang.System.currentTimeMillis(); 870 final long[] javaResult = histogram(RS, inputArray); 871 final long javaTimeEnd = java.lang.System.currentTimeMillis(); 872 assertEquals("javaResult length", histogramBucketCount, javaResult.length); 873 874 final long rsTimeStart = java.lang.System.currentTimeMillis(); 875 876 Allocation inputAllocation = Allocation.createSized(RS, Element.U8(RS), inputArray.length); 877 878 final long copyTimeStart = java.lang.System.currentTimeMillis(); 879 880 inputAllocation.copyFrom(inputArray); 881 882 final long kernelTimeStart = java.lang.System.currentTimeMillis(); 883 final long[] rsResult = s.reduce_histogram(inputAllocation).get(); 884 final long rsTimeEnd = java.lang.System.currentTimeMillis(); 885 assertEquals("rsResult length", histogramBucketCount, rsResult.length); 886 887 // NOTE: The "java time" is actually for the RenderScript histogram intrinsic 888 final boolean success = 889 result("histogram", 890 new timing(javaTimeStart, javaTimeEnd, rsTimeStart, 891 copyTimeStart, kernelTimeStart, rsTimeEnd, inputAllocation), 892 javaResult, rsResult); 893 inputAllocation.destroy(); 894 return success; 895 } 896 897 //----------------------------------------------------------------- 898 899 private boolean patternRedundantGet(RenderScript RS, ScriptC_reduce s) { 900 // Ensure that get() can be called multiple times on the same 901 // result, and returns the same object each time. 902 903 boolean pass = true; 904 905 final int inputLength = 1 << 18; 906 final byte[] inputArray = createInputArrayByte(inputLength, 789); 907 908 final long[] javaResult = histogram(RS, inputArray); 909 assertEquals("javaResult length", histogramBucketCount, javaResult.length); 910 911 final ScriptC_reduce.resultArray256_uint rsResultFuture = s.reduce_histogram(inputArray); 912 final long[] rsResult1 = rsResultFuture.get(); 913 assertEquals("rsResult1 length", histogramBucketCount, rsResult1.length); 914 pass &= result("patternRedundantGet (1)", new timing(inputLength), javaResult, rsResult1); 915 916 final long[] rsResult2 = rsResultFuture.get(); 917 pass &= result("patternRedundantGet (2)", new timing(inputLength), javaResult, rsResult2); 918 919 final boolean success = (rsResult1 == rsResult2); 920 Log.i(TAG, "patternRedundantGet (object equality): " + (success ? "PASSED" : "FAILED")); 921 pass &= success; 922 923 return pass; 924 } 925 926 //----------------------------------------------------------------- 927 928 private Int2 mode(RenderScript RS, final byte[] inputArray) { 929 long[] hsg = histogram(RS, inputArray); 930 931 int modeIdx = 0; 932 for (int i = 1; i < hsg.length; ++i) 933 if (hsg[i] > hsg[modeIdx]) modeIdx = i; 934 return new Int2(modeIdx, (int) hsg[modeIdx]); 935 } 936 937 private boolean mode_array(RenderScript RS, ScriptC_reduce s, int seed, int size[]) { 938 final byte[] inputArray = createInputArrayByte(size[0], seed); 939 940 final Int2 javaResult = mode(RS, inputArray); 941 final Int2 rsResult = s.reduce_mode(inputArray).get(); 942 943 return result("mode", new timing(size[0]), javaResult, rsResult); 944 } 945 946 /////////////////////////////////////////////////////////////////// 947 948 private long sumgcd(final int in1[], final int in2[]) { 949 assertEquals("sumgcd input lengths", in1.length, in2.length); 950 951 long sum = 0; 952 for (int i = 0; i < in1.length; ++i) { 953 int a = in1[i], b = in2[i]; 954 955 while (b != 0) { 956 final int aNew = b; 957 final int bNew = a % b; 958 959 a = aNew; 960 b = bNew; 961 } 962 963 sum += a; 964 } 965 return sum; 966 } 967 968 private boolean sumgcd(RenderScript RS, ScriptC_reduce s, int seed, int size[]) { 969 final int len = size[0]; 970 971 final int[] inputArrayA = createInputArrayInt(len, seed + 0); 972 final int[] inputArrayB = createInputArrayInt(len, seed + 1); 973 974 final long javaTimeStart = java.lang.System.currentTimeMillis(); 975 final long javaResult = sumgcd(inputArrayA, inputArrayB); 976 final long javaTimeEnd = java.lang.System.currentTimeMillis(); 977 978 final long rsTimeStart = java.lang.System.currentTimeMillis(); 979 980 Allocation inputAllocationA = Allocation.createSized(RS, Element.I32(RS), len); 981 Allocation inputAllocationB = Allocation.createSized(RS, Element.I32(RS), len); 982 983 final long copyTimeStart = java.lang.System.currentTimeMillis(); 984 985 inputAllocationA.copyFrom(inputArrayA); 986 inputAllocationB.copyFrom(inputArrayB); 987 988 final long kernelTimeStart = java.lang.System.currentTimeMillis(); 989 final long rsResult = s.reduce_sumgcd(inputAllocationA, inputAllocationB).get(); 990 final long rsTimeEnd = java.lang.System.currentTimeMillis(); 991 992 final boolean success = 993 result("sumgcd", 994 new timing(javaTimeStart, javaTimeEnd, rsTimeStart, copyTimeStart, kernelTimeStart, rsTimeEnd, 995 inputAllocationA, inputAllocationB), 996 javaResult, rsResult); 997 inputAllocationA.destroy(); 998 inputAllocationB.destroy(); 999 return success; 1000 } 1001 1002 /////////////////////////////////////////////////////////////////// 1003 1004 // Return an array of sparse integer values from 0 to maxVal inclusive. 1005 // The array consists of all values k*sparseness (k a nonnegative integer) 1006 // that are less than maxVal, and maxVal itself. For example, if maxVal 1007 // is 20 and sparseness is 6, then the result is { 0, 6, 12, 18, 20 }; 1008 // and if maxVal is 20 and sparseness is 10, then the result is { 0, 10, 20 }. 1009 // 1010 // The elements of the array are sorted in increasing order. 1011 // 1012 // maxVal -- must be nonnegative 1013 // sparseness -- must be positive 1014 private static int[] computeSizePoints(int maxVal, int sparseness) { 1015 assertTrue((maxVal >= 0) && (sparseness > 0)); 1016 1017 final boolean maxValIsExtra = ((maxVal % sparseness) != 0); 1018 int[] result = new int[1 + maxVal / sparseness + (maxValIsExtra ? 1 : 0)]; 1019 1020 for (int i = 0; i * sparseness <= maxVal; ++i) 1021 result[i] = i * sparseness; 1022 if (maxValIsExtra) 1023 result[result.length - 1] = maxVal; 1024 1025 return result; 1026 } 1027 1028 private static final int maxSeedsPerTest = 10; 1029 1030 static interface Test { 1031 // A test execution is characterized by two properties: A seed 1032 // and a size. 1033 // 1034 // The seed is used for generating pseudorandom input data. 1035 // Ideally, we use different seeds for different tests and for 1036 // different executions of the same test at different sizes. 1037 // A test with multiple blocks of input data (i.e., for a 1038 // reduction with multiple inputs) may want multiple seeds; it 1039 // may use the seeds seed..seed+maxSeedsPerTest-1. 1040 // 1041 // The size indicates the amount of input data. It is the number 1042 // of cells in a particular dimension of the iteration space. 1043 boolean run(RenderScript RS, ScriptC_reduce s, int seed, int[] size); 1044 } 1045 1046 static class TestDescription { 1047 public TestDescription(String myTestName, Test myTest, int mySeed, int[] myDefSize, 1048 int myLog2MaxSize, int mySparseness) { 1049 testName = myTestName; 1050 test = myTest; 1051 seed = mySeed; 1052 defSize = myDefSize; 1053 log2MaxSize = myLog2MaxSize; 1054 sparseness = mySparseness; 1055 } 1056 1057 public TestDescription(String myTestName, Test myTest, int mySeed, int[] myDefSize, int myLog2MaxSize) { 1058 testName = myTestName; 1059 test = myTest; 1060 seed = mySeed; 1061 defSize = myDefSize; 1062 log2MaxSize = myLog2MaxSize; 1063 sparseness = 1; 1064 } 1065 1066 public TestDescription(String myTestName, Test myTest, int mySeed, int[] myDefSize) { 1067 testName = myTestName; 1068 test = myTest; 1069 seed = mySeed; 1070 defSize = myDefSize; 1071 log2MaxSize = -1; 1072 sparseness = 1; 1073 } 1074 1075 public final String testName; 1076 1077 public final Test test; 1078 1079 // When executing the test, scale this up by maxSeedsPerTest. 1080 public final int seed; 1081 1082 // If we're only going to run the test once, what size should 1083 // we use? The length of the array is the number of 1084 // dimensions of the input data. 1085 public final int[] defSize; 1086 1087 // If we're going to run the test over a range of sizes, what 1088 // is the maximum size to use? (This constrains the number of 1089 // cells of the input data, not the number of cells ALONG A 1090 // PARTICULAR DIMENSION of the input data.) 1091 public final int log2MaxSize; 1092 1093 // If we're going to run the test "exhaustively" over a range 1094 // of sizes, what is the size of a step through the range? 1095 // 1096 // For 1D, must be 1. 1097 public final int sparseness; 1098 } 1099 1100 private boolean run(TestDescription td, RenderScript RS, ScriptC_reduce s, int seed, int[] size) { 1101 String arrayContent = ""; 1102 for (int i = 0; i < size.length; ++i) { 1103 if (i != 0) 1104 arrayContent += ", "; 1105 arrayContent += size[i]; 1106 } 1107 Log.i(TAG, "Running " + td.testName + "(seed = " + seed + ", size[] = {" + arrayContent + "})"); 1108 return td.test.run(RS, s, seed, size); 1109 } 1110 1111 private final TestDescription[] correctnessTests = { 1112 // alloc and array variants of the same test will use the same 1113 // seed, in case results need to be compared. 1114 1115 new TestDescription("addint1D", this::addint1D, 0, new int[]{100000}, 20), 1116 new TestDescription("addint1D_array", this::addint1D_array, 0, new int[]{100000}, 20), 1117 new TestDescription("addint2D", this::addint2D, 1, new int[]{450, 225}, 20, 5), 1118 new TestDescription("addint3D", this::addint3D, 2, new int[]{37, 48, 49}, 20, 7), 1119 1120 // Bool and NaN variants of the same test will use the same 1121 // seed, in case results need to be compared. 1122 new TestDescription("findMinAbsBool", this::findMinAbsBool, 3, new int[]{100000}, 20), 1123 new TestDescription("findMinAbsNaN", this::findMinAbsNaN, 3, new int[]{100000}, 20), 1124 new TestDescription("findMinAbsBoolInf", this::findMinAbsBoolInf, 4, new int[]{100000}, 20), 1125 new TestDescription("findMinAbsNaNInf", this::findMinAbsNaNInf, 4, new int[]{100000}, 20), 1126 1127 new TestDescription("findMinAndMax", this::findMinAndMax, 5, new int[]{100000}, 20), 1128 new TestDescription("findMinAndMax_array", this::findMinAndMax_array, 5, new int[]{100000}, 20), 1129 new TestDescription("findMinMat2", this::findMinMat2, 6, new int[]{25000}, 17), 1130 new TestDescription("findMinMat4", this::findMinMat4, 7, new int[]{10000}, 15), 1131 new TestDescription("fz", this::fz, 8, new int[]{100000}, 20), 1132 new TestDescription("fz_array", this::fz_array, 8, new int[]{100000}, 20), 1133 new TestDescription("fz2", this::fz2, 9, new int[]{225, 450}, 20, 5), 1134 new TestDescription("fz3", this::fz3, 10, new int[]{59, 48, 37}, 20, 7), 1135 new TestDescription("histogram", this::histogram, 11, new int[]{100000}, 20), 1136 new TestDescription("histogram_array", this::histogram_array, 11, new int[]{100000}, 20), 1137 // might want to add: new TestDescription("mode", this::mode, 12, new int[]{100000}, 20), 1138 new TestDescription("mode_array", this::mode_array, 12, new int[]{100000}, 20), 1139 new TestDescription("sumgcd", this::sumgcd, 13, new int[]{1 << 16}, 20) 1140 }; 1141 1142 private boolean runCorrectnessQuick(RenderScript RS, ScriptC_reduce s) { 1143 boolean pass = true; 1144 1145 for (TestDescription td : correctnessTests) { 1146 pass &= run(td, RS, s, maxSeedsPerTest * td.seed, td.defSize); 1147 } 1148 1149 return pass; 1150 } 1151 1152 // NOTE: Each test execution gets maxSeedsPerTest, and there are 1153 // up to 3 + 5*log2MaxSize test executions in the full (as opposed 1154 // to quick) correctness run of a particular test description, and 1155 // we need an additional seed for pseudorandom size generation. 1156 // Assuming log2MaxSize does not exceed 32, then it should be 1157 // sufficient to reserve 1 + (3+5*32)*maxSeedsPerTest seeds per 1158 // TestDescription. 1159 // 1160 // See runCorrectness1D(). 1161 private static final int seedsPerTestDescriptionCorrectness1D = 1 + (3 + 5 * 32) * maxSeedsPerTest; 1162 1163 // NOTE: Each test execution gets maxSeedsPerTest, and there are 1164 // about 11*((log2MaxSize+1)**2) test executions in the full (as 1165 // opposed to quick) correctness run of a particular test 1166 // description, and we need a seed for pseudorandom size 1167 // generation. Assuming log2MaxSize does not exceed 32, then it 1168 // should be sufficient to reserve 1 + 11*1089*maxSeedsPerTest 1169 // seeds per TestDescription. 1170 // 1171 // See runCorrectness2D(). 1172 private static final int seedsPerTestDescriptionCorrectness2D = 1 + (11 * 1089) * maxSeedsPerTest; 1173 1174 // NOTE: Each test execution gets maxSeedsPerTest, and there are 1175 // about 27*((log2MaxSize+1)**3) + 6*((log2MaxSize+1)**2) test 1176 // executions in the full (as opposed to quick) correctness run of 1177 // a particular test description, and we need a seed for (c). 1178 // Assuming log2MaxSize does not exceed 32, then it should 1179 // be sufficient to reserve 1 + (27*(33**3) + 6*(33**2))*maxSeedsPerTest 1180 // seeds per TestDescription, which can be simplified upwards to 1181 // 1 + (28*(33**3))*maxSeedsPerTest seeds per TestDescription. 1182 private static final int seedsPerTestDescriptionCorrectness3D = 1 + (28 * 35937) * maxSeedsPerTest; 1183 1184 // Each test execution gets a certain number of seeds, and a full 1185 // (as opposed to quick) correctness run of a particular 1186 // TestDescription consists of some number of executions (each of 1187 // which needs up to maxSeedsPerTest) and may require some 1188 // additional seeds. 1189 private static final int seedsPerTestDescriptionCorrectness = 1190 Math.max(seedsPerTestDescriptionCorrectness1D, 1191 Math.max(seedsPerTestDescriptionCorrectness2D, 1192 seedsPerTestDescriptionCorrectness3D)); 1193 1194 private boolean runCorrectness(RenderScript RS, ScriptC_reduce s) { 1195 boolean pass = true; 1196 1197 for (TestDescription td : correctnessTests) { 1198 switch (td.defSize.length) { 1199 case 1: 1200 pass &= runCorrectness1D(td, RS, s); 1201 break; 1202 case 2: 1203 pass &= runCorrectness2D(td, RS, s); 1204 break; 1205 case 3: 1206 pass &= runCorrectness3D(td, RS, s); 1207 break; 1208 default: 1209 assertTrue("unexpected defSize.length " + td.defSize.length, false); 1210 pass &= false; 1211 break; 1212 } 1213 } 1214 1215 return pass; 1216 } 1217 1218 private boolean runCorrectness1D(TestDescription td, RenderScript RS, ScriptC_reduce s) { 1219 assertEquals(1, td.sparseness); 1220 final int log2MaxSize = td.log2MaxSize; 1221 assertTrue(log2MaxSize >= 0); 1222 1223 boolean pass = true; 1224 1225 // We will execute the test with the following sizes: 1226 // (a) Each power of 2 from zero (2**0) up to log2MaxSize (2**log2MaxSize) 1227 // (b) Each size from (a) +/-1 1228 // (c) 2 random sizes between each pair of adjacent points in (a) 1229 int[] testSizes = new int[ 1230 /* a */ (1 + log2MaxSize) + 1231 /* b */ 2 * (1 + log2MaxSize) + 1232 /* c */ 2 * log2MaxSize]; 1233 // See seedsPerTestDescriptionCorrectness1D 1234 1235 final int seedForPickingTestSizes = td.seed * seedsPerTestDescriptionCorrectness; 1236 1237 int nextTestIdx = 0; 1238 1239 // Fill in (a) and (b) 1240 for (int i = 0; i <= log2MaxSize; ++i) { 1241 final int pwrOf2 = 1 << i; 1242 testSizes[nextTestIdx++] = pwrOf2; /* a */ 1243 testSizes[nextTestIdx++] = pwrOf2 - 1; /* b */ 1244 testSizes[nextTestIdx++] = pwrOf2 + 1; /* b */ 1245 } 1246 1247 // Fill in (c) 1248 Random r = new Random(seedForPickingTestSizes); 1249 for (int i = 0; i < log2MaxSize; ++i) { 1250 final int lo = (1 << i) + 1; 1251 final int hi = 1 << (i + 1); 1252 1253 if (lo < hi) { 1254 for (int j = 0; j < 2; ++j) { 1255 testSizes[nextTestIdx++] = r.nextInt(hi - lo) + lo; 1256 } 1257 } 1258 } 1259 1260 Arrays.sort(testSizes); 1261 1262 int[] lastTestSizeArg = new int[]{-1}; 1263 for (int i = 0; i < testSizes.length; ++i) { 1264 if ((testSizes[i] > 0) && (testSizes[i] != lastTestSizeArg[0])) { 1265 lastTestSizeArg[0] = testSizes[i]; 1266 final int seedForTestExecution = seedForPickingTestSizes + 1 + i * maxSeedsPerTest; 1267 pass &= run(td, RS, s, seedForTestExecution, lastTestSizeArg); 1268 } 1269 } 1270 1271 return pass; 1272 } 1273 1274 private boolean runCorrectness2D(TestDescription td, RenderScript RS, ScriptC_reduce s) { 1275 final int log2MaxSize = td.log2MaxSize, maxSize = 1 << log2MaxSize, sparseness = td.sparseness; 1276 assertTrue((log2MaxSize >= 0) && (sparseness >= 1)); 1277 1278 boolean pass = true; 1279 1280 final int[] sizePoints = computeSizePoints(log2MaxSize, sparseness); 1281 1282 // We will execute the test with the following sizes: 1283 // (a) Each dimension at a power of 2 from sizePoints[] 1284 /// such that the sum of the exponents does not exceed 1285 // log2MaxSize 1286 // (b) Each size from (a) with one or both dimensions +/-1, 1287 // except where this would exceed 2**log2MaxSize 1288 // (c) Approximately 2*(sizePoints.length**2) random sizes 1289 ArrayList<int[]> testSizesList = new ArrayList<int[]>(); 1290 // See seedsPerTestDescriptionCorrectness2D 1291 1292 final int seedForPickingTestSizes = td.seed * seedsPerTestDescriptionCorrectness; 1293 1294 // Fill in (a) and (b) 1295 for (int i : sizePoints) { 1296 final int iPwrOf2 = 1 << i; 1297 for (int iDelta = -1; iDelta <= 1; ++iDelta) { 1298 final int iSize = iPwrOf2 + iDelta; 1299 for (int j : sizePoints) { 1300 final int jPwrOf2 = 1 << j; 1301 for (int jDelta = -1; jDelta <= 1; ++jDelta) { 1302 final int jSize = jPwrOf2 + jDelta; 1303 if ((long) iSize * (long) jSize <= maxSize) 1304 testSizesList.add(new int[]{iSize, jSize}); 1305 } 1306 } 1307 } 1308 } 1309 1310 // Fill in (c) 1311 Random r = new Random(seedForPickingTestSizes); 1312 for (int i : sizePoints) { 1313 for (int j : sizePoints) { 1314 final int size0 = 1 + r.nextInt(1 << i); 1315 final int size1 = 1 + r.nextInt(maxSize / size0); 1316 1317 testSizesList.add(new int[]{size0, size1}); 1318 testSizesList.add(new int[]{size1, size0}); 1319 } 1320 } 1321 1322 int[][] testSizes = testSizesList.toArray(new int[0][]); 1323 Arrays.sort(testSizes, 1324 (a, b) -> { 1325 final int comp0 = ((Integer) a[0]).compareTo(b[0]); 1326 return (comp0 != 0 ? comp0 : ((Integer) a[1]).compareTo(b[1])); 1327 }); 1328 1329 int[] lastTestSizeArg = null; 1330 for (int i = 0; i < testSizes.length; ++i) { 1331 if ((testSizes[i][0] <= 0) || (testSizes[i][1] <= 0)) 1332 continue; 1333 if ((lastTestSizeArg != null) && 1334 (testSizes[i][0] == lastTestSizeArg[0]) && 1335 (testSizes[i][1] == lastTestSizeArg[1])) 1336 continue; 1337 lastTestSizeArg = testSizes[i]; 1338 final int seedForTestExecution = seedForPickingTestSizes + 1 + i * maxSeedsPerTest; 1339 pass &= run(td, RS, s, seedForTestExecution, lastTestSizeArg); 1340 } 1341 1342 return pass; 1343 } 1344 1345 private boolean runCorrectness3D(TestDescription td, RenderScript RS, ScriptC_reduce s) { 1346 final int log2MaxSize = td.log2MaxSize, maxSize = 1 << log2MaxSize, sparseness = td.sparseness; 1347 assertTrue((log2MaxSize >= 0) && (sparseness >= 1)); 1348 1349 boolean pass = true; 1350 1351 final int[] sizePoints = computeSizePoints(log2MaxSize, sparseness); 1352 1353 // We will execute the test with the following sizes: 1354 // (a) Each dimension at a power of 2 from sizePoints[] 1355 /// such that the sum of the exponents does not exceed 1356 // log2MaxSize 1357 // (b) Each size from (a) with one or both dimensions +/-1, 1358 // except where this would exceed 2**log2MaxSize 1359 // (c) Approximately 6*(sizePoints.length**2) random sizes 1360 ArrayList<int[]> testSizesList = new ArrayList<int[]>(); 1361 // See seedsPerTestDescriptionCorrectness3D 1362 1363 final int seedForPickingTestSizes = td.seed * seedsPerTestDescriptionCorrectness; 1364 1365 // Fill in (a) and (b) 1366 for (int i : sizePoints) { 1367 final int iPwrOf2 = 1 << i; 1368 for (int iDelta = -1; iDelta <= 1; ++iDelta) { 1369 final int iSize = iPwrOf2 + iDelta; 1370 for (int j : sizePoints) { 1371 final int jPwrOf2 = 1 << j; 1372 for (int jDelta = -1; jDelta <= 1; ++jDelta) { 1373 final int jSize = jPwrOf2 + jDelta; 1374 for (int k : sizePoints) { 1375 final int kPwrOf2 = 1 << k; 1376 for (int kDelta = -1; kDelta <= 1; ++kDelta) { 1377 final int kSize = kPwrOf2 + kDelta; 1378 if ((long) iSize * (long) jSize * (long) kSize <= maxSize) 1379 testSizesList.add(new int[]{iSize, jSize, kSize}); 1380 } 1381 } 1382 } 1383 } 1384 } 1385 } 1386 1387 // Fill in (c) 1388 Random r = new Random(seedForPickingTestSizes); 1389 for (int i : sizePoints) { 1390 for (int j : sizePoints) { 1391 final int size0 = 1 + r.nextInt(1 << i); 1392 final int size1 = 1 + r.nextInt(Math.min(1 << j, maxSize / size0)); 1393 final int size2 = 1 + r.nextInt(maxSize / (size0 * size1)); 1394 1395 testSizesList.add(new int[]{size0, size1, size2}); 1396 testSizesList.add(new int[]{size0, size2, size1}); 1397 testSizesList.add(new int[]{size1, size0, size2}); 1398 testSizesList.add(new int[]{size1, size2, size0}); 1399 testSizesList.add(new int[]{size2, size0, size1}); 1400 testSizesList.add(new int[]{size2, size1, size0}); 1401 } 1402 } 1403 1404 int[][] testSizes = testSizesList.toArray(new int[0][]); 1405 Arrays.sort(testSizes, 1406 (a, b) -> { 1407 int comp = ((Integer) a[0]).compareTo(b[0]); 1408 if (comp == 0) 1409 comp = ((Integer) a[1]).compareTo(b[1]); 1410 if (comp == 0) 1411 comp = ((Integer) a[2]).compareTo(b[2]); 1412 return comp; 1413 }); 1414 1415 int[] lastTestSizeArg = null; 1416 for (int i = 0; i < testSizes.length; ++i) { 1417 if ((testSizes[i][0] <= 0) || (testSizes[i][1] <= 0) || (testSizes[i][2] <= 0)) 1418 continue; 1419 if ((lastTestSizeArg != null) && 1420 (testSizes[i][0] == lastTestSizeArg[0]) && 1421 (testSizes[i][1] == lastTestSizeArg[1]) && 1422 (testSizes[i][2] == lastTestSizeArg[2])) 1423 continue; 1424 1425 // Apply Z-dimension limiting. 1426 // 1427 // The Z dimension is always handled specially by GPU 1428 // drivers, and a high value for this dimension can have 1429 // serious performance implications. For example, Cuda 1430 // and OpenCL encourage Z to be the smallest dimension. 1431 if (testSizes[i][2] > 1024) 1432 continue; 1433 1434 lastTestSizeArg = testSizes[i]; 1435 final int seedForTestExecution = seedForPickingTestSizes + 1 + i * maxSeedsPerTest; 1436 pass &= run(td, RS, s, seedForTestExecution, lastTestSizeArg); 1437 } 1438 1439 return pass; 1440 } 1441 1442 private final TestDescription[] performanceTests = { 1443 new TestDescription("addint1D", this::addint1D, 0, new int[]{100000 << 10}), 1444 new TestDescription("addint2D", this::addint2D, 1, new int[]{450 << 5, 225 << 5}), 1445 new TestDescription("addint3D", this::addint3D, 2, new int[]{37 << 3, 48 << 3, 49 << 3}), 1446 new TestDescription("findMinAndMax", this::findMinAndMax, 3, new int[]{100000 << 9}), 1447 new TestDescription("fz", this::fz, 4, new int[]{100000 << 10}), 1448 new TestDescription("fz2", this::fz2, 5, new int[]{225 << 5, 450 << 5}), 1449 new TestDescription("fz3", this::fz3, 6, new int[]{59 << 3, 48 << 3, 37 << 3}), 1450 new TestDescription("histogram", this::histogram, 7, new int[]{100000 << 10}), 1451 // might want to add: new TestDescription("mode", this::mode, 8, new int[]{100000}), 1452 new TestDescription("sumgcd", this::sumgcd, 9, new int[]{1 << 21}) 1453 }; 1454 1455 private boolean runPerformanceQuick(RenderScript RS, ScriptC_reduce s) { 1456 boolean pass = true; 1457 1458 for (TestDescription td : performanceTests) { 1459 pass &= run(td, RS, s, maxSeedsPerTest * td.seed, td.defSize); 1460 } 1461 1462 return pass; 1463 } 1464 1465 private boolean runCorrectnessPatterns(RenderScript RS, ScriptC_reduce s) { 1466 // Test some very specific usage patterns. 1467 boolean pass = true; 1468 1469 pass &= patternDuplicateAnonymousResult(RS, s); 1470 pass &= patternFindMinAndMaxInf(RS, s); 1471 pass &= patternInterleavedReduce(RS, s); 1472 pass &= patternRedundantGet(RS, s); 1473 1474 return pass; 1475 } 1476 1477 public void run() { 1478 RenderScript pRS = RenderScript.create(mCtx); 1479 ScriptC_reduce s = new ScriptC_reduce(pRS); 1480 s.set_negInf(Float.NEGATIVE_INFINITY); 1481 s.set_posInf(Float.POSITIVE_INFINITY); 1482 1483 boolean pass = true; 1484 1485 pass &= runCorrectnessPatterns(pRS, s); 1486 pass &= runCorrectnessQuick(pRS, s); 1487 pass &= runCorrectness(pRS, s); 1488 // pass &= runPerformanceQuick(pRS, s); 1489 1490 pRS.finish(); 1491 s.destroy(); 1492 pRS.destroy(); 1493 1494 Log.i(TAG, pass ? "PASSED" : "FAILED"); 1495 if (pass) 1496 passTest(); 1497 else 1498 failTest(); 1499 } 1500} 1501 1502// TODO: Add machinery for easily running fuller (i.e., non-sparse) testing. 1503