• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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