Relax TestGpuNnapi accuracy check with a tolerance. am: 97b7166ad0 am: a2cd69d871 am: 627387d9e8

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/modules/NeuralNetworks/+/15756398

Change-Id: I92001b7a8a4aeafb8470d10247464c940d8d592b
diff --git a/runtime/test/TestGpuNnapi.cpp b/runtime/test/TestGpuNnapi.cpp
index 2782e9d..61809c4 100644
--- a/runtime/test/TestGpuNnapi.cpp
+++ b/runtime/test/TestGpuNnapi.cpp
@@ -103,6 +103,7 @@
 //   - ElementType: The corresponding C++ type. Use sizeof(ElementType) to get the element size.
 //   - kIsQuantized: Whether the data type is a quantized type or not.
 //   - kClearData: The CLEAR_DATA used in the compute shader.
+//   - kTolerance: The absolute tolerance used to check the computation result.
 template <Type dataType>
 struct TestTypeHelper;
 template <>
@@ -111,6 +112,7 @@
     static constexpr bool kIsQuantized = false;
     // One float32 of value (1.0) packed into uint32_t
     static constexpr uint32_t kClearData = 0x3f800000;
+    static constexpr double kTolerance = 1e-6;
 };
 template <>
 struct TestTypeHelper<Type::TENSOR_FLOAT16> {
@@ -118,6 +120,7 @@
     static constexpr bool kIsQuantized = false;
     // Two float16 of value (1.0) packed into uint32_t
     static constexpr uint32_t kClearData = 0x3c003c00;
+    static constexpr double kTolerance = 1e-3;
 };
 template <>
 struct TestTypeHelper<Type::TENSOR_QUANT8_ASYMM> {
@@ -125,6 +128,7 @@
     static constexpr bool kIsQuantized = true;
     // Four uint8_t of value (1) packed into uint32_t
     static constexpr uint32_t kClearData = 0x01010101;
+    static constexpr double kTolerance = 0;
 };
 template <>
 struct TestTypeHelper<Type::TENSOR_QUANT8_ASYMM_SIGNED> {
@@ -132,6 +136,7 @@
     static constexpr bool kIsQuantized = true;
     // Four int8_t of value (1) packed into uint32_t
     static constexpr uint32_t kClearData = 0x01010101;
+    static constexpr double kTolerance = 0;
 };
 
 bool isExtensionSupported(const std::vector<VkExtensionProperties>& supportedExtensions,
@@ -960,12 +965,13 @@
             auto [nnapiSuccess, nnapiSyncFd] = nnapi->run(gpuSyncFd);
             ASSERT_TRUE(nnapiSuccess);
 
-            checkResults<dataType>(std::move(nnapiSyncFd));
+            const double tolerance = TestTypeHelper<dataType>::kTolerance;
+            checkResults<dataType>(std::move(nnapiSyncFd), tolerance);
         }
     }
 
     template <Type dataType>
-    void checkResults(base::unique_fd syncFd) {
+    void checkResults(base::unique_fd syncFd, double tolerance) {
         using ElementType = typename TestTypeHelper<dataType>::ElementType;
 
         // Lock the buffer with the sync fence
@@ -981,12 +987,14 @@
         for (uint32_t i = 0; i < kOperandLength; i++) {
             const ElementType actual = reinterpret_cast<ElementType*>(data)[i];
 
-            // We expect bit-exact here because the arithmetic is trivial, and all intermediate
-            // and final results can be exactly represented by the primary data type.
-            if (actual != expected) {
+            // We expect the absolute difference in double is within the tolerance.
+            const double expected_f64 = static_cast<double>(expected);
+            const double actual_f64 = static_cast<double>(actual);
+            const double diff = std::abs(expected_f64 - actual_f64);
+            if (diff > tolerance) {
                 // Print at most kMaxNumberOfPrintedErrors errors by EXPECT_EQ
                 if (numberOfErrors < kMaxNumberOfPrintedErrors) {
-                    EXPECT_EQ(actual, expected)
+                    EXPECT_NEAR(actual_f64, expected_f64, tolerance)
                             << "When comparing element [" << kOperandLength / kOperandSizeX << ", "
                             << kOperandLength % kOperandSizeX << "]";
                 }