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 #define LOG_TAG "neuralnetworks_hidl_hal_test"
18 
19 #include "VtsHalNeuralnetworks.h"
20 
21 #include "1.0/Callbacks.h"
22 
23 namespace android::hardware::neuralnetworks::V1_0::vts::functional {
24 
25 using implementation::PreparedModelCallback;
26 
27 // create device test
TEST_P(NeuralnetworksHidlTest,CreateDevice)28 TEST_P(NeuralnetworksHidlTest, CreateDevice) {}
29 
30 // status test
TEST_P(NeuralnetworksHidlTest,StatusTest)31 TEST_P(NeuralnetworksHidlTest, StatusTest) {
32     Return<DeviceStatus> status = kDevice->getStatus();
33     ASSERT_TRUE(status.isOk());
34     EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
35 }
36 
37 // initialization
TEST_P(NeuralnetworksHidlTest,GetCapabilitiesTest)38 TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) {
39     Return<void> ret =
40             kDevice->getCapabilities([](ErrorStatus status, const Capabilities& capabilities) {
41                 EXPECT_EQ(ErrorStatus::NONE, status);
42                 EXPECT_LT(0.0f, capabilities.float32Performance.execTime);
43                 EXPECT_LT(0.0f, capabilities.float32Performance.powerUsage);
44                 EXPECT_LT(0.0f, capabilities.quantized8Performance.execTime);
45                 EXPECT_LT(0.0f, capabilities.quantized8Performance.powerUsage);
46             });
47     EXPECT_TRUE(ret.isOk());
48 }
49 
50 // detect cycle
TEST_P(NeuralnetworksHidlTest,CycleTest)51 TEST_P(NeuralnetworksHidlTest, CycleTest) {
52     // opnd0 = TENSOR_FLOAT32            // model input
53     // opnd1 = TENSOR_FLOAT32            // model input
54     // opnd2 = INT32                     // model input
55     // opnd3 = ADD(opnd0, opnd4, opnd2)
56     // opnd4 = ADD(opnd1, opnd3, opnd2)
57     // opnd5 = ADD(opnd4, opnd0, opnd2)  // model output
58     //
59     //            +-----+
60     //            |     |
61     //            v     |
62     // 3 = ADD(0, 4, 2) |
63     // |                |
64     // +----------+     |
65     //            |     |
66     //            v     |
67     // 4 = ADD(1, 3, 2) |
68     // |                |
69     // +----------------+
70     // |
71     // |
72     // +-------+
73     //         |
74     //         v
75     // 5 = ADD(4, 0, 2)
76 
77     const std::vector<Operand> operands = {
78             {
79                     // operands[0]
80                     .type = OperandType::TENSOR_FLOAT32,
81                     .dimensions = {1},
82                     .numberOfConsumers = 2,
83                     .scale = 0.0f,
84                     .zeroPoint = 0,
85                     .lifetime = OperandLifeTime::MODEL_INPUT,
86                     .location = {.poolIndex = 0, .offset = 0, .length = 0},
87             },
88             {
89                     // operands[1]
90                     .type = OperandType::TENSOR_FLOAT32,
91                     .dimensions = {1},
92                     .numberOfConsumers = 1,
93                     .scale = 0.0f,
94                     .zeroPoint = 0,
95                     .lifetime = OperandLifeTime::MODEL_INPUT,
96                     .location = {.poolIndex = 0, .offset = 0, .length = 0},
97             },
98             {
99                     // operands[2]
100                     .type = OperandType::INT32,
101                     .dimensions = {},
102                     .numberOfConsumers = 3,
103                     .scale = 0.0f,
104                     .zeroPoint = 0,
105                     .lifetime = OperandLifeTime::MODEL_INPUT,
106                     .location = {.poolIndex = 0, .offset = 0, .length = 0},
107             },
108             {
109                     // operands[3]
110                     .type = OperandType::TENSOR_FLOAT32,
111                     .dimensions = {1},
112                     .numberOfConsumers = 1,
113                     .scale = 0.0f,
114                     .zeroPoint = 0,
115                     .lifetime = OperandLifeTime::TEMPORARY_VARIABLE,
116                     .location = {.poolIndex = 0, .offset = 0, .length = 0},
117             },
118             {
119                     // operands[4]
120                     .type = OperandType::TENSOR_FLOAT32,
121                     .dimensions = {1},
122                     .numberOfConsumers = 2,
123                     .scale = 0.0f,
124                     .zeroPoint = 0,
125                     .lifetime = OperandLifeTime::TEMPORARY_VARIABLE,
126                     .location = {.poolIndex = 0, .offset = 0, .length = 0},
127             },
128             {
129                     // operands[5]
130                     .type = OperandType::TENSOR_FLOAT32,
131                     .dimensions = {1},
132                     .numberOfConsumers = 0,
133                     .scale = 0.0f,
134                     .zeroPoint = 0,
135                     .lifetime = OperandLifeTime::MODEL_OUTPUT,
136                     .location = {.poolIndex = 0, .offset = 0, .length = 0},
137             },
138     };
139 
140     const std::vector<Operation> operations = {
141             {.type = OperationType::ADD, .inputs = {0, 4, 2}, .outputs = {3}},
142             {.type = OperationType::ADD, .inputs = {1, 3, 2}, .outputs = {4}},
143             {.type = OperationType::ADD, .inputs = {4, 0, 2}, .outputs = {5}},
144     };
145 
146     const Model model = {
147             .operands = operands,
148             .operations = operations,
149             .inputIndexes = {0, 1, 2},
150             .outputIndexes = {5},
151             .operandValues = {},
152             .pools = {},
153     };
154 
155     // ensure that getSupportedOperations() checks model validity
156     ErrorStatus supportedOpsErrorStatus = ErrorStatus::GENERAL_FAILURE;
157     Return<void> supportedOpsReturn = kDevice->getSupportedOperations(
158             model, [&model, &supportedOpsErrorStatus](ErrorStatus status,
159                                                       const hidl_vec<bool>& supported) {
160                 supportedOpsErrorStatus = status;
161                 if (status == ErrorStatus::NONE) {
162                     ASSERT_EQ(supported.size(), model.operations.size());
163                 }
164             });
165     ASSERT_TRUE(supportedOpsReturn.isOk());
166     ASSERT_EQ(supportedOpsErrorStatus, ErrorStatus::INVALID_ARGUMENT);
167 
168     // ensure that prepareModel() checks model validity
169     sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback;
170     Return<ErrorStatus> prepareLaunchReturn = kDevice->prepareModel(model, preparedModelCallback);
171     ASSERT_TRUE(prepareLaunchReturn.isOk());
172     //     Note that preparation can fail for reasons other than an
173     //     invalid model (invalid model should result in
174     //     INVALID_ARGUMENT) -- for example, perhaps not all
175     //     operations are supported, or perhaps the device hit some
176     //     kind of capacity limit.
177     EXPECT_NE(prepareLaunchReturn, ErrorStatus::NONE);
178     EXPECT_NE(preparedModelCallback->getStatus(), ErrorStatus::NONE);
179     EXPECT_EQ(preparedModelCallback->getPreparedModel(), nullptr);
180 }
181 
182 }  // namespace android::hardware::neuralnetworks::V1_0::vts::functional
183