blob: 2e37880156d0a2237dd1dd68cd039a22c897b869 [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)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100162{
163 // Enable profiling if required.
164 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100165
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100166 if (m_AsyncModelExecutionEnabled)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100167 {
Finn Williamsca3a3e02021-06-11 15:04:02 +0100168 std::vector<std::shared_ptr<armnn::IWorkingMemHandle>> memHandles;
Finn Williamsd27c13b2021-06-25 10:06:09 +0100169 for (unsigned int i=0; i < numberOfThreads; ++i)
Finn Williamsca3a3e02021-06-11 15:04:02 +0100170 {
171 memHandles.emplace_back(m_Runtime->CreateWorkingMemHandle(networkId));
172 }
173
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100174 if (!m_Threadpool)
175 {
176 m_Threadpool = std::make_unique<armnn::Threadpool>(numberOfThreads, runtime, memHandles);
177 }
178 else
179 {
180 m_Threadpool->LoadMemHandles(memHandles);
181 }
182
Finn Williamsca3a3e02021-06-11 15:04:02 +0100183 m_WorkingMemHandle = memHandles.back();
Finn Williamsd8fb5402021-05-19 20:52:00 +0100184 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100185}
186
187template<typename HalVersion>
188ArmnnPreparedModel_1_2<HalVersion>::~ArmnnPreparedModel_1_2()
189{
190 // Get a hold of the profiler used by this model.
191 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
192
193 // Unload the network associated with this model.
194 m_Runtime->UnloadNetwork(m_NetworkId);
195
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100196 // Unload the network memhandles from the threadpool
197 if (m_AsyncModelExecutionEnabled)
198 {
199 m_Threadpool->UnloadMemHandles(m_NetworkId);
200 }
201
Mike Kellyb5fdf382019-06-11 16:35:25 +0100202 // Dump the profiling info to a file if required.
203 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId, profiler.get());
204}
205
206template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000207Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::execute(const V1_0::Request& request,
Mike Kellyb5fdf382019-06-11 16:35:25 +0100208 const ::android::sp<V1_0::IExecutionCallback>& callback)
209{
Mike Kelly65c42dc2019-07-22 14:06:00 +0100210 if (callback.get() == nullptr)
211 {
212 ALOGE("ArmnnPreparedModel_1_2::execute invalid callback passed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000213 return V1_0::ErrorStatus::INVALID_ARGUMENT;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100214 }
215
Kevin Mayec1e5b82020-02-26 17:00:39 +0000216 auto cb = [callback](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000217 std::vector<V1_2::OutputShape> outputShapes,
218 const V1_2::Timing& timing,
Mike Kelly65c42dc2019-07-22 14:06:00 +0100219 std::string callingFunction)
220 {
221 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
222 };
223
Sadik Armagan188675f2021-02-12 17:16:42 +0000224 return Execute(request, V1_2::MeasureTiming::NO, cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100225}
226
227template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000228Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::execute_1_2(
229 const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000230 V1_2::MeasureTiming measureTiming,
Kevin Mayec1e5b82020-02-26 17:00:39 +0000231 const sp<V1_2::IExecutionCallback>& callback)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100232{
Mike Kelly65c42dc2019-07-22 14:06:00 +0100233 if (callback.get() == nullptr)
234 {
235 ALOGE("ArmnnPreparedModel_1_2::execute_1_2 invalid callback passed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000236 return V1_0::ErrorStatus::INVALID_ARGUMENT;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100237 }
238
Kevin Mayec1e5b82020-02-26 17:00:39 +0000239 auto cb = [callback](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000240 std::vector<V1_2::OutputShape> outputShapes,
241 const V1_2::Timing& timing,
Mike Kelly65c42dc2019-07-22 14:06:00 +0100242 std::string callingFunction)
243 {
244 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
245 };
246
247 return Execute(request, measureTiming, cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100248}
249
Derek Lamberti4de83c52020-03-17 13:40:18 +0000250template<typename HalVersion>
251Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForInputs(
252 armnn::InputTensors& inputs,
253 const V1_0::Request& request,
254 const std::vector<android::nn::RunTimePoolInfo>& memPools)
255{
256 inputs.reserve(request.inputs.size());
257 for (unsigned int i = 0; i < request.inputs.size(); i++)
258 {
259 const auto& inputArg = request.inputs[i];
260
261 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
262 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
263
264 if (inputTensor.GetMemoryArea() == nullptr)
265 {
266 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
267 return V1_0::ErrorStatus::GENERAL_FAILURE;
268 }
269
270 inputs.emplace_back(i, inputTensor);
271 }
272
273 return V1_0::ErrorStatus::NONE;
274}
275
276template<typename HalVersion>
277Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForOutputs(
278 armnn::OutputTensors& outputs,
Sadik Armagan188675f2021-02-12 17:16:42 +0000279 std::vector<V1_2::OutputShape> &outputShapes,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000280 const V1_0::Request& request,
281 const std::vector<android::nn::RunTimePoolInfo>& memPools)
282{
283 outputs.reserve(request.outputs.size());
284 for (unsigned int i = 0; i < request.outputs.size(); i++)
285 {
286 const auto& outputArg = request.outputs[i];
287
288 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
289 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
290 if (outputTensor.GetMemoryArea() == nullptr)
291 {
292 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
293 return V1_0::ErrorStatus::GENERAL_FAILURE;
294 }
295
296 const size_t outputSize = outputTensorInfo.GetNumBytes();
Finn Williamsa4983ce2020-07-23 12:55:12 +0100297
298 if (outputArg.location.length < outputSize)
299 {
300 ALOGW("ArmnnPreparedModel_1_2::Execute failed: outputArg.location.length < outputSize");
301 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
302 }
303
Sadik Armagan188675f2021-02-12 17:16:42 +0000304#if !defined(ARMNN_ANDROID_S)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000305 const size_t bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
306 if (bufferSize < outputSize)
307 {
Finn Williamsa4983ce2020-07-23 12:55:12 +0100308 ALOGW("ArmnnPreparedModel_1_2::Execute failed: bufferSize < outputSize");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000309 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
310 }
Sadik Armagan188675f2021-02-12 17:16:42 +0000311#else
Kevin Maydc873f62021-06-14 11:21:11 +0100312 const size_t bufferSize = memPools.at(outputArg.location.poolIndex).getSize();
Sadik Armagan188675f2021-02-12 17:16:42 +0000313 if (bufferSize < outputSize)
314 {
315 ALOGW("ArmnnPreparedModel_1_2::Execute failed bufferSize (%s) < outputSize (%s)",
316 std::to_string(bufferSize).c_str(), std::to_string(outputSize).c_str());
317 outputShapes[i].isSufficient = false;
318 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
319 }
320#endif
Derek Lamberti4de83c52020-03-17 13:40:18 +0000321 outputs.emplace_back(i, outputTensor);
322 outputShapes[i] = ComputeShape(outputTensorInfo);
323 }
324
325 return V1_0::ErrorStatus::NONE;
326}
327
328template<typename HalVersion>
329Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForIO(
330 armnn::InputTensors& inputs,
331 armnn::OutputTensors& outputs,
332 std::vector<android::nn::RunTimePoolInfo>& memPools,
333 const V1_0::Request& request,
334 CallbackAsync_1_2 callback)
335{
Sadik Armagan188675f2021-02-12 17:16:42 +0000336#if !defined(ARMNN_ANDROID_S)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000337 if (!setRunTimePoolInfosFromHidlMemories(&memPools, request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000338#else
339 if (!setRunTimePoolInfosFromCanonicalMemories(&memPools, uncheckedConvert(request.pools)))
340#endif
Derek Lamberti4de83c52020-03-17 13:40:18 +0000341 {
342 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
343 return V1_0::ErrorStatus::GENERAL_FAILURE;
344 }
Derek Lamberti4de83c52020-03-17 13:40:18 +0000345 // add the inputs and outputs with their data
346 try
347 {
348 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_0::ErrorStatus::NONE)
349 {
350 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
351 return V1_0::ErrorStatus::GENERAL_FAILURE;
352 }
353
Sadik Armagan188675f2021-02-12 17:16:42 +0000354 std::vector<V1_2::OutputShape> outputShapes(request.outputs.size());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000355
356 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
357 if (errorStatus != V1_0::ErrorStatus::NONE)
358 {
359 callback(errorStatus,
360 outputShapes,
361 g_NoTiming,
362 "ArmnnPreparedModel_1_2::Execute");
363 return errorStatus;
364 }
365 }
366 catch (armnn::Exception& e)
367 {
368 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
369 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
370 return V1_0::ErrorStatus::GENERAL_FAILURE;
371 }
372 catch (std::exception& e)
373 {
374 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
375 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
376 return V1_0::ErrorStatus::GENERAL_FAILURE;
377 }
378
379 return V1_0::ErrorStatus::NONE;
380}
381
Mike Kellyb5fdf382019-06-11 16:35:25 +0100382template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000383Return<void> ArmnnPreparedModel_1_2<HalVersion>::executeSynchronously(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000384 V1_2::MeasureTiming measureTiming,
Mike Kelly44381512019-07-08 17:37:35 +0100385 executeSynchronously_cb cb)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100386{
387 ALOGV("ArmnnPreparedModel_1_2::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
388 m_RequestCount++;
389
390 if (cb == nullptr)
391 {
392 ALOGE("ArmnnPreparedModel_1_2::executeSynchronously invalid callback passed");
393 return Void();
394 }
395
Derek Lamberti4de83c52020-03-17 13:40:18 +0000396 TimePoint driverStart;
Mike Kelly44381512019-07-08 17:37:35 +0100397
Sadik Armagan188675f2021-02-12 17:16:42 +0000398 if (measureTiming == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100399 {
400 driverStart = Now();
401 }
402
Mike Kellyb5fdf382019-06-11 16:35:25 +0100403 if (!android::nn::validateRequest(request, m_Model))
404 {
Mike Kelly44381512019-07-08 17:37:35 +0100405 ALOGE("ArmnnPreparedModel_1_2::executeSynchronously invalid request model");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000406 cb(V1_0::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100407 return Void();
408 }
409
Derek Lamberti4de83c52020-03-17 13:40:18 +0000410 auto cbWrapper = [cb](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000411 std::vector<V1_2::OutputShape> outputShapes,
412 const V1_2::Timing& timing,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000413 std::string)
414 {
415 cb(errorStatus, outputShapes, timing);
416 };
Mike Kellyb5fdf382019-06-11 16:35:25 +0100417
418 // map the memory pool into shared pointers
419 // use a shared memory pools vector on the heap, as it is passed to the request thread
Derek Lamberti4de83c52020-03-17 13:40:18 +0000420 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
Mike Kellyb5fdf382019-06-11 16:35:25 +0100421
Derek Lamberti4de83c52020-03-17 13:40:18 +0000422 // allocate the tensors on the heap, as they are passed to the request thread
423 auto inputs = std::make_shared<armnn::InputTensors>();
424 auto outputs = std::make_shared<armnn::OutputTensors>();
425
426 auto prepareStatus = PrepareMemoryForIO(*inputs, *outputs, *memPools, request, cbWrapper);
427 if (prepareStatus != V1_0::ErrorStatus::NONE)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100428 {
Kevin May7bdaac52020-02-10 12:10:07 +0000429 return Void();
430 }
431
Mike Kellyb5fdf382019-06-11 16:35:25 +0100432 ALOGV("ArmnnPreparedModel_1_2::executeSynchronously() before Execution");
433
Derek Lamberti4de83c52020-03-17 13:40:18 +0000434 CallbackContext_1_2 cbCtx;
435 cbCtx.callback = cbWrapper;
436 cbCtx.ctx.measureTimings = measureTiming;
437 cbCtx.ctx.driverStart = driverStart;
438 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
439
440 return Void();
441}
442
443template<typename HalVersion>
444template<typename CallbackContext>
445bool ArmnnPreparedModel_1_2<HalVersion>::ExecuteGraph(
446 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
447 armnn::InputTensors& inputTensors,
448 armnn::OutputTensors& outputTensors,
449 CallbackContext cb)
450{
451 ALOGV("ArmnnPreparedModel_1_2::ExecuteGraph(...)");
452
453 TimePoint driverEnd, deviceStart, deviceEnd;
454
455 DumpTensorsIfRequired("Input", inputTensors);
456
Sadik Armagan188675f2021-02-12 17:16:42 +0000457 std::vector<V1_2::OutputShape> outputShapes(outputTensors.size());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000458 for (unsigned int i = 0; i < outputTensors.size(); i++)
459 {
460 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
461 const armnn::Tensor outputTensor = outputTensorPair.second;
462 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
463
464 outputShapes[i] = ComputeShape(outputTensorInfo);
465 }
466
Mike Kellyb5fdf382019-06-11 16:35:25 +0100467 // run it
468 try
469 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000470 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100471 {
472 deviceStart = Now();
473 }
474
Finn Williamsd8fb5402021-05-19 20:52:00 +0100475 armnn::Status status;
476 if (m_AsyncModelExecutionEnabled)
477 {
478 ALOGW("ArmnnPreparedModel_1_2::ExecuteGraph m_AsyncModelExecutionEnabled true");
479 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
480 }
481 else
482 {
483 ALOGW("ArmnnPreparedModel_1_2::ExecuteGraph m_AsyncModelExecutionEnabled false");
484 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
485 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100486
Sadik Armagan188675f2021-02-12 17:16:42 +0000487 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100488 {
489 deviceEnd = Now();
490 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100491 if (status != armnn::Status::Success)
492 {
493 ALOGW("EnqueueWorkload failed");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000494 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming,
495 "ArmnnPreparedModel_1_2::ExecuteGraph");
496 return false;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100497 }
498 }
Kevin May7bdaac52020-02-10 12:10:07 +0000499 catch (armnn::Exception& e)
500 {
Derek Lamberti4de83c52020-03-17 13:40:18 +0000501 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
502 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
503 return false;
Kevin May7bdaac52020-02-10 12:10:07 +0000504 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000505 catch (std::exception& e)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100506 {
Kevin May7bdaac52020-02-10 12:10:07 +0000507 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000508 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
509 return false;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100510 }
511
Derek Lamberti4de83c52020-03-17 13:40:18 +0000512 CommitPools(*pMemPools);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100513
Derek Lamberti4de83c52020-03-17 13:40:18 +0000514 DumpTensorsIfRequired("Output", outputTensors);
Kevin Mayec1e5b82020-02-26 17:00:39 +0000515
Sadik Armagan188675f2021-02-12 17:16:42 +0000516 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100517 {
518 driverEnd = Now();
Sadik Armagan188675f2021-02-12 17:16:42 +0000519 V1_2::Timing timing;
Mike Kelly44381512019-07-08 17:37:35 +0100520 timing.timeOnDevice = MicrosecondsDuration(deviceEnd, deviceStart);
Derek Lamberti4de83c52020-03-17 13:40:18 +0000521 timing.timeInDriver = MicrosecondsDuration(driverEnd, cb.ctx.driverStart);
522 ALOGV("ArmnnPreparedModel_1_2::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
523 timing.timeInDriver);
524 cb.callback(V1_0::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_2::ExecuteGraph");
525 } else {
526 cb.callback(V1_0::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
Mike Kelly44381512019-07-08 17:37:35 +0100527 }
Derek Lamberti4de83c52020-03-17 13:40:18 +0000528
529 return true;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100530}
531
Derek Lamberti4de83c52020-03-17 13:40:18 +0000532template<typename HalVersion>
533bool ArmnnPreparedModel_1_2<HalVersion>::ExecuteWithDummyInputs()
534{
535 std::vector<std::vector<char>> storage;
536 armnn::InputTensors inputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000537 for (unsigned int i = 0; i < getMainModel(m_Model).inputIndexes.size(); i++)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000538 {
539 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
540 storage.emplace_back(inputTensorInfo.GetNumBytes());
541 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
542
543 inputTensors.emplace_back(i, inputTensor);
544 }
545
546 armnn::OutputTensors outputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000547 for (unsigned int i = 0; i < getMainModel(m_Model).outputIndexes.size(); i++)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000548 {
549 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
550 storage.emplace_back(outputTensorInfo.GetNumBytes());
551 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
552
553 outputTensors.emplace_back(i, outputTensor);
554 }
555
Sadik Armagan188675f2021-02-12 17:16:42 +0000556 auto nullCallback = [](V1_0::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Derek Lamberti4de83c52020-03-17 13:40:18 +0000557 CallbackContext_1_2 callbackContext;
558 callbackContext.callback = nullCallback;
Sadik Armagan188675f2021-02-12 17:16:42 +0000559 callbackContext.ctx.measureTimings = V1_2::MeasureTiming::NO;
Derek Lamberti4de83c52020-03-17 13:40:18 +0000560 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
561 return ExecuteGraph(memPools,
562 inputTensors,
563 outputTensors,
564 callbackContext);
565}
566
567template<typename HalVersion>
568Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::Execute(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000569 V1_2::MeasureTiming measureTiming,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000570 CallbackAsync_1_2 callback)
571{
572 ExecutionContext_1_2 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000573 if (measureTiming == V1_2::MeasureTiming::YES)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000574 {
575 ctx.measureTimings = measureTiming;
576 ctx.driverStart = Now();
577 }
578
579 ALOGV("ArmnnPreparedModel_1_2::execute(): %s", GetModelSummary(m_Model).c_str());
580 m_RequestCount++;
581
582 if (!android::nn::validateRequest(request, m_Model))
583 {
584 callback(V1_0::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
585 return V1_0::ErrorStatus::INVALID_ARGUMENT;
586 }
587
588 if (!m_RequestInputsAndOutputsDumpDir.empty())
589 {
590 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
591 }
592
593 // map the memory pool into shared pointers
594 // use a shared memory pools vector on the heap, as it is passed to the request thread
595 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
596
597 // allocate the tensors on the heap, as they are passed to the request thread
598 auto inputTensors = std::make_shared<armnn::InputTensors>();
599 auto outputTensors = std::make_shared<armnn::OutputTensors>();
600
601 auto prepareStatus = PrepareMemoryForIO(*inputTensors, *outputTensors, *memPools, request, callback);
602 switch(prepareStatus)
603 {
604 case V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
605 return V1_0::ErrorStatus::NONE;
606 case V1_0::ErrorStatus::GENERAL_FAILURE:
607 return V1_0::ErrorStatus::GENERAL_FAILURE;
608 default:
609 {}
610 }
611
Derek Lamberti4de83c52020-03-17 13:40:18 +0000612
613 // post the request for asynchronous execution
614 CallbackContext_1_2 cb;
615 cb.callback = callback;
616 cb.ctx = ctx;
Finn Williamsd8fb5402021-05-19 20:52:00 +0100617
618 if (m_AsyncModelExecutionEnabled)
619 {
620 ALOGV("ArmnnPreparedModel_1_2::execute(...) before ScheduleGraphForExecution");
621 ScheduleGraphForExecution(memPools, inputTensors, outputTensors, cb);
622 ALOGV("ArmnnPreparedModel_1_2::execute(...) after ScheduleGraphForExecution");
623 return V1_0::ErrorStatus::NONE;
624 }
625
626 ALOGV("ArmnnPreparedModel_1_2::execute(...) before PostMsg");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000627 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
628 ALOGV("ArmnnPreparedModel_1_2::execute(...) after PostMsg");
629 return V1_0::ErrorStatus::NONE;
630}
631
Mike Kellyb5fdf382019-06-11 16:35:25 +0100632template<typename HalVersion>
633Return<void> ArmnnPreparedModel_1_2<HalVersion>::configureExecutionBurst(
Derek Lamberti4de83c52020-03-17 13:40:18 +0000634 const sp<V1_2::IBurstCallback>& callback,
635 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
636 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
637 V1_2::IPreparedModel::configureExecutionBurst_cb cb)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100638{
639 ALOGV("ArmnnPreparedModel_1_2::configureExecutionBurst");
Mike Kelly65c42dc2019-07-22 14:06:00 +0100640 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
641 requestChannel,
642 resultChannel,
Kevin May42477c12020-03-26 13:34:14 +0000643 this);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100644
Mike Kelly44381512019-07-08 17:37:35 +0100645 if (burst == nullptr)
646 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000647 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
Mike Kelly44381512019-07-08 17:37:35 +0100648 }
649 else
650 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000651 cb(V1_0::ErrorStatus::NONE, burst);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100652 }
653 return Void();
654}
655
Finn Williamsd8fb5402021-05-19 20:52:00 +0100656/// Schedule the graph prepared from the request for execution
657template<typename HalVersion>
658template<typename CallbackContext>
659void ArmnnPreparedModel_1_2<HalVersion>::ScheduleGraphForExecution(
660 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
661 std::shared_ptr<armnn::InputTensors>& inputTensors,
662 std::shared_ptr<armnn::OutputTensors>& outputTensors,
663 CallbackContext callbackContext)
664{
665 ALOGV("ArmnnPreparedModel_1_2::ScheduleGraphForExecution(...)");
666
667 DumpTensorsIfRequired("Input", *inputTensors);
668
669 unsigned int outputTensorSize = outputTensors.get()->size();
670 std::vector<V1_2::OutputShape> outputShapes(outputTensorSize);
671 for (unsigned int i = 0; i < outputTensorSize; i++)
672 {
673 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors.get()->at(i);
674 const armnn::Tensor outputTensor = outputTensorPair.second;
675 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
676
677 outputShapes[i] = ComputeShape(outputTensorInfo);
678 }
679
680 auto tpCb = std::make_shared<
681 ArmnnThreadPoolCallback_1_2<CallbackContext_1_2>>(this,
682 pMemPools,
683 outputShapes,
684 inputTensors,
685 outputTensors,
686 callbackContext);
687
Finn Williamsca3a3e02021-06-11 15:04:02 +0100688 m_Threadpool->Schedule(m_NetworkId,
689 *tpCb->m_InputTensors,
690 *tpCb->m_OutputTensors,
691 armnn::QosExecPriority::Medium,
692 tpCb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100693 ALOGV("ArmnnPreparedModel_1_2::ScheduleGraphForExecution end");
694}
695
696template<typename HalVersion>
697template <typename CallbackContext>
698void ArmnnPreparedModel_1_2<HalVersion>::ArmnnThreadPoolCallback_1_2<CallbackContext>::Notify(
699 armnn::Status status, armnn::InferenceTimingPair timeTaken)
700{
701 ALOGV("ArmnnPreparedModel_1_2::ArmnnThreadPoolCallback_1_2 Notify");
702
703 TimePoint driverEnd;
704
705 CommitPools(*m_MemPools);
706
707 m_Model->DumpTensorsIfRequired("Output", *m_OutputTensors);
708
709 if (status != armnn::Status::Success)
710 {
711 ALOGW("ArmnnThreadPoolCallback::Notify EnqueueWorkload failed");
712 m_CallbackContext.callback(
713 V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel::ExecuteGraph");
714 return;
715 }
716
717 if (m_CallbackContext.ctx.measureTimings == V1_2::MeasureTiming::YES)
718 {
719 driverEnd = std::chrono::steady_clock::now();
720 V1_2::Timing timing;
721 timing.timeOnDevice = MicrosecondsDuration(timeTaken.second, timeTaken.first);
722 timing.timeInDriver = MicrosecondsDuration(driverEnd, m_CallbackContext.ctx.driverStart);
723 ALOGV("ArmnnPreparedModel_1_2::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
724 timing.timeInDriver);
725 m_CallbackContext.callback(
726 V1_0::ErrorStatus::NONE, m_OutputShapes, timing, "ArmnnPreparedModel_1_2::ExecuteGraph");
727 } else {
728 m_CallbackContext.callback(
729 V1_0::ErrorStatus::NONE, m_OutputShapes, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
730 }
731 return;
732}
733
Kevin May42477c12020-03-26 13:34:14 +0000734#if defined(ARMNN_ANDROID_NN_V1_2) || defined(ARMNN_ANDROID_NN_V1_3)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100735template class ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>;
Derek Lamberti4de83c52020-03-17 13:40:18 +0000736template bool ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>::ExecuteGraph<CallbackContext_1_2>(
737 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
738 armnn::InputTensors& pInputTensors,
739 armnn::OutputTensors& pOutputTensors,
740 CallbackContext_1_2 cb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100741
742template void ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>::ScheduleGraphForExecution<CallbackContext_1_2>(
743 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
744 std::shared_ptr<armnn::InputTensors>& inputTensors,
745 std::shared_ptr<armnn::OutputTensors>& outputTensors,
746 CallbackContext_1_2 callbackContext);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100747#endif
748
749} // namespace armnn_driver