blob: 7f35e60fa5f853d6ebb0f82a83b51a1654b59f21 [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);
Colm Donelan12396f72022-02-15 14:59:08 +0000233 if (profiler && m_GpuProfilingEnabled)
234 {
235 // Dump the profiling info to a file if required.
236 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId,
237 profiler.get());
238 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100239
240 // Unload the network associated with this model.
241 m_Runtime->UnloadNetwork(m_NetworkId);
242
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100243 // Unload the network memhandles from the threadpool
244 if (m_AsyncModelExecutionEnabled)
245 {
246 m_Threadpool->UnloadMemHandles(m_NetworkId);
247 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100248}
249
250template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000251Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::execute(const V1_0::Request& request,
Mike Kellyb5fdf382019-06-11 16:35:25 +0100252 const ::android::sp<V1_0::IExecutionCallback>& callback)
253{
Mike Kelly65c42dc2019-07-22 14:06:00 +0100254 if (callback.get() == nullptr)
255 {
256 ALOGE("ArmnnPreparedModel_1_2::execute invalid callback passed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000257 return V1_0::ErrorStatus::INVALID_ARGUMENT;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100258 }
259
Kevin Mayec1e5b82020-02-26 17:00:39 +0000260 auto cb = [callback](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000261 std::vector<V1_2::OutputShape> outputShapes,
262 const V1_2::Timing& timing,
Mike Kelly65c42dc2019-07-22 14:06:00 +0100263 std::string callingFunction)
264 {
265 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
266 };
267
Sadik Armagan188675f2021-02-12 17:16:42 +0000268 return Execute(request, V1_2::MeasureTiming::NO, cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100269}
270
271template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000272Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::execute_1_2(
273 const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000274 V1_2::MeasureTiming measureTiming,
Kevin Mayec1e5b82020-02-26 17:00:39 +0000275 const sp<V1_2::IExecutionCallback>& callback)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100276{
Mike Kelly65c42dc2019-07-22 14:06:00 +0100277 if (callback.get() == nullptr)
278 {
279 ALOGE("ArmnnPreparedModel_1_2::execute_1_2 invalid callback passed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000280 return V1_0::ErrorStatus::INVALID_ARGUMENT;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100281 }
282
Kevin Mayec1e5b82020-02-26 17:00:39 +0000283 auto cb = [callback](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000284 std::vector<V1_2::OutputShape> outputShapes,
285 const V1_2::Timing& timing,
Mike Kelly65c42dc2019-07-22 14:06:00 +0100286 std::string callingFunction)
287 {
288 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
289 };
290
291 return Execute(request, measureTiming, cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100292}
293
Derek Lamberti4de83c52020-03-17 13:40:18 +0000294template<typename HalVersion>
295Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForInputs(
296 armnn::InputTensors& inputs,
297 const V1_0::Request& request,
298 const std::vector<android::nn::RunTimePoolInfo>& memPools)
299{
300 inputs.reserve(request.inputs.size());
301 for (unsigned int i = 0; i < request.inputs.size(); i++)
302 {
303 const auto& inputArg = request.inputs[i];
304
Cathal Corbette27d4e82021-10-28 12:28:35 +0100305 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
306 // inputs (of type InputTensors) is composed of a vector of ConstTensors.
307 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
308 inputTensorInfo.SetConstant();
Derek Lamberti4de83c52020-03-17 13:40:18 +0000309 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
310
311 if (inputTensor.GetMemoryArea() == nullptr)
312 {
313 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
314 return V1_0::ErrorStatus::GENERAL_FAILURE;
315 }
316
317 inputs.emplace_back(i, inputTensor);
318 }
319
320 return V1_0::ErrorStatus::NONE;
321}
322
323template<typename HalVersion>
324Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForOutputs(
325 armnn::OutputTensors& outputs,
Sadik Armagan188675f2021-02-12 17:16:42 +0000326 std::vector<V1_2::OutputShape> &outputShapes,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000327 const V1_0::Request& request,
328 const std::vector<android::nn::RunTimePoolInfo>& memPools)
329{
330 outputs.reserve(request.outputs.size());
331 for (unsigned int i = 0; i < request.outputs.size(); i++)
332 {
333 const auto& outputArg = request.outputs[i];
334
335 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
336 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
337 if (outputTensor.GetMemoryArea() == nullptr)
338 {
339 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
340 return V1_0::ErrorStatus::GENERAL_FAILURE;
341 }
342
343 const size_t outputSize = outputTensorInfo.GetNumBytes();
Finn Williamsa4983ce2020-07-23 12:55:12 +0100344
345 if (outputArg.location.length < outputSize)
346 {
347 ALOGW("ArmnnPreparedModel_1_2::Execute failed: outputArg.location.length < outputSize");
348 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
349 }
350
Sadik Armagan188675f2021-02-12 17:16:42 +0000351#if !defined(ARMNN_ANDROID_S)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000352 const size_t bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
353 if (bufferSize < outputSize)
354 {
Finn Williamsa4983ce2020-07-23 12:55:12 +0100355 ALOGW("ArmnnPreparedModel_1_2::Execute failed: bufferSize < outputSize");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000356 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
357 }
Sadik Armagan188675f2021-02-12 17:16:42 +0000358#else
Kevin Maydc873f62021-06-14 11:21:11 +0100359 const size_t bufferSize = memPools.at(outputArg.location.poolIndex).getSize();
Sadik Armagan188675f2021-02-12 17:16:42 +0000360 if (bufferSize < outputSize)
361 {
362 ALOGW("ArmnnPreparedModel_1_2::Execute failed bufferSize (%s) < outputSize (%s)",
363 std::to_string(bufferSize).c_str(), std::to_string(outputSize).c_str());
364 outputShapes[i].isSufficient = false;
365 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
366 }
367#endif
Derek Lamberti4de83c52020-03-17 13:40:18 +0000368 outputs.emplace_back(i, outputTensor);
369 outputShapes[i] = ComputeShape(outputTensorInfo);
370 }
371
372 return V1_0::ErrorStatus::NONE;
373}
374
375template<typename HalVersion>
376Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForIO(
377 armnn::InputTensors& inputs,
378 armnn::OutputTensors& outputs,
379 std::vector<android::nn::RunTimePoolInfo>& memPools,
380 const V1_0::Request& request,
381 CallbackAsync_1_2 callback)
382{
Sadik Armagan188675f2021-02-12 17:16:42 +0000383#if !defined(ARMNN_ANDROID_S)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000384 if (!setRunTimePoolInfosFromHidlMemories(&memPools, request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000385#else
386 if (!setRunTimePoolInfosFromCanonicalMemories(&memPools, uncheckedConvert(request.pools)))
387#endif
Derek Lamberti4de83c52020-03-17 13:40:18 +0000388 {
389 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
390 return V1_0::ErrorStatus::GENERAL_FAILURE;
391 }
Derek Lamberti4de83c52020-03-17 13:40:18 +0000392 // add the inputs and outputs with their data
393 try
394 {
395 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_0::ErrorStatus::NONE)
396 {
397 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
398 return V1_0::ErrorStatus::GENERAL_FAILURE;
399 }
400
Sadik Armagan188675f2021-02-12 17:16:42 +0000401 std::vector<V1_2::OutputShape> outputShapes(request.outputs.size());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000402
403 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
404 if (errorStatus != V1_0::ErrorStatus::NONE)
405 {
406 callback(errorStatus,
407 outputShapes,
408 g_NoTiming,
409 "ArmnnPreparedModel_1_2::Execute");
410 return errorStatus;
411 }
412 }
413 catch (armnn::Exception& e)
414 {
415 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
416 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
417 return V1_0::ErrorStatus::GENERAL_FAILURE;
418 }
419 catch (std::exception& e)
420 {
421 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
422 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
423 return V1_0::ErrorStatus::GENERAL_FAILURE;
424 }
425
426 return V1_0::ErrorStatus::NONE;
427}
428
Mike Kellyb5fdf382019-06-11 16:35:25 +0100429template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000430Return<void> ArmnnPreparedModel_1_2<HalVersion>::executeSynchronously(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000431 V1_2::MeasureTiming measureTiming,
Mike Kelly44381512019-07-08 17:37:35 +0100432 executeSynchronously_cb cb)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100433{
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100434 if (!m_PreparedFromCache)
435 {
436 ALOGV("ArmnnPreparedModel_1_2::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
437 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100438 m_RequestCount++;
439
440 if (cb == nullptr)
441 {
442 ALOGE("ArmnnPreparedModel_1_2::executeSynchronously invalid callback passed");
443 return Void();
444 }
445
Derek Lamberti4de83c52020-03-17 13:40:18 +0000446 TimePoint driverStart;
Mike Kelly44381512019-07-08 17:37:35 +0100447
Sadik Armagan188675f2021-02-12 17:16:42 +0000448 if (measureTiming == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100449 {
450 driverStart = Now();
451 }
452
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100453 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Mike Kellyb5fdf382019-06-11 16:35:25 +0100454 {
Mike Kelly44381512019-07-08 17:37:35 +0100455 ALOGE("ArmnnPreparedModel_1_2::executeSynchronously invalid request model");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000456 cb(V1_0::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100457 return Void();
458 }
459
Derek Lamberti4de83c52020-03-17 13:40:18 +0000460 auto cbWrapper = [cb](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000461 std::vector<V1_2::OutputShape> outputShapes,
462 const V1_2::Timing& timing,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000463 std::string)
464 {
465 cb(errorStatus, outputShapes, timing);
466 };
Mike Kellyb5fdf382019-06-11 16:35:25 +0100467
468 // map the memory pool into shared pointers
469 // use a shared memory pools vector on the heap, as it is passed to the request thread
Derek Lamberti4de83c52020-03-17 13:40:18 +0000470 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
Mike Kellyb5fdf382019-06-11 16:35:25 +0100471
Derek Lamberti4de83c52020-03-17 13:40:18 +0000472 // allocate the tensors on the heap, as they are passed to the request thread
473 auto inputs = std::make_shared<armnn::InputTensors>();
474 auto outputs = std::make_shared<armnn::OutputTensors>();
475
476 auto prepareStatus = PrepareMemoryForIO(*inputs, *outputs, *memPools, request, cbWrapper);
477 if (prepareStatus != V1_0::ErrorStatus::NONE)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100478 {
Kevin May7bdaac52020-02-10 12:10:07 +0000479 return Void();
480 }
481
Mike Kellyb5fdf382019-06-11 16:35:25 +0100482 ALOGV("ArmnnPreparedModel_1_2::executeSynchronously() before Execution");
483
Derek Lamberti4de83c52020-03-17 13:40:18 +0000484 CallbackContext_1_2 cbCtx;
485 cbCtx.callback = cbWrapper;
486 cbCtx.ctx.measureTimings = measureTiming;
487 cbCtx.ctx.driverStart = driverStart;
488 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
489
490 return Void();
491}
492
493template<typename HalVersion>
494template<typename CallbackContext>
495bool ArmnnPreparedModel_1_2<HalVersion>::ExecuteGraph(
496 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
497 armnn::InputTensors& inputTensors,
498 armnn::OutputTensors& outputTensors,
499 CallbackContext cb)
500{
501 ALOGV("ArmnnPreparedModel_1_2::ExecuteGraph(...)");
502
503 TimePoint driverEnd, deviceStart, deviceEnd;
504
505 DumpTensorsIfRequired("Input", inputTensors);
506
Sadik Armagan188675f2021-02-12 17:16:42 +0000507 std::vector<V1_2::OutputShape> outputShapes(outputTensors.size());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000508 for (unsigned int i = 0; i < outputTensors.size(); i++)
509 {
510 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
511 const armnn::Tensor outputTensor = outputTensorPair.second;
512 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
513
514 outputShapes[i] = ComputeShape(outputTensorInfo);
515 }
516
Mike Kellyb5fdf382019-06-11 16:35:25 +0100517 // run it
518 try
519 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000520 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100521 {
522 deviceStart = Now();
523 }
524
Finn Williamsd8fb5402021-05-19 20:52:00 +0100525 armnn::Status status;
526 if (m_AsyncModelExecutionEnabled)
527 {
528 ALOGW("ArmnnPreparedModel_1_2::ExecuteGraph m_AsyncModelExecutionEnabled true");
529 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
530 }
531 else
532 {
533 ALOGW("ArmnnPreparedModel_1_2::ExecuteGraph m_AsyncModelExecutionEnabled false");
David Monahan80696032022-02-02 12:17:46 +0000534 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100535 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100536
Sadik Armagan188675f2021-02-12 17:16:42 +0000537 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100538 {
539 deviceEnd = Now();
540 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100541 if (status != armnn::Status::Success)
542 {
543 ALOGW("EnqueueWorkload failed");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000544 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming,
545 "ArmnnPreparedModel_1_2::ExecuteGraph");
546 return false;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100547 }
548 }
Kevin May7bdaac52020-02-10 12:10:07 +0000549 catch (armnn::Exception& e)
550 {
Derek Lamberti4de83c52020-03-17 13:40:18 +0000551 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
552 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
553 return false;
Kevin May7bdaac52020-02-10 12:10:07 +0000554 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000555 catch (std::exception& e)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100556 {
Kevin May7bdaac52020-02-10 12:10:07 +0000557 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000558 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
559 return false;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100560 }
561
Derek Lamberti4de83c52020-03-17 13:40:18 +0000562 CommitPools(*pMemPools);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100563
Derek Lamberti4de83c52020-03-17 13:40:18 +0000564 DumpTensorsIfRequired("Output", outputTensors);
Kevin Mayec1e5b82020-02-26 17:00:39 +0000565
Sadik Armagan188675f2021-02-12 17:16:42 +0000566 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100567 {
568 driverEnd = Now();
Sadik Armagan188675f2021-02-12 17:16:42 +0000569 V1_2::Timing timing;
Mike Kelly44381512019-07-08 17:37:35 +0100570 timing.timeOnDevice = MicrosecondsDuration(deviceEnd, deviceStart);
Derek Lamberti4de83c52020-03-17 13:40:18 +0000571 timing.timeInDriver = MicrosecondsDuration(driverEnd, cb.ctx.driverStart);
Zingo Andersen7c561492022-01-25 11:09:41 +0100572 ALOGV("ArmnnPreparedModel_1_2::execute timing - Device = %lu Driver = %lu",
573 static_cast<unsigned long>(timing.timeOnDevice), static_cast<unsigned long>(timing.timeInDriver));
Derek Lamberti4de83c52020-03-17 13:40:18 +0000574 cb.callback(V1_0::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_2::ExecuteGraph");
575 } else {
576 cb.callback(V1_0::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
Mike Kelly44381512019-07-08 17:37:35 +0100577 }
Derek Lamberti4de83c52020-03-17 13:40:18 +0000578
579 return true;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100580}
581
Derek Lamberti4de83c52020-03-17 13:40:18 +0000582template<typename HalVersion>
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100583bool ArmnnPreparedModel_1_2<HalVersion>::ExecuteWithDummyInputs(unsigned int numInputs, unsigned int numOutputs)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000584{
585 std::vector<std::vector<char>> storage;
586 armnn::InputTensors inputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100587 for (unsigned int i = 0; i < numInputs; i++)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000588 {
Cathal Corbette27d4e82021-10-28 12:28:35 +0100589 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
590 // pInputTensors (of type InputTensors) is composed of a vector of ConstTensors.
591 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
592 inputTensorInfo.SetConstant();
593
Derek Lamberti4de83c52020-03-17 13:40:18 +0000594 storage.emplace_back(inputTensorInfo.GetNumBytes());
595 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
596
597 inputTensors.emplace_back(i, inputTensor);
598 }
599
600 armnn::OutputTensors outputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100601 for (unsigned int i = 0; i < numOutputs; i++)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000602 {
603 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
604 storage.emplace_back(outputTensorInfo.GetNumBytes());
605 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
606
607 outputTensors.emplace_back(i, outputTensor);
608 }
609
Sadik Armagan188675f2021-02-12 17:16:42 +0000610 auto nullCallback = [](V1_0::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Derek Lamberti4de83c52020-03-17 13:40:18 +0000611 CallbackContext_1_2 callbackContext;
612 callbackContext.callback = nullCallback;
Sadik Armagan188675f2021-02-12 17:16:42 +0000613 callbackContext.ctx.measureTimings = V1_2::MeasureTiming::NO;
Derek Lamberti4de83c52020-03-17 13:40:18 +0000614 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
615 return ExecuteGraph(memPools,
616 inputTensors,
617 outputTensors,
618 callbackContext);
619}
620
621template<typename HalVersion>
622Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::Execute(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000623 V1_2::MeasureTiming measureTiming,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000624 CallbackAsync_1_2 callback)
625{
626 ExecutionContext_1_2 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000627 if (measureTiming == V1_2::MeasureTiming::YES)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000628 {
629 ctx.measureTimings = measureTiming;
630 ctx.driverStart = Now();
631 }
632
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100633 if (!m_PreparedFromCache)
634 {
635 ALOGV("ArmnnPreparedModel_1_2::execute(): %s", GetModelSummary(m_Model).c_str());
636 }
Derek Lamberti4de83c52020-03-17 13:40:18 +0000637 m_RequestCount++;
638
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100639 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Derek Lamberti4de83c52020-03-17 13:40:18 +0000640 {
641 callback(V1_0::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
642 return V1_0::ErrorStatus::INVALID_ARGUMENT;
643 }
644
645 if (!m_RequestInputsAndOutputsDumpDir.empty())
646 {
647 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
648 }
649
650 // map the memory pool into shared pointers
651 // use a shared memory pools vector on the heap, as it is passed to the request thread
652 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
653
654 // allocate the tensors on the heap, as they are passed to the request thread
655 auto inputTensors = std::make_shared<armnn::InputTensors>();
656 auto outputTensors = std::make_shared<armnn::OutputTensors>();
657
658 auto prepareStatus = PrepareMemoryForIO(*inputTensors, *outputTensors, *memPools, request, callback);
659 switch(prepareStatus)
660 {
661 case V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
662 return V1_0::ErrorStatus::NONE;
663 case V1_0::ErrorStatus::GENERAL_FAILURE:
664 return V1_0::ErrorStatus::GENERAL_FAILURE;
665 default:
666 {}
667 }
668
Derek Lamberti4de83c52020-03-17 13:40:18 +0000669
670 // post the request for asynchronous execution
671 CallbackContext_1_2 cb;
672 cb.callback = callback;
673 cb.ctx = ctx;
Finn Williamsd8fb5402021-05-19 20:52:00 +0100674
675 if (m_AsyncModelExecutionEnabled)
676 {
677 ALOGV("ArmnnPreparedModel_1_2::execute(...) before ScheduleGraphForExecution");
678 ScheduleGraphForExecution(memPools, inputTensors, outputTensors, cb);
679 ALOGV("ArmnnPreparedModel_1_2::execute(...) after ScheduleGraphForExecution");
680 return V1_0::ErrorStatus::NONE;
681 }
682
683 ALOGV("ArmnnPreparedModel_1_2::execute(...) before PostMsg");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000684 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
685 ALOGV("ArmnnPreparedModel_1_2::execute(...) after PostMsg");
686 return V1_0::ErrorStatus::NONE;
687}
688
Mike Kellyb5fdf382019-06-11 16:35:25 +0100689template<typename HalVersion>
690Return<void> ArmnnPreparedModel_1_2<HalVersion>::configureExecutionBurst(
Derek Lamberti4de83c52020-03-17 13:40:18 +0000691 const sp<V1_2::IBurstCallback>& callback,
692 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
693 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
694 V1_2::IPreparedModel::configureExecutionBurst_cb cb)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100695{
696 ALOGV("ArmnnPreparedModel_1_2::configureExecutionBurst");
Mike Kelly65c42dc2019-07-22 14:06:00 +0100697 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
698 requestChannel,
699 resultChannel,
Kevin May42477c12020-03-26 13:34:14 +0000700 this);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100701
Mike Kelly44381512019-07-08 17:37:35 +0100702 if (burst == nullptr)
703 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000704 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
Mike Kelly44381512019-07-08 17:37:35 +0100705 }
706 else
707 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000708 cb(V1_0::ErrorStatus::NONE, burst);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100709 }
710 return Void();
711}
712
Finn Williamsd8fb5402021-05-19 20:52:00 +0100713/// Schedule the graph prepared from the request for execution
714template<typename HalVersion>
715template<typename CallbackContext>
716void ArmnnPreparedModel_1_2<HalVersion>::ScheduleGraphForExecution(
717 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
718 std::shared_ptr<armnn::InputTensors>& inputTensors,
719 std::shared_ptr<armnn::OutputTensors>& outputTensors,
720 CallbackContext callbackContext)
721{
722 ALOGV("ArmnnPreparedModel_1_2::ScheduleGraphForExecution(...)");
723
724 DumpTensorsIfRequired("Input", *inputTensors);
725
726 unsigned int outputTensorSize = outputTensors.get()->size();
727 std::vector<V1_2::OutputShape> outputShapes(outputTensorSize);
728 for (unsigned int i = 0; i < outputTensorSize; i++)
729 {
730 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors.get()->at(i);
731 const armnn::Tensor outputTensor = outputTensorPair.second;
732 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
733
734 outputShapes[i] = ComputeShape(outputTensorInfo);
735 }
736
737 auto tpCb = std::make_shared<
738 ArmnnThreadPoolCallback_1_2<CallbackContext_1_2>>(this,
739 pMemPools,
740 outputShapes,
741 inputTensors,
742 outputTensors,
743 callbackContext);
744
Finn Williamsca3a3e02021-06-11 15:04:02 +0100745 m_Threadpool->Schedule(m_NetworkId,
746 *tpCb->m_InputTensors,
747 *tpCb->m_OutputTensors,
748 armnn::QosExecPriority::Medium,
749 tpCb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100750 ALOGV("ArmnnPreparedModel_1_2::ScheduleGraphForExecution end");
751}
752
753template<typename HalVersion>
754template <typename CallbackContext>
755void ArmnnPreparedModel_1_2<HalVersion>::ArmnnThreadPoolCallback_1_2<CallbackContext>::Notify(
756 armnn::Status status, armnn::InferenceTimingPair timeTaken)
757{
758 ALOGV("ArmnnPreparedModel_1_2::ArmnnThreadPoolCallback_1_2 Notify");
759
760 TimePoint driverEnd;
761
762 CommitPools(*m_MemPools);
763
764 m_Model->DumpTensorsIfRequired("Output", *m_OutputTensors);
765
766 if (status != armnn::Status::Success)
767 {
768 ALOGW("ArmnnThreadPoolCallback::Notify EnqueueWorkload failed");
769 m_CallbackContext.callback(
770 V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel::ExecuteGraph");
771 return;
772 }
773
774 if (m_CallbackContext.ctx.measureTimings == V1_2::MeasureTiming::YES)
775 {
776 driverEnd = std::chrono::steady_clock::now();
777 V1_2::Timing timing;
778 timing.timeOnDevice = MicrosecondsDuration(timeTaken.second, timeTaken.first);
779 timing.timeInDriver = MicrosecondsDuration(driverEnd, m_CallbackContext.ctx.driverStart);
Zingo Andersen7c561492022-01-25 11:09:41 +0100780 ALOGV("ArmnnPreparedModel_1_2::execute timing - Device = %lu Driver = %lu",
781 static_cast<unsigned long>(timing.timeOnDevice), static_cast<unsigned long>(timing.timeInDriver));
Finn Williamsd8fb5402021-05-19 20:52:00 +0100782 m_CallbackContext.callback(
783 V1_0::ErrorStatus::NONE, m_OutputShapes, timing, "ArmnnPreparedModel_1_2::ExecuteGraph");
784 } else {
785 m_CallbackContext.callback(
786 V1_0::ErrorStatus::NONE, m_OutputShapes, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
787 }
788 return;
789}
790
Kevin May42477c12020-03-26 13:34:14 +0000791#if defined(ARMNN_ANDROID_NN_V1_2) || defined(ARMNN_ANDROID_NN_V1_3)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100792template class ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>;
Derek Lamberti4de83c52020-03-17 13:40:18 +0000793template bool ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>::ExecuteGraph<CallbackContext_1_2>(
794 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
795 armnn::InputTensors& pInputTensors,
796 armnn::OutputTensors& pOutputTensors,
797 CallbackContext_1_2 cb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100798
799template void ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>::ScheduleGraphForExecution<CallbackContext_1_2>(
800 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
801 std::shared_ptr<armnn::InputTensors>& inputTensors,
802 std::shared_ptr<armnn::OutputTensors>& outputTensors,
803 CallbackContext_1_2 callbackContext);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100804#endif
805
806} // namespace armnn_driver