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 <HalInterfaces.h>
18 #include <MemoryUtils.h>
19 #include <Utils.h>
20 #include <android-base/scopeguard.h>
21 #include <gtest/gtest.h>
22
23 #include "GeneratedTestUtils.h"
24 #include "Memory.h"
25 #include "ModelBuilder.h"
26 #include "TestNeuralNetworksWrapper.h"
27
28 namespace android::nn::compliance_test {
29
30 using namespace test_helper;
31 using HidlModel = V1_3::Model;
32 using WrapperModel = test_wrapper::Model;
33 using WrapperOperandType = test_wrapper::OperandType;
34 using WrapperType = test_wrapper::Type;
35
36 // Tag for the compilance tests
37 class ComplianceTest : public ::testing::Test {};
38
39 // Creates a HIDL model from a wrapper model.
createHidlModel(const WrapperModel & wrapperModel)40 static HidlModel createHidlModel(const WrapperModel& wrapperModel) {
41 auto modelBuilder = reinterpret_cast<const ModelBuilder*>(wrapperModel.getHandle());
42 EXPECT_TRUE(modelBuilder->isFinished());
43 EXPECT_TRUE(modelBuilder->isValid());
44 return convertToV1_3(modelBuilder->makeModel());
45 }
46
testAvailableSinceV1_3(const WrapperModel & wrapperModel)47 static void testAvailableSinceV1_3(const WrapperModel& wrapperModel) {
48 HidlModel hidlModel = createHidlModel(wrapperModel);
49 ASSERT_FALSE(compliantWithV1_2(hidlModel));
50 ASSERT_FALSE(compliantWithV1_1(hidlModel));
51 ASSERT_FALSE(compliantWithV1_0(hidlModel));
52 }
53
testAvailableSinceV1_2(const WrapperModel & wrapperModel)54 static void testAvailableSinceV1_2(const WrapperModel& wrapperModel) {
55 HidlModel hidlModel = createHidlModel(wrapperModel);
56 ASSERT_TRUE(compliantWithV1_2(hidlModel));
57 ASSERT_FALSE(compliantWithV1_1(hidlModel));
58 ASSERT_FALSE(compliantWithV1_0(hidlModel));
59 }
60
testAvailableSinceV1_1(const WrapperModel & wrapperModel)61 static void testAvailableSinceV1_1(const WrapperModel& wrapperModel) {
62 HidlModel hidlModel = createHidlModel(wrapperModel);
63 ASSERT_TRUE(compliantWithV1_2(hidlModel));
64 ASSERT_TRUE(compliantWithV1_1(hidlModel));
65 ASSERT_FALSE(compliantWithV1_0(hidlModel));
66 }
67
testAvailableSinceV1_0(const WrapperModel & wrapperModel)68 static void testAvailableSinceV1_0(const WrapperModel& wrapperModel) {
69 HidlModel hidlModel = createHidlModel(wrapperModel);
70 ASSERT_TRUE(compliantWithV1_2(hidlModel));
71 ASSERT_TRUE(compliantWithV1_1(hidlModel));
72 ASSERT_TRUE(compliantWithV1_0(hidlModel));
73 }
74
testAvailableSinceV1_2(const V1_3::Request & request)75 static void testAvailableSinceV1_2(const V1_3::Request& request) {
76 ASSERT_FALSE(compliantWithV1_0(request));
77 ASSERT_TRUE(compliantWithV1_2(request));
78 }
79
testAvailableSinceV1_3(const V1_3::Request & request)80 static void testAvailableSinceV1_3(const V1_3::Request& request) {
81 ASSERT_FALSE(compliantWithV1_0(request));
82 ASSERT_FALSE(compliantWithV1_2(request));
83 }
84
85 static const WrapperOperandType kTypeTensorFloat(WrapperType::TENSOR_FLOAT32, {1});
86 static const WrapperOperandType kTypeTensorFloatRank0(WrapperType::TENSOR_FLOAT32, {});
87 static const WrapperOperandType kTypeInt32(WrapperType::INT32, {});
88
89 const int32_t kNoActivation = ANEURALNETWORKS_FUSED_NONE;
90
TEST_F(ComplianceTest,Rank0TensorModelInput)91 TEST_F(ComplianceTest, Rank0TensorModelInput) {
92 // A simple ADD operation: op1 ADD op2 = op3, with op1 and op2 of rank 0.
93 WrapperModel model;
94 auto op1 = model.addOperand(&kTypeTensorFloatRank0);
95 auto op2 = model.addOperand(&kTypeTensorFloatRank0);
96 auto op3 = model.addOperand(&kTypeTensorFloat);
97 auto act = model.addConstantOperand(&kTypeInt32, kNoActivation);
98 model.addOperation(ANEURALNETWORKS_ADD, {op1, op2, act}, {op3});
99 model.identifyInputsAndOutputs({op1, op2}, {op3});
100 ASSERT_TRUE(model.isValid());
101 model.finish();
102 testAvailableSinceV1_2(model);
103 }
104
TEST_F(ComplianceTest,Rank0TensorModelOutput)105 TEST_F(ComplianceTest, Rank0TensorModelOutput) {
106 // A simple ADD operation: op1 ADD op2 = op3, with op3 of rank 0.
107 WrapperModel model;
108 auto op1 = model.addOperand(&kTypeTensorFloat);
109 auto op2 = model.addOperand(&kTypeTensorFloat);
110 auto op3 = model.addOperand(&kTypeTensorFloatRank0);
111 auto act = model.addConstantOperand(&kTypeInt32, kNoActivation);
112 model.addOperation(ANEURALNETWORKS_ADD, {op1, op2, act}, {op3});
113 model.identifyInputsAndOutputs({op1, op2}, {op3});
114 ASSERT_TRUE(model.isValid());
115 model.finish();
116 testAvailableSinceV1_2(model);
117 }
118
TEST_F(ComplianceTest,Rank0TensorTemporaryVariable)119 TEST_F(ComplianceTest, Rank0TensorTemporaryVariable) {
120 // Two ADD operations: op1 ADD op2 = op3, op3 ADD op4 = op5, with op3 of rank 0.
121 WrapperModel model;
122 auto op1 = model.addOperand(&kTypeTensorFloat);
123 auto op2 = model.addOperand(&kTypeTensorFloat);
124 auto op3 = model.addOperand(&kTypeTensorFloatRank0);
125 auto op4 = model.addOperand(&kTypeTensorFloat);
126 auto op5 = model.addOperand(&kTypeTensorFloat);
127 auto act = model.addConstantOperand(&kTypeInt32, kNoActivation);
128 model.addOperation(ANEURALNETWORKS_ADD, {op1, op2, act}, {op3});
129 model.addOperation(ANEURALNETWORKS_ADD, {op3, op4, act}, {op5});
130 model.identifyInputsAndOutputs({op1, op2, op4}, {op5});
131 ASSERT_TRUE(model.isValid());
132 model.finish();
133 testAvailableSinceV1_2(model);
134 }
135
136 // Hardware buffers are an Android concept, which aren't necessarily
137 // available on other platforms such as ChromeOS, which also build NNAPI.
138 #if defined(__ANDROID__)
TEST_F(ComplianceTest,HardwareBufferModel)139 TEST_F(ComplianceTest, HardwareBufferModel) {
140 const size_t memorySize = 20;
141 AHardwareBuffer_Desc desc{
142 .width = memorySize,
143 .height = 1,
144 .layers = 1,
145 .format = AHARDWAREBUFFER_FORMAT_BLOB,
146 .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
147 };
148
149 AHardwareBuffer* buffer = nullptr;
150 ASSERT_EQ(AHardwareBuffer_allocate(&desc, &buffer), 0);
151 auto allocateGuard =
152 android::base::make_scope_guard([buffer]() { AHardwareBuffer_release(buffer); });
153
154 test_wrapper::Memory memory(buffer);
155 ASSERT_TRUE(memory.isValid());
156
157 // A simple ADD operation: op1 ADD op2 = op3, with op2 using a const hardware buffer.
158 WrapperModel model;
159 auto op1 = model.addOperand(&kTypeTensorFloat);
160 auto op2 = model.addOperand(&kTypeTensorFloat);
161 auto op3 = model.addOperand(&kTypeTensorFloat);
162 auto act = model.addConstantOperand(&kTypeInt32, kNoActivation);
163 model.setOperandValueFromMemory(op2, &memory, 0, sizeof(float));
164 model.addOperation(ANEURALNETWORKS_ADD, {op1, op2, act}, {op3});
165 model.identifyInputsAndOutputs({op1}, {op3});
166 ASSERT_TRUE(model.isValid());
167 model.finish();
168 testAvailableSinceV1_2(model);
169 }
170
TEST_F(ComplianceTest,HardwareBufferRequest)171 TEST_F(ComplianceTest, HardwareBufferRequest) {
172 const auto [n, ahwb] = MemoryRuntimeAHWB::create(1024);
173 ASSERT_EQ(n, ANEURALNETWORKS_NO_ERROR);
174 V1_3::Request::MemoryPool sharedMemoryPool,
175 ahwbMemoryPool = convertToV1_3(ahwb->getMemoryPool());
176 sharedMemoryPool.hidlMemory(allocateSharedMemory(1024));
177 ASSERT_TRUE(sharedMemoryPool.hidlMemory().valid());
178 ASSERT_TRUE(ahwbMemoryPool.hidlMemory().valid());
179
180 // AHardwareBuffer as input.
181 testAvailableSinceV1_2(V1_3::Request{
182 .inputs = {{.hasNoValue = false, .location = {.poolIndex = 0}, .dimensions = {}}},
183 .outputs = {{.hasNoValue = false, .location = {.poolIndex = 1}, .dimensions = {}}},
184 .pools = {ahwbMemoryPool, sharedMemoryPool},
185 });
186
187 // AHardwareBuffer as output.
188 testAvailableSinceV1_2(V1_3::Request{
189 .inputs = {{.hasNoValue = false, .location = {.poolIndex = 0}, .dimensions = {}}},
190 .outputs = {{.hasNoValue = false, .location = {.poolIndex = 1}, .dimensions = {}}},
191 .pools = {sharedMemoryPool, ahwbMemoryPool},
192 });
193 }
194 #endif
195
TEST_F(ComplianceTest,DeviceMemory)196 TEST_F(ComplianceTest, DeviceMemory) {
197 V1_3::Request::MemoryPool sharedMemoryPool, deviceMemoryPool;
198 sharedMemoryPool.hidlMemory(allocateSharedMemory(1024));
199 ASSERT_TRUE(sharedMemoryPool.hidlMemory().valid());
200 deviceMemoryPool.token(1);
201
202 // Device memory as input.
203 testAvailableSinceV1_3(V1_3::Request{
204 .inputs = {{.hasNoValue = false, .location = {.poolIndex = 0}, .dimensions = {}}},
205 .outputs = {{.hasNoValue = false, .location = {.poolIndex = 1}, .dimensions = {}}},
206 .pools = {deviceMemoryPool, sharedMemoryPool},
207 });
208
209 // Device memory as output.
210 testAvailableSinceV1_3(V1_3::Request{
211 .inputs = {{.hasNoValue = false, .location = {.poolIndex = 0}, .dimensions = {}}},
212 .outputs = {{.hasNoValue = false, .location = {.poolIndex = 1}, .dimensions = {}}},
213 .pools = {sharedMemoryPool, deviceMemoryPool},
214 });
215 }
216
217 class GeneratedComplianceTest : public generated_tests::GeneratedTestBase {};
218
TEST_P(GeneratedComplianceTest,Test)219 TEST_P(GeneratedComplianceTest, Test) {
220 generated_tests::GeneratedModel model;
221 generated_tests::createModel(testModel, &model);
222 ASSERT_TRUE(model.isValid());
223 model.finish();
224 switch (testModel.minSupportedVersion) {
225 case TestHalVersion::V1_0:
226 testAvailableSinceV1_0(model);
227 break;
228 case TestHalVersion::V1_1:
229 testAvailableSinceV1_1(model);
230 break;
231 case TestHalVersion::V1_2:
232 testAvailableSinceV1_2(model);
233 break;
234 case TestHalVersion::V1_3:
235 testAvailableSinceV1_3(model);
236 break;
237 case TestHalVersion::UNKNOWN:
238 FAIL();
239 }
240 }
241
__anon209684820202(const TestModel& testModel) 242 INSTANTIATE_GENERATED_TEST(GeneratedComplianceTest, [](const TestModel& testModel) {
243 return !testModel.expectFailure && testModel.minSupportedVersion != TestHalVersion::UNKNOWN;
244 });
245
246 } // namespace android::nn::compliance_test
247