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