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