blob: 8aa28d7e5c63baace109d0537d83a31e369cccdd [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
11#include <boost/format.hpp>
12#include <log/log.h>
13#include <OperationsUtils.h>
surmeh01deb3bdb2018-07-05 12:06:04 +010014#include <ValidateHal.h>
Kevin Mayec1e5b82020-02-26 17:00:39 +000015
surmeh01deb3bdb2018-07-05 12:06:04 +010016
telsoa015307bc12018-03-09 13:51:08 +000017#include <cassert>
18#include <cinttypes>
19
20using namespace android;
21
22namespace
23{
24using namespace armnn_driver;
25
Kevin Mayec1e5b82020-02-26 17:00:39 +000026void NotifyCallbackAndCheck(const ::android::sp<V1_0::IExecutionCallback>& callback, V1_0::ErrorStatus errorStatus,
telsoa015307bc12018-03-09 13:51:08 +000027 std::string callingFunction)
28{
29 Return<void> returned = callback->notify(errorStatus);
30 // This check is required, if the callback fails and it isn't checked it will bring down the service
31 if (!returned.isOk())
32 {
33 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
34 callingFunction.c_str(), returned.description().c_str());
35 }
36}
37
38bool ValidateRequestArgument(const RequestArgument& requestArg, const armnn::TensorInfo& tensorInfo)
39{
40 if (requestArg.dimensions.size() != 0)
41 {
42 if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
43 {
44 ALOGE("Mismatched dimensions (request argument: %zu, expected: %u)",
45 requestArg.dimensions.size(), tensorInfo.GetNumDimensions());
46 return false;
47 }
48
49 for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
50 {
Finn Williamsa4983ce2020-07-23 12:55:12 +010051 if (requestArg.dimensions[d] != 0 && requestArg.dimensions[d] != tensorInfo.GetShape()[d])
telsoa015307bc12018-03-09 13:51:08 +000052 {
53 ALOGE("Mismatched size for dimension %d (request argument: %u, expected %u)",
54 d, requestArg.dimensions[d], tensorInfo.GetShape()[d]);
55 return false;
56 }
57 }
58 }
59
60 return true;
61}
62
63armnn::Tensor GetTensorForRequestArgument(const RequestArgument& requestArg,
64 const armnn::TensorInfo& tensorInfo,
65 const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
66{
67 if (!ValidateRequestArgument(requestArg, tensorInfo))
68 {
69 return armnn::Tensor();
70 }
71
72 return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
73}
74
75inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
76{
77 return tensorNamePrefix + std::to_string(index);
78}
79
Matteo Martincighe48bdff2018-09-03 13:50:50 +010080} // anonymous namespace
telsoa015307bc12018-03-09 13:51:08 +000081
telsoa01ce3e84a2018-08-31 09:31:35 +010082using namespace android::hardware;
83
telsoa015307bc12018-03-09 13:51:08 +000084namespace armnn_driver
85{
Matteo Martincighe48bdff2018-09-03 13:50:50 +010086template<typename HalVersion>
Derek Lamberti4de83c52020-03-17 13:40:18 +000087RequestThread<ArmnnPreparedModel, HalVersion, CallbackContext_1_0>
88 ArmnnPreparedModel<HalVersion>::m_RequestThread;
telsoa015307bc12018-03-09 13:51:08 +000089
Matteo Martincighe48bdff2018-09-03 13:50:50 +010090template<typename HalVersion>
telsoa015307bc12018-03-09 13:51:08 +000091template <typename TensorBindingCollection>
Matteo Martincighe48bdff2018-09-03 13:50:50 +010092void ArmnnPreparedModel<HalVersion>::DumpTensorsIfRequired(char const* tensorNamePrefix,
93 const TensorBindingCollection& tensorBindings)
telsoa015307bc12018-03-09 13:51:08 +000094{
95 if (!m_RequestInputsAndOutputsDumpDir.empty())
96 {
97 const std::string requestName = boost::str(boost::format("%1%_%2%.dump") % m_NetworkId % m_RequestCount);
98 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
99 {
100 DumpTensor(m_RequestInputsAndOutputsDumpDir,
101 requestName,
102 BuildTensorName(tensorNamePrefix, i),
103 tensorBindings[i].second);
104 }
105 }
106}
107
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100108template<typename HalVersion>
109ArmnnPreparedModel<HalVersion>::ArmnnPreparedModel(armnn::NetworkId networkId,
110 armnn::IRuntime* runtime,
111 const HalModel& model,
112 const std::string& requestInputsAndOutputsDumpDir,
113 const bool gpuProfilingEnabled)
telsoa01ce3e84a2018-08-31 09:31:35 +0100114 : m_NetworkId(networkId)
115 , m_Runtime(runtime)
116 , m_Model(model)
117 , m_RequestCount(0)
118 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
119 , m_GpuProfilingEnabled(gpuProfilingEnabled)
telsoa015307bc12018-03-09 13:51:08 +0000120{
telsoa01ce3e84a2018-08-31 09:31:35 +0100121 // Enable profiling if required.
122 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
telsoa015307bc12018-03-09 13:51:08 +0000123}
124
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100125template<typename HalVersion>
126ArmnnPreparedModel<HalVersion>::~ArmnnPreparedModel()
telsoa015307bc12018-03-09 13:51:08 +0000127{
telsoa01ce3e84a2018-08-31 09:31:35 +0100128 // Get a hold of the profiler used by this model.
129 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
130
131 // Unload the network associated with this model.
telsoa015307bc12018-03-09 13:51:08 +0000132 m_Runtime->UnloadNetwork(m_NetworkId);
telsoa01ce3e84a2018-08-31 09:31:35 +0100133
134 // Dump the profiling info to a file if required.
135 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId, profiler.get());
telsoa015307bc12018-03-09 13:51:08 +0000136}
137
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100138template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000139Return<V1_0::ErrorStatus> ArmnnPreparedModel<HalVersion>::execute(
140 const V1_0::Request& request,
141 const ::android::sp<V1_0::IExecutionCallback>& callback)
telsoa015307bc12018-03-09 13:51:08 +0000142{
143 ALOGV("ArmnnPreparedModel::execute(): %s", GetModelSummary(m_Model).c_str());
144 m_RequestCount++;
145
146 if (callback.get() == nullptr) {
147 ALOGE("ArmnnPreparedModel::execute invalid callback passed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000148 return V1_0::ErrorStatus::INVALID_ARGUMENT;
telsoa015307bc12018-03-09 13:51:08 +0000149 }
150
151 if (!android::nn::validateRequest(request, m_Model))
152 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000153 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::INVALID_ARGUMENT, "ArmnnPreparedModel::execute");
154 return V1_0::ErrorStatus::INVALID_ARGUMENT;
telsoa015307bc12018-03-09 13:51:08 +0000155 }
156
157 if (!m_RequestInputsAndOutputsDumpDir.empty())
158 {
159 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(callback.get()));
160 }
161
162 // allocate the tensors on the heap, as they are passed to the request thread
163 auto pInputTensors = std::make_shared<armnn::InputTensors>();
164 auto pOutputTensors = std::make_shared<armnn::OutputTensors>();
165
166 // map the memory pool into shared pointers
167 // use a shared memory pools vector on the heap, as it is passed to the request thread
168 auto pMemPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
169 if (!setRunTimePoolInfosFromHidlMemories(pMemPools.get(), request.pools))
170 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000171 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
172 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000173 }
174
175 // add the inputs and outputs with their data
176 try
177 {
178 pInputTensors->reserve(request.inputs.size());
179 for (unsigned int i = 0; i < request.inputs.size(); i++)
180 {
181 const auto& inputArg = request.inputs[i];
182
183 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
184 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, *pMemPools);
185 if (inputTensor.GetMemoryArea() == nullptr)
186 {
187 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
Kevin Mayec1e5b82020-02-26 17:00:39 +0000188 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000189 }
190
191 pInputTensors->emplace_back(i, inputTensor);
192 }
193
194 pOutputTensors->reserve(request.outputs.size());
195 for (unsigned int i = 0; i < request.outputs.size(); i++)
196 {
197 const auto& outputArg = request.outputs[i];
198
199 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
200 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, *pMemPools);
201 if (outputTensor.GetMemoryArea() == nullptr)
202 {
203 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
Kevin Mayec1e5b82020-02-26 17:00:39 +0000204 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000205 }
206
207 pOutputTensors->emplace_back(i, outputTensor);
208 }
209 }
Kevin May7bdaac52020-02-10 12:10:07 +0000210 catch (armnn::Exception& e)
211 {
212 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000213 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
214 return V1_0::ErrorStatus::GENERAL_FAILURE;
Kevin May7bdaac52020-02-10 12:10:07 +0000215 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000216 catch (std::exception& e)
telsoa015307bc12018-03-09 13:51:08 +0000217 {
Kevin May7bdaac52020-02-10 12:10:07 +0000218 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000219 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
220 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000221 }
222
223 ALOGV("ArmnnPreparedModel::execute(...) before PostMsg");
telsoa015307bc12018-03-09 13:51:08 +0000224
Kevin Mayec1e5b82020-02-26 17:00:39 +0000225 auto cb = [callback](V1_0::ErrorStatus errorStatus, std::string callingFunction)
Mike Kelly65c42dc2019-07-22 14:06:00 +0100226 {
227 NotifyCallbackAndCheck(callback, errorStatus, callingFunction);
228 };
229
Derek Lamberti4de83c52020-03-17 13:40:18 +0000230 CallbackContext_1_0 armnnCb;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100231 armnnCb.callback = cb;
232 // post the request for asynchronous execution
233 m_RequestThread.PostMsg(this, pMemPools, pInputTensors, pOutputTensors, armnnCb);
234 ALOGV("ArmnnPreparedModel::execute(...) after PostMsg");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000235 return V1_0::ErrorStatus::NONE; // successfully queued
telsoa015307bc12018-03-09 13:51:08 +0000236}
237
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100238template<typename HalVersion>
239void ArmnnPreparedModel<HalVersion>::ExecuteGraph(
240 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000241 armnn::InputTensors& inputTensors,
242 armnn::OutputTensors& outputTensors,
243 CallbackContext_1_0 cb)
telsoa015307bc12018-03-09 13:51:08 +0000244{
245 ALOGV("ArmnnPreparedModel::ExecuteGraph(...)");
246
Derek Lamberti4de83c52020-03-17 13:40:18 +0000247 DumpTensorsIfRequired("Input", inputTensors);
telsoa015307bc12018-03-09 13:51:08 +0000248
249 // run it
250 try
251 {
Derek Lamberti4de83c52020-03-17 13:40:18 +0000252 armnn::Status status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
Matthew Bentham16196e22019-04-01 17:17:58 +0100253 if (status != armnn::Status::Success)
254 {
255 ALOGW("EnqueueWorkload failed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000256 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::ExecuteGraph");
Matthew Bentham16196e22019-04-01 17:17:58 +0100257 return;
258 }
telsoa015307bc12018-03-09 13:51:08 +0000259 }
Kevin May7bdaac52020-02-10 12:10:07 +0000260 catch (armnn::Exception& e)
261 {
262 ALOGW("armnn::Exception caught from EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000263 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::ExecuteGraph");
Kevin May7bdaac52020-02-10 12:10:07 +0000264 return;
265 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000266 catch (std::exception& e)
telsoa015307bc12018-03-09 13:51:08 +0000267 {
Kevin May7bdaac52020-02-10 12:10:07 +0000268 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000269 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::ExecuteGraph");
telsoa015307bc12018-03-09 13:51:08 +0000270 return;
271 }
272
Derek Lamberti4de83c52020-03-17 13:40:18 +0000273 DumpTensorsIfRequired("Output", outputTensors);
telsoa015307bc12018-03-09 13:51:08 +0000274
275 // Commit output buffers.
276 // Note that we update *all* pools, even if they aren't actually used as outputs -
277 // this is simpler and is what the CpuExecutor does.
278 for (android::nn::RunTimePoolInfo& pool : *pMemPools)
279 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000280 // Type android::nn::RunTimePoolInfo has changed between Android P & Q and Android R, where
281 // update() has been removed and flush() added.
282 #if defined(ARMNN_ANDROID_R) // Use the new Android implementation.
283 pool.flush();
284 #else
285 pool.update();
286 #endif
telsoa015307bc12018-03-09 13:51:08 +0000287 }
288
Kevin Mayec1e5b82020-02-26 17:00:39 +0000289 cb.callback(V1_0::ErrorStatus::NONE, "ExecuteGraph");
telsoa015307bc12018-03-09 13:51:08 +0000290}
291
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100292template<typename HalVersion>
Matthew Bentham16196e22019-04-01 17:17:58 +0100293bool ArmnnPreparedModel<HalVersion>::ExecuteWithDummyInputs()
telsoa015307bc12018-03-09 13:51:08 +0000294{
295 std::vector<std::vector<char>> storage;
296 armnn::InputTensors inputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000297 for (unsigned int i = 0; i < getMainModel(m_Model).inputIndexes.size(); i++)
telsoa015307bc12018-03-09 13:51:08 +0000298 {
299 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
300 storage.emplace_back(inputTensorInfo.GetNumBytes());
301 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
302
303 inputTensors.emplace_back(i, inputTensor);
304 }
305
306 armnn::OutputTensors outputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000307 for (unsigned int i = 0; i < getMainModel(m_Model).outputIndexes.size(); i++)
telsoa015307bc12018-03-09 13:51:08 +0000308 {
309 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
310 storage.emplace_back(outputTensorInfo.GetNumBytes());
311 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
312
313 outputTensors.emplace_back(i, outputTensor);
314 }
315
316 try
317 {
Matthew Bentham16196e22019-04-01 17:17:58 +0100318 armnn::Status status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
319 if (status != armnn::Status::Success)
320 {
321 ALOGW("ExecuteWithDummyInputs: EnqueueWorkload failed");
322 return false;
323 }
telsoa015307bc12018-03-09 13:51:08 +0000324 }
Kevin May7bdaac52020-02-10 12:10:07 +0000325 catch (armnn::Exception& e)
326 {
327 ALOGW("ExecuteWithDummyInputs: armnn::Exception caught from EnqueueWorkload: %s", e.what());
328 return false;
329 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000330 catch (std::exception& e)
telsoa015307bc12018-03-09 13:51:08 +0000331 {
Kevin May7bdaac52020-02-10 12:10:07 +0000332 ALOGE("ExecuteWithDummyInputs: std::exception caught from EnqueueWorkload: %s", e.what());
Matthew Bentham16196e22019-04-01 17:17:58 +0100333 return false;
telsoa015307bc12018-03-09 13:51:08 +0000334 }
Matthew Bentham16196e22019-04-01 17:17:58 +0100335 return true;
telsoa015307bc12018-03-09 13:51:08 +0000336}
337
arovir01b0717b52018-09-05 17:03:25 +0100338///
339/// Class template specializations
340///
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100341
arovir01b0717b52018-09-05 17:03:25 +0100342template class ArmnnPreparedModel<hal_1_0::HalPolicy>;
343
Matteo Martincigh8b287c22018-09-07 09:25:10 +0100344#ifdef ARMNN_ANDROID_NN_V1_1
arovir01b0717b52018-09-05 17:03:25 +0100345template class ArmnnPreparedModel<hal_1_1::HalPolicy>;
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100346#endif
347
Mike Kellyb5fdf382019-06-11 16:35:25 +0100348#ifdef ARMNN_ANDROID_NN_V1_2
349template class ArmnnPreparedModel<hal_1_1::HalPolicy>;
350template class ArmnnPreparedModel<hal_1_2::HalPolicy>;
351#endif
Kevin May42477c12020-03-26 13:34:14 +0000352
353#ifdef ARMNN_ANDROID_NN_V1_3
354template class ArmnnPreparedModel<hal_1_1::HalPolicy>;
355template class ArmnnPreparedModel<hal_1_2::HalPolicy>;
356template class ArmnnPreparedModel<hal_1_3::HalPolicy>;
357#endif
Nikhil Raj77605822018-09-03 11:25:56 +0100358} // namespace armnn_driver