1 /*
2 * Copyright (C) 2017 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 "Models.h"
20 #include <android/hidl/memory/1.0/IMemory.h>
21 #include <hidlmemory/mapping.h>
22 #include <vector>
23
24 namespace android {
25 namespace hardware {
26 namespace neuralnetworks {
27 namespace V1_0 {
28 namespace vts {
29 namespace functional {
30
31 // create a valid model
createValidTestModel()32 Model createValidTestModel() {
33 const std::vector<float> operand2Data = {5.0f, 6.0f, 7.0f, 8.0f};
34 const uint32_t size = operand2Data.size() * sizeof(float);
35
36 const uint32_t operand1 = 0;
37 const uint32_t operand2 = 1;
38 const uint32_t operand3 = 2;
39 const uint32_t operand4 = 3;
40
41 const std::vector<Operand> operands = {
42 {
43 .type = OperandType::TENSOR_FLOAT32,
44 .dimensions = {1, 2, 2, 1},
45 .numberOfConsumers = 1,
46 .scale = 0.0f,
47 .zeroPoint = 0,
48 .lifetime = OperandLifeTime::MODEL_INPUT,
49 .location = {.poolIndex = 0, .offset = 0, .length = 0},
50 },
51 {
52 .type = OperandType::TENSOR_FLOAT32,
53 .dimensions = {1, 2, 2, 1},
54 .numberOfConsumers = 1,
55 .scale = 0.0f,
56 .zeroPoint = 0,
57 .lifetime = OperandLifeTime::CONSTANT_COPY,
58 .location = {.poolIndex = 0, .offset = 0, .length = size},
59 },
60 {
61 .type = OperandType::INT32,
62 .dimensions = {},
63 .numberOfConsumers = 1,
64 .scale = 0.0f,
65 .zeroPoint = 0,
66 .lifetime = OperandLifeTime::CONSTANT_COPY,
67 .location = {.poolIndex = 0, .offset = size, .length = sizeof(int32_t)},
68 },
69 {
70 .type = OperandType::TENSOR_FLOAT32,
71 .dimensions = {1, 2, 2, 1},
72 .numberOfConsumers = 0,
73 .scale = 0.0f,
74 .zeroPoint = 0,
75 .lifetime = OperandLifeTime::MODEL_OUTPUT,
76 .location = {.poolIndex = 0, .offset = 0, .length = 0},
77 },
78 };
79
80 const std::vector<Operation> operations = {{
81 .type = OperationType::ADD, .inputs = {operand1, operand2, operand3}, .outputs = {operand4},
82 }};
83
84 const std::vector<uint32_t> inputIndexes = {operand1};
85 const std::vector<uint32_t> outputIndexes = {operand4};
86 std::vector<uint8_t> operandValues(
87 reinterpret_cast<const uint8_t*>(operand2Data.data()),
88 reinterpret_cast<const uint8_t*>(operand2Data.data()) + size);
89 int32_t activation[1] = {static_cast<int32_t>(FusedActivationFunc::NONE)};
90 operandValues.insert(operandValues.end(), reinterpret_cast<const uint8_t*>(&activation[0]),
91 reinterpret_cast<const uint8_t*>(&activation[1]));
92
93 const std::vector<hidl_memory> pools = {};
94
95 return {
96 .operands = operands,
97 .operations = operations,
98 .inputIndexes = inputIndexes,
99 .outputIndexes = outputIndexes,
100 .operandValues = operandValues,
101 .pools = pools,
102 };
103 }
104
105 // create first invalid model
createInvalidTestModel1()106 Model createInvalidTestModel1() {
107 Model model = createValidTestModel();
108 model.operations[0].type = static_cast<OperationType>(0xDEADBEEF); /* INVALID */
109 return model;
110 }
111
112 // create second invalid model
createInvalidTestModel2()113 Model createInvalidTestModel2() {
114 Model model = createValidTestModel();
115 const uint32_t operand1 = 0;
116 const uint32_t operand5 = 4; // INVALID OPERAND
117 model.inputIndexes = std::vector<uint32_t>({operand1, operand5 /* INVALID OPERAND */});
118 return model;
119 }
120
121 // allocator helper
allocateSharedMemory(int64_t size,const std::string & type="ashmem")122 hidl_memory allocateSharedMemory(int64_t size, const std::string& type = "ashmem") {
123 hidl_memory memory;
124
125 sp<IAllocator> allocator = IAllocator::getService(type);
126 if (!allocator.get()) {
127 return {};
128 }
129
130 Return<void> ret = allocator->allocate(size, [&](bool success, const hidl_memory& mem) {
131 ASSERT_TRUE(success);
132 memory = mem;
133 });
134 if (!ret.isOk()) {
135 return {};
136 }
137
138 return memory;
139 }
140
141 // create a valid request
createValidTestRequest()142 Request createValidTestRequest() {
143 std::vector<float> inputData = {1.0f, 2.0f, 3.0f, 4.0f};
144 std::vector<float> outputData = {-1.0f, -1.0f, -1.0f, -1.0f};
145 const uint32_t INPUT = 0;
146 const uint32_t OUTPUT = 1;
147
148 // prepare inputs
149 uint32_t inputSize = static_cast<uint32_t>(inputData.size() * sizeof(float));
150 uint32_t outputSize = static_cast<uint32_t>(outputData.size() * sizeof(float));
151 std::vector<RequestArgument> inputs = {{
152 .location = {.poolIndex = INPUT, .offset = 0, .length = inputSize}, .dimensions = {},
153 }};
154 std::vector<RequestArgument> outputs = {{
155 .location = {.poolIndex = OUTPUT, .offset = 0, .length = outputSize}, .dimensions = {},
156 }};
157 std::vector<hidl_memory> pools = {allocateSharedMemory(inputSize),
158 allocateSharedMemory(outputSize)};
159 if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) {
160 return {};
161 }
162
163 // load data
164 sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
165 sp<IMemory> outputMemory = mapMemory(pools[OUTPUT]);
166 if (inputMemory.get() == nullptr || outputMemory.get() == nullptr) {
167 return {};
168 }
169 float* inputPtr = reinterpret_cast<float*>(static_cast<void*>(inputMemory->getPointer()));
170 float* outputPtr = reinterpret_cast<float*>(static_cast<void*>(outputMemory->getPointer()));
171 if (inputPtr == nullptr || outputPtr == nullptr) {
172 return {};
173 }
174 inputMemory->update();
175 outputMemory->update();
176 std::copy(inputData.begin(), inputData.end(), inputPtr);
177 std::copy(outputData.begin(), outputData.end(), outputPtr);
178 inputMemory->commit();
179 outputMemory->commit();
180
181 return {.inputs = inputs, .outputs = outputs, .pools = pools};
182 }
183
184 // create first invalid request
createInvalidTestRequest1()185 Request createInvalidTestRequest1() {
186 Request request = createValidTestRequest();
187 const uint32_t INVALID = 2;
188 std::vector<float> inputData = {1.0f, 2.0f, 3.0f, 4.0f};
189 uint32_t inputSize = static_cast<uint32_t>(inputData.size() * sizeof(float));
190 request.inputs[0].location = {
191 .poolIndex = INVALID /* INVALID */, .offset = 0, .length = inputSize};
192 return request;
193 }
194
195 // create second invalid request
createInvalidTestRequest2()196 Request createInvalidTestRequest2() {
197 Request request = createValidTestRequest();
198 request.inputs[0].dimensions = std::vector<uint32_t>({1, 2, 3, 4, 5, 6, 7, 8} /* INVALID */);
199 return request;
200 }
201
202 } // namespace functional
203 } // namespace vts
204 } // namespace V1_0
205 } // namespace neuralnetworks
206 } // namespace hardware
207 } // namespace android
208