blob: 085ab96fe5ccce00801a448a82f9fa0f21d0509f [file] [log] [blame]
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -07001/*
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 "RequestBuilder"
18
19#include "RequestBuilder.h"
20
David Gross83e24dc2017-09-10 14:31:58 -070021#include "CompilationBuilder.h"
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -070022#include "CpuExecutor.h"
23#include "HalInterfaces.h"
24#include "Manager.h"
25#include "ModelBuilder.h"
26
Michael Butler689d8922017-09-01 10:58:46 -070027#include <mutex>
Jean-Luc Brouillet389f26c2017-09-02 23:05:37 -070028#include <thread>
Michael Butler689d8922017-09-01 10:58:46 -070029#include <vector>
30
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -070031namespace android {
32namespace nn {
33
Jean-Luc Brouillet389f26c2017-09-02 23:05:37 -070034int ModelArgumentInfo::setFromPointer(const Operand& operand,
35 const ANeuralNetworksOperandType* type, void* data,
36 uint32_t length) {
37 int n = updateDimensionInfo(operand, type);
38 if (n != ANEURALNETWORKS_NO_ERROR) {
39 return n;
40 }
41 state = ModelArgumentInfo::POINTER;
42 locationAndDimension.location = {.poolIndex = RUN_TIME, .offset = 0, .length = length};
43 buffer = data;
44 return ANEURALNETWORKS_NO_ERROR;
45}
46
47int ModelArgumentInfo::setFromMemory(const Operand& operand, const ANeuralNetworksOperandType* type,
48 uint32_t poolIndex, uint32_t offset, uint32_t length) {
49 int n = updateDimensionInfo(operand, type);
50 if (n != ANEURALNETWORKS_NO_ERROR) {
51 return n;
52 }
53 state = ModelArgumentInfo::MEMORY;
54 locationAndDimension.location = {.poolIndex = poolIndex, .offset = offset, .length = length};
55 buffer = nullptr;
56 return ANEURALNETWORKS_NO_ERROR;
57}
58
59int ModelArgumentInfo::updateDimensionInfo(const Operand& operand,
60 const ANeuralNetworksOperandType* newType) {
61 if (newType == nullptr) {
62 locationAndDimension.dimensions = hidl_vec<uint32_t>();
63 } else {
64 uint32_t count = newType->dimensions.count;
65 if (static_cast<OperandType>(newType->type) != operand.type ||
66 count != operand.dimensions.size()) {
67 LOG(ERROR) << "ANeuralNetworksRequest_setInput/Output incompatible types";
68 return ANEURALNETWORKS_BAD_DATA;
69 }
70 for (uint32_t i = 0; i < count; i++) {
71 locationAndDimension.dimensions[i] = newType->dimensions.data[i];
72 }
73 }
74 return ANEURALNETWORKS_NO_ERROR;
75}
76
David Gross83e24dc2017-09-10 14:31:58 -070077RequestBuilder::RequestBuilder(const CompilationBuilder* compilation) :
78 mModel(compilation->mModel),
79 mInputs(mModel->inputCount()),
80 mOutputs(mModel->outputCount()),
81 mMemories(mModel->getMemories()) {
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -070082 LOG(DEBUG) << "RequestBuilder::RequestBuilder";
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -070083 for (auto& p : mInputs) {
Jean-Luc Brouillet389f26c2017-09-02 23:05:37 -070084 p.state = ModelArgumentInfo::UNSPECIFIED;
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -070085 }
86 for (auto& p : mOutputs) {
Jean-Luc Brouillet389f26c2017-09-02 23:05:37 -070087 p.state = ModelArgumentInfo::UNSPECIFIED;
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -070088 }
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -070089}
90
91int RequestBuilder::setInput(uint32_t index, const ANeuralNetworksOperandType* type,
92 const void* buffer, uint32_t length) {
93 uint32_t count = static_cast<uint32_t>(mInputs.size());
94 if (index >= count) {
95 LOG(ERROR) << "ANeuralNetworksRequest_setInput bad index " << index << " " << count;
96 return ANEURALNETWORKS_BAD_DATA;
97 }
Jean-Luc Brouillet389f26c2017-09-02 23:05:37 -070098 return mInputs[index].setFromPointer(mModel->getInputOperand(index), type,
99 const_cast<void*>(buffer), length);
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700100}
101
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700102int RequestBuilder::setInputFromMemory(uint32_t index, const ANeuralNetworksOperandType* type,
103 const Memory* memory, uint32_t offset, uint32_t length) {
104 uint32_t count = static_cast<uint32_t>(mInputs.size());
105 if (index >= count) {
106 LOG(ERROR) << "ANeuralNetworksRequest_setInputFromMemory bad index " << index << " "
107 << count;
108 return ANEURALNETWORKS_BAD_DATA;
109 }
Miao Wang105807d2017-09-05 14:41:05 -0700110 if (!memory->validateSize(offset, length)) {
111 return ANEURALNETWORKS_BAD_DATA;
112 }
Jean-Luc Brouillet389f26c2017-09-02 23:05:37 -0700113 uint32_t poolIndex = mMemories.add(memory);
114 return mInputs[index].setFromMemory(mModel->getInputOperand(index), type, poolIndex, offset,
115 length);
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700116}
117
118int RequestBuilder::setOutput(uint32_t index, const ANeuralNetworksOperandType* type, void* buffer,
119 uint32_t length) {
120 uint32_t count = static_cast<uint32_t>(mOutputs.size());
121 if (index >= count) {
122 LOG(ERROR) << "ANeuralNetworksRequest_setOutput bad index " << index << " " << count;
123 return ANEURALNETWORKS_BAD_DATA;
124 }
Jean-Luc Brouillet389f26c2017-09-02 23:05:37 -0700125 return mOutputs[index].setFromPointer(mModel->getOutputOperand(index), type, buffer, length);
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700126}
127
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700128int RequestBuilder::setOutputFromMemory(uint32_t index, const ANeuralNetworksOperandType* type,
129 const Memory* memory, uint32_t offset, uint32_t length) {
130 uint32_t count = static_cast<uint32_t>(mOutputs.size());
131 if (index >= count) {
132 LOG(ERROR) << "ANeuralNetworksRequest_setOutputFromMemory bad index " << index << " "
133 << count;
134 return ANEURALNETWORKS_BAD_DATA;
135 }
Miao Wang105807d2017-09-05 14:41:05 -0700136 if (!memory->validateSize(offset, length)) {
137 return ANEURALNETWORKS_BAD_DATA;
138 }
Jean-Luc Brouillet389f26c2017-09-02 23:05:37 -0700139 uint32_t poolIndex = mMemories.add(memory);
140 return mOutputs[index].setFromMemory(mModel->getOutputOperand(index), type, poolIndex, offset,
141 length);
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700142}
143
Michael Butler689d8922017-09-01 10:58:46 -0700144int RequestBuilder::startCompute(sp<Event>* event) {
145 *event = nullptr;
146
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700147 // TODO validate that we have full types for all inputs and outputs,
148 // that the graph is not cyclic,
Yang Nif1817c62017-08-22 16:18:50 -0700149 /*
150 TODO: For non-optional inputs, also verify that buffers are not null.
151
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700152 for (auto& p : mInputs) {
Jean-Luc Brouillet389f26c2017-09-02 23:05:37 -0700153 if (p.state == ModelArgumentInfo::UNSPECIFIED) {
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700154 LOG(ERROR) << "ANeuralNetworksRequest_startCompute not all inputs specified";
155 return ANEURALNETWORKS_BAD_DATA;
156 }
157 }
Yang Nif1817c62017-08-22 16:18:50 -0700158 */
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700159 for (auto& p : mOutputs) {
Jean-Luc Brouillet389f26c2017-09-02 23:05:37 -0700160 if (p.state == ModelArgumentInfo::UNSPECIFIED) {
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700161 LOG(ERROR) << "ANeuralNetworksRequest_startCompute not all outputs specified";
162 return ANEURALNETWORKS_BAD_DATA;
163 }
164 }
165 LOG(DEBUG) << "RequestBuilder::startCompute";
166
167 std::shared_ptr<Device> device = DeviceManager::get()->getAvailableDriver();
168 Model model;
169 mModel->setHidlModel(&model);
170
Michael Butler689d8922017-09-01 10:58:46 -0700171 return device == nullptr ? startComputeOnCpu(model, event)
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700172 : startComputeOnDevice(device->getInterface(), model, event);
173}
174
175// Figures out how to place each of the input or outputs in a buffer. This just does the layout,
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700176// it does not copy data. Aligns each input a bit.
177int RequestBuilder::allocatePointerArgumentsToPool(std::vector<ModelArgumentInfo>* args,
178 Memory* memory) {
179 uint32_t nextPoolIndex = mMemories.size();
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700180 int64_t total = 0;
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700181 for (auto& info : *args) {
182 if (info.state == ModelArgumentInfo::POINTER) {
183 DataLocation& loc = info.locationAndDimension.location;
184 // TODO Good enough alignment?
185 total += alignBytesNeeded(static_cast<uint32_t>(total), loc.length);
186 loc.poolIndex = nextPoolIndex;
187 loc.offset = static_cast<uint32_t>(total);
188 total += loc.length;
189 }
190 };
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700191 if (total > 0xFFFFFFFF) {
192 LOG(ERROR) << "ANeuralNetworksRequest_startCompute Size of all inputs or outputs exceeds "
193 "2^32.";
194 return ANEURALNETWORKS_BAD_DATA;
195 }
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700196 hidl_memory hidlMemory;
197 if (total > 0) {
Jean-Luc Brouillet389f26c2017-09-02 23:05:37 -0700198 memory->create(total); // TODO check error
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700199 mMemories.add(memory);
200 }
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700201 return ANEURALNETWORKS_NO_ERROR;
202}
203
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700204static void copyLocationAndDimension(const std::vector<ModelArgumentInfo>& argumentInfos,
205 hidl_vec<InputOutputInfo>* ioInfos) {
206 size_t count = argumentInfos.size();
207 ioInfos->resize(count);
208 for (size_t i = 0; i < count; i++) {
209 (*ioInfos)[i] = argumentInfos[i].locationAndDimension;
210 }
211}
212
Jean-Luc Brouillet389f26c2017-09-02 23:05:37 -0700213int RequestBuilder::startComputeOnDevice(sp<IDevice> driver, const Model& model, sp<Event>* event) {
Michael Butler689d8922017-09-01 10:58:46 -0700214 *event = nullptr;
215
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700216 LOG(DEBUG) << "RequestBuilder::startComputeOnDevice1";
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700217 // TODO Dangerous! In async, the model will outlive it here. Safe for now
218 sp<IPreparedModel> preparedModel = driver->prepareModel(model);
219 if (preparedModel == nullptr) {
220 return ANEURALNETWORKS_OP_FAILED;
221 }
222
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700223 // Layout the input and output data
224 int n = allocatePointerArgumentsToPool(&mInputs, &mInputPointerArguments);
225 if (n != ANEURALNETWORKS_NO_ERROR) {
226 return n;
227 }
228 n = allocatePointerArgumentsToPool(&mOutputs, &mOutputPointerArguments);
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700229 if (n != ANEURALNETWORKS_NO_ERROR) {
230 return n;
231 }
232
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700233 // Copy the input data that was specified via a pointer.
234 // mInputPointerArguments.update();
235 for (auto& info : mInputs) {
236 if (info.state == ModelArgumentInfo::POINTER) {
237 DataLocation& loc = info.locationAndDimension.location;
Jean-Luc Brouillet2150f1d2017-09-01 13:29:08 -0700238 uint8_t* data = nullptr;
239 int n = mInputPointerArguments.getPointer(&data);
240 if (n != ANEURALNETWORKS_NO_ERROR) {
241 return n;
242 }
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700243 memcpy(data + loc.offset, info.buffer, loc.length);
244 }
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700245 }
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700246 // TODO: Add mInputPointerArguments.commit() and .update() at all the right places
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700247
248 Request request;
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700249 copyLocationAndDimension(mInputs, &request.inputs);
250 copyLocationAndDimension(mOutputs, &request.outputs);
251 uint32_t count = mMemories.size();
252 request.pools.resize(count);
253 for (uint32_t i = 0; i < count; i++) {
254 request.pools[i] = mMemories[i]->getHidlMemory();
255 }
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700256
Michael Butler689d8922017-09-01 10:58:46 -0700257 // Prepare the event for asynchronous execution. The sp<Event> object is
258 // returned when the request has been successfully launched, otherwise a
259 // nullptr is returned. The sp is used for ref-counting purposes. Without
260 // it, the HIDL service could attempt to communicate with a dead event
261 // object.
262 //
263 // TODO: Explain the "dead event" problem further, either here or
264 // in the design document.
265 sp<Event> eventSp = new Event();
266
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700267 LOG(DEBUG) << "Before preparedModel->execute() " << toString(request);
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700268 // Execute the request.
Michael Butler689d8922017-09-01 10:58:46 -0700269 // TODO: What happens to the Event if the service dies abnormally
270 // -- won't that keep the Event live forever, because the service
271 // never has the opportunity to bump the reference count down? Or
272 // maybe the HIDL infrastructure handles this magically? At worst,
273 // it seems like this is a small memory leak, if the Event stays
274 // alive forever.
275 if (!preparedModel->execute(request, eventSp)) {
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700276 LOG(DEBUG) << "**Execute failed**";
277 return ANEURALNETWORKS_OP_FAILED;
278 }
279
Michael Butler689d8922017-09-01 10:58:46 -0700280 // TODO: Remove this synchronization point when the block of code below is
281 // removed.
282 Event::Status status = eventSp->wait();
283 if (status != Event::Status::SUCCESS) {
284 LOG(DEBUG) << "**Execute async failed**";
285 return ANEURALNETWORKS_OP_FAILED;
286 }
287
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700288 // Copy the output data from shared memory to the output buffers.
Michael Butler689d8922017-09-01 10:58:46 -0700289 // TODO: Move this block of code somewhere else. It should not be in the
290 // startCompute function.
291 // TODO: outputMemory->update(); outputMemory->commit()
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700292 for (auto& info : mOutputs) {
293 if (info.state == ModelArgumentInfo::POINTER) {
294 DataLocation& loc = info.locationAndDimension.location;
Jean-Luc Brouillet2150f1d2017-09-01 13:29:08 -0700295 uint8_t* data = nullptr;
296 int n = mOutputPointerArguments.getPointer(&data);
297 if (n != ANEURALNETWORKS_NO_ERROR) {
298 return n;
299 }
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700300 memcpy(info.buffer, data + loc.offset, loc.length);
301 }
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700302 }
303 LOG(DEBUG) << "RequestBuilder::startComputeOnDevice completed";
304
Michael Butler689d8922017-09-01 10:58:46 -0700305 *event = eventSp;
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700306 return ANEURALNETWORKS_NO_ERROR;
307}
308
Michael Butler689d8922017-09-01 10:58:46 -0700309static void asyncStartComputeOnCpu(const Model& model, const Request& request,
310 const std::vector<RunTimePoolInfo>& runTimePoolInfos,
311 const sp<IEvent>& event) {
312 CpuExecutor executor;
313 int err = executor.run(model, request, runTimePoolInfos);
314 Status executionStatus = err == ANEURALNETWORKS_NO_ERROR ? Status::SUCCESS : Status::ERROR;
315 event->notify(executionStatus);
316}
317
318int RequestBuilder::startComputeOnCpu([[maybe_unused]] const Model& model, sp<Event>* event) {
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700319 // TODO: use a thread pool
Michael Butler689d8922017-09-01 10:58:46 -0700320
321 // Prepare the event for asynchronous execution. The sp<Event> object is
322 // returned when the request has been successfully launched, otherwise a
323 // nullptr is returned.
324 sp<Event> eventSp = new Event();
325 *event = nullptr;
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700326
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700327 std::vector<RunTimePoolInfo> runTimePoolInfos;
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700328 uint32_t count = mMemories.size();
329 runTimePoolInfos.resize(count);
330 for (uint32_t i = 0; i < count; i++) {
331 const Memory* mem = mMemories[i];
332 runTimePoolInfos[i].set(mem->getHidlMemory());
333 }
334 // Create as many pools as there are input / output.
335 auto fixPointerArguments = [&runTimePoolInfos](std::vector<ModelArgumentInfo>& argumentInfos) {
336 for (ModelArgumentInfo& argumentInfo : argumentInfos) {
337 if (argumentInfo.state == ModelArgumentInfo::POINTER) {
Jean-Luc Brouillet389f26c2017-09-02 23:05:37 -0700338 RunTimePoolInfo runTimeInfo = {
339 .buffer = static_cast<uint8_t*>(argumentInfo.buffer)};
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700340 argumentInfo.locationAndDimension.location.poolIndex =
Jean-Luc Brouillet389f26c2017-09-02 23:05:37 -0700341 static_cast<uint32_t>(runTimePoolInfos.size());
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700342 argumentInfo.locationAndDimension.location.offset = 0;
343 runTimePoolInfos.push_back(runTimeInfo);
344 }
345 }
346 };
347 fixPointerArguments(mInputs);
348 fixPointerArguments(mOutputs);
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700349
Jean-Luc Brouillet8b99bb12017-08-20 18:16:36 -0700350 Request request;
351 copyLocationAndDimension(mInputs, &request.inputs);
352 copyLocationAndDimension(mOutputs, &request.outputs);
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700353
Michael Butler689d8922017-09-01 10:58:46 -0700354 // TODO: should model be moved with a std::cref?
355 std::thread thread(asyncStartComputeOnCpu, model, std::move(request),
356 std::move(runTimePoolInfos), eventSp);
357 eventSp->bind_thread(std::move(thread));
358
359 *event = eventSp;
360 return ANEURALNETWORKS_NO_ERROR;
Jean-Luc Brouillet707dbd22017-07-25 00:17:50 -0700361}
362
Jean-Luc Brouillet389f26c2017-09-02 23:05:37 -0700363} // namespace nn
364} // namespace android