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