blob: 60beac4f568490736d7fe476dbde7c83a50e0726 [file] [log] [blame]
telsoa015307bc12018-03-09 13:51:08 +00001//
2// Copyright © 2017 Arm Ltd. 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
telsoa015307bc12018-03-09 13:51:08 +000011#include <log/log.h>
12#include <OperationsUtils.h>
surmeh01deb3bdb2018-07-05 12:06:04 +010013#include <ValidateHal.h>
Kevin Mayec1e5b82020-02-26 17:00:39 +000014
telsoa015307bc12018-03-09 13:51:08 +000015#include <cassert>
16#include <cinttypes>
17
Sadik Armagan188675f2021-02-12 17:16:42 +000018#ifdef ARMNN_ANDROID_S
19#include <LegacyUtils.h>
20#endif
21
telsoa015307bc12018-03-09 13:51:08 +000022using namespace android;
23
24namespace
25{
26using namespace armnn_driver;
27
Kevin Mayec1e5b82020-02-26 17:00:39 +000028void NotifyCallbackAndCheck(const ::android::sp<V1_0::IExecutionCallback>& callback, V1_0::ErrorStatus errorStatus,
telsoa015307bc12018-03-09 13:51:08 +000029 std::string callingFunction)
30{
31 Return<void> returned = callback->notify(errorStatus);
32 // This check is required, if the callback fails and it isn't checked it will bring down the service
33 if (!returned.isOk())
34 {
35 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
36 callingFunction.c_str(), returned.description().c_str());
37 }
38}
39
Sadik Armagan188675f2021-02-12 17:16:42 +000040bool ValidateRequestArgument(const V1_0::RequestArgument& requestArg, const armnn::TensorInfo& tensorInfo)
telsoa015307bc12018-03-09 13:51:08 +000041{
42 if (requestArg.dimensions.size() != 0)
43 {
44 if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
45 {
46 ALOGE("Mismatched dimensions (request argument: %zu, expected: %u)",
47 requestArg.dimensions.size(), tensorInfo.GetNumDimensions());
48 return false;
49 }
50
51 for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
52 {
Finn Williamsa4983ce2020-07-23 12:55:12 +010053 if (requestArg.dimensions[d] != 0 && requestArg.dimensions[d] != tensorInfo.GetShape()[d])
telsoa015307bc12018-03-09 13:51:08 +000054 {
55 ALOGE("Mismatched size for dimension %d (request argument: %u, expected %u)",
56 d, requestArg.dimensions[d], tensorInfo.GetShape()[d]);
57 return false;
58 }
59 }
60 }
61
62 return true;
63}
64
Sadik Armagan188675f2021-02-12 17:16:42 +000065armnn::Tensor GetTensorForRequestArgument(const V1_0::RequestArgument& requestArg,
telsoa015307bc12018-03-09 13:51:08 +000066 const armnn::TensorInfo& tensorInfo,
67 const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
68{
69 if (!ValidateRequestArgument(requestArg, tensorInfo))
70 {
71 return armnn::Tensor();
72 }
73
74 return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
75}
76
77inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
78{
79 return tensorNamePrefix + std::to_string(index);
80}
81
Matteo Martincighe48bdff2018-09-03 13:50:50 +010082} // anonymous namespace
telsoa015307bc12018-03-09 13:51:08 +000083
telsoa01ce3e84a2018-08-31 09:31:35 +010084using namespace android::hardware;
85
telsoa015307bc12018-03-09 13:51:08 +000086namespace armnn_driver
87{
Matteo Martincighe48bdff2018-09-03 13:50:50 +010088template<typename HalVersion>
Derek Lamberti4de83c52020-03-17 13:40:18 +000089RequestThread<ArmnnPreparedModel, HalVersion, CallbackContext_1_0>
90 ArmnnPreparedModel<HalVersion>::m_RequestThread;
telsoa015307bc12018-03-09 13:51:08 +000091
Matteo Martincighe48bdff2018-09-03 13:50:50 +010092template<typename HalVersion>
telsoa015307bc12018-03-09 13:51:08 +000093template <typename TensorBindingCollection>
Matteo Martincighe48bdff2018-09-03 13:50:50 +010094void ArmnnPreparedModel<HalVersion>::DumpTensorsIfRequired(char const* tensorNamePrefix,
95 const TensorBindingCollection& tensorBindings)
telsoa015307bc12018-03-09 13:51:08 +000096{
97 if (!m_RequestInputsAndOutputsDumpDir.empty())
98 {
Colm Donelan08d9a1c2020-09-09 17:56:55 +010099 const std::string requestName = std::to_string(m_NetworkId) + "_" + std::to_string(m_RequestCount) + ".dump";
telsoa015307bc12018-03-09 13:51:08 +0000100 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
101 {
102 DumpTensor(m_RequestInputsAndOutputsDumpDir,
103 requestName,
104 BuildTensorName(tensorNamePrefix, i),
105 tensorBindings[i].second);
106 }
107 }
108}
109
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100110template<typename HalVersion>
111ArmnnPreparedModel<HalVersion>::ArmnnPreparedModel(armnn::NetworkId networkId,
112 armnn::IRuntime* runtime,
113 const HalModel& model,
114 const std::string& requestInputsAndOutputsDumpDir,
115 const bool gpuProfilingEnabled)
telsoa01ce3e84a2018-08-31 09:31:35 +0100116 : m_NetworkId(networkId)
117 , m_Runtime(runtime)
118 , m_Model(model)
119 , m_RequestCount(0)
120 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
121 , m_GpuProfilingEnabled(gpuProfilingEnabled)
telsoa015307bc12018-03-09 13:51:08 +0000122{
telsoa01ce3e84a2018-08-31 09:31:35 +0100123 // Enable profiling if required.
124 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
telsoa015307bc12018-03-09 13:51:08 +0000125}
126
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100127template<typename HalVersion>
128ArmnnPreparedModel<HalVersion>::~ArmnnPreparedModel()
telsoa015307bc12018-03-09 13:51:08 +0000129{
telsoa01ce3e84a2018-08-31 09:31:35 +0100130 // Get a hold of the profiler used by this model.
131 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
132
133 // Unload the network associated with this model.
telsoa015307bc12018-03-09 13:51:08 +0000134 m_Runtime->UnloadNetwork(m_NetworkId);
telsoa01ce3e84a2018-08-31 09:31:35 +0100135
136 // Dump the profiling info to a file if required.
137 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId, profiler.get());
telsoa015307bc12018-03-09 13:51:08 +0000138}
139
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100140template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000141Return<V1_0::ErrorStatus> ArmnnPreparedModel<HalVersion>::execute(
142 const V1_0::Request& request,
143 const ::android::sp<V1_0::IExecutionCallback>& callback)
telsoa015307bc12018-03-09 13:51:08 +0000144{
145 ALOGV("ArmnnPreparedModel::execute(): %s", GetModelSummary(m_Model).c_str());
146 m_RequestCount++;
147
148 if (callback.get() == nullptr) {
149 ALOGE("ArmnnPreparedModel::execute invalid callback passed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000150 return V1_0::ErrorStatus::INVALID_ARGUMENT;
telsoa015307bc12018-03-09 13:51:08 +0000151 }
152
153 if (!android::nn::validateRequest(request, m_Model))
154 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000155 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::INVALID_ARGUMENT, "ArmnnPreparedModel::execute");
156 return V1_0::ErrorStatus::INVALID_ARGUMENT;
telsoa015307bc12018-03-09 13:51:08 +0000157 }
158
159 if (!m_RequestInputsAndOutputsDumpDir.empty())
160 {
161 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(callback.get()));
162 }
163
164 // allocate the tensors on the heap, as they are passed to the request thread
165 auto pInputTensors = std::make_shared<armnn::InputTensors>();
166 auto pOutputTensors = std::make_shared<armnn::OutputTensors>();
167
168 // map the memory pool into shared pointers
169 // use a shared memory pools vector on the heap, as it is passed to the request thread
170 auto pMemPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
Sadik Armagan188675f2021-02-12 17:16:42 +0000171#if !defined(ARMNN_ANDROID_S)
telsoa015307bc12018-03-09 13:51:08 +0000172 if (!setRunTimePoolInfosFromHidlMemories(pMemPools.get(), request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000173#else
174 if (!setRunTimePoolInfosFromCanonicalMemories(pMemPools.get(), uncheckedConvert(request.pools)))
175#endif
telsoa015307bc12018-03-09 13:51:08 +0000176 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000177 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
178 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000179 }
telsoa015307bc12018-03-09 13:51:08 +0000180 // add the inputs and outputs with their data
181 try
182 {
183 pInputTensors->reserve(request.inputs.size());
184 for (unsigned int i = 0; i < request.inputs.size(); i++)
185 {
186 const auto& inputArg = request.inputs[i];
187
188 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
189 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, *pMemPools);
190 if (inputTensor.GetMemoryArea() == nullptr)
191 {
192 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
Kevin Mayec1e5b82020-02-26 17:00:39 +0000193 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000194 }
195
196 pInputTensors->emplace_back(i, inputTensor);
197 }
198
199 pOutputTensors->reserve(request.outputs.size());
200 for (unsigned int i = 0; i < request.outputs.size(); i++)
201 {
202 const auto& outputArg = request.outputs[i];
203
204 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
205 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, *pMemPools);
206 if (outputTensor.GetMemoryArea() == nullptr)
207 {
208 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
Kevin Mayec1e5b82020-02-26 17:00:39 +0000209 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000210 }
211
212 pOutputTensors->emplace_back(i, outputTensor);
213 }
214 }
Kevin May7bdaac52020-02-10 12:10:07 +0000215 catch (armnn::Exception& e)
216 {
217 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000218 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
219 return V1_0::ErrorStatus::GENERAL_FAILURE;
Kevin May7bdaac52020-02-10 12:10:07 +0000220 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000221 catch (std::exception& e)
telsoa015307bc12018-03-09 13:51:08 +0000222 {
Kevin May7bdaac52020-02-10 12:10:07 +0000223 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000224 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
225 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000226 }
227
228 ALOGV("ArmnnPreparedModel::execute(...) before PostMsg");
telsoa015307bc12018-03-09 13:51:08 +0000229
Kevin Mayec1e5b82020-02-26 17:00:39 +0000230 auto cb = [callback](V1_0::ErrorStatus errorStatus, std::string callingFunction)
Mike Kelly65c42dc2019-07-22 14:06:00 +0100231 {
232 NotifyCallbackAndCheck(callback, errorStatus, callingFunction);
233 };
234
Derek Lamberti4de83c52020-03-17 13:40:18 +0000235 CallbackContext_1_0 armnnCb;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100236 armnnCb.callback = cb;
237 // post the request for asynchronous execution
238 m_RequestThread.PostMsg(this, pMemPools, pInputTensors, pOutputTensors, armnnCb);
239 ALOGV("ArmnnPreparedModel::execute(...) after PostMsg");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000240 return V1_0::ErrorStatus::NONE; // successfully queued
telsoa015307bc12018-03-09 13:51:08 +0000241}
242
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100243template<typename HalVersion>
244void ArmnnPreparedModel<HalVersion>::ExecuteGraph(
245 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000246 armnn::InputTensors& inputTensors,
247 armnn::OutputTensors& outputTensors,
248 CallbackContext_1_0 cb)
telsoa015307bc12018-03-09 13:51:08 +0000249{
250 ALOGV("ArmnnPreparedModel::ExecuteGraph(...)");
251
Derek Lamberti4de83c52020-03-17 13:40:18 +0000252 DumpTensorsIfRequired("Input", inputTensors);
telsoa015307bc12018-03-09 13:51:08 +0000253
254 // run it
255 try
256 {
Derek Lamberti4de83c52020-03-17 13:40:18 +0000257 armnn::Status status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
Matthew Bentham16196e22019-04-01 17:17:58 +0100258 if (status != armnn::Status::Success)
259 {
260 ALOGW("EnqueueWorkload failed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000261 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::ExecuteGraph");
Matthew Bentham16196e22019-04-01 17:17:58 +0100262 return;
263 }
telsoa015307bc12018-03-09 13:51:08 +0000264 }
Kevin May7bdaac52020-02-10 12:10:07 +0000265 catch (armnn::Exception& e)
266 {
267 ALOGW("armnn::Exception caught from EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000268 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::ExecuteGraph");
Kevin May7bdaac52020-02-10 12:10:07 +0000269 return;
270 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000271 catch (std::exception& e)
telsoa015307bc12018-03-09 13:51:08 +0000272 {
Kevin May7bdaac52020-02-10 12:10:07 +0000273 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000274 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::ExecuteGraph");
telsoa015307bc12018-03-09 13:51:08 +0000275 return;
276 }
277
Derek Lamberti4de83c52020-03-17 13:40:18 +0000278 DumpTensorsIfRequired("Output", outputTensors);
telsoa015307bc12018-03-09 13:51:08 +0000279
280 // Commit output buffers.
281 // Note that we update *all* pools, even if they aren't actually used as outputs -
282 // this is simpler and is what the CpuExecutor does.
283 for (android::nn::RunTimePoolInfo& pool : *pMemPools)
284 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000285 // Type android::nn::RunTimePoolInfo has changed between Android P & Q and Android R, where
286 // update() has been removed and flush() added.
Sadik Armagan188675f2021-02-12 17:16:42 +0000287 #if defined(ARMNN_ANDROID_R) || defined(ARMNN_ANDROID_S) // Use the new Android implementation.
Kevin Mayec1e5b82020-02-26 17:00:39 +0000288 pool.flush();
289 #else
290 pool.update();
291 #endif
telsoa015307bc12018-03-09 13:51:08 +0000292 }
293
Kevin Mayec1e5b82020-02-26 17:00:39 +0000294 cb.callback(V1_0::ErrorStatus::NONE, "ExecuteGraph");
telsoa015307bc12018-03-09 13:51:08 +0000295}
296
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100297template<typename HalVersion>
Matthew Bentham16196e22019-04-01 17:17:58 +0100298bool ArmnnPreparedModel<HalVersion>::ExecuteWithDummyInputs()
telsoa015307bc12018-03-09 13:51:08 +0000299{
300 std::vector<std::vector<char>> storage;
301 armnn::InputTensors inputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000302 for (unsigned int i = 0; i < getMainModel(m_Model).inputIndexes.size(); i++)
telsoa015307bc12018-03-09 13:51:08 +0000303 {
304 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
305 storage.emplace_back(inputTensorInfo.GetNumBytes());
306 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
307
308 inputTensors.emplace_back(i, inputTensor);
309 }
310
311 armnn::OutputTensors outputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000312 for (unsigned int i = 0; i < getMainModel(m_Model).outputIndexes.size(); i++)
telsoa015307bc12018-03-09 13:51:08 +0000313 {
314 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
315 storage.emplace_back(outputTensorInfo.GetNumBytes());
316 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
317
318 outputTensors.emplace_back(i, outputTensor);
319 }
320
321 try
322 {
Matthew Bentham16196e22019-04-01 17:17:58 +0100323 armnn::Status status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
324 if (status != armnn::Status::Success)
325 {
326 ALOGW("ExecuteWithDummyInputs: EnqueueWorkload failed");
327 return false;
328 }
telsoa015307bc12018-03-09 13:51:08 +0000329 }
Kevin May7bdaac52020-02-10 12:10:07 +0000330 catch (armnn::Exception& e)
331 {
332 ALOGW("ExecuteWithDummyInputs: armnn::Exception caught from EnqueueWorkload: %s", e.what());
333 return false;
334 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000335 catch (std::exception& e)
telsoa015307bc12018-03-09 13:51:08 +0000336 {
Kevin May7bdaac52020-02-10 12:10:07 +0000337 ALOGE("ExecuteWithDummyInputs: std::exception caught from EnqueueWorkload: %s", e.what());
Matthew Bentham16196e22019-04-01 17:17:58 +0100338 return false;
telsoa015307bc12018-03-09 13:51:08 +0000339 }
Matthew Bentham16196e22019-04-01 17:17:58 +0100340 return true;
telsoa015307bc12018-03-09 13:51:08 +0000341}
342
arovir01b0717b52018-09-05 17:03:25 +0100343///
344/// Class template specializations
345///
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100346
arovir01b0717b52018-09-05 17:03:25 +0100347template class ArmnnPreparedModel<hal_1_0::HalPolicy>;
348
Matteo Martincigh8b287c22018-09-07 09:25:10 +0100349#ifdef ARMNN_ANDROID_NN_V1_1
arovir01b0717b52018-09-05 17:03:25 +0100350template class ArmnnPreparedModel<hal_1_1::HalPolicy>;
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100351#endif
352
Mike Kellyb5fdf382019-06-11 16:35:25 +0100353#ifdef ARMNN_ANDROID_NN_V1_2
354template class ArmnnPreparedModel<hal_1_1::HalPolicy>;
355template class ArmnnPreparedModel<hal_1_2::HalPolicy>;
356#endif
Kevin May42477c12020-03-26 13:34:14 +0000357
358#ifdef ARMNN_ANDROID_NN_V1_3
359template class ArmnnPreparedModel<hal_1_1::HalPolicy>;
360template class ArmnnPreparedModel<hal_1_2::HalPolicy>;
361template class ArmnnPreparedModel<hal_1_3::HalPolicy>;
362#endif
Nikhil Raj77605822018-09-03 11:25:56 +0100363} // namespace armnn_driver