blob: c6b6b71c6b63048a9d04057da66e57066c081118 [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
18using namespace android;
19
20namespace
21{
22using namespace armnn_driver;
23
Kevin Mayec1e5b82020-02-26 17:00:39 +000024void NotifyCallbackAndCheck(const ::android::sp<V1_0::IExecutionCallback>& callback, V1_0::ErrorStatus errorStatus,
telsoa015307bc12018-03-09 13:51:08 +000025 std::string callingFunction)
26{
27 Return<void> returned = callback->notify(errorStatus);
28 // This check is required, if the callback fails and it isn't checked it will bring down the service
29 if (!returned.isOk())
30 {
31 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
32 callingFunction.c_str(), returned.description().c_str());
33 }
34}
35
36bool ValidateRequestArgument(const RequestArgument& requestArg, const armnn::TensorInfo& tensorInfo)
37{
38 if (requestArg.dimensions.size() != 0)
39 {
40 if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
41 {
42 ALOGE("Mismatched dimensions (request argument: %zu, expected: %u)",
43 requestArg.dimensions.size(), tensorInfo.GetNumDimensions());
44 return false;
45 }
46
47 for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
48 {
Finn Williamsa4983ce2020-07-23 12:55:12 +010049 if (requestArg.dimensions[d] != 0 && requestArg.dimensions[d] != tensorInfo.GetShape()[d])
telsoa015307bc12018-03-09 13:51:08 +000050 {
51 ALOGE("Mismatched size for dimension %d (request argument: %u, expected %u)",
52 d, requestArg.dimensions[d], tensorInfo.GetShape()[d]);
53 return false;
54 }
55 }
56 }
57
58 return true;
59}
60
61armnn::Tensor GetTensorForRequestArgument(const RequestArgument& requestArg,
62 const armnn::TensorInfo& tensorInfo,
63 const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
64{
65 if (!ValidateRequestArgument(requestArg, tensorInfo))
66 {
67 return armnn::Tensor();
68 }
69
70 return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
71}
72
73inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
74{
75 return tensorNamePrefix + std::to_string(index);
76}
77
Matteo Martincighe48bdff2018-09-03 13:50:50 +010078} // anonymous namespace
telsoa015307bc12018-03-09 13:51:08 +000079
telsoa01ce3e84a2018-08-31 09:31:35 +010080using namespace android::hardware;
81
telsoa015307bc12018-03-09 13:51:08 +000082namespace armnn_driver
83{
Matteo Martincighe48bdff2018-09-03 13:50:50 +010084template<typename HalVersion>
Derek Lamberti4de83c52020-03-17 13:40:18 +000085RequestThread<ArmnnPreparedModel, HalVersion, CallbackContext_1_0>
86 ArmnnPreparedModel<HalVersion>::m_RequestThread;
telsoa015307bc12018-03-09 13:51:08 +000087
Matteo Martincighe48bdff2018-09-03 13:50:50 +010088template<typename HalVersion>
telsoa015307bc12018-03-09 13:51:08 +000089template <typename TensorBindingCollection>
Matteo Martincighe48bdff2018-09-03 13:50:50 +010090void ArmnnPreparedModel<HalVersion>::DumpTensorsIfRequired(char const* tensorNamePrefix,
91 const TensorBindingCollection& tensorBindings)
telsoa015307bc12018-03-09 13:51:08 +000092{
93 if (!m_RequestInputsAndOutputsDumpDir.empty())
94 {
Colm Donelan08d9a1c2020-09-09 17:56:55 +010095 const std::string requestName = std::to_string(m_NetworkId) + "_" + std::to_string(m_RequestCount) + ".dump";
telsoa015307bc12018-03-09 13:51:08 +000096 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
97 {
98 DumpTensor(m_RequestInputsAndOutputsDumpDir,
99 requestName,
100 BuildTensorName(tensorNamePrefix, i),
101 tensorBindings[i].second);
102 }
103 }
104}
105
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100106template<typename HalVersion>
107ArmnnPreparedModel<HalVersion>::ArmnnPreparedModel(armnn::NetworkId networkId,
108 armnn::IRuntime* runtime,
109 const HalModel& model,
110 const std::string& requestInputsAndOutputsDumpDir,
111 const bool gpuProfilingEnabled)
telsoa01ce3e84a2018-08-31 09:31:35 +0100112 : m_NetworkId(networkId)
113 , m_Runtime(runtime)
114 , m_Model(model)
115 , m_RequestCount(0)
116 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
117 , m_GpuProfilingEnabled(gpuProfilingEnabled)
telsoa015307bc12018-03-09 13:51:08 +0000118{
telsoa01ce3e84a2018-08-31 09:31:35 +0100119 // Enable profiling if required.
120 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
telsoa015307bc12018-03-09 13:51:08 +0000121}
122
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100123template<typename HalVersion>
124ArmnnPreparedModel<HalVersion>::~ArmnnPreparedModel()
telsoa015307bc12018-03-09 13:51:08 +0000125{
telsoa01ce3e84a2018-08-31 09:31:35 +0100126 // Get a hold of the profiler used by this model.
127 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
128
129 // Unload the network associated with this model.
telsoa015307bc12018-03-09 13:51:08 +0000130 m_Runtime->UnloadNetwork(m_NetworkId);
telsoa01ce3e84a2018-08-31 09:31:35 +0100131
132 // Dump the profiling info to a file if required.
133 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId, profiler.get());
telsoa015307bc12018-03-09 13:51:08 +0000134}
135
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100136template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000137Return<V1_0::ErrorStatus> ArmnnPreparedModel<HalVersion>::execute(
138 const V1_0::Request& request,
139 const ::android::sp<V1_0::IExecutionCallback>& callback)
telsoa015307bc12018-03-09 13:51:08 +0000140{
141 ALOGV("ArmnnPreparedModel::execute(): %s", GetModelSummary(m_Model).c_str());
142 m_RequestCount++;
143
144 if (callback.get() == nullptr) {
145 ALOGE("ArmnnPreparedModel::execute invalid callback passed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000146 return V1_0::ErrorStatus::INVALID_ARGUMENT;
telsoa015307bc12018-03-09 13:51:08 +0000147 }
148
149 if (!android::nn::validateRequest(request, m_Model))
150 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000151 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::INVALID_ARGUMENT, "ArmnnPreparedModel::execute");
152 return V1_0::ErrorStatus::INVALID_ARGUMENT;
telsoa015307bc12018-03-09 13:51:08 +0000153 }
154
155 if (!m_RequestInputsAndOutputsDumpDir.empty())
156 {
157 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(callback.get()));
158 }
159
160 // allocate the tensors on the heap, as they are passed to the request thread
161 auto pInputTensors = std::make_shared<armnn::InputTensors>();
162 auto pOutputTensors = std::make_shared<armnn::OutputTensors>();
163
164 // map the memory pool into shared pointers
165 // use a shared memory pools vector on the heap, as it is passed to the request thread
166 auto pMemPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
167 if (!setRunTimePoolInfosFromHidlMemories(pMemPools.get(), request.pools))
168 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000169 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
170 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000171 }
172
173 // add the inputs and outputs with their data
174 try
175 {
176 pInputTensors->reserve(request.inputs.size());
177 for (unsigned int i = 0; i < request.inputs.size(); i++)
178 {
179 const auto& inputArg = request.inputs[i];
180
181 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
182 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, *pMemPools);
183 if (inputTensor.GetMemoryArea() == nullptr)
184 {
185 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
Kevin Mayec1e5b82020-02-26 17:00:39 +0000186 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000187 }
188
189 pInputTensors->emplace_back(i, inputTensor);
190 }
191
192 pOutputTensors->reserve(request.outputs.size());
193 for (unsigned int i = 0; i < request.outputs.size(); i++)
194 {
195 const auto& outputArg = request.outputs[i];
196
197 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
198 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, *pMemPools);
199 if (outputTensor.GetMemoryArea() == nullptr)
200 {
201 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
Kevin Mayec1e5b82020-02-26 17:00:39 +0000202 return V1_0::ErrorStatus::GENERAL_FAILURE;
telsoa015307bc12018-03-09 13:51:08 +0000203 }
204
205 pOutputTensors->emplace_back(i, outputTensor);
206 }
207 }
Kevin May7bdaac52020-02-10 12:10:07 +0000208 catch (armnn::Exception& e)
209 {
210 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000211 NotifyCallbackAndCheck(callback, V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::execute");
212 return V1_0::ErrorStatus::GENERAL_FAILURE;
Kevin May7bdaac52020-02-10 12:10:07 +0000213 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000214 catch (std::exception& e)
telsoa015307bc12018-03-09 13:51:08 +0000215 {
Kevin May7bdaac52020-02-10 12:10:07 +0000216 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
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 }
220
221 ALOGV("ArmnnPreparedModel::execute(...) before PostMsg");
telsoa015307bc12018-03-09 13:51:08 +0000222
Kevin Mayec1e5b82020-02-26 17:00:39 +0000223 auto cb = [callback](V1_0::ErrorStatus errorStatus, std::string callingFunction)
Mike Kelly65c42dc2019-07-22 14:06:00 +0100224 {
225 NotifyCallbackAndCheck(callback, errorStatus, callingFunction);
226 };
227
Derek Lamberti4de83c52020-03-17 13:40:18 +0000228 CallbackContext_1_0 armnnCb;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100229 armnnCb.callback = cb;
230 // post the request for asynchronous execution
231 m_RequestThread.PostMsg(this, pMemPools, pInputTensors, pOutputTensors, armnnCb);
232 ALOGV("ArmnnPreparedModel::execute(...) after PostMsg");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000233 return V1_0::ErrorStatus::NONE; // successfully queued
telsoa015307bc12018-03-09 13:51:08 +0000234}
235
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100236template<typename HalVersion>
237void ArmnnPreparedModel<HalVersion>::ExecuteGraph(
238 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000239 armnn::InputTensors& inputTensors,
240 armnn::OutputTensors& outputTensors,
241 CallbackContext_1_0 cb)
telsoa015307bc12018-03-09 13:51:08 +0000242{
243 ALOGV("ArmnnPreparedModel::ExecuteGraph(...)");
244
Derek Lamberti4de83c52020-03-17 13:40:18 +0000245 DumpTensorsIfRequired("Input", inputTensors);
telsoa015307bc12018-03-09 13:51:08 +0000246
247 // run it
248 try
249 {
Derek Lamberti4de83c52020-03-17 13:40:18 +0000250 armnn::Status status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
Matthew Bentham16196e22019-04-01 17:17:58 +0100251 if (status != armnn::Status::Success)
252 {
253 ALOGW("EnqueueWorkload failed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000254 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::ExecuteGraph");
Matthew Bentham16196e22019-04-01 17:17:58 +0100255 return;
256 }
telsoa015307bc12018-03-09 13:51:08 +0000257 }
Kevin May7bdaac52020-02-10 12:10:07 +0000258 catch (armnn::Exception& e)
259 {
260 ALOGW("armnn::Exception caught from EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000261 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::ExecuteGraph");
Kevin May7bdaac52020-02-10 12:10:07 +0000262 return;
263 }
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 from EnqueueWorkload: %s", e.what());
Kevin Mayec1e5b82020-02-26 17:00:39 +0000267 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, "ArmnnPreparedModel::ExecuteGraph");
telsoa015307bc12018-03-09 13:51:08 +0000268 return;
269 }
270
Derek Lamberti4de83c52020-03-17 13:40:18 +0000271 DumpTensorsIfRequired("Output", outputTensors);
telsoa015307bc12018-03-09 13:51:08 +0000272
273 // Commit output buffers.
274 // Note that we update *all* pools, even if they aren't actually used as outputs -
275 // this is simpler and is what the CpuExecutor does.
276 for (android::nn::RunTimePoolInfo& pool : *pMemPools)
277 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000278 // Type android::nn::RunTimePoolInfo has changed between Android P & Q and Android R, where
279 // update() has been removed and flush() added.
280 #if defined(ARMNN_ANDROID_R) // Use the new Android implementation.
281 pool.flush();
282 #else
283 pool.update();
284 #endif
telsoa015307bc12018-03-09 13:51:08 +0000285 }
286
Kevin Mayec1e5b82020-02-26 17:00:39 +0000287 cb.callback(V1_0::ErrorStatus::NONE, "ExecuteGraph");
telsoa015307bc12018-03-09 13:51:08 +0000288}
289
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100290template<typename HalVersion>
Matthew Bentham16196e22019-04-01 17:17:58 +0100291bool ArmnnPreparedModel<HalVersion>::ExecuteWithDummyInputs()
telsoa015307bc12018-03-09 13:51:08 +0000292{
293 std::vector<std::vector<char>> storage;
294 armnn::InputTensors inputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000295 for (unsigned int i = 0; i < getMainModel(m_Model).inputIndexes.size(); i++)
telsoa015307bc12018-03-09 13:51:08 +0000296 {
297 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
298 storage.emplace_back(inputTensorInfo.GetNumBytes());
299 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
300
301 inputTensors.emplace_back(i, inputTensor);
302 }
303
304 armnn::OutputTensors outputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000305 for (unsigned int i = 0; i < getMainModel(m_Model).outputIndexes.size(); i++)
telsoa015307bc12018-03-09 13:51:08 +0000306 {
307 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
308 storage.emplace_back(outputTensorInfo.GetNumBytes());
309 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
310
311 outputTensors.emplace_back(i, outputTensor);
312 }
313
314 try
315 {
Matthew Bentham16196e22019-04-01 17:17:58 +0100316 armnn::Status status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
317 if (status != armnn::Status::Success)
318 {
319 ALOGW("ExecuteWithDummyInputs: EnqueueWorkload failed");
320 return false;
321 }
telsoa015307bc12018-03-09 13:51:08 +0000322 }
Kevin May7bdaac52020-02-10 12:10:07 +0000323 catch (armnn::Exception& e)
324 {
325 ALOGW("ExecuteWithDummyInputs: armnn::Exception caught from EnqueueWorkload: %s", e.what());
326 return false;
327 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000328 catch (std::exception& e)
telsoa015307bc12018-03-09 13:51:08 +0000329 {
Kevin May7bdaac52020-02-10 12:10:07 +0000330 ALOGE("ExecuteWithDummyInputs: std::exception caught from EnqueueWorkload: %s", e.what());
Matthew Bentham16196e22019-04-01 17:17:58 +0100331 return false;
telsoa015307bc12018-03-09 13:51:08 +0000332 }
Matthew Bentham16196e22019-04-01 17:17:58 +0100333 return true;
telsoa015307bc12018-03-09 13:51:08 +0000334}
335
arovir01b0717b52018-09-05 17:03:25 +0100336///
337/// Class template specializations
338///
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100339
arovir01b0717b52018-09-05 17:03:25 +0100340template class ArmnnPreparedModel<hal_1_0::HalPolicy>;
341
Matteo Martincigh8b287c22018-09-07 09:25:10 +0100342#ifdef ARMNN_ANDROID_NN_V1_1
arovir01b0717b52018-09-05 17:03:25 +0100343template class ArmnnPreparedModel<hal_1_1::HalPolicy>;
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100344#endif
345
Mike Kellyb5fdf382019-06-11 16:35:25 +0100346#ifdef ARMNN_ANDROID_NN_V1_2
347template class ArmnnPreparedModel<hal_1_1::HalPolicy>;
348template class ArmnnPreparedModel<hal_1_2::HalPolicy>;
349#endif
Kevin May42477c12020-03-26 13:34:14 +0000350
351#ifdef ARMNN_ANDROID_NN_V1_3
352template class ArmnnPreparedModel<hal_1_1::HalPolicy>;
353template class ArmnnPreparedModel<hal_1_2::HalPolicy>;
354template class ArmnnPreparedModel<hal_1_3::HalPolicy>;
355#endif
Nikhil Raj77605822018-09-03 11:25:56 +0100356} // namespace armnn_driver