| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* Same as UT_reduce_backward.java, except this test case exercises |
| * pragmas before the functions (forward reference), and the other |
| * test case exercises the pragmas after the functions (backward |
| * reference). |
| */ |
| |
| package com.android.rs.test; |
| |
| import android.content.Context; |
| import android.content.res.Resources; |
| import android.renderscript.*; |
| import android.util.Log; |
| import java.lang.Float; |
| import java.util.Random; |
| |
| public class UT_reduce extends UnitTest { |
| private static final String TAG = "reduce"; |
| |
| protected UT_reduce(RSTestCore rstc, Resources res, Context ctx) { |
| super(rstc, "reduce", ctx); |
| } |
| |
| private byte[] createInputArrayByte(int len, int seed) { |
| byte[] array = new byte[len]; |
| (new Random(seed)).nextBytes(array); |
| return array; |
| } |
| |
| private float[] createInputArrayFloat(int len, int seed) { |
| Random rand = new Random(seed); |
| float[] array = new float[len]; |
| for (int i = 0; i < len; ++i) |
| array[i] = rand.nextFloat(); |
| return array; |
| } |
| |
| private int[] createInputArrayInt(int len, int seed) { |
| Random rand = new Random(seed); |
| int[] array = new int[len]; |
| for (int i = 0; i < len; ++i) |
| array[i] = rand.nextInt(); |
| return array; |
| } |
| |
| private int[] createInputArrayInt(int len, int seed, int eltRange) { |
| Random rand = new Random(seed); |
| int[] array = new int[len]; |
| for (int i = 0; i < len; ++i) |
| array[i] = rand.nextInt(eltRange); |
| return array; |
| } |
| |
| private <T extends Number> boolean result(String testName, T javaRslt, T rsRslt) { |
| final boolean success = javaRslt.equals(rsRslt); |
| Log.i(TAG, |
| testName + ": java " + javaRslt + ", rs " + rsRslt + ": " + |
| (success ? "PASSED" : "FAILED")); |
| return success; |
| } |
| |
| private boolean result(String testName, Int2 javaRslt, Int2 rsRslt) { |
| final boolean success = (javaRslt.x == rsRslt.x) && (javaRslt.y == rsRslt.y); |
| Log.i(TAG, |
| testName + |
| ": java (" + javaRslt.x + ", " + javaRslt.y + ")" + |
| ", rs (" + rsRslt.x + ", " + rsRslt.y + ")" + |
| ": " + (success ? "PASSED" : "FAILED")); |
| return success; |
| } |
| |
| /////////////////////////////////////////////////////////////////// |
| |
| private int addint(int[] input) { |
| int rslt = 0; |
| for (int idx = 0; idx < input.length; ++idx) |
| rslt += input[idx]; |
| return rslt; |
| } |
| |
| private boolean addint1D(RenderScript RS, ScriptC_reduce s) { |
| final int[] input = createInputArrayInt(100000, 0, 1 << 13); |
| |
| final int javaRslt = addint(input); |
| final int rsRslt = s.reduce_addint(input).get(); |
| |
| return result("addint1D", javaRslt, rsRslt); |
| } |
| |
| private boolean addint2D(RenderScript RS, ScriptC_reduce s) { |
| final int dimX = 450, dimY = 225; |
| |
| final int[] inputArray = createInputArrayInt(dimX * dimY, 1, 1 << 13); |
| Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS)); |
| typeBuilder.setX(dimX).setY(dimY); |
| Allocation inputAllocation = Allocation.createTyped(RS, typeBuilder.create()); |
| inputAllocation.copy2DRangeFrom(0, 0, dimX, dimY, inputArray); |
| |
| final int javaRslt = addint(inputArray); |
| final int rsRslt = s.reduce_addint(inputAllocation).get(); |
| |
| return result("addint2D", javaRslt, rsRslt); |
| } |
| |
| /////////////////////////////////////////////////////////////////// |
| |
| private float dp(float[] input1, float[] input2) { |
| _RS_ASSERT("dp input length mismatch", input1.length == input2.length); |
| |
| float rslt = 0; |
| for (int idx = 0; idx < input1.length; ++idx) |
| rslt += input1[idx] * input2[idx]; |
| return rslt; |
| } |
| |
| private boolean dp(RenderScript RS, ScriptC_reduce s) { |
| final float[] input1 = createInputArrayFloat(100000, 2); |
| final float[] input2 = createInputArrayFloat(100000, 3); |
| |
| final float javaRslt = dp(input1, input2); |
| final float rsRslt = s.reduce_dp(input1, input2).get(); |
| |
| // NOTE: Using a floating point equality check to test for |
| // correctness -- as we do below -- is a bad idea. It's only |
| // reliable if the Java and RenderScript implementation of dp |
| // use the same algorithm. Equality could be broken by |
| // different optimizations between the two, or running the |
| // RenderScript algorithm multithreaded, or running the |
| // RenderScript algorithm on a GPU rather than the CPU. |
| // |
| // Should we be checking instead that the results are |
| // "sufficiently close"? Cooking the input set to try to |
| // ensure a deterministic result? Changing to integers |
| // instead? |
| return result("dp", javaRslt, rsRslt); |
| } |
| |
| /////////////////////////////////////////////////////////////////// |
| |
| private Int2 findMinAndMax(float[] input) { |
| float minVal = Float.POSITIVE_INFINITY; |
| int minIdx = -1; |
| float maxVal = Float.NEGATIVE_INFINITY; |
| int maxIdx = -1; |
| |
| for (int idx = 0; idx < input.length; ++idx) { |
| if (input[idx] < minVal) { |
| minVal = input[idx]; |
| minIdx = idx; |
| } |
| if (input[idx] > maxVal) { |
| maxVal = input[idx]; |
| maxIdx = idx; |
| } |
| } |
| |
| return new Int2(minIdx, maxIdx); |
| } |
| |
| private boolean findMinAndMax(RenderScript RS, ScriptC_reduce s) { |
| final float[] input = createInputArrayFloat(100000, 4); |
| |
| final Int2 javaRslt = findMinAndMax(input); |
| final Int2 rsRslt = s.reduce_findMinAndMax(input).get(); |
| |
| return result("findMinAndMax", javaRslt, rsRslt); |
| } |
| |
| /////////////////////////////////////////////////////////////////// |
| |
| private boolean fz(RenderScript RS, ScriptC_reduce s) { |
| final int inputLen = 100000; |
| int[] input = createInputArrayInt(inputLen, 5); |
| // just in case we got unlucky |
| input[(new Random(6)).nextInt(inputLen)] = 0; |
| |
| final int rsRslt = s.reduce_fz(input).get(); |
| |
| final boolean success = (input[rsRslt] == 0); |
| Log.i(TAG, |
| "fz: input[" + rsRslt + "] == " + input[rsRslt] + ": " + |
| (success ? "PASSED" : "FAILED")); |
| return success; |
| } |
| |
| /////////////////////////////////////////////////////////////////// |
| |
| private boolean fz2(RenderScript RS, ScriptC_reduce s) { |
| final int dimX = 225, dimY = 450; |
| final int inputLen = dimX * dimY; |
| |
| int[] inputArray = createInputArrayInt(inputLen, 7); |
| // just in case we got unlucky |
| inputArray[(new Random(8)).nextInt(inputLen)] = 0; |
| |
| Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS)); |
| typeBuilder.setX(dimX).setY(dimY); |
| Allocation inputAllocation = Allocation.createTyped(RS, typeBuilder.create()); |
| inputAllocation.copy2DRangeFrom(0, 0, dimX, dimY, inputArray); |
| |
| final Int2 rsRslt = s.reduce_fz2(inputAllocation).get(); |
| |
| final int cellVal = inputArray[rsRslt.x + dimX * rsRslt.y]; |
| final boolean success = (cellVal == 0); |
| Log.i(TAG, |
| "fz2: input[" + rsRslt.x + ", " + rsRslt.y + "] == " + cellVal + ": " + |
| (success ? "PASSED" : "FAILED")); |
| return success; |
| } |
| |
| /////////////////////////////////////////////////////////////////// |
| |
| private boolean fz3(RenderScript RS, ScriptC_reduce s) { |
| final int dimX = 59, dimY = 48, dimZ = 37; |
| final int inputLen = dimX * dimY * dimZ; |
| |
| int[] inputArray = createInputArrayInt(inputLen, 9); |
| // just in case we got unlucky |
| inputArray[(new Random(10)).nextInt(inputLen)] = 0; |
| |
| Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS)); |
| typeBuilder.setX(dimX).setY(dimY).setZ(dimZ); |
| Allocation inputAllocation = Allocation.createTyped(RS, typeBuilder.create()); |
| inputAllocation.copy3DRangeFrom(0, 0, 0, dimX, dimY, dimZ, inputArray); |
| |
| final Int3 rsRslt = s.reduce_fz3(inputAllocation).get(); |
| |
| final int cellVal = inputArray[rsRslt.x + dimX * rsRslt.y + dimX * dimY * rsRslt.z]; |
| final boolean success = (cellVal == 0); |
| Log.i(TAG, |
| "fz3: input[" + rsRslt.x + ", " + rsRslt.y + ", " + rsRslt.z + "] == " + cellVal + ": " + |
| (success ? "PASSED" : "FAILED")); |
| return success; |
| } |
| |
| /////////////////////////////////////////////////////////////////// |
| |
| private static final int histogramBucketCount = 256; |
| |
| private long[] histogram(RenderScript RS, final byte[] inputArray) { |
| Allocation inputAllocation = Allocation.createSized(RS, Element.U8(RS), inputArray.length); |
| inputAllocation.copyFrom(inputArray); |
| |
| Allocation outputAllocation = Allocation.createSized(RS, Element.U32(RS), histogramBucketCount); |
| |
| ScriptIntrinsicHistogram scriptHsg = ScriptIntrinsicHistogram.create(RS, Element.U8(RS)); |
| scriptHsg.setOutput(outputAllocation); |
| scriptHsg.forEach(inputAllocation); |
| |
| int[] outputArrayMistyped = new int[histogramBucketCount]; |
| outputAllocation.copyTo(outputArrayMistyped); |
| |
| long[] outputArray = new long[histogramBucketCount]; |
| for (int i = 0; i < histogramBucketCount; ++i) |
| outputArray[i] = outputArrayMistyped[i] & (long)0xffffffff; |
| return outputArray; |
| } |
| |
| private boolean histogram(RenderScript RS, ScriptC_reduce s) { |
| final byte[] inputArray = createInputArrayByte(100000, 11); |
| |
| final long[] javaRslt = histogram(RS, inputArray); |
| _RS_ASSERT("javaRslt unexpected length: " + javaRslt.length, javaRslt.length == histogramBucketCount); |
| final long[] rsRslt = s.reduce_histogram(inputArray).get(); |
| _RS_ASSERT("rsRslt unexpected length: " + rsRslt.length, rsRslt.length == histogramBucketCount); |
| |
| for (int i = 0; i < histogramBucketCount; ++i) { |
| if (javaRslt[i] != rsRslt[i]) { |
| Log.i(TAG, |
| "histogram[" + i + "]: java " + javaRslt[i] + ", rs " + rsRslt[i] + ": FAILED"); |
| return false; |
| } |
| } |
| |
| Log.i(TAG, "histogram: PASSED"); |
| return true; |
| } |
| |
| //----------------------------------------------------------------- |
| |
| private Int2 mode(RenderScript RS, final byte[] inputArray) { |
| long[] hsg = histogram(RS, inputArray); |
| |
| int modeIdx = 0; |
| for (int i = 1; i < hsg.length; ++i) |
| if (hsg[i] > hsg[modeIdx]) modeIdx =i; |
| return new Int2(modeIdx, (int)hsg[modeIdx]); |
| } |
| |
| private boolean mode(RenderScript RS, ScriptC_reduce s) { |
| final byte[] inputArray = createInputArrayByte(100000, 12); |
| |
| final Int2 javaRslt = mode(RS, inputArray); |
| final Int2 rsRslt = s.reduce_mode(inputArray).get(); |
| |
| return result("mode", javaRslt, rsRslt); |
| } |
| |
| /////////////////////////////////////////////////////////////////// |
| |
| public void run() { |
| RenderScript pRS = RenderScript.create(mCtx); |
| ScriptC_reduce s = new ScriptC_reduce(pRS); |
| s.set_negInf(Float.NEGATIVE_INFINITY); |
| s.set_posInf(Float.POSITIVE_INFINITY); |
| |
| boolean pass = true; |
| pass &= addint1D(pRS, s); |
| pass &= addint2D(pRS, s); |
| pass &= dp(pRS, s); |
| pass &= findMinAndMax(pRS, s); |
| pass &= fz(pRS, s); |
| pass &= fz2(pRS, s); |
| pass &= fz3(pRS, s); |
| pass &= histogram(pRS, s); |
| pass &= mode(pRS, s); |
| |
| pRS.finish(); |
| pRS.destroy(); |
| |
| Log.i(TAG, pass ? "PASSED" : "FAILED"); |
| if (pass) |
| passTest(); |
| else |
| failTest(); |
| } |
| } |