blob: f3d05ef53d7d559b30fe29587cb63ae4c3011edf [file] [log] [blame]
Mike Kellyb5fdf382019-06-11 16:35:25 +01001//
Mike Kellye2d611e2021-10-14 12:35:58 +01002// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
Mike Kellyb5fdf382019-06-11 16:35:25 +01003// SPDX-License-Identifier: MIT
4//
5
6#define LOG_TAG "ArmnnDriver"
7
8#include "ArmnnPreparedModel_1_2.hpp"
Finn Williamsd8fb5402021-05-19 20:52:00 +01009
Mike Kellyb5fdf382019-06-11 16:35:25 +010010#include "Utils.hpp"
11
Mike Kellyb5fdf382019-06-11 16:35:25 +010012#include <log/log.h>
13#include <OperationsUtils.h>
14#include <ExecutionBurstServer.h>
15#include <ValidateHal.h>
16
Mike Kellyb5fdf382019-06-11 16:35:25 +010017#include <cinttypes>
18
Sadik Armagan188675f2021-02-12 17:16:42 +000019#ifdef ARMNN_ANDROID_S
20#include <LegacyUtils.h>
21#endif
22
Mike Kellyb5fdf382019-06-11 16:35:25 +010023using namespace android;
24using namespace android::hardware;
25
Mike Kellyb5fdf382019-06-11 16:35:25 +010026namespace {
27
Sadik Armagan188675f2021-02-12 17:16:42 +000028static const V1_2::Timing g_NoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX};
Mike Kellyb5fdf382019-06-11 16:35:25 +010029using namespace armnn_driver;
Mike Kelly44381512019-07-08 17:37:35 +010030using TimePoint = std::chrono::steady_clock::time_point;
31
32TimePoint Now()
33{
34 return std::chrono::steady_clock::now();
35}
36
37unsigned long MicrosecondsDuration(TimePoint endPoint, TimePoint startPoint)
38{
39 return static_cast<unsigned long>(std::chrono::duration_cast<std::chrono::microseconds>(
40 endPoint - startPoint).count());
41}
Mike Kellyb5fdf382019-06-11 16:35:25 +010042
Mike Kelly65c42dc2019-07-22 14:06:00 +010043void NotifyCallbackAndCheck(const ::android::sp<V1_0::IExecutionCallback>& callback,
Kevin Mayec1e5b82020-02-26 17:00:39 +000044 V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000045 std::vector<V1_2::OutputShape>,
46 const V1_2::Timing,
Mike Kellyb5fdf382019-06-11 16:35:25 +010047 std::string callingFunction)
48{
49 Return<void> returned = callback->notify(errorStatus);
50 // This check is required, if the callback fails and it isn't checked it will bring down the service
51 if (!returned.isOk())
52 {
53 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
54 callingFunction.c_str(), returned.description().c_str());
55 }
56}
57
Mike Kelly65c42dc2019-07-22 14:06:00 +010058void NotifyCallbackAndCheck(const ::android::sp<V1_2::IExecutionCallback>& callback,
Kevin Mayec1e5b82020-02-26 17:00:39 +000059 V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000060 std::vector<V1_2::OutputShape> outputShapes,
61 const V1_2::Timing timing,
Mike Kellyb5fdf382019-06-11 16:35:25 +010062 std::string callingFunction)
63{
Mike Kelly65c42dc2019-07-22 14:06:00 +010064 Return<void> returned = callback->notify_1_2(errorStatus, outputShapes, timing);
Mike Kellyb5fdf382019-06-11 16:35:25 +010065 // This check is required, if the callback fails and it isn't checked it will bring down the service
66 if (!returned.isOk())
67 {
68 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
69 callingFunction.c_str(), returned.description().c_str());
70 }
71}
72
Sadik Armagan188675f2021-02-12 17:16:42 +000073bool ValidateRequestArgument(const V1_0::RequestArgument& requestArg, const armnn::TensorInfo& tensorInfo)
Mike Kellyb5fdf382019-06-11 16:35:25 +010074{
75 if (requestArg.dimensions.size() != 0)
76 {
77 if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
78 {
79 ALOGE("Mismatched dimensions (request argument: %zu, expected: %u)",
80 requestArg.dimensions.size(), tensorInfo.GetNumDimensions());
81 return false;
82 }
83
84 for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
85 {
Finn Williamsa4983ce2020-07-23 12:55:12 +010086 if (requestArg.dimensions[d] != 0 && requestArg.dimensions[d] != tensorInfo.GetShape()[d])
Mike Kellyb5fdf382019-06-11 16:35:25 +010087 {
88 ALOGE("Mismatched size for dimension %d (request argument: %u, expected %u)",
89 d, requestArg.dimensions[d], tensorInfo.GetShape()[d]);
90 return false;
91 }
92 }
93 }
94
95 return true;
96}
97
Sadik Armagan188675f2021-02-12 17:16:42 +000098armnn::Tensor GetTensorForRequestArgument(const V1_0::RequestArgument& requestArg,
Mike Kellyb5fdf382019-06-11 16:35:25 +010099 const armnn::TensorInfo& tensorInfo,
100 const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
101{
102 if (!ValidateRequestArgument(requestArg, tensorInfo))
103 {
104 return armnn::Tensor();
105 }
106
107 return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
108}
109
110inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
111{
112 return tensorNamePrefix + std::to_string(index);
113}
114
115} // anonymous namespace
116
117using namespace android::hardware;
118
119namespace armnn_driver
120{
121
122template<typename HalVersion>
Derek Lamberti4de83c52020-03-17 13:40:18 +0000123RequestThread<ArmnnPreparedModel_1_2, HalVersion, CallbackContext_1_2>
Mike Kelly65c42dc2019-07-22 14:06:00 +0100124 ArmnnPreparedModel_1_2<HalVersion>::m_RequestThread;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100125
126template<typename HalVersion>
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100127std::unique_ptr<armnn::Threadpool> ArmnnPreparedModel_1_2<HalVersion>::m_Threadpool(nullptr);
128
129template<typename HalVersion>
Mike Kellyb5fdf382019-06-11 16:35:25 +0100130template<typename TensorBindingCollection>
131void ArmnnPreparedModel_1_2<HalVersion>::DumpTensorsIfRequired(char const* tensorNamePrefix,
132 const TensorBindingCollection& tensorBindings)
133{
134 if (!m_RequestInputsAndOutputsDumpDir.empty())
135 {
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100136 const std::string requestName = std::to_string(m_NetworkId) + "_" + std::to_string(m_RequestCount) + ".dump";
Mike Kellyb5fdf382019-06-11 16:35:25 +0100137 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
138 {
139 DumpTensor(m_RequestInputsAndOutputsDumpDir,
140 requestName,
141 BuildTensorName(tensorNamePrefix, i),
142 tensorBindings[i].second);
143 }
144 }
145}
146
147template<typename HalVersion>
148ArmnnPreparedModel_1_2<HalVersion>::ArmnnPreparedModel_1_2(armnn::NetworkId networkId,
149 armnn::IRuntime* runtime,
150 const V1_2::Model& model,
151 const std::string& requestInputsAndOutputsDumpDir,
Finn Williamsd8fb5402021-05-19 20:52:00 +0100152 const bool gpuProfilingEnabled,
Finn Williamsca3a3e02021-06-11 15:04:02 +0100153 const bool asyncModelExecutionEnabled,
154 const unsigned int numberOfThreads)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100155 : m_NetworkId(networkId)
156 , m_Runtime(runtime)
157 , m_Model(model)
158 , m_RequestCount(0)
159 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
160 , m_GpuProfilingEnabled(gpuProfilingEnabled)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100161 , m_AsyncModelExecutionEnabled(asyncModelExecutionEnabled)
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100162 , m_PreparedFromCache(false)
163{
164 // Enable profiling if required.
165 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
166
167 if (m_AsyncModelExecutionEnabled)
168 {
169 std::vector<std::shared_ptr<armnn::IWorkingMemHandle>> memHandles;
170 for (unsigned int i=0; i < numberOfThreads; ++i)
171 {
172 memHandles.emplace_back(m_Runtime->CreateWorkingMemHandle(networkId));
173 }
174
175 if (!m_Threadpool)
176 {
177 m_Threadpool = std::make_unique<armnn::Threadpool>(numberOfThreads, runtime, memHandles);
178 }
179 else
180 {
181 m_Threadpool->LoadMemHandles(memHandles);
182 }
183
184 m_WorkingMemHandle = memHandles.back();
185 }
186}
187
188template<typename HalVersion>
189ArmnnPreparedModel_1_2<HalVersion>::ArmnnPreparedModel_1_2(armnn::NetworkId networkId,
190 armnn::IRuntime* runtime,
191 const std::string& requestInputsAndOutputsDumpDir,
192 const bool gpuProfilingEnabled,
193 const bool asyncModelExecutionEnabled,
194 const unsigned int numberOfThreads,
195 const bool preparedFromCache)
196 : m_NetworkId(networkId)
197 , m_Runtime(runtime)
198 , m_RequestCount(0)
199 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
200 , m_GpuProfilingEnabled(gpuProfilingEnabled)
201 , m_AsyncModelExecutionEnabled(asyncModelExecutionEnabled)
202 , m_PreparedFromCache(preparedFromCache)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100203{
204 // Enable profiling if required.
205 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100206
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100207 if (m_AsyncModelExecutionEnabled)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100208 {
Finn Williamsca3a3e02021-06-11 15:04:02 +0100209 std::vector<std::shared_ptr<armnn::IWorkingMemHandle>> memHandles;
Finn Williamsd27c13b2021-06-25 10:06:09 +0100210 for (unsigned int i=0; i < numberOfThreads; ++i)
Finn Williamsca3a3e02021-06-11 15:04:02 +0100211 {
212 memHandles.emplace_back(m_Runtime->CreateWorkingMemHandle(networkId));
213 }
214
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100215 if (!m_Threadpool)
216 {
217 m_Threadpool = std::make_unique<armnn::Threadpool>(numberOfThreads, runtime, memHandles);
218 }
219 else
220 {
221 m_Threadpool->LoadMemHandles(memHandles);
222 }
223
Finn Williamsca3a3e02021-06-11 15:04:02 +0100224 m_WorkingMemHandle = memHandles.back();
Finn Williamsd8fb5402021-05-19 20:52:00 +0100225 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100226}
227
228template<typename HalVersion>
229ArmnnPreparedModel_1_2<HalVersion>::~ArmnnPreparedModel_1_2()
230{
231 // Get a hold of the profiler used by this model.
232 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
233
234 // Unload the network associated with this model.
235 m_Runtime->UnloadNetwork(m_NetworkId);
236
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100237 // Unload the network memhandles from the threadpool
238 if (m_AsyncModelExecutionEnabled)
239 {
240 m_Threadpool->UnloadMemHandles(m_NetworkId);
241 }
242
Mike Kellyb5fdf382019-06-11 16:35:25 +0100243 // Dump the profiling info to a file if required.
244 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId, profiler.get());
245}
246
247template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000248Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::execute(const V1_0::Request& request,
Mike Kellyb5fdf382019-06-11 16:35:25 +0100249 const ::android::sp<V1_0::IExecutionCallback>& callback)
250{
Mike Kelly65c42dc2019-07-22 14:06:00 +0100251 if (callback.get() == nullptr)
252 {
253 ALOGE("ArmnnPreparedModel_1_2::execute invalid callback passed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000254 return V1_0::ErrorStatus::INVALID_ARGUMENT;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100255 }
256
Kevin Mayec1e5b82020-02-26 17:00:39 +0000257 auto cb = [callback](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000258 std::vector<V1_2::OutputShape> outputShapes,
259 const V1_2::Timing& timing,
Mike Kelly65c42dc2019-07-22 14:06:00 +0100260 std::string callingFunction)
261 {
262 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
263 };
264
Sadik Armagan188675f2021-02-12 17:16:42 +0000265 return Execute(request, V1_2::MeasureTiming::NO, cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100266}
267
268template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000269Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::execute_1_2(
270 const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000271 V1_2::MeasureTiming measureTiming,
Kevin Mayec1e5b82020-02-26 17:00:39 +0000272 const sp<V1_2::IExecutionCallback>& callback)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100273{
Mike Kelly65c42dc2019-07-22 14:06:00 +0100274 if (callback.get() == nullptr)
275 {
276 ALOGE("ArmnnPreparedModel_1_2::execute_1_2 invalid callback passed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000277 return V1_0::ErrorStatus::INVALID_ARGUMENT;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100278 }
279
Kevin Mayec1e5b82020-02-26 17:00:39 +0000280 auto cb = [callback](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000281 std::vector<V1_2::OutputShape> outputShapes,
282 const V1_2::Timing& timing,
Mike Kelly65c42dc2019-07-22 14:06:00 +0100283 std::string callingFunction)
284 {
285 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
286 };
287
288 return Execute(request, measureTiming, cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100289}
290
Derek Lamberti4de83c52020-03-17 13:40:18 +0000291template<typename HalVersion>
292Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForInputs(
293 armnn::InputTensors& inputs,
294 const V1_0::Request& request,
295 const std::vector<android::nn::RunTimePoolInfo>& memPools)
296{
297 inputs.reserve(request.inputs.size());
298 for (unsigned int i = 0; i < request.inputs.size(); i++)
299 {
300 const auto& inputArg = request.inputs[i];
301
Cathal Corbette27d4e82021-10-28 12:28:35 +0100302 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
303 // inputs (of type InputTensors) is composed of a vector of ConstTensors.
304 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
305 inputTensorInfo.SetConstant();
Derek Lamberti4de83c52020-03-17 13:40:18 +0000306 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
307
308 if (inputTensor.GetMemoryArea() == nullptr)
309 {
310 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
311 return V1_0::ErrorStatus::GENERAL_FAILURE;
312 }
313
314 inputs.emplace_back(i, inputTensor);
315 }
316
317 return V1_0::ErrorStatus::NONE;
318}
319
320template<typename HalVersion>
321Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForOutputs(
322 armnn::OutputTensors& outputs,
Sadik Armagan188675f2021-02-12 17:16:42 +0000323 std::vector<V1_2::OutputShape> &outputShapes,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000324 const V1_0::Request& request,
325 const std::vector<android::nn::RunTimePoolInfo>& memPools)
326{
327 outputs.reserve(request.outputs.size());
328 for (unsigned int i = 0; i < request.outputs.size(); i++)
329 {
330 const auto& outputArg = request.outputs[i];
331
332 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
333 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
334 if (outputTensor.GetMemoryArea() == nullptr)
335 {
336 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
337 return V1_0::ErrorStatus::GENERAL_FAILURE;
338 }
339
340 const size_t outputSize = outputTensorInfo.GetNumBytes();
Finn Williamsa4983ce2020-07-23 12:55:12 +0100341
342 if (outputArg.location.length < outputSize)
343 {
344 ALOGW("ArmnnPreparedModel_1_2::Execute failed: outputArg.location.length < outputSize");
345 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
346 }
347
Sadik Armagan188675f2021-02-12 17:16:42 +0000348#if !defined(ARMNN_ANDROID_S)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000349 const size_t bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
350 if (bufferSize < outputSize)
351 {
Finn Williamsa4983ce2020-07-23 12:55:12 +0100352 ALOGW("ArmnnPreparedModel_1_2::Execute failed: bufferSize < outputSize");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000353 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
354 }
Sadik Armagan188675f2021-02-12 17:16:42 +0000355#else
Kevin Maydc873f62021-06-14 11:21:11 +0100356 const size_t bufferSize = memPools.at(outputArg.location.poolIndex).getSize();
Sadik Armagan188675f2021-02-12 17:16:42 +0000357 if (bufferSize < outputSize)
358 {
359 ALOGW("ArmnnPreparedModel_1_2::Execute failed bufferSize (%s) < outputSize (%s)",
360 std::to_string(bufferSize).c_str(), std::to_string(outputSize).c_str());
361 outputShapes[i].isSufficient = false;
362 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
363 }
364#endif
Derek Lamberti4de83c52020-03-17 13:40:18 +0000365 outputs.emplace_back(i, outputTensor);
366 outputShapes[i] = ComputeShape(outputTensorInfo);
367 }
368
369 return V1_0::ErrorStatus::NONE;
370}
371
372template<typename HalVersion>
373Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForIO(
374 armnn::InputTensors& inputs,
375 armnn::OutputTensors& outputs,
376 std::vector<android::nn::RunTimePoolInfo>& memPools,
377 const V1_0::Request& request,
378 CallbackAsync_1_2 callback)
379{
Sadik Armagan188675f2021-02-12 17:16:42 +0000380#if !defined(ARMNN_ANDROID_S)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000381 if (!setRunTimePoolInfosFromHidlMemories(&memPools, request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000382#else
383 if (!setRunTimePoolInfosFromCanonicalMemories(&memPools, uncheckedConvert(request.pools)))
384#endif
Derek Lamberti4de83c52020-03-17 13:40:18 +0000385 {
386 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
387 return V1_0::ErrorStatus::GENERAL_FAILURE;
388 }
Derek Lamberti4de83c52020-03-17 13:40:18 +0000389 // add the inputs and outputs with their data
390 try
391 {
392 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_0::ErrorStatus::NONE)
393 {
394 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
395 return V1_0::ErrorStatus::GENERAL_FAILURE;
396 }
397
Sadik Armagan188675f2021-02-12 17:16:42 +0000398 std::vector<V1_2::OutputShape> outputShapes(request.outputs.size());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000399
400 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
401 if (errorStatus != V1_0::ErrorStatus::NONE)
402 {
403 callback(errorStatus,
404 outputShapes,
405 g_NoTiming,
406 "ArmnnPreparedModel_1_2::Execute");
407 return errorStatus;
408 }
409 }
410 catch (armnn::Exception& e)
411 {
412 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
413 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
414 return V1_0::ErrorStatus::GENERAL_FAILURE;
415 }
416 catch (std::exception& e)
417 {
418 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
419 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
420 return V1_0::ErrorStatus::GENERAL_FAILURE;
421 }
422
423 return V1_0::ErrorStatus::NONE;
424}
425
Mike Kellyb5fdf382019-06-11 16:35:25 +0100426template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000427Return<void> ArmnnPreparedModel_1_2<HalVersion>::executeSynchronously(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000428 V1_2::MeasureTiming measureTiming,
Mike Kelly44381512019-07-08 17:37:35 +0100429 executeSynchronously_cb cb)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100430{
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100431 if (!m_PreparedFromCache)
432 {
433 ALOGV("ArmnnPreparedModel_1_2::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
434 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100435 m_RequestCount++;
436
437 if (cb == nullptr)
438 {
439 ALOGE("ArmnnPreparedModel_1_2::executeSynchronously invalid callback passed");
440 return Void();
441 }
442
Derek Lamberti4de83c52020-03-17 13:40:18 +0000443 TimePoint driverStart;
Mike Kelly44381512019-07-08 17:37:35 +0100444
Sadik Armagan188675f2021-02-12 17:16:42 +0000445 if (measureTiming == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100446 {
447 driverStart = Now();
448 }
449
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100450 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Mike Kellyb5fdf382019-06-11 16:35:25 +0100451 {
Mike Kelly44381512019-07-08 17:37:35 +0100452 ALOGE("ArmnnPreparedModel_1_2::executeSynchronously invalid request model");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000453 cb(V1_0::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100454 return Void();
455 }
456
Derek Lamberti4de83c52020-03-17 13:40:18 +0000457 auto cbWrapper = [cb](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000458 std::vector<V1_2::OutputShape> outputShapes,
459 const V1_2::Timing& timing,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000460 std::string)
461 {
462 cb(errorStatus, outputShapes, timing);
463 };
Mike Kellyb5fdf382019-06-11 16:35:25 +0100464
465 // map the memory pool into shared pointers
466 // use a shared memory pools vector on the heap, as it is passed to the request thread
Derek Lamberti4de83c52020-03-17 13:40:18 +0000467 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
Mike Kellyb5fdf382019-06-11 16:35:25 +0100468
Derek Lamberti4de83c52020-03-17 13:40:18 +0000469 // allocate the tensors on the heap, as they are passed to the request thread
470 auto inputs = std::make_shared<armnn::InputTensors>();
471 auto outputs = std::make_shared<armnn::OutputTensors>();
472
473 auto prepareStatus = PrepareMemoryForIO(*inputs, *outputs, *memPools, request, cbWrapper);
474 if (prepareStatus != V1_0::ErrorStatus::NONE)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100475 {
Kevin May7bdaac52020-02-10 12:10:07 +0000476 return Void();
477 }
478
Mike Kellyb5fdf382019-06-11 16:35:25 +0100479 ALOGV("ArmnnPreparedModel_1_2::executeSynchronously() before Execution");
480
Derek Lamberti4de83c52020-03-17 13:40:18 +0000481 CallbackContext_1_2 cbCtx;
482 cbCtx.callback = cbWrapper;
483 cbCtx.ctx.measureTimings = measureTiming;
484 cbCtx.ctx.driverStart = driverStart;
485 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
486
487 return Void();
488}
489
490template<typename HalVersion>
491template<typename CallbackContext>
492bool ArmnnPreparedModel_1_2<HalVersion>::ExecuteGraph(
493 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
494 armnn::InputTensors& inputTensors,
495 armnn::OutputTensors& outputTensors,
496 CallbackContext cb)
497{
498 ALOGV("ArmnnPreparedModel_1_2::ExecuteGraph(...)");
499
500 TimePoint driverEnd, deviceStart, deviceEnd;
501
502 DumpTensorsIfRequired("Input", inputTensors);
503
Sadik Armagan188675f2021-02-12 17:16:42 +0000504 std::vector<V1_2::OutputShape> outputShapes(outputTensors.size());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000505 for (unsigned int i = 0; i < outputTensors.size(); i++)
506 {
507 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
508 const armnn::Tensor outputTensor = outputTensorPair.second;
509 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
510
511 outputShapes[i] = ComputeShape(outputTensorInfo);
512 }
513
Mike Kellyb5fdf382019-06-11 16:35:25 +0100514 // run it
515 try
516 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000517 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100518 {
519 deviceStart = Now();
520 }
521
Finn Williamsd8fb5402021-05-19 20:52:00 +0100522 armnn::Status status;
523 if (m_AsyncModelExecutionEnabled)
524 {
525 ALOGW("ArmnnPreparedModel_1_2::ExecuteGraph m_AsyncModelExecutionEnabled true");
526 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
527 }
528 else
529 {
530 ALOGW("ArmnnPreparedModel_1_2::ExecuteGraph m_AsyncModelExecutionEnabled false");
531 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
532 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100533
Sadik Armagan188675f2021-02-12 17:16:42 +0000534 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100535 {
536 deviceEnd = Now();
537 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100538 if (status != armnn::Status::Success)
539 {
540 ALOGW("EnqueueWorkload failed");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000541 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming,
542 "ArmnnPreparedModel_1_2::ExecuteGraph");
543 return false;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100544 }
545 }
Kevin May7bdaac52020-02-10 12:10:07 +0000546 catch (armnn::Exception& e)
547 {
Derek Lamberti4de83c52020-03-17 13:40:18 +0000548 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
549 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
550 return false;
Kevin May7bdaac52020-02-10 12:10:07 +0000551 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000552 catch (std::exception& e)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100553 {
Kevin May7bdaac52020-02-10 12:10:07 +0000554 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000555 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
556 return false;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100557 }
558
Derek Lamberti4de83c52020-03-17 13:40:18 +0000559 CommitPools(*pMemPools);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100560
Derek Lamberti4de83c52020-03-17 13:40:18 +0000561 DumpTensorsIfRequired("Output", outputTensors);
Kevin Mayec1e5b82020-02-26 17:00:39 +0000562
Sadik Armagan188675f2021-02-12 17:16:42 +0000563 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100564 {
565 driverEnd = Now();
Sadik Armagan188675f2021-02-12 17:16:42 +0000566 V1_2::Timing timing;
Mike Kelly44381512019-07-08 17:37:35 +0100567 timing.timeOnDevice = MicrosecondsDuration(deviceEnd, deviceStart);
Derek Lamberti4de83c52020-03-17 13:40:18 +0000568 timing.timeInDriver = MicrosecondsDuration(driverEnd, cb.ctx.driverStart);
569 ALOGV("ArmnnPreparedModel_1_2::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
570 timing.timeInDriver);
571 cb.callback(V1_0::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_2::ExecuteGraph");
572 } else {
573 cb.callback(V1_0::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
Mike Kelly44381512019-07-08 17:37:35 +0100574 }
Derek Lamberti4de83c52020-03-17 13:40:18 +0000575
576 return true;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100577}
578
Derek Lamberti4de83c52020-03-17 13:40:18 +0000579template<typename HalVersion>
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100580bool ArmnnPreparedModel_1_2<HalVersion>::ExecuteWithDummyInputs(unsigned int numInputs, unsigned int numOutputs)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000581{
582 std::vector<std::vector<char>> storage;
583 armnn::InputTensors inputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100584 for (unsigned int i = 0; i < numInputs; i++)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000585 {
Cathal Corbette27d4e82021-10-28 12:28:35 +0100586 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
587 // pInputTensors (of type InputTensors) is composed of a vector of ConstTensors.
588 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
589 inputTensorInfo.SetConstant();
590
Derek Lamberti4de83c52020-03-17 13:40:18 +0000591 storage.emplace_back(inputTensorInfo.GetNumBytes());
592 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
593
594 inputTensors.emplace_back(i, inputTensor);
595 }
596
597 armnn::OutputTensors outputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100598 for (unsigned int i = 0; i < numOutputs; i++)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000599 {
600 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
601 storage.emplace_back(outputTensorInfo.GetNumBytes());
602 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
603
604 outputTensors.emplace_back(i, outputTensor);
605 }
606
Sadik Armagan188675f2021-02-12 17:16:42 +0000607 auto nullCallback = [](V1_0::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Derek Lamberti4de83c52020-03-17 13:40:18 +0000608 CallbackContext_1_2 callbackContext;
609 callbackContext.callback = nullCallback;
Sadik Armagan188675f2021-02-12 17:16:42 +0000610 callbackContext.ctx.measureTimings = V1_2::MeasureTiming::NO;
Derek Lamberti4de83c52020-03-17 13:40:18 +0000611 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
612 return ExecuteGraph(memPools,
613 inputTensors,
614 outputTensors,
615 callbackContext);
616}
617
618template<typename HalVersion>
619Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::Execute(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000620 V1_2::MeasureTiming measureTiming,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000621 CallbackAsync_1_2 callback)
622{
623 ExecutionContext_1_2 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000624 if (measureTiming == V1_2::MeasureTiming::YES)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000625 {
626 ctx.measureTimings = measureTiming;
627 ctx.driverStart = Now();
628 }
629
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100630 if (!m_PreparedFromCache)
631 {
632 ALOGV("ArmnnPreparedModel_1_2::execute(): %s", GetModelSummary(m_Model).c_str());
633 }
Derek Lamberti4de83c52020-03-17 13:40:18 +0000634 m_RequestCount++;
635
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100636 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Derek Lamberti4de83c52020-03-17 13:40:18 +0000637 {
638 callback(V1_0::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
639 return V1_0::ErrorStatus::INVALID_ARGUMENT;
640 }
641
642 if (!m_RequestInputsAndOutputsDumpDir.empty())
643 {
644 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
645 }
646
647 // map the memory pool into shared pointers
648 // use a shared memory pools vector on the heap, as it is passed to the request thread
649 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
650
651 // allocate the tensors on the heap, as they are passed to the request thread
652 auto inputTensors = std::make_shared<armnn::InputTensors>();
653 auto outputTensors = std::make_shared<armnn::OutputTensors>();
654
655 auto prepareStatus = PrepareMemoryForIO(*inputTensors, *outputTensors, *memPools, request, callback);
656 switch(prepareStatus)
657 {
658 case V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
659 return V1_0::ErrorStatus::NONE;
660 case V1_0::ErrorStatus::GENERAL_FAILURE:
661 return V1_0::ErrorStatus::GENERAL_FAILURE;
662 default:
663 {}
664 }
665
Derek Lamberti4de83c52020-03-17 13:40:18 +0000666
667 // post the request for asynchronous execution
668 CallbackContext_1_2 cb;
669 cb.callback = callback;
670 cb.ctx = ctx;
Finn Williamsd8fb5402021-05-19 20:52:00 +0100671
672 if (m_AsyncModelExecutionEnabled)
673 {
674 ALOGV("ArmnnPreparedModel_1_2::execute(...) before ScheduleGraphForExecution");
675 ScheduleGraphForExecution(memPools, inputTensors, outputTensors, cb);
676 ALOGV("ArmnnPreparedModel_1_2::execute(...) after ScheduleGraphForExecution");
677 return V1_0::ErrorStatus::NONE;
678 }
679
680 ALOGV("ArmnnPreparedModel_1_2::execute(...) before PostMsg");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000681 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
682 ALOGV("ArmnnPreparedModel_1_2::execute(...) after PostMsg");
683 return V1_0::ErrorStatus::NONE;
684}
685
Mike Kellyb5fdf382019-06-11 16:35:25 +0100686template<typename HalVersion>
687Return<void> ArmnnPreparedModel_1_2<HalVersion>::configureExecutionBurst(
Derek Lamberti4de83c52020-03-17 13:40:18 +0000688 const sp<V1_2::IBurstCallback>& callback,
689 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
690 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
691 V1_2::IPreparedModel::configureExecutionBurst_cb cb)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100692{
693 ALOGV("ArmnnPreparedModel_1_2::configureExecutionBurst");
Mike Kelly65c42dc2019-07-22 14:06:00 +0100694 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
695 requestChannel,
696 resultChannel,
Kevin May42477c12020-03-26 13:34:14 +0000697 this);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100698
Mike Kelly44381512019-07-08 17:37:35 +0100699 if (burst == nullptr)
700 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000701 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
Mike Kelly44381512019-07-08 17:37:35 +0100702 }
703 else
704 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000705 cb(V1_0::ErrorStatus::NONE, burst);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100706 }
707 return Void();
708}
709
Finn Williamsd8fb5402021-05-19 20:52:00 +0100710/// Schedule the graph prepared from the request for execution
711template<typename HalVersion>
712template<typename CallbackContext>
713void ArmnnPreparedModel_1_2<HalVersion>::ScheduleGraphForExecution(
714 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
715 std::shared_ptr<armnn::InputTensors>& inputTensors,
716 std::shared_ptr<armnn::OutputTensors>& outputTensors,
717 CallbackContext callbackContext)
718{
719 ALOGV("ArmnnPreparedModel_1_2::ScheduleGraphForExecution(...)");
720
721 DumpTensorsIfRequired("Input", *inputTensors);
722
723 unsigned int outputTensorSize = outputTensors.get()->size();
724 std::vector<V1_2::OutputShape> outputShapes(outputTensorSize);
725 for (unsigned int i = 0; i < outputTensorSize; i++)
726 {
727 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors.get()->at(i);
728 const armnn::Tensor outputTensor = outputTensorPair.second;
729 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
730
731 outputShapes[i] = ComputeShape(outputTensorInfo);
732 }
733
734 auto tpCb = std::make_shared<
735 ArmnnThreadPoolCallback_1_2<CallbackContext_1_2>>(this,
736 pMemPools,
737 outputShapes,
738 inputTensors,
739 outputTensors,
740 callbackContext);
741
Finn Williamsca3a3e02021-06-11 15:04:02 +0100742 m_Threadpool->Schedule(m_NetworkId,
743 *tpCb->m_InputTensors,
744 *tpCb->m_OutputTensors,
745 armnn::QosExecPriority::Medium,
746 tpCb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100747 ALOGV("ArmnnPreparedModel_1_2::ScheduleGraphForExecution end");
748}
749
750template<typename HalVersion>
751template <typename CallbackContext>
752void ArmnnPreparedModel_1_2<HalVersion>::ArmnnThreadPoolCallback_1_2<CallbackContext>::Notify(
753 armnn::Status status, armnn::InferenceTimingPair timeTaken)
754{
755 ALOGV("ArmnnPreparedModel_1_2::ArmnnThreadPoolCallback_1_2 Notify");
756
757 TimePoint driverEnd;
758
759 CommitPools(*m_MemPools);
760
761 m_Model->DumpTensorsIfRequired("Output", *m_OutputTensors);
762
763 if (status != armnn::Status::Success)
764 {
765 ALOGW("ArmnnThreadPoolCallback::Notify EnqueueWorkload failed");
766 m_CallbackContext.callback(
767 V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel::ExecuteGraph");
768 return;
769 }
770
771 if (m_CallbackContext.ctx.measureTimings == V1_2::MeasureTiming::YES)
772 {
773 driverEnd = std::chrono::steady_clock::now();
774 V1_2::Timing timing;
775 timing.timeOnDevice = MicrosecondsDuration(timeTaken.second, timeTaken.first);
776 timing.timeInDriver = MicrosecondsDuration(driverEnd, m_CallbackContext.ctx.driverStart);
777 ALOGV("ArmnnPreparedModel_1_2::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
778 timing.timeInDriver);
779 m_CallbackContext.callback(
780 V1_0::ErrorStatus::NONE, m_OutputShapes, timing, "ArmnnPreparedModel_1_2::ExecuteGraph");
781 } else {
782 m_CallbackContext.callback(
783 V1_0::ErrorStatus::NONE, m_OutputShapes, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
784 }
785 return;
786}
787
Kevin May42477c12020-03-26 13:34:14 +0000788#if defined(ARMNN_ANDROID_NN_V1_2) || defined(ARMNN_ANDROID_NN_V1_3)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100789template class ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>;
Derek Lamberti4de83c52020-03-17 13:40:18 +0000790template bool ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>::ExecuteGraph<CallbackContext_1_2>(
791 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
792 armnn::InputTensors& pInputTensors,
793 armnn::OutputTensors& pOutputTensors,
794 CallbackContext_1_2 cb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100795
796template void ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>::ScheduleGraphForExecution<CallbackContext_1_2>(
797 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
798 std::shared_ptr<armnn::InputTensors>& inputTensors,
799 std::shared_ptr<armnn::OutputTensors>& outputTensors,
800 CallbackContext_1_2 callbackContext);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100801#endif
802
803} // namespace armnn_driver