1 /*
2  * Copyright (C) 2018 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 #include <gmock/gmock.h>
18 #include <gtest/gtest.h>
19 
20 #include <limits>
21 #include <utility>
22 #include <vector>
23 
24 #include "HalInterfaces.h"
25 #include "MemoryUtils.h"
26 #include "OperationsExecutionUtils.h"
27 #include "QuantUtils.h"
28 #include "Utils.h"
29 #include "ValidateHal.h"
30 #include "nnapi/TypeUtils.h"
31 #include "nnapi/Types.h"
32 
33 namespace android {
34 namespace nn {
35 namespace wrapper {
36 
37 namespace {
38 using ::testing::ElementsAreArray;
39 }  // namespace
40 
TEST(CalculateBroadcastedShapeTest,Basic)41 TEST(CalculateBroadcastedShapeTest, Basic) {
42     Shape shape1;
43     Shape shape2;
44     shape1.dimensions = {4, 3, 2, 1};
45     shape2.dimensions = {3, 1, 5};
46 
47     Shape expectedOutputShape;
48     expectedOutputShape.dimensions = {4, 3, 2, 5};
49 
50     Shape actualOutputShape;
51     EXPECT_TRUE(calculateBroadcastedShape(shape1, shape2, &actualOutputShape));
52     EXPECT_THAT(actualOutputShape.dimensions, ElementsAreArray(expectedOutputShape.dimensions));
53 
54     EXPECT_TRUE(calculateBroadcastedShape(shape2, shape1, &actualOutputShape));
55     EXPECT_THAT(actualOutputShape.dimensions, ElementsAreArray(expectedOutputShape.dimensions));
56 }
57 
TEST(CalculateBroadcastedShapeTest,FailsOnIncompatible)58 TEST(CalculateBroadcastedShapeTest, FailsOnIncompatible) {
59     Shape shape1;
60     Shape shape2;
61     shape1.dimensions = {5};
62     shape2.dimensions = {3};
63 
64     Shape actualOutputShape;
65     EXPECT_FALSE(calculateBroadcastedShape(shape1, shape2, &actualOutputShape));
66     EXPECT_FALSE(calculateBroadcastedShape(shape2, shape1, &actualOutputShape));
67 }
68 
getExtensionType(uint16_t extensionPrefix,uint16_t typeWithinExtension)69 static int32_t getExtensionType(uint16_t extensionPrefix, uint16_t typeWithinExtension) {
70     int32_t type = (extensionPrefix << kExtensionTypeBits) | typeWithinExtension;
71     EXPECT_TRUE(isExtensionOperandType(static_cast<V1_3::OperandType>(type)));
72     return type;
73 }
74 
TEST(TensorHasUnspecifiedDimensionsTest,ExtensionTensorWithUnspecifiedRank)75 TEST(TensorHasUnspecifiedDimensionsTest, ExtensionTensorWithUnspecifiedRank) {
76     // Regression test for b/124285861.
77     EXPECT_TRUE(tensorHasUnspecifiedDimensions(getExtensionType(1, 0), /*dim=*/nullptr,
78                                                /*dimCount=*/0));
79 }
80 
TEST(ValidateOperandTypeTest,ExtensionTensorWithUnspecifiedRank)81 TEST(ValidateOperandTypeTest, ExtensionTensorWithUnspecifiedRank) {
82     // Regression test for b/124104123.
83     constexpr uint16_t kExtensionPrefix = 1;
84     constexpr uint16_t kTypeWithinExtension = 0;
85     int32_t extensionType = getExtensionType(kExtensionPrefix, kTypeWithinExtension);
86     ANeuralNetworksOperandType type = {
87             .type = extensionType,
88             .dimensionCount = 0,
89             .dimensions = nullptr,
90     };
91     Extension::OperandTypeInformation info = {
92             .type = kTypeWithinExtension,
93             .isTensor = true,
94             .byteSize = 4,
95     };
96     EXPECT_EQ(validateOperandType(type, &info, /*tag=*/"test", /*allowPartial=*/true),
97               ANEURALNETWORKS_NO_ERROR);
98     EXPECT_EQ(validateOperandType(type, &info, /*tag=*/"test", /*allowPartial=*/false),
99               ANEURALNETWORKS_BAD_DATA);
100 }
101 
TEST(ValidateOperandTypeTest,ExtensionTypeDimensionProductOverflow)102 TEST(ValidateOperandTypeTest, ExtensionTypeDimensionProductOverflow) {
103     // Regression test for b/146044137.
104     constexpr uint16_t kExtensionPrefix = 1;
105     constexpr uint16_t kTypeWithinExtension = 0;
106     int32_t extensionType = getExtensionType(kExtensionPrefix, kTypeWithinExtension);
107     uint32_t dimensions[] = {5, 4, 4, 786433, 5, 3, 16777216, 4, 5};
108     ANeuralNetworksOperandType type = {
109             .type = extensionType,
110             .dimensionCount = std::size(dimensions),
111             .dimensions = dimensions,
112     };
113     Extension::OperandTypeInformation info = {
114             .type = kTypeWithinExtension,
115             .isTensor = true,
116             .byteSize = 1,
117     };
118     EXPECT_EQ(validateOperandType(type, &info, /*tag=*/"test", /*allowPartial=*/true),
119               ANEURALNETWORKS_BAD_DATA);
120 }
121 
TEST(ValidateOperandTypeTest,TensorSizeDimensionProductOverflow)122 TEST(ValidateOperandTypeTest, TensorSizeDimensionProductOverflow) {
123     // Regression test for b/146044137.
124     uint32_t dimensions[] = {256, 256, 256, 256};
125     ANeuralNetworksOperandType type = {
126             .type = ANEURALNETWORKS_TENSOR_FLOAT32,
127             .dimensionCount = std::size(dimensions),
128             .dimensions = dimensions,
129     };
130     EXPECT_EQ(validateOperandType(type, nullptr, /*tag=*/"test", /*allowPartial=*/true),
131               ANEURALNETWORKS_BAD_DATA);
132 }
133 
TEST(ValidateRequestTest,UnknownOutputRank)134 TEST(ValidateRequestTest, UnknownOutputRank) {
135     V1_3::Request::MemoryPool pool;
136     pool.hidlMemory(allocateSharedMemory(2 * sizeof(float)));
137     ASSERT_TRUE(pool.hidlMemory().valid());
138     const V1_3::Model model = {
139             .main =
140                     {
141                             .operands = {{
142                                                  .type = V1_3::OperandType::TENSOR_FLOAT32,
143                                                  .dimensions = {1},
144                                                  .numberOfConsumers = 1,
145                                                  .lifetime = V1_3::OperandLifeTime::SUBGRAPH_INPUT,
146                                          },
147                                          {
148                                                  .type = V1_3::OperandType::TENSOR_FLOAT32,
149                                                  .dimensions = {},  // unknown output rank
150                                                  .numberOfConsumers = 0,
151                                                  .lifetime = V1_3::OperandLifeTime::SUBGRAPH_OUTPUT,
152                                          }},
153                             .operations = {{
154                                     .type = V1_3::OperationType::ABS,
155                                     .inputs = {0},
156                                     .outputs = {1},
157                             }},
158                             .inputIndexes = {0},
159                             .outputIndexes = {1},
160                     },
161     };
162     const V1_3::Request request = {
163             .inputs = {{
164                     .location = {.poolIndex = 0, .offset = 0, .length = sizeof(float)},
165                     .dimensions = {},
166             }},
167             .outputs = {{
168                     .location = {.poolIndex = 0, .offset = sizeof(float), .length = sizeof(float)},
169                     .dimensions = {},
170             }},
171             .pools = {std::move(pool)},
172     };
173     EXPECT_FALSE(validateRequest(request, model, /*allowUnspecifiedOutput=*/false));
174 }
175 
TEST(ValidateRequestTest,ScalarOutput)176 TEST(ValidateRequestTest, ScalarOutput) {
177     V1_3::Request::MemoryPool pool;
178     pool.hidlMemory(allocateSharedMemory(sizeof(float) + sizeof(int32_t)));
179     ASSERT_TRUE(pool.hidlMemory().valid());
180     const V1_3::Model model = {
181             .main =
182                     {
183                             .operands = {{
184                                                  .type = V1_3::OperandType::TENSOR_FLOAT32,
185                                                  .dimensions = {1},
186                                                  .numberOfConsumers = 1,
187                                                  .lifetime = V1_3::OperandLifeTime::SUBGRAPH_INPUT,
188                                          },
189                                          {
190                                                  .type = V1_3::OperandType::INT32,
191                                                  .dimensions = {},
192                                                  .numberOfConsumers = 0,
193                                                  .lifetime = V1_3::OperandLifeTime::SUBGRAPH_OUTPUT,
194                                          }},
195                             .operations = {{
196                                     .type = V1_3::OperationType::RANK,
197                                     .inputs = {0},
198                                     .outputs = {1},
199                             }},
200                             .inputIndexes = {0},
201                             .outputIndexes = {1},
202                     },
203     };
204     const V1_3::Request request = {
205             .inputs = {{
206                     .location = {.poolIndex = 0, .offset = 0, .length = sizeof(float)},
207                     .dimensions = {},
208             }},
209             .outputs = {{
210                     .location = {.poolIndex = 0,
211                                  .offset = sizeof(float),
212                                  .length = sizeof(int32_t)},
213                     .dimensions = {},
214             }},
215             .pools = {std::move(pool)},
216     };
217     EXPECT_TRUE(validateRequest(request, model, /*allowUnspecifiedOutput=*/false));
218 }
219 
220 class CombineDimensionsTest : public ::testing::Test {
221    protected:
testCompatible(const std::vector<uint32_t> & lhs,const std::vector<uint32_t> & rhs,const std::vector<uint32_t> & expected)222     void testCompatible(const std::vector<uint32_t>& lhs, const std::vector<uint32_t>& rhs,
223                         const std::vector<uint32_t>& expected) {
224         SCOPED_TRACE("lhs = " + toString(lhs) + ", rhs = " + toString(rhs));
225         const auto res = combineDimensions(lhs, rhs);
226         ASSERT_TRUE(res.has_value());
227         EXPECT_EQ(res.value(), expected);
228     }
229 
testIncompatible(const std::vector<uint32_t> & lhs,const std::vector<uint32_t> & rhs)230     void testIncompatible(const std::vector<uint32_t>& lhs, const std::vector<uint32_t>& rhs) {
231         SCOPED_TRACE("lhs = " + toString(lhs) + ", rhs = " + toString(rhs));
232         const auto res = combineDimensions(lhs, rhs);
233         EXPECT_FALSE(res.has_value());
234     }
235 };
236 
TEST_F(CombineDimensionsTest,Rank)237 TEST_F(CombineDimensionsTest, Rank) {
238     testCompatible({}, {1, 2, 3, 4}, {1, 2, 3, 4});
239     testCompatible({1, 2, 3, 4}, {}, {1, 2, 3, 4});
240     testCompatible({}, {}, {});
241     testIncompatible({1, 2, 3}, {1, 2, 3, 4});
242     testIncompatible({1, 2, 3, 4}, {1, 2, 3});
243 }
244 
TEST_F(CombineDimensionsTest,Dimensions)245 TEST_F(CombineDimensionsTest, Dimensions) {
246     testCompatible({0, 0, 0, 0}, {1, 2, 3, 4}, {1, 2, 3, 4});
247     testCompatible({1, 2, 3, 4}, {0, 0, 0, 0}, {1, 2, 3, 4});
248     testCompatible({0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0});
249     testIncompatible({1, 2, 3, 4}, {2, 2, 3, 4});
250     testIncompatible({1, 2, 3, 4}, {1, 2, 3, 3});
251 }
252 
TEST(QuantizationUtilsTest,QuantizeMultiplierSmallerThanOneExp)253 TEST(QuantizationUtilsTest, QuantizeMultiplierSmallerThanOneExp) {
254     auto checkInvalidQuantization = [](double value) {
255         int32_t q;
256         int s;
257         EXPECT_FALSE(QuantizeMultiplierSmallerThanOneExp(value, &q, &s));
258     };
259 
260     checkInvalidQuantization(-0.1);
261     checkInvalidQuantization(0.0);
262     // If we get close enough to 1.0 it crashes and dies in one of two ways:
263     // Either the shift becomes negative or we trigger the 'less-than-one' CHECK.
264     checkInvalidQuantization(1 - 1e-15);
265     checkInvalidQuantization(1 - 1e-17);
266     checkInvalidQuantization(1.0);
267 
268     auto checkQuantization = [](double value, int32_t goldenQuantized, int goldenShift) {
269         int32_t q;
270         int s;
271         EXPECT_TRUE(QuantizeMultiplierSmallerThanOneExp(value, &q, &s));
272         EXPECT_EQ(q, goldenQuantized);
273         EXPECT_EQ(s, goldenShift);
274     };
275 
276     checkQuantization(0.25, 1073741824, -1);
277     checkQuantization(0.50 - 5e-9, 2147483627, -1);
278     checkQuantization(0.50 - 1e-10, 1073741824, 0);
279     checkQuantization(0.50, 1073741824, 0);
280     checkQuantization(0.75, 1610612736, 0);
281     checkQuantization(1 - 1e-9, 2147483646, 0);
282 }
283 
TEST(QuantizationUtilsTest,QuantizeMultiplierGreaterThanOne)284 TEST(QuantizationUtilsTest, QuantizeMultiplierGreaterThanOne) {
285     auto checkInvalidQuantization = [](double value) {
286         int32_t q;
287         int s;
288         EXPECT_FALSE(QuantizeMultiplierGreaterThanOne(value, &q, &s));
289     };
290 
291     checkInvalidQuantization(1 + 1e-16);
292 
293     auto checkQuantization = [](double value, int32_t goldenQuantized, int goldenShift) {
294         int32_t q;
295         int s;
296         EXPECT_TRUE(QuantizeMultiplierGreaterThanOne(value, &q, &s));
297         EXPECT_EQ(q, goldenQuantized);
298         EXPECT_EQ(s, goldenShift);
299     };
300 
301     checkQuantization(1 + 1e-11, 1073741824, 1);
302     checkQuantization(1.25, 1342177280, 1);
303     checkQuantization(1.50, 1610612736, 1);
304     checkQuantization(1.50, 1610612736, 1);
305     checkQuantization(1.75, 1879048192, 1);
306     checkQuantization(2 - 1e-9, 2147483647, 1);
307     checkQuantization(2 - 1e-11, 1073741824, 2);
308     checkQuantization(2, 1073741824, 2);
309 }
310 
TEST(QuantizationUtilTest,QuantizeMultiplier)311 TEST(QuantizationUtilTest, QuantizeMultiplier) {
312     auto checkQuantization = [](double value, int32_t goldenQuantized, int goldenShift) {
313         int32_t q;
314         int s;
315         EXPECT_TRUE(QuantizeMultiplier(value, &q, &s));
316         EXPECT_EQ(q, goldenQuantized);
317         EXPECT_EQ(s, goldenShift);
318     };
319 
320     checkQuantization(-4, -1073741824, 3);
321     checkQuantization(-2, -1073741824, 2);
322     checkQuantization(-1, -1073741824, 1);
323     checkQuantization(-0.5, -1073741824, 0);
324     checkQuantization(-0.25, -1073741824, -1);
325     checkQuantization(-0.125, -1073741824, -2);
326     checkQuantization(0, 0, 0);
327     checkQuantization(0.125, 1073741824, -2);
328     checkQuantization(0.25, 1073741824, -1);
329     checkQuantization(0.5, 1073741824, 0);
330     checkQuantization(1, 1073741824, 1);
331     checkQuantization(2, 1073741824, 2);
332     checkQuantization(4, 1073741824, 3);
333 }
334 
TEST(QuantizationUtilTest,QuantizeMultiplierUnderflow)335 TEST(QuantizationUtilTest, QuantizeMultiplierUnderflow) {
336     auto checkQuantization = [](double value, int32_t goldenQuantized, int goldenShift) {
337         int32_t q;
338         int s;
339         EXPECT_TRUE(QuantizeMultiplier(value, &q, &s));
340         EXPECT_EQ(q, goldenQuantized);
341         EXPECT_EQ(s, goldenShift);
342     };
343 
344     checkQuantization(std::ldexp(1.0f, -31), 1073741824, -30);
345     checkQuantization(std::ldexp(1.0f, -32), 1073741824, -31);
346     checkQuantization(std::ldexp(0.99f, -32), 0, 0);
347     checkQuantization(std::ldexp(1.0f, -33), 0, 0);
348 }
349 
TEST(QuantizationUtilTest,GetInvSqrtQuantizedMultiplierExp)350 TEST(QuantizationUtilTest, GetInvSqrtQuantizedMultiplierExp) {
351     auto checkInvSqrtQuantization = [](int32_t input, int32_t goldenInvSqrt, int goldenShift) {
352         int32_t q;
353         int s;
354         EXPECT_TRUE(GetInvSqrtQuantizedMultiplierExp(input, 1, &q, &s));
355         EXPECT_EQ(q, goldenInvSqrt);
356         EXPECT_EQ(s, goldenShift);
357     };
358 
359     const auto kInt32Max = std::numeric_limits<std::int32_t>::max();
360     checkInvSqrtQuantization(0, kInt32Max, 0);
361     checkInvSqrtQuantization(1, kInt32Max, 0);
362     checkInvSqrtQuantization(2, 1518498372, 0);
363     checkInvSqrtQuantization(3, 1239850284, 0);
364     checkInvSqrtQuantization(4, 1073741828, 0);
365     checkInvSqrtQuantization(100, 214748363, 0);
366     checkInvSqrtQuantization(10000, 343597361, 4);
367     checkInvSqrtQuantization(1000000, 274877901, 7);
368     checkInvSqrtQuantization(100000000, 219902323, 10);
369     checkInvSqrtQuantization((1 << 30), 268435457, 12);
370     checkInvSqrtQuantization(kInt32Max, 189812531, 12);
371 }
372 
373 }  // namespace wrapper
374 }  // namespace nn
375 }  // namespace android
376