blob: 326351c04de0edbac72810099442cc4c7dd68b4f [file] [log] [blame]
telsoa015307bc12018-03-09 13:51:08 +00001//
Mike Kellye2d611e2021-10-14 12:35:58 +01002// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
David Beck93e48982018-09-05 13:05:09 +01003// SPDX-License-Identifier: MIT
telsoa015307bc12018-03-09 13:51:08 +00004//
5
6#define LOG_TAG "ArmnnDriver"
7
8#include "ArmnnPreparedModel.hpp"
9#include "Utils.hpp"
10
Narumol Prangnawarat558a1d42022-02-07 13:12:24 +000011#include <armnn/Types.hpp>
12
telsoa015307bc12018-03-09 13:51:08 +000013#include <log/log.h>
14#include <OperationsUtils.h>
surmeh01deb3bdb2018-07-05 12:06:04 +010015#include <ValidateHal.h>
Kevin Mayec1e5b82020-02-26 17:00:39 +000016
telsoa015307bc12018-03-09 13:51:08 +000017#include <cinttypes>
18
Sadik Armagan188675f2021-02-12 17:16:42 +000019#ifdef ARMNN_ANDROID_S
20#include <LegacyUtils.h>
21#endif
22
telsoa015307bc12018-03-09 13:51:08 +000023using namespace android;
24
25namespace
26{
27using namespace armnn_driver;
28
Kevin Mayec1e5b82020-02-26 17:00:39 +000029void NotifyCallbackAndCheck(const ::android::sp<V1_0::IExecutionCallback>& callback, V1_0::ErrorStatus errorStatus,
telsoa015307bc12018-03-09 13:51:08 +000030 std::string callingFunction)
31{
32 Return<void> returned = callback->notify(errorStatus);
33 // This check is required, if the callback fails and it isn't checked it will bring down the service
34 if (!returned.isOk())
35 {
36 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
37 callingFunction.c_str(), returned.description().c_str());
38 }
39}
40
Sadik Armagan188675f2021-02-12 17:16:42 +000041bool ValidateRequestArgument(const V1_0::RequestArgument& requestArg, const armnn::TensorInfo& tensorInfo)
telsoa015307bc12018-03-09 13:51:08 +000042{
43 if (requestArg.dimensions.size() != 0)
44 {
45 if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
46 {
47 ALOGE("Mismatched dimensions (request argument: %zu, expected: %u)",
48 requestArg.dimensions.size(), tensorInfo.GetNumDimensions());
49 return false;
50 }
51
52 for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
53 {
Finn Williamsa4983ce2020-07-23 12:55:12 +010054 if (requestArg.dimensions[d] != 0 && requestArg.dimensions[d] != tensorInfo.GetShape()[d])
telsoa015307bc12018-03-09 13:51:08 +000055 {
56 ALOGE("Mismatched size for dimension %d (request argument: %u, expected %u)",
57 d, requestArg.dimensions[d], tensorInfo.GetShape()[d]);
58 return false;
59 }
60 }
61 }
62
63 return true;
64}
65
Sadik Armagan188675f2021-02-12 17:16:42 +000066armnn::Tensor GetTensorForRequestArgument(const V1_0::RequestArgument& requestArg,
telsoa015307bc12018-03-09 13:51:08 +000067 const armnn::TensorInfo& tensorInfo,
68 const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
69{
70 if (!ValidateRequestArgument(requestArg, tensorInfo))
71 {
72 return armnn::Tensor();
73 }
74
75 return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
76}
77
78inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
79{
80 return tensorNamePrefix + std::to_string(index);
81}
82
Matteo Martincighe48bdff2018-09-03 13:50:50 +010083} // anonymous namespace
telsoa015307bc12018-03-09 13:51:08 +000084
telsoa01ce3e84a2018-08-31 09:31:35 +010085using namespace android::hardware;
86
telsoa015307bc12018-03-09 13:51:08 +000087namespace armnn_driver
88{
Matteo Martincighe48bdff2018-09-03 13:50:50 +010089template<typename HalVersion>
Derek Lamberti4de83c52020-03-17 13:40:18 +000090RequestThread<ArmnnPreparedModel, HalVersion, CallbackContext_1_0>
91 ArmnnPreparedModel<HalVersion>::m_RequestThread;
telsoa015307bc12018-03-09 13:51:08 +000092
Matteo Martincighe48bdff2018-09-03 13:50:50 +010093template<typename HalVersion>
Finn Williamsfdf2eae2021-07-08 13:07:19 +010094std::unique_ptr<armnn::Threadpool> ArmnnPreparedModel<HalVersion>::m_Threadpool(nullptr);
95
96template<typename HalVersion>
telsoa015307bc12018-03-09 13:51:08 +000097template <typename TensorBindingCollection>
Matteo Martincighe48bdff2018-09-03 13:50:50 +010098void ArmnnPreparedModel<HalVersion>::DumpTensorsIfRequired(char const* tensorNamePrefix,
99 const TensorBindingCollection& tensorBindings)
telsoa015307bc12018-03-09 13:51:08 +0000100{
101 if (!m_RequestInputsAndOutputsDumpDir.empty())
102 {
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100103 const std::string requestName = std::to_string(m_NetworkId) + "_" + std::to_string(m_RequestCount) + ".dump";
telsoa015307bc12018-03-09 13:51:08 +0000104 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
105 {
106 DumpTensor(m_RequestInputsAndOutputsDumpDir,
107 requestName,
108 BuildTensorName(tensorNamePrefix, i),
109 tensorBindings[i].second);
110 }
111 }
112}
113
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100114template<typename HalVersion>
115ArmnnPreparedModel<HalVersion>::ArmnnPreparedModel(armnn::NetworkId networkId,
116 armnn::IRuntime* runtime,
117 const HalModel& model,
118 const std::string& requestInputsAndOutputsDumpDir,
Finn Williamsd8fb5402021-05-19 20:52:00 +0100119 const bool gpuProfilingEnabled,
Finn Williamsca3a3e02021-06-11 15:04:02 +0100120 const bool asyncModelExecutionEnabled,
Narumol Prangnawarat558a1d42022-02-07 13:12:24 +0000121 const unsigned int numberOfThreads,
122 const bool importEnabled,
123 const bool exportEnabled)
telsoa01ce3e84a2018-08-31 09:31:35 +0100124 : m_NetworkId(networkId)
125 , m_Runtime(runtime)
126 , m_Model(model)
127 , m_RequestCount(0)
128 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
129 , m_GpuProfilingEnabled(gpuProfilingEnabled)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100130 , m_AsyncModelExecutionEnabled(asyncModelExecutionEnabled)
Narumol Prangnawarat558a1d42022-02-07 13:12:24 +0000131 , m_EnableImport(importEnabled)
132 , m_EnableExport(exportEnabled)
telsoa015307bc12018-03-09 13:51:08 +0000133{
telsoa01ce3e84a2018-08-31 09:31:35 +0100134 // Enable profiling if required.
135 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100136
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100137 if (m_AsyncModelExecutionEnabled)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100138 {
Finn Williamsca3a3e02021-06-11 15:04:02 +0100139 std::vector<std::shared_ptr<armnn::IWorkingMemHandle>> memHandles;
Finn Williamsd27c13b2021-06-25 10:06:09 +0100140 for (unsigned int i=0; i < numberOfThreads; ++i)
Finn Williamsca3a3e02021-06-11 15:04:02 +0100141 {
142 memHandles.emplace_back(m_Runtime->CreateWorkingMemHandle(networkId));
143 }
144
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100145 if (!m_Threadpool)
146 {
147 m_Threadpool = std::make_unique<armnn::Threadpool>(numberOfThreads, runtime, memHandles);
148 }
149 else
150 {
151 m_Threadpool->LoadMemHandles(memHandles);
152 }
153
Finn Williamsca3a3e02021-06-11 15:04:02 +0100154 m_WorkingMemHandle = memHandles.back();
Finn Williamsd8fb5402021-05-19 20:52:00 +0100155 }
telsoa015307bc12018-03-09 13:51:08 +0000156}
157
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100158template<typename HalVersion>
159ArmnnPreparedModel<HalVersion>::~ArmnnPreparedModel()
telsoa015307bc12018-03-09 13:51:08 +0000160{
telsoa01ce3e84a2018-08-31 09:31:35 +0100161 // Get a hold of the profiler used by this model.
162 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
Colm Donelan12396f72022-02-15 14:59:08 +0000163 if (profiler && m_GpuProfilingEnabled)
164 {
165 // Dump the profiling info to a file if required.
166 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId,
167 profiler.get());
168 }
telsoa01ce3e84a2018-08-31 09:31:35 +0100169
170 // Unload the network associated with this model.
telsoa015307bc12018-03-09 13:51:08 +0000171 m_Runtime->UnloadNetwork(m_NetworkId);
telsoa01ce3e84a2018-08-31 09:31:35 +0100172
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100173 // Unload the network memhandles from the threadpool
174 if (m_AsyncModelExecutionEnabled)
175 {
176 m_Threadpool->UnloadMemHandles(m_NetworkId);
177 }
telsoa015307bc12018-03-09 13:51:08 +0000178}
179
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100180template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000181Return<V1_0::ErrorStatus> ArmnnPreparedModel<HalVersion>::execute(
182 const V1_0::Request& request,
183 const ::android::sp<V1_0::IExecutionCallback>& callback)
telsoa015307bc12018-03-09 13:51:08 +0000184{
185 ALOGV("ArmnnPreparedModel::execute(): %s", GetModelSummary(m_Model).c_str());
186 m_RequestCount++;
187
188 if (callback.get() == nullptr) {
189 ALOGE("ArmnnPreparedModel::execute invalid callback passed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000190 return V1_0::ErrorStatus::INVALID_ARGUMENT;
telsoa015307bc12018-03-09 13:51:08 +0000191 }
192
193 if (!android::nn::validateRequest(request, m_Model))
194 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000195 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::INVALID_ARGUMENT, "ArmnnPreparedModel::execute");
196 return V1_0::ErrorStatus::INVALID_ARGUMENT;
telsoa015307bc12018-03-09 13:51:08 +0000197 }
198
199 if (!m_RequestInputsAndOutputsDumpDir.empty())
200 {
201 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(callback.get()));
202 }
203
204 // allocate the tensors on the heap, as they are passed to the request thread
205 auto pInputTensors = std::make_shared<armnn::InputTensors>();
206 auto pOutputTensors = std::make_shared<armnn::OutputTensors>();
207
208 // map the memory pool into shared pointers
209 // use a shared memory pools vector on the heap, as it is passed to the request thread
210 auto pMemPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
Sadik Armagan188675f2021-02-12 17:16:42 +0000211#if !defined(ARMNN_ANDROID_S)
telsoa015307bc12018-03-09 13:51:08 +0000212 if (!setRunTimePoolInfosFromHidlMemories(pMemPools.get(), request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000213#else
214 if (!setRunTimePoolInfosFromCanonicalMemories(pMemPools.get(), uncheckedConvert(request.pools)))
215#endif
telsoa015307bc12018-03-09 13:51:08 +0000216 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000217 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
218 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000219 }
telsoa015307bc12018-03-09 13:51:08 +0000220 // add the inputs and outputs with their data
221 try
222 {
223 pInputTensors->reserve(request.inputs.size());
224 for (unsigned int i = 0; i < request.inputs.size(); i++)
225 {
226 const auto& inputArg = request.inputs[i];
227
Cathal Corbette27d4e82021-10-28 12:28:35 +0100228 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
229 // pInputTensors (of type InputTensors) is composed of a vector of ConstTensors.
230 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
231 inputTensorInfo.SetConstant();
telsoa015307bc12018-03-09 13:51:08 +0000232 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, *pMemPools);
233 if (inputTensor.GetMemoryArea() == nullptr)
234 {
235 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
Kevin Mayec1e5b82020-02-26 17:00:39 +0000236 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000237 }
238
239 pInputTensors->emplace_back(i, inputTensor);
240 }
241
242 pOutputTensors->reserve(request.outputs.size());
243 for (unsigned int i = 0; i < request.outputs.size(); i++)
244 {
245 const auto& outputArg = request.outputs[i];
246
247 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
248 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, *pMemPools);
249 if (outputTensor.GetMemoryArea() == nullptr)
250 {
251 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
Kevin Mayec1e5b82020-02-26 17:00:39 +0000252 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000253 }
254
255 pOutputTensors->emplace_back(i, outputTensor);
256 }
257 }
Kevin May7bdaac52020-02-10 12:10:07 +0000258 catch (armnn::Exception& e)
259 {
260 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000261 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
262 return V1_0::ErrorStatus::GENERAL_FAILURE;
Kevin May7bdaac52020-02-10 12:10:07 +0000263 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000264 catch (std::exception& e)
telsoa015307bc12018-03-09 13:51:08 +0000265 {
Kevin May7bdaac52020-02-10 12:10:07 +0000266 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000267 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
268 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000269 }
270
Kevin Mayec1e5b82020-02-26 17:00:39 +0000271 auto cb = [callback](V1_0::ErrorStatus errorStatus, std::string callingFunction)
Mike Kelly65c42dc2019-07-22 14:06:00 +0100272 {
273 NotifyCallbackAndCheck(callback, errorStatus, callingFunction);
274 };
275
Derek Lamberti4de83c52020-03-17 13:40:18 +0000276 CallbackContext_1_0 armnnCb;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100277 armnnCb.callback = cb;
Finn Williamsd8fb5402021-05-19 20:52:00 +0100278
279 if (m_AsyncModelExecutionEnabled)
280 {
281 ALOGV("ArmnnPreparedModel::execute(...) before ScheduleGraphForExecution");
282 ScheduleGraphForExecution(pMemPools, pInputTensors, pOutputTensors, armnnCb);
283 ALOGV("ArmnnPreparedModel::execute(...) after ScheduleGraphForExecution");
284 return V1_0::ErrorStatus::NONE;
285 }
286
Mike Kelly65c42dc2019-07-22 14:06:00 +0100287 // post the request for asynchronous execution
Finn Williamsd8fb5402021-05-19 20:52:00 +0100288 ALOGV("ArmnnPreparedModel::execute(...) before PostMsg");
Mike Kelly65c42dc2019-07-22 14:06:00 +0100289 m_RequestThread.PostMsg(this, pMemPools, pInputTensors, pOutputTensors, armnnCb);
290 ALOGV("ArmnnPreparedModel::execute(...) after PostMsg");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000291 return V1_0::ErrorStatus::NONE; // successfully queued
telsoa015307bc12018-03-09 13:51:08 +0000292}
293
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100294template<typename HalVersion>
295void ArmnnPreparedModel<HalVersion>::ExecuteGraph(
296 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000297 armnn::InputTensors& inputTensors,
298 armnn::OutputTensors& outputTensors,
299 CallbackContext_1_0 cb)
telsoa015307bc12018-03-09 13:51:08 +0000300{
301 ALOGV("ArmnnPreparedModel::ExecuteGraph(...)");
302
Derek Lamberti4de83c52020-03-17 13:40:18 +0000303 DumpTensorsIfRequired("Input", inputTensors);
telsoa015307bc12018-03-09 13:51:08 +0000304
305 // run it
306 try
307 {
Finn Williamsd8fb5402021-05-19 20:52:00 +0100308 armnn::Status status;
309 if (m_AsyncModelExecutionEnabled)
310 {
311 ALOGW("ArmnnPreparedModel::ExecuteGraph m_AsyncModelExecutionEnabled true");
312 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
313 }
314 else
315 {
316 ALOGW("ArmnnPreparedModel::ExecuteGraph m_AsyncModelExecutionEnabled false");
Narumol Prangnawarat558a1d42022-02-07 13:12:24 +0000317 // Create a vector of Input and Output Ids which can be imported. An empty vector means all will be copied.
318 std::vector<armnn::ImportedInputId> importedInputIds;
319 if (m_EnableImport)
320 {
321 importedInputIds = m_Runtime->ImportInputs(m_NetworkId, inputTensors, armnn::MemorySource::Malloc);
322 }
323 std::vector<armnn::ImportedOutputId> importedOutputIds;
324 if (m_EnableExport)
325 {
326 importedOutputIds = m_Runtime->ImportOutputs(m_NetworkId, outputTensors, armnn::MemorySource::Malloc);
327 }
328 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors,
329 importedInputIds, importedOutputIds);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100330 }
331
Matthew Bentham16196e22019-04-01 17:17:58 +0100332 if (status != armnn::Status::Success)
333 {
334 ALOGW("EnqueueWorkload failed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000335 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::ExecuteGraph");
Matthew Bentham16196e22019-04-01 17:17:58 +0100336 return;
337 }
telsoa015307bc12018-03-09 13:51:08 +0000338 }
Kevin May7bdaac52020-02-10 12:10:07 +0000339 catch (armnn::Exception& e)
340 {
341 ALOGW("armnn::Exception caught from EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000342 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::ExecuteGraph");
Kevin May7bdaac52020-02-10 12:10:07 +0000343 return;
344 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000345 catch (std::exception& e)
telsoa015307bc12018-03-09 13:51:08 +0000346 {
Kevin May7bdaac52020-02-10 12:10:07 +0000347 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000348 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::ExecuteGraph");
telsoa015307bc12018-03-09 13:51:08 +0000349 return;
350 }
351
Derek Lamberti4de83c52020-03-17 13:40:18 +0000352 DumpTensorsIfRequired("Output", outputTensors);
telsoa015307bc12018-03-09 13:51:08 +0000353
354 // Commit output buffers.
355 // Note that we update *all* pools, even if they aren't actually used as outputs -
356 // this is simpler and is what the CpuExecutor does.
357 for (android::nn::RunTimePoolInfo& pool : *pMemPools)
358 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000359 // Type android::nn::RunTimePoolInfo has changed between Android P & Q and Android R, where
360 // update() has been removed and flush() added.
Sadik Armagan188675f2021-02-12 17:16:42 +0000361 #if defined(ARMNN_ANDROID_R) || defined(ARMNN_ANDROID_S) // Use the new Android implementation.
Kevin Mayec1e5b82020-02-26 17:00:39 +0000362 pool.flush();
363 #else
364 pool.update();
365 #endif
telsoa015307bc12018-03-09 13:51:08 +0000366 }
367
Kevin Mayec1e5b82020-02-26 17:00:39 +0000368 cb.callback(V1_0::ErrorStatus::NONE, "ExecuteGraph");
telsoa015307bc12018-03-09 13:51:08 +0000369}
370
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100371template<typename HalVersion>
Matthew Bentham16196e22019-04-01 17:17:58 +0100372bool ArmnnPreparedModel<HalVersion>::ExecuteWithDummyInputs()
telsoa015307bc12018-03-09 13:51:08 +0000373{
374 std::vector<std::vector<char>> storage;
375 armnn::InputTensors inputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000376 for (unsigned int i = 0; i < getMainModel(m_Model).inputIndexes.size(); i++)
telsoa015307bc12018-03-09 13:51:08 +0000377 {
Cathal Corbette27d4e82021-10-28 12:28:35 +0100378 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
379 // pInputTensors (of type InputTensors) is composed of a vector of ConstTensors.
380 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
381 inputTensorInfo.SetConstant();
382
telsoa015307bc12018-03-09 13:51:08 +0000383 storage.emplace_back(inputTensorInfo.GetNumBytes());
384 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
385
386 inputTensors.emplace_back(i, inputTensor);
387 }
388
389 armnn::OutputTensors outputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000390 for (unsigned int i = 0; i < getMainModel(m_Model).outputIndexes.size(); i++)
telsoa015307bc12018-03-09 13:51:08 +0000391 {
392 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
393 storage.emplace_back(outputTensorInfo.GetNumBytes());
394 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
395
396 outputTensors.emplace_back(i, outputTensor);
397 }
398
399 try
400 {
Finn Williams8fde84b2021-05-31 14:57:15 +0100401 armnn::Status status;
402 if (m_AsyncModelExecutionEnabled)
403 {
404 ALOGW("ArmnnPreparedModel::ExecuteGraph m_AsyncModelExecutionEnabled true");
405 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
406 }
407 else
408 {
409 ALOGW("ArmnnPreparedModel::ExecuteGraph m_AsyncModelExecutionEnabled false");
Narumol Prangnawarat558a1d42022-02-07 13:12:24 +0000410 // Create a vector of Input and Output Ids which can be imported. An empty vector means all will be copied.
411 std::vector<armnn::ImportedInputId> importedInputIds;
412 if (m_EnableImport)
413 {
414 importedInputIds = m_Runtime->ImportInputs(m_NetworkId, inputTensors, armnn::MemorySource::Malloc);
415 }
416 std::vector<armnn::ImportedOutputId> importedOutputIds;
417 if (m_EnableExport)
418 {
419 importedOutputIds = m_Runtime->ImportOutputs(m_NetworkId, outputTensors, armnn::MemorySource::Malloc);
420 }
421 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors,
422 importedInputIds, importedOutputIds);
Finn Williams8fde84b2021-05-31 14:57:15 +0100423 }
Matthew Bentham16196e22019-04-01 17:17:58 +0100424 if (status != armnn::Status::Success)
425 {
426 ALOGW("ExecuteWithDummyInputs: EnqueueWorkload failed");
427 return false;
428 }
telsoa015307bc12018-03-09 13:51:08 +0000429 }
Kevin May7bdaac52020-02-10 12:10:07 +0000430 catch (armnn::Exception& e)
431 {
432 ALOGW("ExecuteWithDummyInputs: armnn::Exception caught from EnqueueWorkload: %s", e.what());
433 return false;
434 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000435 catch (std::exception& e)
telsoa015307bc12018-03-09 13:51:08 +0000436 {
Kevin May7bdaac52020-02-10 12:10:07 +0000437 ALOGE("ExecuteWithDummyInputs: std::exception caught from EnqueueWorkload: %s", e.what());
Matthew Bentham16196e22019-04-01 17:17:58 +0100438 return false;
telsoa015307bc12018-03-09 13:51:08 +0000439 }
Matthew Bentham16196e22019-04-01 17:17:58 +0100440 return true;
telsoa015307bc12018-03-09 13:51:08 +0000441}
442
Finn Williamsd8fb5402021-05-19 20:52:00 +0100443/// Schedule the graph prepared from the request for execution
444template<typename HalVersion>
445template<typename CallbackContext>
446void ArmnnPreparedModel<HalVersion>::ScheduleGraphForExecution(
447 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
448 std::shared_ptr<armnn::InputTensors>& inputTensors,
449 std::shared_ptr<armnn::OutputTensors>& outputTensors,
450 CallbackContext callbackContext)
451{
452 ALOGV("ArmnnPreparedModel::ScheduleGraphForExecution(...)");
453
454 DumpTensorsIfRequired("Input", *inputTensors);
455
456
457 auto tpCb = std::make_shared<
458 ArmnnThreadPoolCallback<CallbackContext_1_0>>(this,
459 pMemPools,
460 inputTensors,
461 outputTensors,
462 callbackContext);
463
Finn Williamsca3a3e02021-06-11 15:04:02 +0100464 m_Threadpool->Schedule(m_NetworkId,
465 *tpCb->m_InputTensors,
466 *tpCb->m_OutputTensors,
467 armnn::QosExecPriority::Medium,
468 tpCb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100469 ALOGV("ArmnnPreparedModel::ScheduleGraphForExecution end");
470}
471
472template<typename HalVersion>
473template <typename CallbackContext>
474void ArmnnPreparedModel<HalVersion>::ArmnnThreadPoolCallback<CallbackContext>::Notify(
475 armnn::Status status, armnn::InferenceTimingPair timeTaken)
476{
477 armnn::IgnoreUnused(status, timeTaken);
478 ALOGV("ArmnnPreparedModel::ArmnnThreadPoolCallback_1_2 Notify");
479
480 m_Model->DumpTensorsIfRequired("Output", *m_OutputTensors);
481
482 // Commit output buffers.
483 // Note that we update *all* pools, even if they aren't actually used as outputs -
484 // this is simpler and is what the CpuExecutor does.
485 for (android::nn::RunTimePoolInfo& pool : *m_MemPools)
486 {
487 // Type android::nn::RunTimePoolInfo has changed between Android P & Q and Android R, where
488 // update() has been removed and flush() added.
489 #if defined(ARMNN_ANDROID_R) || defined(ARMNN_ANDROID_S) // Use the new Android implementation.
490 pool.flush();
491 #else
492 pool.update();
493 #endif
494 }
495
496 m_CallbackContext.callback(V1_0::ErrorStatus::NONE, "ArmnnPreparedModel::ArmnnThreadPoolCallback_1_2 Notify");
497 return;
498}
499
arovir01b0717b52018-09-05 17:03:25 +0100500///
501/// Class template specializations
502///
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100503
arovir01b0717b52018-09-05 17:03:25 +0100504template class ArmnnPreparedModel<hal_1_0::HalPolicy>;
Finn Williamsd8fb5402021-05-19 20:52:00 +0100505template void ArmnnPreparedModel<hal_1_0::HalPolicy>::ScheduleGraphForExecution<CallbackContext_1_0>(
506 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
507 std::shared_ptr<armnn::InputTensors>& inputTensors,
508 std::shared_ptr<armnn::OutputTensors>& outputTensors,
509 CallbackContext_1_0 callbackContext);
arovir01b0717b52018-09-05 17:03:25 +0100510
Matteo Martincigh8b287c22018-09-07 09:25:10 +0100511#ifdef ARMNN_ANDROID_NN_V1_1
arovir01b0717b52018-09-05 17:03:25 +0100512template class ArmnnPreparedModel<hal_1_1::HalPolicy>;
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100513#endif
514
Mike Kellyb5fdf382019-06-11 16:35:25 +0100515#ifdef ARMNN_ANDROID_NN_V1_2
516template class ArmnnPreparedModel<hal_1_1::HalPolicy>;
517template class ArmnnPreparedModel<hal_1_2::HalPolicy>;
518#endif
Kevin May42477c12020-03-26 13:34:14 +0000519
520#ifdef ARMNN_ANDROID_NN_V1_3
521template class ArmnnPreparedModel<hal_1_1::HalPolicy>;
522template class ArmnnPreparedModel<hal_1_2::HalPolicy>;
523template class ArmnnPreparedModel<hal_1_3::HalPolicy>;
524#endif
Nikhil Raj77605822018-09-03 11:25:56 +0100525} // namespace armnn_driver