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