blob: 5a10d546f58327c74f1610f5fa0f88f88f6ebd3d [file] [log] [blame]
Mike Kellyb5fdf382019-06-11 16:35:25 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// 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
17#include <cassert>
18#include <cinttypes>
19
Sadik Armagan188675f2021-02-12 17:16:42 +000020#ifdef ARMNN_ANDROID_S
21#include <LegacyUtils.h>
22#endif
23
Mike Kellyb5fdf382019-06-11 16:35:25 +010024using namespace android;
25using namespace android::hardware;
26
Mike Kellyb5fdf382019-06-11 16:35:25 +010027namespace {
28
Sadik Armagan188675f2021-02-12 17:16:42 +000029static const V1_2::Timing g_NoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX};
Mike Kellyb5fdf382019-06-11 16:35:25 +010030using namespace armnn_driver;
Mike Kelly44381512019-07-08 17:37:35 +010031using TimePoint = std::chrono::steady_clock::time_point;
32
33TimePoint Now()
34{
35 return std::chrono::steady_clock::now();
36}
37
38unsigned long MicrosecondsDuration(TimePoint endPoint, TimePoint startPoint)
39{
40 return static_cast<unsigned long>(std::chrono::duration_cast<std::chrono::microseconds>(
41 endPoint - startPoint).count());
42}
Mike Kellyb5fdf382019-06-11 16:35:25 +010043
Mike Kelly65c42dc2019-07-22 14:06:00 +010044void NotifyCallbackAndCheck(const ::android::sp<V1_0::IExecutionCallback>& callback,
Kevin Mayec1e5b82020-02-26 17:00:39 +000045 V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000046 std::vector<V1_2::OutputShape>,
47 const V1_2::Timing,
Mike Kellyb5fdf382019-06-11 16:35:25 +010048 std::string callingFunction)
49{
50 Return<void> returned = callback->notify(errorStatus);
51 // This check is required, if the callback fails and it isn't checked it will bring down the service
52 if (!returned.isOk())
53 {
54 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
55 callingFunction.c_str(), returned.description().c_str());
56 }
57}
58
Mike Kelly65c42dc2019-07-22 14:06:00 +010059void NotifyCallbackAndCheck(const ::android::sp<V1_2::IExecutionCallback>& callback,
Kevin Mayec1e5b82020-02-26 17:00:39 +000060 V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000061 std::vector<V1_2::OutputShape> outputShapes,
62 const V1_2::Timing timing,
Mike Kellyb5fdf382019-06-11 16:35:25 +010063 std::string callingFunction)
64{
Mike Kelly65c42dc2019-07-22 14:06:00 +010065 Return<void> returned = callback->notify_1_2(errorStatus, outputShapes, timing);
Mike Kellyb5fdf382019-06-11 16:35:25 +010066 // This check is required, if the callback fails and it isn't checked it will bring down the service
67 if (!returned.isOk())
68 {
69 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
70 callingFunction.c_str(), returned.description().c_str());
71 }
72}
73
Sadik Armagan188675f2021-02-12 17:16:42 +000074bool ValidateRequestArgument(const V1_0::RequestArgument& requestArg, const armnn::TensorInfo& tensorInfo)
Mike Kellyb5fdf382019-06-11 16:35:25 +010075{
76 if (requestArg.dimensions.size() != 0)
77 {
78 if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
79 {
80 ALOGE("Mismatched dimensions (request argument: %zu, expected: %u)",
81 requestArg.dimensions.size(), tensorInfo.GetNumDimensions());
82 return false;
83 }
84
85 for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
86 {
Finn Williamsa4983ce2020-07-23 12:55:12 +010087 if (requestArg.dimensions[d] != 0 && requestArg.dimensions[d] != tensorInfo.GetShape()[d])
Mike Kellyb5fdf382019-06-11 16:35:25 +010088 {
89 ALOGE("Mismatched size for dimension %d (request argument: %u, expected %u)",
90 d, requestArg.dimensions[d], tensorInfo.GetShape()[d]);
91 return false;
92 }
93 }
94 }
95
96 return true;
97}
98
Sadik Armagan188675f2021-02-12 17:16:42 +000099armnn::Tensor GetTensorForRequestArgument(const V1_0::RequestArgument& requestArg,
Mike Kellyb5fdf382019-06-11 16:35:25 +0100100 const armnn::TensorInfo& tensorInfo,
101 const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
102{
103 if (!ValidateRequestArgument(requestArg, tensorInfo))
104 {
105 return armnn::Tensor();
106 }
107
108 return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
109}
110
111inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
112{
113 return tensorNamePrefix + std::to_string(index);
114}
115
116} // anonymous namespace
117
118using namespace android::hardware;
119
120namespace armnn_driver
121{
122
123template<typename HalVersion>
Derek Lamberti4de83c52020-03-17 13:40:18 +0000124RequestThread<ArmnnPreparedModel_1_2, HalVersion, CallbackContext_1_2>
Mike Kelly65c42dc2019-07-22 14:06:00 +0100125 ArmnnPreparedModel_1_2<HalVersion>::m_RequestThread;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100126
127template<typename HalVersion>
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100128std::unique_ptr<armnn::Threadpool> ArmnnPreparedModel_1_2<HalVersion>::m_Threadpool(nullptr);
129
130template<typename HalVersion>
Mike Kellyb5fdf382019-06-11 16:35:25 +0100131template<typename TensorBindingCollection>
132void ArmnnPreparedModel_1_2<HalVersion>::DumpTensorsIfRequired(char const* tensorNamePrefix,
133 const TensorBindingCollection& tensorBindings)
134{
135 if (!m_RequestInputsAndOutputsDumpDir.empty())
136 {
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100137 const std::string requestName = std::to_string(m_NetworkId) + "_" + std::to_string(m_RequestCount) + ".dump";
Mike Kellyb5fdf382019-06-11 16:35:25 +0100138 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
139 {
140 DumpTensor(m_RequestInputsAndOutputsDumpDir,
141 requestName,
142 BuildTensorName(tensorNamePrefix, i),
143 tensorBindings[i].second);
144 }
145 }
146}
147
148template<typename HalVersion>
149ArmnnPreparedModel_1_2<HalVersion>::ArmnnPreparedModel_1_2(armnn::NetworkId networkId,
150 armnn::IRuntime* runtime,
151 const V1_2::Model& model,
152 const std::string& requestInputsAndOutputsDumpDir,
Finn Williamsd8fb5402021-05-19 20:52:00 +0100153 const bool gpuProfilingEnabled,
Finn Williamsca3a3e02021-06-11 15:04:02 +0100154 const bool asyncModelExecutionEnabled,
155 const unsigned int numberOfThreads)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100156 : m_NetworkId(networkId)
157 , m_Runtime(runtime)
158 , m_Model(model)
159 , m_RequestCount(0)
160 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
161 , m_GpuProfilingEnabled(gpuProfilingEnabled)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100162 , m_AsyncModelExecutionEnabled(asyncModelExecutionEnabled)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100163{
164 // Enable profiling if required.
165 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100166
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100167 if (m_AsyncModelExecutionEnabled)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100168 {
Finn Williamsca3a3e02021-06-11 15:04:02 +0100169 std::vector<std::shared_ptr<armnn::IWorkingMemHandle>> memHandles;
Finn Williamsd27c13b2021-06-25 10:06:09 +0100170 for (unsigned int i=0; i < numberOfThreads; ++i)
Finn Williamsca3a3e02021-06-11 15:04:02 +0100171 {
172 memHandles.emplace_back(m_Runtime->CreateWorkingMemHandle(networkId));
173 }
174
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100175 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
Finn Williamsca3a3e02021-06-11 15:04:02 +0100184 m_WorkingMemHandle = memHandles.back();
Finn Williamsd8fb5402021-05-19 20:52:00 +0100185 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100186}
187
188template<typename HalVersion>
189ArmnnPreparedModel_1_2<HalVersion>::~ArmnnPreparedModel_1_2()
190{
191 // Get a hold of the profiler used by this model.
192 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
193
194 // Unload the network associated with this model.
195 m_Runtime->UnloadNetwork(m_NetworkId);
196
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100197 // Unload the network memhandles from the threadpool
198 if (m_AsyncModelExecutionEnabled)
199 {
200 m_Threadpool->UnloadMemHandles(m_NetworkId);
201 }
202
Mike Kellyb5fdf382019-06-11 16:35:25 +0100203 // Dump the profiling info to a file if required.
204 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId, profiler.get());
205}
206
207template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000208Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::execute(const V1_0::Request& request,
Mike Kellyb5fdf382019-06-11 16:35:25 +0100209 const ::android::sp<V1_0::IExecutionCallback>& callback)
210{
Mike Kelly65c42dc2019-07-22 14:06:00 +0100211 if (callback.get() == nullptr)
212 {
213 ALOGE("ArmnnPreparedModel_1_2::execute invalid callback passed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000214 return V1_0::ErrorStatus::INVALID_ARGUMENT;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100215 }
216
Kevin Mayec1e5b82020-02-26 17:00:39 +0000217 auto cb = [callback](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000218 std::vector<V1_2::OutputShape> outputShapes,
219 const V1_2::Timing& timing,
Mike Kelly65c42dc2019-07-22 14:06:00 +0100220 std::string callingFunction)
221 {
222 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
223 };
224
Sadik Armagan188675f2021-02-12 17:16:42 +0000225 return Execute(request, V1_2::MeasureTiming::NO, cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100226}
227
228template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000229Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::execute_1_2(
230 const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000231 V1_2::MeasureTiming measureTiming,
Kevin Mayec1e5b82020-02-26 17:00:39 +0000232 const sp<V1_2::IExecutionCallback>& callback)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100233{
Mike Kelly65c42dc2019-07-22 14:06:00 +0100234 if (callback.get() == nullptr)
235 {
236 ALOGE("ArmnnPreparedModel_1_2::execute_1_2 invalid callback passed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000237 return V1_0::ErrorStatus::INVALID_ARGUMENT;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100238 }
239
Kevin Mayec1e5b82020-02-26 17:00:39 +0000240 auto cb = [callback](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000241 std::vector<V1_2::OutputShape> outputShapes,
242 const V1_2::Timing& timing,
Mike Kelly65c42dc2019-07-22 14:06:00 +0100243 std::string callingFunction)
244 {
245 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
246 };
247
248 return Execute(request, measureTiming, cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100249}
250
Derek Lamberti4de83c52020-03-17 13:40:18 +0000251template<typename HalVersion>
252Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForInputs(
253 armnn::InputTensors& inputs,
254 const V1_0::Request& request,
255 const std::vector<android::nn::RunTimePoolInfo>& memPools)
256{
257 inputs.reserve(request.inputs.size());
258 for (unsigned int i = 0; i < request.inputs.size(); i++)
259 {
260 const auto& inputArg = request.inputs[i];
261
262 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
263 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
264
265 if (inputTensor.GetMemoryArea() == nullptr)
266 {
267 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
268 return V1_0::ErrorStatus::GENERAL_FAILURE;
269 }
270
271 inputs.emplace_back(i, inputTensor);
272 }
273
274 return V1_0::ErrorStatus::NONE;
275}
276
277template<typename HalVersion>
278Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForOutputs(
279 armnn::OutputTensors& outputs,
Sadik Armagan188675f2021-02-12 17:16:42 +0000280 std::vector<V1_2::OutputShape> &outputShapes,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000281 const V1_0::Request& request,
282 const std::vector<android::nn::RunTimePoolInfo>& memPools)
283{
284 outputs.reserve(request.outputs.size());
285 for (unsigned int i = 0; i < request.outputs.size(); i++)
286 {
287 const auto& outputArg = request.outputs[i];
288
289 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
290 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
291 if (outputTensor.GetMemoryArea() == nullptr)
292 {
293 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
294 return V1_0::ErrorStatus::GENERAL_FAILURE;
295 }
296
297 const size_t outputSize = outputTensorInfo.GetNumBytes();
Finn Williamsa4983ce2020-07-23 12:55:12 +0100298
299 if (outputArg.location.length < outputSize)
300 {
301 ALOGW("ArmnnPreparedModel_1_2::Execute failed: outputArg.location.length < outputSize");
302 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
303 }
304
Sadik Armagan188675f2021-02-12 17:16:42 +0000305#if !defined(ARMNN_ANDROID_S)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000306 const size_t bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
307 if (bufferSize < outputSize)
308 {
Finn Williamsa4983ce2020-07-23 12:55:12 +0100309 ALOGW("ArmnnPreparedModel_1_2::Execute failed: bufferSize < outputSize");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000310 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
311 }
Sadik Armagan188675f2021-02-12 17:16:42 +0000312#else
Kevin Maydc873f62021-06-14 11:21:11 +0100313 const size_t bufferSize = memPools.at(outputArg.location.poolIndex).getSize();
Sadik Armagan188675f2021-02-12 17:16:42 +0000314 if (bufferSize < outputSize)
315 {
316 ALOGW("ArmnnPreparedModel_1_2::Execute failed bufferSize (%s) < outputSize (%s)",
317 std::to_string(bufferSize).c_str(), std::to_string(outputSize).c_str());
318 outputShapes[i].isSufficient = false;
319 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
320 }
321#endif
Derek Lamberti4de83c52020-03-17 13:40:18 +0000322 outputs.emplace_back(i, outputTensor);
323 outputShapes[i] = ComputeShape(outputTensorInfo);
324 }
325
326 return V1_0::ErrorStatus::NONE;
327}
328
329template<typename HalVersion>
330Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForIO(
331 armnn::InputTensors& inputs,
332 armnn::OutputTensors& outputs,
333 std::vector<android::nn::RunTimePoolInfo>& memPools,
334 const V1_0::Request& request,
335 CallbackAsync_1_2 callback)
336{
Sadik Armagan188675f2021-02-12 17:16:42 +0000337#if !defined(ARMNN_ANDROID_S)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000338 if (!setRunTimePoolInfosFromHidlMemories(&memPools, request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000339#else
340 if (!setRunTimePoolInfosFromCanonicalMemories(&memPools, uncheckedConvert(request.pools)))
341#endif
Derek Lamberti4de83c52020-03-17 13:40:18 +0000342 {
343 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
344 return V1_0::ErrorStatus::GENERAL_FAILURE;
345 }
Derek Lamberti4de83c52020-03-17 13:40:18 +0000346 // add the inputs and outputs with their data
347 try
348 {
349 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_0::ErrorStatus::NONE)
350 {
351 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
352 return V1_0::ErrorStatus::GENERAL_FAILURE;
353 }
354
Sadik Armagan188675f2021-02-12 17:16:42 +0000355 std::vector<V1_2::OutputShape> outputShapes(request.outputs.size());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000356
357 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
358 if (errorStatus != V1_0::ErrorStatus::NONE)
359 {
360 callback(errorStatus,
361 outputShapes,
362 g_NoTiming,
363 "ArmnnPreparedModel_1_2::Execute");
364 return errorStatus;
365 }
366 }
367 catch (armnn::Exception& e)
368 {
369 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
370 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
371 return V1_0::ErrorStatus::GENERAL_FAILURE;
372 }
373 catch (std::exception& e)
374 {
375 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
376 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
377 return V1_0::ErrorStatus::GENERAL_FAILURE;
378 }
379
380 return V1_0::ErrorStatus::NONE;
381}
382
Mike Kellyb5fdf382019-06-11 16:35:25 +0100383template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000384Return<void> ArmnnPreparedModel_1_2<HalVersion>::executeSynchronously(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000385 V1_2::MeasureTiming measureTiming,
Mike Kelly44381512019-07-08 17:37:35 +0100386 executeSynchronously_cb cb)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100387{
388 ALOGV("ArmnnPreparedModel_1_2::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
389 m_RequestCount++;
390
391 if (cb == nullptr)
392 {
393 ALOGE("ArmnnPreparedModel_1_2::executeSynchronously invalid callback passed");
394 return Void();
395 }
396
Derek Lamberti4de83c52020-03-17 13:40:18 +0000397 TimePoint driverStart;
Mike Kelly44381512019-07-08 17:37:35 +0100398
Sadik Armagan188675f2021-02-12 17:16:42 +0000399 if (measureTiming == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100400 {
401 driverStart = Now();
402 }
403
Mike Kellyb5fdf382019-06-11 16:35:25 +0100404 if (!android::nn::validateRequest(request, m_Model))
405 {
Mike Kelly44381512019-07-08 17:37:35 +0100406 ALOGE("ArmnnPreparedModel_1_2::executeSynchronously invalid request model");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000407 cb(V1_0::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100408 return Void();
409 }
410
Derek Lamberti4de83c52020-03-17 13:40:18 +0000411 auto cbWrapper = [cb](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000412 std::vector<V1_2::OutputShape> outputShapes,
413 const V1_2::Timing& timing,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000414 std::string)
415 {
416 cb(errorStatus, outputShapes, timing);
417 };
Mike Kellyb5fdf382019-06-11 16:35:25 +0100418
419 // map the memory pool into shared pointers
420 // use a shared memory pools vector on the heap, as it is passed to the request thread
Derek Lamberti4de83c52020-03-17 13:40:18 +0000421 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
Mike Kellyb5fdf382019-06-11 16:35:25 +0100422
Derek Lamberti4de83c52020-03-17 13:40:18 +0000423 // allocate the tensors on the heap, as they are passed to the request thread
424 auto inputs = std::make_shared<armnn::InputTensors>();
425 auto outputs = std::make_shared<armnn::OutputTensors>();
426
427 auto prepareStatus = PrepareMemoryForIO(*inputs, *outputs, *memPools, request, cbWrapper);
428 if (prepareStatus != V1_0::ErrorStatus::NONE)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100429 {
Kevin May7bdaac52020-02-10 12:10:07 +0000430 return Void();
431 }
432
Mike Kellyb5fdf382019-06-11 16:35:25 +0100433 ALOGV("ArmnnPreparedModel_1_2::executeSynchronously() before Execution");
434
Derek Lamberti4de83c52020-03-17 13:40:18 +0000435 CallbackContext_1_2 cbCtx;
436 cbCtx.callback = cbWrapper;
437 cbCtx.ctx.measureTimings = measureTiming;
438 cbCtx.ctx.driverStart = driverStart;
439 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
440
441 return Void();
442}
443
444template<typename HalVersion>
445template<typename CallbackContext>
446bool ArmnnPreparedModel_1_2<HalVersion>::ExecuteGraph(
447 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
448 armnn::InputTensors& inputTensors,
449 armnn::OutputTensors& outputTensors,
450 CallbackContext cb)
451{
452 ALOGV("ArmnnPreparedModel_1_2::ExecuteGraph(...)");
453
454 TimePoint driverEnd, deviceStart, deviceEnd;
455
456 DumpTensorsIfRequired("Input", inputTensors);
457
Sadik Armagan188675f2021-02-12 17:16:42 +0000458 std::vector<V1_2::OutputShape> outputShapes(outputTensors.size());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000459 for (unsigned int i = 0; i < outputTensors.size(); i++)
460 {
461 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
462 const armnn::Tensor outputTensor = outputTensorPair.second;
463 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
464
465 outputShapes[i] = ComputeShape(outputTensorInfo);
466 }
467
Mike Kellyb5fdf382019-06-11 16:35:25 +0100468 // run it
469 try
470 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000471 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100472 {
473 deviceStart = Now();
474 }
475
Finn Williamsd8fb5402021-05-19 20:52:00 +0100476 armnn::Status status;
477 if (m_AsyncModelExecutionEnabled)
478 {
479 ALOGW("ArmnnPreparedModel_1_2::ExecuteGraph m_AsyncModelExecutionEnabled true");
480 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
481 }
482 else
483 {
484 ALOGW("ArmnnPreparedModel_1_2::ExecuteGraph m_AsyncModelExecutionEnabled false");
485 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
486 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100487
Sadik Armagan188675f2021-02-12 17:16:42 +0000488 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100489 {
490 deviceEnd = Now();
491 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100492 if (status != armnn::Status::Success)
493 {
494 ALOGW("EnqueueWorkload failed");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000495 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming,
496 "ArmnnPreparedModel_1_2::ExecuteGraph");
497 return false;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100498 }
499 }
Kevin May7bdaac52020-02-10 12:10:07 +0000500 catch (armnn::Exception& e)
501 {
Derek Lamberti4de83c52020-03-17 13:40:18 +0000502 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
503 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
504 return false;
Kevin May7bdaac52020-02-10 12:10:07 +0000505 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000506 catch (std::exception& e)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100507 {
Kevin May7bdaac52020-02-10 12:10:07 +0000508 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000509 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
510 return false;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100511 }
512
Derek Lamberti4de83c52020-03-17 13:40:18 +0000513 CommitPools(*pMemPools);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100514
Derek Lamberti4de83c52020-03-17 13:40:18 +0000515 DumpTensorsIfRequired("Output", outputTensors);
Kevin Mayec1e5b82020-02-26 17:00:39 +0000516
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 driverEnd = Now();
Sadik Armagan188675f2021-02-12 17:16:42 +0000520 V1_2::Timing timing;
Mike Kelly44381512019-07-08 17:37:35 +0100521 timing.timeOnDevice = MicrosecondsDuration(deviceEnd, deviceStart);
Derek Lamberti4de83c52020-03-17 13:40:18 +0000522 timing.timeInDriver = MicrosecondsDuration(driverEnd, cb.ctx.driverStart);
523 ALOGV("ArmnnPreparedModel_1_2::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
524 timing.timeInDriver);
525 cb.callback(V1_0::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_2::ExecuteGraph");
526 } else {
527 cb.callback(V1_0::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
Mike Kelly44381512019-07-08 17:37:35 +0100528 }
Derek Lamberti4de83c52020-03-17 13:40:18 +0000529
530 return true;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100531}
532
Derek Lamberti4de83c52020-03-17 13:40:18 +0000533template<typename HalVersion>
534bool ArmnnPreparedModel_1_2<HalVersion>::ExecuteWithDummyInputs()
535{
536 std::vector<std::vector<char>> storage;
537 armnn::InputTensors inputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000538 for (unsigned int i = 0; i < getMainModel(m_Model).inputIndexes.size(); i++)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000539 {
540 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
541 storage.emplace_back(inputTensorInfo.GetNumBytes());
542 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
543
544 inputTensors.emplace_back(i, inputTensor);
545 }
546
547 armnn::OutputTensors outputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000548 for (unsigned int i = 0; i < getMainModel(m_Model).outputIndexes.size(); i++)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000549 {
550 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
551 storage.emplace_back(outputTensorInfo.GetNumBytes());
552 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
553
554 outputTensors.emplace_back(i, outputTensor);
555 }
556
Sadik Armagan188675f2021-02-12 17:16:42 +0000557 auto nullCallback = [](V1_0::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Derek Lamberti4de83c52020-03-17 13:40:18 +0000558 CallbackContext_1_2 callbackContext;
559 callbackContext.callback = nullCallback;
Sadik Armagan188675f2021-02-12 17:16:42 +0000560 callbackContext.ctx.measureTimings = V1_2::MeasureTiming::NO;
Derek Lamberti4de83c52020-03-17 13:40:18 +0000561 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
562 return ExecuteGraph(memPools,
563 inputTensors,
564 outputTensors,
565 callbackContext);
566}
567
568template<typename HalVersion>
569Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::Execute(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000570 V1_2::MeasureTiming measureTiming,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000571 CallbackAsync_1_2 callback)
572{
573 ExecutionContext_1_2 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000574 if (measureTiming == V1_2::MeasureTiming::YES)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000575 {
576 ctx.measureTimings = measureTiming;
577 ctx.driverStart = Now();
578 }
579
580 ALOGV("ArmnnPreparedModel_1_2::execute(): %s", GetModelSummary(m_Model).c_str());
581 m_RequestCount++;
582
583 if (!android::nn::validateRequest(request, m_Model))
584 {
585 callback(V1_0::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
586 return V1_0::ErrorStatus::INVALID_ARGUMENT;
587 }
588
589 if (!m_RequestInputsAndOutputsDumpDir.empty())
590 {
591 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
592 }
593
594 // map the memory pool into shared pointers
595 // use a shared memory pools vector on the heap, as it is passed to the request thread
596 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
597
598 // allocate the tensors on the heap, as they are passed to the request thread
599 auto inputTensors = std::make_shared<armnn::InputTensors>();
600 auto outputTensors = std::make_shared<armnn::OutputTensors>();
601
602 auto prepareStatus = PrepareMemoryForIO(*inputTensors, *outputTensors, *memPools, request, callback);
603 switch(prepareStatus)
604 {
605 case V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
606 return V1_0::ErrorStatus::NONE;
607 case V1_0::ErrorStatus::GENERAL_FAILURE:
608 return V1_0::ErrorStatus::GENERAL_FAILURE;
609 default:
610 {}
611 }
612
Derek Lamberti4de83c52020-03-17 13:40:18 +0000613
614 // post the request for asynchronous execution
615 CallbackContext_1_2 cb;
616 cb.callback = callback;
617 cb.ctx = ctx;
Finn Williamsd8fb5402021-05-19 20:52:00 +0100618
619 if (m_AsyncModelExecutionEnabled)
620 {
621 ALOGV("ArmnnPreparedModel_1_2::execute(...) before ScheduleGraphForExecution");
622 ScheduleGraphForExecution(memPools, inputTensors, outputTensors, cb);
623 ALOGV("ArmnnPreparedModel_1_2::execute(...) after ScheduleGraphForExecution");
624 return V1_0::ErrorStatus::NONE;
625 }
626
627 ALOGV("ArmnnPreparedModel_1_2::execute(...) before PostMsg");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000628 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
629 ALOGV("ArmnnPreparedModel_1_2::execute(...) after PostMsg");
630 return V1_0::ErrorStatus::NONE;
631}
632
Mike Kellyb5fdf382019-06-11 16:35:25 +0100633template<typename HalVersion>
634Return<void> ArmnnPreparedModel_1_2<HalVersion>::configureExecutionBurst(
Derek Lamberti4de83c52020-03-17 13:40:18 +0000635 const sp<V1_2::IBurstCallback>& callback,
636 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
637 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
638 V1_2::IPreparedModel::configureExecutionBurst_cb cb)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100639{
640 ALOGV("ArmnnPreparedModel_1_2::configureExecutionBurst");
Mike Kelly65c42dc2019-07-22 14:06:00 +0100641 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
642 requestChannel,
643 resultChannel,
Kevin May42477c12020-03-26 13:34:14 +0000644 this);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100645
Mike Kelly44381512019-07-08 17:37:35 +0100646 if (burst == nullptr)
647 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000648 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
Mike Kelly44381512019-07-08 17:37:35 +0100649 }
650 else
651 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000652 cb(V1_0::ErrorStatus::NONE, burst);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100653 }
654 return Void();
655}
656
Finn Williamsd8fb5402021-05-19 20:52:00 +0100657/// Schedule the graph prepared from the request for execution
658template<typename HalVersion>
659template<typename CallbackContext>
660void ArmnnPreparedModel_1_2<HalVersion>::ScheduleGraphForExecution(
661 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
662 std::shared_ptr<armnn::InputTensors>& inputTensors,
663 std::shared_ptr<armnn::OutputTensors>& outputTensors,
664 CallbackContext callbackContext)
665{
666 ALOGV("ArmnnPreparedModel_1_2::ScheduleGraphForExecution(...)");
667
668 DumpTensorsIfRequired("Input", *inputTensors);
669
670 unsigned int outputTensorSize = outputTensors.get()->size();
671 std::vector<V1_2::OutputShape> outputShapes(outputTensorSize);
672 for (unsigned int i = 0; i < outputTensorSize; i++)
673 {
674 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors.get()->at(i);
675 const armnn::Tensor outputTensor = outputTensorPair.second;
676 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
677
678 outputShapes[i] = ComputeShape(outputTensorInfo);
679 }
680
681 auto tpCb = std::make_shared<
682 ArmnnThreadPoolCallback_1_2<CallbackContext_1_2>>(this,
683 pMemPools,
684 outputShapes,
685 inputTensors,
686 outputTensors,
687 callbackContext);
688
Finn Williamsca3a3e02021-06-11 15:04:02 +0100689 m_Threadpool->Schedule(m_NetworkId,
690 *tpCb->m_InputTensors,
691 *tpCb->m_OutputTensors,
692 armnn::QosExecPriority::Medium,
693 tpCb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100694 ALOGV("ArmnnPreparedModel_1_2::ScheduleGraphForExecution end");
695}
696
697template<typename HalVersion>
698template <typename CallbackContext>
699void ArmnnPreparedModel_1_2<HalVersion>::ArmnnThreadPoolCallback_1_2<CallbackContext>::Notify(
700 armnn::Status status, armnn::InferenceTimingPair timeTaken)
701{
702 ALOGV("ArmnnPreparedModel_1_2::ArmnnThreadPoolCallback_1_2 Notify");
703
704 TimePoint driverEnd;
705
706 CommitPools(*m_MemPools);
707
708 m_Model->DumpTensorsIfRequired("Output", *m_OutputTensors);
709
710 if (status != armnn::Status::Success)
711 {
712 ALOGW("ArmnnThreadPoolCallback::Notify EnqueueWorkload failed");
713 m_CallbackContext.callback(
714 V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel::ExecuteGraph");
715 return;
716 }
717
718 if (m_CallbackContext.ctx.measureTimings == V1_2::MeasureTiming::YES)
719 {
720 driverEnd = std::chrono::steady_clock::now();
721 V1_2::Timing timing;
722 timing.timeOnDevice = MicrosecondsDuration(timeTaken.second, timeTaken.first);
723 timing.timeInDriver = MicrosecondsDuration(driverEnd, m_CallbackContext.ctx.driverStart);
724 ALOGV("ArmnnPreparedModel_1_2::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
725 timing.timeInDriver);
726 m_CallbackContext.callback(
727 V1_0::ErrorStatus::NONE, m_OutputShapes, timing, "ArmnnPreparedModel_1_2::ExecuteGraph");
728 } else {
729 m_CallbackContext.callback(
730 V1_0::ErrorStatus::NONE, m_OutputShapes, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
731 }
732 return;
733}
734
Kevin May42477c12020-03-26 13:34:14 +0000735#if defined(ARMNN_ANDROID_NN_V1_2) || defined(ARMNN_ANDROID_NN_V1_3)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100736template class ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>;
Derek Lamberti4de83c52020-03-17 13:40:18 +0000737template bool ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>::ExecuteGraph<CallbackContext_1_2>(
738 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
739 armnn::InputTensors& pInputTensors,
740 armnn::OutputTensors& pOutputTensors,
741 CallbackContext_1_2 cb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100742
743template void ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>::ScheduleGraphForExecution<CallbackContext_1_2>(
744 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
745 std::shared_ptr<armnn::InputTensors>& inputTensors,
746 std::shared_ptr<armnn::OutputTensors>& outputTensors,
747 CallbackContext_1_2 callbackContext);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100748#endif
749
750} // namespace armnn_driver