Add test for atomics

Test to validate the RS atomic ops work.  Runs kernel
using atomics to sum up values with multiple threads.

Change-Id: I2672fa5b595a8ddb0ad1d6e759941bcebe174e5e
diff --git a/tests/src/android/renderscript/cts/AtomicTest.rs b/tests/src/android/renderscript/cts/AtomicTest.rs
new file mode 100644
index 0000000..2a78ffd
--- /dev/null
+++ b/tests/src/android/renderscript/cts/AtomicTest.rs
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include "shared.rsh"
+#include "rs_atomic.rsh"
+
+volatile int32_t gISum;
+volatile uint32_t gUSum;
+
+
+void __attribute__((kernel)) test_Inc(int32_t v) {
+    rsAtomicInc(&gISum);
+}
+void __attribute__((kernel)) test_uInc(uint32_t v) {
+    rsAtomicInc(&gUSum);
+}
+
+void __attribute__((kernel)) test_Dec(int32_t v) {
+    rsAtomicDec(&gISum);
+}
+void __attribute__((kernel)) test_uDec(uint32_t v) {
+    rsAtomicDec(&gUSum);
+}
+
+#define TEST_OP(op)                                     \
+void __attribute__((kernel)) test_##op(int32_t v) {     \
+    rsAtomic##op(&gISum, v);                            \
+}                                                       \
+void __attribute__((kernel)) test_u##op(uint32_t v) {   \
+    rsAtomic##op(&gUSum, v);                            \
+}
+
+TEST_OP(Add)
+TEST_OP(Sub)
+TEST_OP(And)
+TEST_OP(Or)
+TEST_OP(Xor)
+TEST_OP(Min)
+TEST_OP(Max)
+
+// the folowing functions copy the global to an allocation
+// to allow the calling code to read it back.
+void getValueS(rs_allocation v) {
+    rsSetElementAt_int(v, gISum, 0);
+}
+
+void getValueU(rs_allocation v) {
+    rsSetElementAt_uint(v, gUSum, 0);
+}
+
+void computeReference_Min(rs_allocation a, rs_allocation result) {
+    uint32_t dimX = rsAllocationGetDimX(a);
+    uint32_t dimY = rsAllocationGetDimY(a);
+    for (uint32_t y = 0; y < dimY; y++) {
+        for (uint32_t x = 0; x < dimX; x++) {
+            int v = rsGetElementAt_int(a, x, y);
+            gISum = min(gISum, v);
+        }
+    }
+    rsSetElementAt_int(result, gISum, 0);
+}
+
+void computeReference_uMin(rs_allocation a, rs_allocation result) {
+    uint32_t dimX = rsAllocationGetDimX(a);
+    uint32_t dimY = rsAllocationGetDimY(a);
+    for (uint32_t y = 0; y < dimY; y++) {
+        for (uint32_t x = 0; x < dimX; x++) {
+            uint v = rsGetElementAt_uint(a, x, y);
+            gUSum = min(gUSum, v);
+        }
+    }
+    rsSetElementAt_uint(result, gUSum, 0);
+}
+
+void computeReference_Max(rs_allocation a, rs_allocation result) {
+    uint32_t dimX = rsAllocationGetDimX(a);
+    uint32_t dimY = rsAllocationGetDimY(a);
+    for (uint32_t y = 0; y < dimY; y++) {
+        for (uint32_t x = 0; x < dimX; x++) {
+            int v = rsGetElementAt_int(a, x, y);
+            gISum = max(gISum, v);
+        }
+    }
+    rsSetElementAt_int(result, gISum, 0);
+}
+
+void computeReference_uMax(rs_allocation a, rs_allocation result) {
+    uint32_t dimX = rsAllocationGetDimX(a);
+    uint32_t dimY = rsAllocationGetDimY(a);
+    for (uint32_t y = 0; y < dimY; y++) {
+        for (uint32_t x = 0; x < dimX; x++) {
+            uint v = rsGetElementAt_uint(a, x, y);
+            gUSum = max(gUSum, v);
+        }
+    }
+    rsSetElementAt_uint(result, gUSum, 0);
+}
+
+
+void __attribute__((kernel)) test_Cas(int32_t v) {
+    int tmp = gISum;
+    int retryCount = 10000;
+    while (retryCount && (rsAtomicCas(&gISum, tmp, tmp + 1) != tmp)) {
+        retryCount--;
+        tmp = gISum;
+    }
+}
+void __attribute__((kernel)) test_uCas(uint32_t v) {
+    uint tmp = gUSum;
+    int retryCount = 10000;
+    while (retryCount && (rsAtomicCas(&gUSum, tmp, tmp + 1) != tmp)) {
+        retryCount--;
+        tmp = gUSum;
+    }
+}
+
+
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/AtomicTest.java b/tests/tests/renderscript/src/android/renderscript/cts/AtomicTest.java
new file mode 100644
index 0000000..a0e3b7a
--- /dev/null
+++ b/tests/tests/renderscript/src/android/renderscript/cts/AtomicTest.java
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+package android.renderscript.cts;
+import java.util.Random;
+import android.renderscript.*;
+
+public class AtomicTest extends RSBaseCompute {
+    int[] mSrcData;
+    int[] mReturnData = new int[1];
+    int[] mRefData = new int[1];
+    ScriptC_AtomicTest mScript;
+    Allocation mSrc;
+    Allocation mReturn;
+
+    private void initS(boolean fillData, int sz) {
+        mSrcData = new int[sz * sz];
+        mScript = new ScriptC_AtomicTest(mRS);
+        mSrc = Allocation.createTyped(mRS, Type.createXY(mRS, Element.I32(mRS), sz, sz));
+        mReturn = Allocation.createSized(mRS, Element.I32(mRS), 1);
+        if (fillData) {
+            RSUtils.genRandomInts(0, mSrcData, true, 32);
+            mSrc.copyFrom(mSrcData);
+        }
+    }
+
+    private void initU(boolean fillData, int sz) {
+        mSrcData = new int[sz * sz];
+        mScript = new ScriptC_AtomicTest(mRS);
+        mSrc = Allocation.createTyped(mRS, Type.createXY(mRS, Element.U32(mRS), sz, sz));
+        mReturn = Allocation.createSized(mRS, Element.U32(mRS), 1);
+        if (fillData) {
+            RSUtils.genRandomInts(0, mSrcData, false, 32);
+            mSrc.copyFrom(mSrcData);
+        }
+    }
+
+    public void testCas() {
+        initS(true, 1024);
+        mScript.set_gISum(10);
+        mScript.forEach_test_Cas(mSrc);
+        mScript.invoke_getValueS(mReturn);
+        mReturn.copyTo(mReturnData);
+        assertEquals("Incorrect value for Cas ", (10 + 1024*1024), mReturnData[0]);
+    }
+
+    public void testUCas() {
+        initU(true, 1024);
+        mScript.set_gUSum(10);
+        mScript.forEach_test_uCas(mSrc);
+        mScript.invoke_getValueU(mReturn);
+        mReturn.copyTo(mReturnData);
+        assertEquals("Incorrect value for UCas ", (10 + 1024*1024), mReturnData[0]);
+    }
+
+    public void testInc() {
+        initS(true, 1024);
+        mScript.set_gISum(10);
+        mScript.forEach_test_Inc(mSrc);
+        mScript.invoke_getValueS(mReturn);
+        mReturn.copyTo(mReturnData);
+        assertEquals("Incorrect value for Inc ", (10 + 1024*1024), mReturnData[0]);
+    }
+
+    public void testUInc() {
+        initU(true, 1024);
+        mScript.set_gUSum(10);
+        mScript.forEach_test_uInc(mSrc);
+        mScript.invoke_getValueU(mReturn);
+        mReturn.copyTo(mReturnData);
+        assertEquals("Incorrect value for UInc ", (10 + 1024*1024), mReturnData[0]);
+    }
+
+    public void testDec() {
+        initS(true, 1024);
+        mScript.set_gISum(10 + 1024*1024);
+        mScript.forEach_test_Dec(mSrc);
+        mScript.invoke_getValueS(mReturn);
+        mReturn.copyTo(mReturnData);
+        assertEquals("Incorrect value for Dec ", 10, mReturnData[0]);
+    }
+
+    public void testUDec() {
+        initU(true, 1024);
+        mScript.set_gUSum(10 + 1024*1024);
+        mScript.forEach_test_uDec(mSrc);
+        mScript.invoke_getValueU(mReturn);
+        mReturn.copyTo(mReturnData);
+        assertEquals("Incorrect value for UDec ", 10, mReturnData[0]);
+    }
+
+
+    public void testAdd() {
+        initS(true, 1024);
+        mScript.set_gISum(10);
+        mScript.forEach_test_Add(mSrc);
+        mScript.invoke_getValueS(mReturn);
+        mReturn.copyTo(mReturnData);
+
+        int sExpected = 10;
+        for (int i=0; i < mSrcData.length; i++) {
+            sExpected += mSrcData[i];
+        }
+        assertEquals("Incorrect value for Add ", sExpected, mReturnData[0]);
+    }
+
+    public void testUAdd() {
+        initU(true, 1024);
+        mScript.set_gUSum(10);
+        mScript.forEach_test_uAdd(mSrc);
+        mScript.invoke_getValueU(mReturn);
+        mReturn.copyTo(mReturnData);
+
+        int sExpected = 10;
+        for (int i=0; i < mSrcData.length; i++) {
+            sExpected += mSrcData[i];
+        }
+        assertEquals("Incorrect value for UAdd ", sExpected, mReturnData[0]);
+    }
+
+    public void testSub() {
+        initS(true, 1024);
+        mScript.set_gISum(10);
+        mScript.forEach_test_Sub(mSrc);
+        mScript.invoke_getValueS(mReturn);
+        mReturn.copyTo(mReturnData);
+
+        int sExpected = 10;
+        for (int i=0; i < mSrcData.length; i++) {
+            sExpected -= mSrcData[i];
+        }
+        assertEquals("Incorrect value for Sub ", sExpected, mReturnData[0]);
+    }
+
+    public void testUSub() {
+        initU(true, 1024);
+        mScript.set_gUSum(10);
+        mScript.forEach_test_uSub(mSrc);
+        mScript.invoke_getValueU(mReturn);
+        mReturn.copyTo(mReturnData);
+
+        int sExpected = 10;
+        for (int i=0; i < mSrcData.length; i++) {
+            sExpected -= mSrcData[i];
+        }
+        assertEquals("Incorrect value for USub ", sExpected, mReturnData[0]);
+    }
+
+    public void testXor() {
+        initS(true, 1024);
+        mScript.set_gISum(10);
+        mScript.forEach_test_Xor(mSrc);
+        mScript.invoke_getValueS(mReturn);
+        mReturn.copyTo(mReturnData);
+
+        int sExpected = 10;
+        for (int i=0; i < mSrcData.length; i++) {
+            sExpected ^= mSrcData[i];
+        }
+        assertEquals("Incorrect value for Xor ", sExpected, mReturnData[0]);
+    }
+
+    public void testUXor() {
+        initU(true, 1024);
+        mScript.set_gUSum(10);
+        mScript.forEach_test_uXor(mSrc);
+        mScript.invoke_getValueU(mReturn);
+        mReturn.copyTo(mReturnData);
+
+        int sExpected = 10;
+        for (int i=0; i < mSrcData.length; i++) {
+            sExpected ^= mSrcData[i];
+        }
+        assertEquals("Incorrect value for UXor ", sExpected, mReturnData[0]);
+    }
+
+    public void testMin() {
+        for (int i = 0; i < 16; i++) {
+            initS(true, 256);
+
+            mScript.set_gISum(0x7fffffff);
+            mScript.forEach_test_Min(mSrc);
+            mScript.invoke_getValueS(mReturn);
+            mReturn.copyTo(mReturnData);
+
+            mScript.set_gISum(0x7fffffff);
+            mScript.invoke_computeReference_Min(mSrc, mReturn);
+            mReturn.copyTo(mRefData);
+
+            assertEquals("Incorrect value for Min ", mRefData[0], mReturnData[0]);
+        }
+    }
+
+    public void testUMin() {
+        for (int i = 0; i < 16; i++) {
+            initU(true, 256);
+
+            mScript.set_gUSum(0xffffffffL);
+            mScript.forEach_test_uMin(mSrc);
+            mScript.invoke_getValueU(mReturn);
+            mReturn.copyTo(mReturnData);
+
+            mScript.set_gUSum(0xffffffffL);
+            mScript.invoke_computeReference_uMin(mSrc, mReturn);
+            mReturn.copyTo(mRefData);
+
+            assertEquals("Incorrect value for UMin ", mRefData[0], mReturnData[0]);
+        }
+    }
+
+    public void testMax() {
+        for (int i = 0; i < 16; i++) {
+            initS(true, 256);
+
+            mScript.set_gISum(0);
+            mScript.forEach_test_Max(mSrc);
+            mScript.invoke_getValueS(mReturn);
+            mReturn.copyTo(mReturnData);
+
+            mScript.set_gISum(0);
+            mScript.invoke_computeReference_Max(mSrc, mReturn);
+            mReturn.copyTo(mRefData);
+
+            assertEquals("Incorrect value for Min ", mRefData[0], mReturnData[0]);
+        }
+    }
+
+    public void testUMax() {
+        for (int i = 0; i < 16; i++) {
+            initU(true, 256);
+
+            mScript.set_gISum(0);
+            mScript.forEach_test_uMax(mSrc);
+            mScript.invoke_getValueU(mReturn);
+            mReturn.copyTo(mReturnData);
+
+            mScript.set_gISum(0);
+            mScript.invoke_computeReference_uMax(mSrc, mReturn);
+            mReturn.copyTo(mRefData);
+
+            assertEquals("Incorrect value for UMax ", mRefData[0], mReturnData[0]);
+        }
+    }
+
+    public void testAnd() {
+        Random r = new Random(78);
+
+        for (int i = 0; i < 64; i++) {
+            initS(false, 128);
+
+            for (int j = 0; j < mSrcData.length; j++) {
+                mSrcData[j] = ~0;
+            }
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x40000000;
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x10000000;
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x02000000;
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x00c00000;
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x00010000;
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x00080000;
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x00001000;
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x00000200;
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x0000000f;
+            mSrc.copyFrom(mSrcData);
+
+            mScript.set_gISum(0xffffffff);
+            mScript.forEach_test_And(mSrc);
+            mScript.invoke_getValueS(mReturn);
+            mReturn.copyTo(mReturnData);
+
+            int sExpected = 0xffffffff;
+            for (int j = 0; j < mSrcData.length; j++) {
+                sExpected &= mSrcData[j];
+            }
+            assertEquals("Incorrect value for And ", sExpected, mReturnData[0]);
+        }
+    }
+
+    public void testUAnd() {
+        Random r = new Random(78);
+
+        for (int i = 0; i < 64; i++) {
+            initU(false, 128);
+
+            for (int j = 0; j < mSrcData.length; j++) {
+                mSrcData[j] = ~0;
+            }
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x40000000;
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x10000000;
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x02000000;
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x00c00000;
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x00010000;
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x00080000;
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x00001000;
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x00000200;
+            mSrcData[r.nextInt(mSrcData.length)] = ~0x0000000f;
+            mSrc.copyFrom(mSrcData);
+
+            mScript.set_gUSum(0xffffffffL);
+            mScript.forEach_test_uAnd(mSrc);
+            mScript.invoke_getValueU(mReturn);
+            mReturn.copyTo(mReturnData);
+
+            int sExpected = 0xffffffff;
+            for (int j = 0; j < mSrcData.length; j++) {
+                sExpected &= mSrcData[j];
+            }
+            assertEquals("Incorrect value for uAnd ", sExpected, mReturnData[0]);
+        }
+    }
+
+    public void testOr() {
+        Random r = new Random(78);
+
+        for (int i = 0; i < 64; i++) {
+            initS(false, 128);
+
+            for (int j = 0; j < mSrcData.length; j++) {
+                mSrcData[j] = 0;
+            }
+            mSrcData[r.nextInt(mSrcData.length)] = 0x40000000;
+            mSrcData[r.nextInt(mSrcData.length)] = 0x10000000;
+            mSrcData[r.nextInt(mSrcData.length)] = 0x02000000;
+            mSrcData[r.nextInt(mSrcData.length)] = 0x00c00000;
+            mSrcData[r.nextInt(mSrcData.length)] = 0x00010000;
+            mSrcData[r.nextInt(mSrcData.length)] = 0x00080000;
+            mSrcData[r.nextInt(mSrcData.length)] = 0x00001000;
+            mSrcData[r.nextInt(mSrcData.length)] = 0x00000200;
+            mSrcData[r.nextInt(mSrcData.length)] = 0x0000000f;
+            mSrc.copyFrom(mSrcData);
+
+            mScript.set_gISum(0);
+            mScript.forEach_test_Or(mSrc);
+            mScript.invoke_getValueS(mReturn);
+            mReturn.copyTo(mReturnData);
+
+            int sExpected = 0;
+            for (int j = 0; j < mSrcData.length; j++) {
+                sExpected |= mSrcData[j];
+            }
+            assertEquals("Incorrect value for Or ", sExpected, mReturnData[0]);
+        }
+    }
+
+    public void testUOr() {
+        Random r = new Random(78);
+
+        for (int i = 0; i < 64; i++) {
+            initU(false, 128);
+
+            for (int j = 0; j < mSrcData.length; j++) {
+                mSrcData[j] = 0;
+            }
+            mSrcData[r.nextInt(mSrcData.length)] = 0x40000000;
+            mSrcData[r.nextInt(mSrcData.length)] = 0x10000000;
+            mSrcData[r.nextInt(mSrcData.length)] = 0x02000000;
+            mSrcData[r.nextInt(mSrcData.length)] = 0x00c00000;
+            mSrcData[r.nextInt(mSrcData.length)] = 0x00010000;
+            mSrcData[r.nextInt(mSrcData.length)] = 0x00080000;
+            mSrcData[r.nextInt(mSrcData.length)] = 0x00001000;
+            mSrcData[r.nextInt(mSrcData.length)] = 0x00000200;
+            mSrcData[r.nextInt(mSrcData.length)] = 0x0000000f;
+            mSrc.copyFrom(mSrcData);
+
+            mScript.set_gUSum(0);
+            mScript.forEach_test_uOr(mSrc);
+            mScript.invoke_getValueU(mReturn);
+            mReturn.copyTo(mReturnData);
+
+            int sExpected = 0;
+            for (int j = 0; j < mSrcData.length; j++) {
+                sExpected |= mSrcData[j];
+            }
+            assertEquals("Incorrect value for UOr ", sExpected, mReturnData[0]);
+        }
+    }
+
+}
+