blob: 417404358a98271215f6be0f939c4eb9f35b7bb1 [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 Prangnawaratd1a947f2022-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
Colm Donelan0fc16c62022-03-16 11:54:13 +000017#include <chrono>
telsoa015307bc12018-03-09 13:51:08 +000018#include <cinttypes>
19
Sadik Armagan188675f2021-02-12 17:16:42 +000020#ifdef ARMNN_ANDROID_S
21#include <LegacyUtils.h>
22#endif
23
telsoa015307bc12018-03-09 13:51:08 +000024using namespace android;
25
26namespace
27{
28using namespace armnn_driver;
29
Kevin Mayec1e5b82020-02-26 17:00:39 +000030void NotifyCallbackAndCheck(const ::android::sp<V1_0::IExecutionCallback>& callback, V1_0::ErrorStatus errorStatus,
telsoa015307bc12018-03-09 13:51:08 +000031 std::string callingFunction)
32{
33 Return<void> returned = callback->notify(errorStatus);
34 // This check is required, if the callback fails and it isn't checked it will bring down the service
35 if (!returned.isOk())
36 {
37 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
38 callingFunction.c_str(), returned.description().c_str());
39 }
40}
41
Sadik Armagan188675f2021-02-12 17:16:42 +000042bool ValidateRequestArgument(const V1_0::RequestArgument& requestArg, const armnn::TensorInfo& tensorInfo)
telsoa015307bc12018-03-09 13:51:08 +000043{
44 if (requestArg.dimensions.size() != 0)
45 {
46 if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
47 {
48 ALOGE("Mismatched dimensions (request argument: %zu, expected: %u)",
49 requestArg.dimensions.size(), tensorInfo.GetNumDimensions());
50 return false;
51 }
52
53 for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
54 {
Finn Williamsa4983ce2020-07-23 12:55:12 +010055 if (requestArg.dimensions[d] != 0 && requestArg.dimensions[d] != tensorInfo.GetShape()[d])
telsoa015307bc12018-03-09 13:51:08 +000056 {
57 ALOGE("Mismatched size for dimension %d (request argument: %u, expected %u)",
58 d, requestArg.dimensions[d], tensorInfo.GetShape()[d]);
59 return false;
60 }
61 }
62 }
63
64 return true;
65}
66
Sadik Armagan188675f2021-02-12 17:16:42 +000067armnn::Tensor GetTensorForRequestArgument(const V1_0::RequestArgument& requestArg,
telsoa015307bc12018-03-09 13:51:08 +000068 const armnn::TensorInfo& tensorInfo,
69 const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
70{
71 if (!ValidateRequestArgument(requestArg, tensorInfo))
72 {
73 return armnn::Tensor();
74 }
75
76 return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
77}
78
79inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
80{
81 return tensorNamePrefix + std::to_string(index);
82}
83
Matteo Martincighe48bdff2018-09-03 13:50:50 +010084} // anonymous namespace
telsoa015307bc12018-03-09 13:51:08 +000085
telsoa01ce3e84a2018-08-31 09:31:35 +010086using namespace android::hardware;
87
telsoa015307bc12018-03-09 13:51:08 +000088namespace armnn_driver
89{
Matteo Martincighe48bdff2018-09-03 13:50:50 +010090template<typename HalVersion>
Derek Lamberti4de83c52020-03-17 13:40:18 +000091RequestThread<ArmnnPreparedModel, HalVersion, CallbackContext_1_0>
92 ArmnnPreparedModel<HalVersion>::m_RequestThread;
telsoa015307bc12018-03-09 13:51:08 +000093
Matteo Martincighe48bdff2018-09-03 13:50:50 +010094template<typename HalVersion>
Finn Williamsfdf2eae2021-07-08 13:07:19 +010095std::unique_ptr<armnn::Threadpool> ArmnnPreparedModel<HalVersion>::m_Threadpool(nullptr);
96
97template<typename HalVersion>
telsoa015307bc12018-03-09 13:51:08 +000098template <typename TensorBindingCollection>
Matteo Martincighe48bdff2018-09-03 13:50:50 +010099void ArmnnPreparedModel<HalVersion>::DumpTensorsIfRequired(char const* tensorNamePrefix,
100 const TensorBindingCollection& tensorBindings)
telsoa015307bc12018-03-09 13:51:08 +0000101{
102 if (!m_RequestInputsAndOutputsDumpDir.empty())
103 {
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100104 const std::string requestName = std::to_string(m_NetworkId) + "_" + std::to_string(m_RequestCount) + ".dump";
telsoa015307bc12018-03-09 13:51:08 +0000105 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
106 {
107 DumpTensor(m_RequestInputsAndOutputsDumpDir,
108 requestName,
109 BuildTensorName(tensorNamePrefix, i),
110 tensorBindings[i].second);
111 }
112 }
113}
114
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100115template<typename HalVersion>
116ArmnnPreparedModel<HalVersion>::ArmnnPreparedModel(armnn::NetworkId networkId,
117 armnn::IRuntime* runtime,
118 const HalModel& model,
119 const std::string& requestInputsAndOutputsDumpDir,
Finn Williamsd8fb5402021-05-19 20:52:00 +0100120 const bool gpuProfilingEnabled,
Finn Williamsca3a3e02021-06-11 15:04:02 +0100121 const bool asyncModelExecutionEnabled,
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000122 const unsigned int numberOfThreads,
123 const bool importEnabled,
124 const bool exportEnabled)
telsoa01ce3e84a2018-08-31 09:31:35 +0100125 : m_NetworkId(networkId)
126 , m_Runtime(runtime)
127 , m_Model(model)
128 , m_RequestCount(0)
129 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
130 , m_GpuProfilingEnabled(gpuProfilingEnabled)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100131 , m_AsyncModelExecutionEnabled(asyncModelExecutionEnabled)
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000132 , m_EnableImport(importEnabled)
133 , m_EnableExport(exportEnabled)
telsoa015307bc12018-03-09 13:51:08 +0000134{
telsoa01ce3e84a2018-08-31 09:31:35 +0100135 // Enable profiling if required.
136 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100137
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100138 if (m_AsyncModelExecutionEnabled)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100139 {
Finn Williamsca3a3e02021-06-11 15:04:02 +0100140 std::vector<std::shared_ptr<armnn::IWorkingMemHandle>> memHandles;
Finn Williamsd27c13b2021-06-25 10:06:09 +0100141 for (unsigned int i=0; i < numberOfThreads; ++i)
Finn Williamsca3a3e02021-06-11 15:04:02 +0100142 {
143 memHandles.emplace_back(m_Runtime->CreateWorkingMemHandle(networkId));
144 }
145
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100146 if (!m_Threadpool)
147 {
148 m_Threadpool = std::make_unique<armnn::Threadpool>(numberOfThreads, runtime, memHandles);
149 }
150 else
151 {
152 m_Threadpool->LoadMemHandles(memHandles);
153 }
154
Finn Williamsca3a3e02021-06-11 15:04:02 +0100155 m_WorkingMemHandle = memHandles.back();
Finn Williamsd8fb5402021-05-19 20:52:00 +0100156 }
telsoa015307bc12018-03-09 13:51:08 +0000157}
158
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100159template<typename HalVersion>
160ArmnnPreparedModel<HalVersion>::~ArmnnPreparedModel()
telsoa015307bc12018-03-09 13:51:08 +0000161{
telsoa01ce3e84a2018-08-31 09:31:35 +0100162 // Get a hold of the profiler used by this model.
163 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
Colm Donelan2048b682022-02-15 14:59:08 +0000164 if (profiler && m_GpuProfilingEnabled)
165 {
166 // Dump the profiling info to a file if required.
167 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId,
168 profiler.get());
169 }
telsoa01ce3e84a2018-08-31 09:31:35 +0100170
171 // Unload the network associated with this model.
telsoa015307bc12018-03-09 13:51:08 +0000172 m_Runtime->UnloadNetwork(m_NetworkId);
telsoa01ce3e84a2018-08-31 09:31:35 +0100173
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100174 // Unload the network memhandles from the threadpool
175 if (m_AsyncModelExecutionEnabled)
176 {
177 m_Threadpool->UnloadMemHandles(m_NetworkId);
178 }
telsoa015307bc12018-03-09 13:51:08 +0000179}
180
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100181template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000182Return<V1_0::ErrorStatus> ArmnnPreparedModel<HalVersion>::execute(
183 const V1_0::Request& request,
184 const ::android::sp<V1_0::IExecutionCallback>& callback)
telsoa015307bc12018-03-09 13:51:08 +0000185{
186 ALOGV("ArmnnPreparedModel::execute(): %s", GetModelSummary(m_Model).c_str());
187 m_RequestCount++;
188
189 if (callback.get() == nullptr) {
190 ALOGE("ArmnnPreparedModel::execute invalid callback passed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000191 return V1_0::ErrorStatus::INVALID_ARGUMENT;
telsoa015307bc12018-03-09 13:51:08 +0000192 }
193
194 if (!android::nn::validateRequest(request, m_Model))
195 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000196 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::INVALID_ARGUMENT, "ArmnnPreparedModel::execute");
197 return V1_0::ErrorStatus::INVALID_ARGUMENT;
telsoa015307bc12018-03-09 13:51:08 +0000198 }
199
200 if (!m_RequestInputsAndOutputsDumpDir.empty())
201 {
202 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(callback.get()));
203 }
204
205 // allocate the tensors on the heap, as they are passed to the request thread
206 auto pInputTensors = std::make_shared<armnn::InputTensors>();
207 auto pOutputTensors = std::make_shared<armnn::OutputTensors>();
208
209 // map the memory pool into shared pointers
210 // use a shared memory pools vector on the heap, as it is passed to the request thread
211 auto pMemPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
Sadik Armagan188675f2021-02-12 17:16:42 +0000212#if !defined(ARMNN_ANDROID_S)
telsoa015307bc12018-03-09 13:51:08 +0000213 if (!setRunTimePoolInfosFromHidlMemories(pMemPools.get(), request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000214#else
215 if (!setRunTimePoolInfosFromCanonicalMemories(pMemPools.get(), uncheckedConvert(request.pools)))
216#endif
telsoa015307bc12018-03-09 13:51:08 +0000217 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000218 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
219 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000220 }
telsoa015307bc12018-03-09 13:51:08 +0000221 // add the inputs and outputs with their data
222 try
223 {
224 pInputTensors->reserve(request.inputs.size());
225 for (unsigned int i = 0; i < request.inputs.size(); i++)
226 {
227 const auto& inputArg = request.inputs[i];
228
Cathal Corbette27d4e82021-10-28 12:28:35 +0100229 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
230 // pInputTensors (of type InputTensors) is composed of a vector of ConstTensors.
231 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
232 inputTensorInfo.SetConstant();
telsoa015307bc12018-03-09 13:51:08 +0000233 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, *pMemPools);
234 if (inputTensor.GetMemoryArea() == nullptr)
235 {
236 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
Kevin Mayec1e5b82020-02-26 17:00:39 +0000237 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000238 }
239
240 pInputTensors->emplace_back(i, inputTensor);
241 }
242
243 pOutputTensors->reserve(request.outputs.size());
244 for (unsigned int i = 0; i < request.outputs.size(); i++)
245 {
246 const auto& outputArg = request.outputs[i];
247
248 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
249 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, *pMemPools);
250 if (outputTensor.GetMemoryArea() == nullptr)
251 {
252 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
Kevin Mayec1e5b82020-02-26 17:00:39 +0000253 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000254 }
255
256 pOutputTensors->emplace_back(i, outputTensor);
257 }
258 }
Kevin May7bdaac52020-02-10 12:10:07 +0000259 catch (armnn::Exception& e)
260 {
261 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000262 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
263 return V1_0::ErrorStatus::GENERAL_FAILURE;
Kevin May7bdaac52020-02-10 12:10:07 +0000264 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000265 catch (std::exception& e)
telsoa015307bc12018-03-09 13:51:08 +0000266 {
Kevin May7bdaac52020-02-10 12:10:07 +0000267 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000268 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
269 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000270 }
271
Kevin Mayec1e5b82020-02-26 17:00:39 +0000272 auto cb = [callback](V1_0::ErrorStatus errorStatus, std::string callingFunction)
Mike Kelly65c42dc2019-07-22 14:06:00 +0100273 {
274 NotifyCallbackAndCheck(callback, errorStatus, callingFunction);
275 };
276
Derek Lamberti4de83c52020-03-17 13:40:18 +0000277 CallbackContext_1_0 armnnCb;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100278 armnnCb.callback = cb;
Finn Williamsd8fb5402021-05-19 20:52:00 +0100279
280 if (m_AsyncModelExecutionEnabled)
281 {
282 ALOGV("ArmnnPreparedModel::execute(...) before ScheduleGraphForExecution");
283 ScheduleGraphForExecution(pMemPools, pInputTensors, pOutputTensors, armnnCb);
284 ALOGV("ArmnnPreparedModel::execute(...) after ScheduleGraphForExecution");
285 return V1_0::ErrorStatus::NONE;
286 }
287
Mike Kelly65c42dc2019-07-22 14:06:00 +0100288 // post the request for asynchronous execution
Finn Williamsd8fb5402021-05-19 20:52:00 +0100289 ALOGV("ArmnnPreparedModel::execute(...) before PostMsg");
Mike Kelly65c42dc2019-07-22 14:06:00 +0100290 m_RequestThread.PostMsg(this, pMemPools, pInputTensors, pOutputTensors, armnnCb);
291 ALOGV("ArmnnPreparedModel::execute(...) after PostMsg");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000292 return V1_0::ErrorStatus::NONE; // successfully queued
telsoa015307bc12018-03-09 13:51:08 +0000293}
294
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100295template<typename HalVersion>
296void ArmnnPreparedModel<HalVersion>::ExecuteGraph(
297 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000298 armnn::InputTensors& inputTensors,
299 armnn::OutputTensors& outputTensors,
300 CallbackContext_1_0 cb)
telsoa015307bc12018-03-09 13:51:08 +0000301{
302 ALOGV("ArmnnPreparedModel::ExecuteGraph(...)");
Colm Donelan0fc16c62022-03-16 11:54:13 +0000303 // Capture the graph execution start time.
304 std::chrono::time_point<std::chrono::system_clock> graphExecutionStart = std::chrono::system_clock::now();
telsoa015307bc12018-03-09 13:51:08 +0000305
Derek Lamberti4de83c52020-03-17 13:40:18 +0000306 DumpTensorsIfRequired("Input", inputTensors);
telsoa015307bc12018-03-09 13:51:08 +0000307
308 // run it
309 try
310 {
Finn Williamsd8fb5402021-05-19 20:52:00 +0100311 armnn::Status status;
312 if (m_AsyncModelExecutionEnabled)
313 {
314 ALOGW("ArmnnPreparedModel::ExecuteGraph m_AsyncModelExecutionEnabled true");
315 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
316 }
317 else
318 {
319 ALOGW("ArmnnPreparedModel::ExecuteGraph m_AsyncModelExecutionEnabled false");
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000320 // Create a vector of Input and Output Ids which can be imported. An empty vector means all will be copied.
321 std::vector<armnn::ImportedInputId> importedInputIds;
322 if (m_EnableImport)
323 {
324 importedInputIds = m_Runtime->ImportInputs(m_NetworkId, inputTensors, armnn::MemorySource::Malloc);
325 }
326 std::vector<armnn::ImportedOutputId> importedOutputIds;
327 if (m_EnableExport)
328 {
329 importedOutputIds = m_Runtime->ImportOutputs(m_NetworkId, outputTensors, armnn::MemorySource::Malloc);
330 }
331 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors,
332 importedInputIds, importedOutputIds);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100333 }
Matthew Bentham16196e22019-04-01 17:17:58 +0100334 if (status != armnn::Status::Success)
335 {
336 ALOGW("EnqueueWorkload failed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000337 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::ExecuteGraph");
Matthew Bentham16196e22019-04-01 17:17:58 +0100338 return;
339 }
telsoa015307bc12018-03-09 13:51:08 +0000340 }
Kevin May7bdaac52020-02-10 12:10:07 +0000341 catch (armnn::Exception& e)
342 {
343 ALOGW("armnn::Exception caught from EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000344 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::ExecuteGraph");
Kevin May7bdaac52020-02-10 12:10:07 +0000345 return;
346 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000347 catch (std::exception& e)
telsoa015307bc12018-03-09 13:51:08 +0000348 {
Kevin May7bdaac52020-02-10 12:10:07 +0000349 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000350 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::ExecuteGraph");
telsoa015307bc12018-03-09 13:51:08 +0000351 return;
352 }
353
Derek Lamberti4de83c52020-03-17 13:40:18 +0000354 DumpTensorsIfRequired("Output", outputTensors);
telsoa015307bc12018-03-09 13:51:08 +0000355
356 // Commit output buffers.
357 // Note that we update *all* pools, even if they aren't actually used as outputs -
358 // this is simpler and is what the CpuExecutor does.
359 for (android::nn::RunTimePoolInfo& pool : *pMemPools)
360 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000361 // Type android::nn::RunTimePoolInfo has changed between Android P & Q and Android R, where
362 // update() has been removed and flush() added.
Sadik Armagan188675f2021-02-12 17:16:42 +0000363 #if defined(ARMNN_ANDROID_R) || defined(ARMNN_ANDROID_S) // Use the new Android implementation.
Kevin Mayec1e5b82020-02-26 17:00:39 +0000364 pool.flush();
365 #else
366 pool.update();
367 #endif
telsoa015307bc12018-03-09 13:51:08 +0000368 }
369
Colm Donelan0fc16c62022-03-16 11:54:13 +0000370 // Log the total time in this call. This is a good number to compare to that printed out by
371 // RuntimeImpl::EnqueueWorkload. The difference should be the execution overhead of the driver.
372 ALOGI("ArmnnPreparedModel::ExecuteGraph Execution time = %lld µs",
373 std::chrono::duration_cast<std::chrono::microseconds>
374 (std::chrono::system_clock::now() - graphExecutionStart).count());
375
Kevin Mayec1e5b82020-02-26 17:00:39 +0000376 cb.callback(V1_0::ErrorStatus::NONE, "ExecuteGraph");
telsoa015307bc12018-03-09 13:51:08 +0000377}
378
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100379template<typename HalVersion>
Matthew Bentham16196e22019-04-01 17:17:58 +0100380bool ArmnnPreparedModel<HalVersion>::ExecuteWithDummyInputs()
telsoa015307bc12018-03-09 13:51:08 +0000381{
382 std::vector<std::vector<char>> storage;
383 armnn::InputTensors inputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000384 for (unsigned int i = 0; i < getMainModel(m_Model).inputIndexes.size(); i++)
telsoa015307bc12018-03-09 13:51:08 +0000385 {
Cathal Corbette27d4e82021-10-28 12:28:35 +0100386 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
387 // pInputTensors (of type InputTensors) is composed of a vector of ConstTensors.
388 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
389 inputTensorInfo.SetConstant();
390
telsoa015307bc12018-03-09 13:51:08 +0000391 storage.emplace_back(inputTensorInfo.GetNumBytes());
392 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
393
394 inputTensors.emplace_back(i, inputTensor);
395 }
396
397 armnn::OutputTensors outputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000398 for (unsigned int i = 0; i < getMainModel(m_Model).outputIndexes.size(); i++)
telsoa015307bc12018-03-09 13:51:08 +0000399 {
400 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
401 storage.emplace_back(outputTensorInfo.GetNumBytes());
402 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
403
404 outputTensors.emplace_back(i, outputTensor);
405 }
406
407 try
408 {
Finn Williams8fde84b2021-05-31 14:57:15 +0100409 armnn::Status status;
410 if (m_AsyncModelExecutionEnabled)
411 {
412 ALOGW("ArmnnPreparedModel::ExecuteGraph m_AsyncModelExecutionEnabled true");
413 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
414 }
415 else
416 {
417 ALOGW("ArmnnPreparedModel::ExecuteGraph m_AsyncModelExecutionEnabled false");
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000418 // Create a vector of Input and Output Ids which can be imported. An empty vector means all will be copied.
419 std::vector<armnn::ImportedInputId> importedInputIds;
420 if (m_EnableImport)
421 {
422 importedInputIds = m_Runtime->ImportInputs(m_NetworkId, inputTensors, armnn::MemorySource::Malloc);
423 }
424 std::vector<armnn::ImportedOutputId> importedOutputIds;
425 if (m_EnableExport)
426 {
427 importedOutputIds = m_Runtime->ImportOutputs(m_NetworkId, outputTensors, armnn::MemorySource::Malloc);
428 }
429 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors,
430 importedInputIds, importedOutputIds);
Finn Williams8fde84b2021-05-31 14:57:15 +0100431 }
Matthew Bentham16196e22019-04-01 17:17:58 +0100432 if (status != armnn::Status::Success)
433 {
434 ALOGW("ExecuteWithDummyInputs: EnqueueWorkload failed");
435 return false;
436 }
telsoa015307bc12018-03-09 13:51:08 +0000437 }
Kevin May7bdaac52020-02-10 12:10:07 +0000438 catch (armnn::Exception& e)
439 {
440 ALOGW("ExecuteWithDummyInputs: armnn::Exception caught from EnqueueWorkload: %s", e.what());
441 return false;
442 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000443 catch (std::exception& e)
telsoa015307bc12018-03-09 13:51:08 +0000444 {
Kevin May7bdaac52020-02-10 12:10:07 +0000445 ALOGE("ExecuteWithDummyInputs: std::exception caught from EnqueueWorkload: %s", e.what());
Matthew Bentham16196e22019-04-01 17:17:58 +0100446 return false;
telsoa015307bc12018-03-09 13:51:08 +0000447 }
Matthew Bentham16196e22019-04-01 17:17:58 +0100448 return true;
telsoa015307bc12018-03-09 13:51:08 +0000449}
450
Finn Williamsd8fb5402021-05-19 20:52:00 +0100451/// Schedule the graph prepared from the request for execution
452template<typename HalVersion>
453template<typename CallbackContext>
454void ArmnnPreparedModel<HalVersion>::ScheduleGraphForExecution(
455 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
456 std::shared_ptr<armnn::InputTensors>& inputTensors,
457 std::shared_ptr<armnn::OutputTensors>& outputTensors,
458 CallbackContext callbackContext)
459{
460 ALOGV("ArmnnPreparedModel::ScheduleGraphForExecution(...)");
461
462 DumpTensorsIfRequired("Input", *inputTensors);
463
464
465 auto tpCb = std::make_shared<
466 ArmnnThreadPoolCallback<CallbackContext_1_0>>(this,
467 pMemPools,
468 inputTensors,
469 outputTensors,
470 callbackContext);
471
Finn Williamsca3a3e02021-06-11 15:04:02 +0100472 m_Threadpool->Schedule(m_NetworkId,
473 *tpCb->m_InputTensors,
474 *tpCb->m_OutputTensors,
475 armnn::QosExecPriority::Medium,
476 tpCb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100477 ALOGV("ArmnnPreparedModel::ScheduleGraphForExecution end");
478}
479
480template<typename HalVersion>
481template <typename CallbackContext>
482void ArmnnPreparedModel<HalVersion>::ArmnnThreadPoolCallback<CallbackContext>::Notify(
483 armnn::Status status, armnn::InferenceTimingPair timeTaken)
484{
485 armnn::IgnoreUnused(status, timeTaken);
486 ALOGV("ArmnnPreparedModel::ArmnnThreadPoolCallback_1_2 Notify");
487
488 m_Model->DumpTensorsIfRequired("Output", *m_OutputTensors);
489
490 // Commit output buffers.
491 // Note that we update *all* pools, even if they aren't actually used as outputs -
492 // this is simpler and is what the CpuExecutor does.
493 for (android::nn::RunTimePoolInfo& pool : *m_MemPools)
494 {
495 // Type android::nn::RunTimePoolInfo has changed between Android P & Q and Android R, where
496 // update() has been removed and flush() added.
497 #if defined(ARMNN_ANDROID_R) || defined(ARMNN_ANDROID_S) // Use the new Android implementation.
498 pool.flush();
499 #else
500 pool.update();
501 #endif
502 }
503
504 m_CallbackContext.callback(V1_0::ErrorStatus::NONE, "ArmnnPreparedModel::ArmnnThreadPoolCallback_1_2 Notify");
505 return;
506}
507
arovir01b0717b52018-09-05 17:03:25 +0100508///
509/// Class template specializations
510///
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100511
arovir01b0717b52018-09-05 17:03:25 +0100512template class ArmnnPreparedModel<hal_1_0::HalPolicy>;
Finn Williamsd8fb5402021-05-19 20:52:00 +0100513template void ArmnnPreparedModel<hal_1_0::HalPolicy>::ScheduleGraphForExecution<CallbackContext_1_0>(
514 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
515 std::shared_ptr<armnn::InputTensors>& inputTensors,
516 std::shared_ptr<armnn::OutputTensors>& outputTensors,
517 CallbackContext_1_0 callbackContext);
arovir01b0717b52018-09-05 17:03:25 +0100518
Matteo Martincigh8b287c22018-09-07 09:25:10 +0100519#ifdef ARMNN_ANDROID_NN_V1_1
arovir01b0717b52018-09-05 17:03:25 +0100520template class ArmnnPreparedModel<hal_1_1::HalPolicy>;
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100521#endif
522
Mike Kellyb5fdf382019-06-11 16:35:25 +0100523#ifdef ARMNN_ANDROID_NN_V1_2
524template class ArmnnPreparedModel<hal_1_1::HalPolicy>;
525template class ArmnnPreparedModel<hal_1_2::HalPolicy>;
526#endif
Kevin May42477c12020-03-26 13:34:14 +0000527
528#ifdef ARMNN_ANDROID_NN_V1_3
529template class ArmnnPreparedModel<hal_1_1::HalPolicy>;
530template class ArmnnPreparedModel<hal_1_2::HalPolicy>;
531template class ArmnnPreparedModel<hal_1_3::HalPolicy>;
532#endif
Nikhil Raj77605822018-09-03 11:25:56 +0100533} // namespace armnn_driver