blob: a2148c29b9cc8366ff49082e7566846329e36537 [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"
9#include "Utils.hpp"
10
Mike Kellyb5fdf382019-06-11 16:35:25 +010011#include <log/log.h>
12#include <OperationsUtils.h>
13#include <ExecutionBurstServer.h>
14#include <ValidateHal.h>
15
16#include <cassert>
17#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>
127template<typename TensorBindingCollection>
128void ArmnnPreparedModel_1_2<HalVersion>::DumpTensorsIfRequired(char const* tensorNamePrefix,
129 const TensorBindingCollection& tensorBindings)
130{
131 if (!m_RequestInputsAndOutputsDumpDir.empty())
132 {
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100133 const std::string requestName = std::to_string(m_NetworkId) + "_" + std::to_string(m_RequestCount) + ".dump";
Mike Kellyb5fdf382019-06-11 16:35:25 +0100134 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
135 {
136 DumpTensor(m_RequestInputsAndOutputsDumpDir,
137 requestName,
138 BuildTensorName(tensorNamePrefix, i),
139 tensorBindings[i].second);
140 }
141 }
142}
143
144template<typename HalVersion>
145ArmnnPreparedModel_1_2<HalVersion>::ArmnnPreparedModel_1_2(armnn::NetworkId networkId,
146 armnn::IRuntime* runtime,
147 const V1_2::Model& model,
148 const std::string& requestInputsAndOutputsDumpDir,
149 const bool gpuProfilingEnabled)
150 : m_NetworkId(networkId)
151 , m_Runtime(runtime)
152 , m_Model(model)
153 , m_RequestCount(0)
154 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
155 , m_GpuProfilingEnabled(gpuProfilingEnabled)
156{
157 // Enable profiling if required.
158 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
159}
160
161template<typename HalVersion>
162ArmnnPreparedModel_1_2<HalVersion>::~ArmnnPreparedModel_1_2()
163{
164 // Get a hold of the profiler used by this model.
165 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
166
167 // Unload the network associated with this model.
168 m_Runtime->UnloadNetwork(m_NetworkId);
169
170 // Dump the profiling info to a file if required.
171 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId, profiler.get());
172}
173
174template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000175Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::execute(const V1_0::Request& request,
Mike Kellyb5fdf382019-06-11 16:35:25 +0100176 const ::android::sp<V1_0::IExecutionCallback>& callback)
177{
Mike Kelly65c42dc2019-07-22 14:06:00 +0100178 if (callback.get() == nullptr)
179 {
180 ALOGE("ArmnnPreparedModel_1_2::execute invalid callback passed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000181 return V1_0::ErrorStatus::INVALID_ARGUMENT;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100182 }
183
Kevin Mayec1e5b82020-02-26 17:00:39 +0000184 auto cb = [callback](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000185 std::vector<V1_2::OutputShape> outputShapes,
186 const V1_2::Timing& timing,
Mike Kelly65c42dc2019-07-22 14:06:00 +0100187 std::string callingFunction)
188 {
189 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
190 };
191
Sadik Armagan188675f2021-02-12 17:16:42 +0000192 return Execute(request, V1_2::MeasureTiming::NO, cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100193}
194
195template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000196Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::execute_1_2(
197 const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000198 V1_2::MeasureTiming measureTiming,
Kevin Mayec1e5b82020-02-26 17:00:39 +0000199 const sp<V1_2::IExecutionCallback>& callback)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100200{
Mike Kelly65c42dc2019-07-22 14:06:00 +0100201 if (callback.get() == nullptr)
202 {
203 ALOGE("ArmnnPreparedModel_1_2::execute_1_2 invalid callback passed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000204 return V1_0::ErrorStatus::INVALID_ARGUMENT;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100205 }
206
Kevin Mayec1e5b82020-02-26 17:00:39 +0000207 auto cb = [callback](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000208 std::vector<V1_2::OutputShape> outputShapes,
209 const V1_2::Timing& timing,
Mike Kelly65c42dc2019-07-22 14:06:00 +0100210 std::string callingFunction)
211 {
212 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
213 };
214
215 return Execute(request, measureTiming, cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100216}
217
Derek Lamberti4de83c52020-03-17 13:40:18 +0000218template<typename HalVersion>
219Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForInputs(
220 armnn::InputTensors& inputs,
221 const V1_0::Request& request,
222 const std::vector<android::nn::RunTimePoolInfo>& memPools)
223{
224 inputs.reserve(request.inputs.size());
225 for (unsigned int i = 0; i < request.inputs.size(); i++)
226 {
227 const auto& inputArg = request.inputs[i];
228
229 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
230 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
231
232 if (inputTensor.GetMemoryArea() == nullptr)
233 {
234 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
235 return V1_0::ErrorStatus::GENERAL_FAILURE;
236 }
237
238 inputs.emplace_back(i, inputTensor);
239 }
240
241 return V1_0::ErrorStatus::NONE;
242}
243
244template<typename HalVersion>
245Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForOutputs(
246 armnn::OutputTensors& outputs,
Sadik Armagan188675f2021-02-12 17:16:42 +0000247 std::vector<V1_2::OutputShape> &outputShapes,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000248 const V1_0::Request& request,
249 const std::vector<android::nn::RunTimePoolInfo>& memPools)
250{
251 outputs.reserve(request.outputs.size());
252 for (unsigned int i = 0; i < request.outputs.size(); i++)
253 {
254 const auto& outputArg = request.outputs[i];
255
256 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
257 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
258 if (outputTensor.GetMemoryArea() == nullptr)
259 {
260 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
261 return V1_0::ErrorStatus::GENERAL_FAILURE;
262 }
263
264 const size_t outputSize = outputTensorInfo.GetNumBytes();
Finn Williamsa4983ce2020-07-23 12:55:12 +0100265
266 if (outputArg.location.length < outputSize)
267 {
268 ALOGW("ArmnnPreparedModel_1_2::Execute failed: outputArg.location.length < outputSize");
269 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
270 }
271
Sadik Armagan188675f2021-02-12 17:16:42 +0000272#if !defined(ARMNN_ANDROID_S)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000273 const size_t bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
274 if (bufferSize < outputSize)
275 {
Finn Williamsa4983ce2020-07-23 12:55:12 +0100276 ALOGW("ArmnnPreparedModel_1_2::Execute failed: bufferSize < outputSize");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000277 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
278 }
Sadik Armagan188675f2021-02-12 17:16:42 +0000279#else
280 const size_t bufferSize = memPools.at(outputArg.location.poolIndex).getMemory().size;
281 if (bufferSize < outputSize)
282 {
283 ALOGW("ArmnnPreparedModel_1_2::Execute failed bufferSize (%s) < outputSize (%s)",
284 std::to_string(bufferSize).c_str(), std::to_string(outputSize).c_str());
285 outputShapes[i].isSufficient = false;
286 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
287 }
288#endif
Derek Lamberti4de83c52020-03-17 13:40:18 +0000289 outputs.emplace_back(i, outputTensor);
290 outputShapes[i] = ComputeShape(outputTensorInfo);
291 }
292
293 return V1_0::ErrorStatus::NONE;
294}
295
296template<typename HalVersion>
297Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForIO(
298 armnn::InputTensors& inputs,
299 armnn::OutputTensors& outputs,
300 std::vector<android::nn::RunTimePoolInfo>& memPools,
301 const V1_0::Request& request,
302 CallbackAsync_1_2 callback)
303{
Sadik Armagan188675f2021-02-12 17:16:42 +0000304#if !defined(ARMNN_ANDROID_S)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000305 if (!setRunTimePoolInfosFromHidlMemories(&memPools, request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000306#else
307 if (!setRunTimePoolInfosFromCanonicalMemories(&memPools, uncheckedConvert(request.pools)))
308#endif
Derek Lamberti4de83c52020-03-17 13:40:18 +0000309 {
310 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
311 return V1_0::ErrorStatus::GENERAL_FAILURE;
312 }
Derek Lamberti4de83c52020-03-17 13:40:18 +0000313 // add the inputs and outputs with their data
314 try
315 {
316 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_0::ErrorStatus::NONE)
317 {
318 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
319 return V1_0::ErrorStatus::GENERAL_FAILURE;
320 }
321
Sadik Armagan188675f2021-02-12 17:16:42 +0000322 std::vector<V1_2::OutputShape> outputShapes(request.outputs.size());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000323
324 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
325 if (errorStatus != V1_0::ErrorStatus::NONE)
326 {
327 callback(errorStatus,
328 outputShapes,
329 g_NoTiming,
330 "ArmnnPreparedModel_1_2::Execute");
331 return errorStatus;
332 }
333 }
334 catch (armnn::Exception& e)
335 {
336 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
337 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
338 return V1_0::ErrorStatus::GENERAL_FAILURE;
339 }
340 catch (std::exception& e)
341 {
342 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
343 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
344 return V1_0::ErrorStatus::GENERAL_FAILURE;
345 }
346
347 return V1_0::ErrorStatus::NONE;
348}
349
Mike Kellyb5fdf382019-06-11 16:35:25 +0100350template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000351Return<void> ArmnnPreparedModel_1_2<HalVersion>::executeSynchronously(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000352 V1_2::MeasureTiming measureTiming,
Mike Kelly44381512019-07-08 17:37:35 +0100353 executeSynchronously_cb cb)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100354{
355 ALOGV("ArmnnPreparedModel_1_2::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
356 m_RequestCount++;
357
358 if (cb == nullptr)
359 {
360 ALOGE("ArmnnPreparedModel_1_2::executeSynchronously invalid callback passed");
361 return Void();
362 }
363
Derek Lamberti4de83c52020-03-17 13:40:18 +0000364 TimePoint driverStart;
Mike Kelly44381512019-07-08 17:37:35 +0100365
Sadik Armagan188675f2021-02-12 17:16:42 +0000366 if (measureTiming == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100367 {
368 driverStart = Now();
369 }
370
Mike Kellyb5fdf382019-06-11 16:35:25 +0100371 if (!android::nn::validateRequest(request, m_Model))
372 {
Mike Kelly44381512019-07-08 17:37:35 +0100373 ALOGE("ArmnnPreparedModel_1_2::executeSynchronously invalid request model");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000374 cb(V1_0::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100375 return Void();
376 }
377
Derek Lamberti4de83c52020-03-17 13:40:18 +0000378 auto cbWrapper = [cb](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000379 std::vector<V1_2::OutputShape> outputShapes,
380 const V1_2::Timing& timing,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000381 std::string)
382 {
383 cb(errorStatus, outputShapes, timing);
384 };
Mike Kellyb5fdf382019-06-11 16:35:25 +0100385
386 // map the memory pool into shared pointers
387 // use a shared memory pools vector on the heap, as it is passed to the request thread
Derek Lamberti4de83c52020-03-17 13:40:18 +0000388 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
Mike Kellyb5fdf382019-06-11 16:35:25 +0100389
Derek Lamberti4de83c52020-03-17 13:40:18 +0000390 // allocate the tensors on the heap, as they are passed to the request thread
391 auto inputs = std::make_shared<armnn::InputTensors>();
392 auto outputs = std::make_shared<armnn::OutputTensors>();
393
394 auto prepareStatus = PrepareMemoryForIO(*inputs, *outputs, *memPools, request, cbWrapper);
395 if (prepareStatus != V1_0::ErrorStatus::NONE)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100396 {
Kevin May7bdaac52020-02-10 12:10:07 +0000397 return Void();
398 }
399
Mike Kellyb5fdf382019-06-11 16:35:25 +0100400 ALOGV("ArmnnPreparedModel_1_2::executeSynchronously() before Execution");
401
Derek Lamberti4de83c52020-03-17 13:40:18 +0000402 CallbackContext_1_2 cbCtx;
403 cbCtx.callback = cbWrapper;
404 cbCtx.ctx.measureTimings = measureTiming;
405 cbCtx.ctx.driverStart = driverStart;
406 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
407
408 return Void();
409}
410
411template<typename HalVersion>
412template<typename CallbackContext>
413bool ArmnnPreparedModel_1_2<HalVersion>::ExecuteGraph(
414 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
415 armnn::InputTensors& inputTensors,
416 armnn::OutputTensors& outputTensors,
417 CallbackContext cb)
418{
419 ALOGV("ArmnnPreparedModel_1_2::ExecuteGraph(...)");
420
421 TimePoint driverEnd, deviceStart, deviceEnd;
422
423 DumpTensorsIfRequired("Input", inputTensors);
424
Sadik Armagan188675f2021-02-12 17:16:42 +0000425 std::vector<V1_2::OutputShape> outputShapes(outputTensors.size());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000426 for (unsigned int i = 0; i < outputTensors.size(); i++)
427 {
428 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
429 const armnn::Tensor outputTensor = outputTensorPair.second;
430 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
431
432 outputShapes[i] = ComputeShape(outputTensorInfo);
433 }
434
Mike Kellyb5fdf382019-06-11 16:35:25 +0100435 // run it
436 try
437 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000438 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100439 {
440 deviceStart = Now();
441 }
442
Derek Lamberti4de83c52020-03-17 13:40:18 +0000443 armnn::Status status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100444
Sadik Armagan188675f2021-02-12 17:16:42 +0000445 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100446 {
447 deviceEnd = Now();
448 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100449 if (status != armnn::Status::Success)
450 {
451 ALOGW("EnqueueWorkload failed");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000452 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming,
453 "ArmnnPreparedModel_1_2::ExecuteGraph");
454 return false;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100455 }
456 }
Kevin May7bdaac52020-02-10 12:10:07 +0000457 catch (armnn::Exception& e)
458 {
Derek Lamberti4de83c52020-03-17 13:40:18 +0000459 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
460 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
461 return false;
Kevin May7bdaac52020-02-10 12:10:07 +0000462 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000463 catch (std::exception& e)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100464 {
Kevin May7bdaac52020-02-10 12:10:07 +0000465 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000466 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
467 return false;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100468 }
469
Derek Lamberti4de83c52020-03-17 13:40:18 +0000470 CommitPools(*pMemPools);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100471
Derek Lamberti4de83c52020-03-17 13:40:18 +0000472 DumpTensorsIfRequired("Output", outputTensors);
Kevin Mayec1e5b82020-02-26 17:00:39 +0000473
Sadik Armagan188675f2021-02-12 17:16:42 +0000474 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100475 {
476 driverEnd = Now();
Sadik Armagan188675f2021-02-12 17:16:42 +0000477 V1_2::Timing timing;
Mike Kelly44381512019-07-08 17:37:35 +0100478 timing.timeOnDevice = MicrosecondsDuration(deviceEnd, deviceStart);
Derek Lamberti4de83c52020-03-17 13:40:18 +0000479 timing.timeInDriver = MicrosecondsDuration(driverEnd, cb.ctx.driverStart);
480 ALOGV("ArmnnPreparedModel_1_2::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
481 timing.timeInDriver);
482 cb.callback(V1_0::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_2::ExecuteGraph");
483 } else {
484 cb.callback(V1_0::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
Mike Kelly44381512019-07-08 17:37:35 +0100485 }
Derek Lamberti4de83c52020-03-17 13:40:18 +0000486
487 return true;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100488}
489
Derek Lamberti4de83c52020-03-17 13:40:18 +0000490template<typename HalVersion>
491bool ArmnnPreparedModel_1_2<HalVersion>::ExecuteWithDummyInputs()
492{
493 std::vector<std::vector<char>> storage;
494 armnn::InputTensors inputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000495 for (unsigned int i = 0; i < getMainModel(m_Model).inputIndexes.size(); i++)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000496 {
497 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
498 storage.emplace_back(inputTensorInfo.GetNumBytes());
499 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
500
501 inputTensors.emplace_back(i, inputTensor);
502 }
503
504 armnn::OutputTensors outputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000505 for (unsigned int i = 0; i < getMainModel(m_Model).outputIndexes.size(); i++)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000506 {
507 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
508 storage.emplace_back(outputTensorInfo.GetNumBytes());
509 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
510
511 outputTensors.emplace_back(i, outputTensor);
512 }
513
Sadik Armagan188675f2021-02-12 17:16:42 +0000514 auto nullCallback = [](V1_0::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Derek Lamberti4de83c52020-03-17 13:40:18 +0000515 CallbackContext_1_2 callbackContext;
516 callbackContext.callback = nullCallback;
Sadik Armagan188675f2021-02-12 17:16:42 +0000517 callbackContext.ctx.measureTimings = V1_2::MeasureTiming::NO;
Derek Lamberti4de83c52020-03-17 13:40:18 +0000518 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
519 return ExecuteGraph(memPools,
520 inputTensors,
521 outputTensors,
522 callbackContext);
523}
524
525template<typename HalVersion>
526Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::Execute(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000527 V1_2::MeasureTiming measureTiming,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000528 CallbackAsync_1_2 callback)
529{
530 ExecutionContext_1_2 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000531 if (measureTiming == V1_2::MeasureTiming::YES)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000532 {
533 ctx.measureTimings = measureTiming;
534 ctx.driverStart = Now();
535 }
536
537 ALOGV("ArmnnPreparedModel_1_2::execute(): %s", GetModelSummary(m_Model).c_str());
538 m_RequestCount++;
539
540 if (!android::nn::validateRequest(request, m_Model))
541 {
542 callback(V1_0::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
543 return V1_0::ErrorStatus::INVALID_ARGUMENT;
544 }
545
546 if (!m_RequestInputsAndOutputsDumpDir.empty())
547 {
548 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
549 }
550
551 // map the memory pool into shared pointers
552 // use a shared memory pools vector on the heap, as it is passed to the request thread
553 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
554
555 // allocate the tensors on the heap, as they are passed to the request thread
556 auto inputTensors = std::make_shared<armnn::InputTensors>();
557 auto outputTensors = std::make_shared<armnn::OutputTensors>();
558
559 auto prepareStatus = PrepareMemoryForIO(*inputTensors, *outputTensors, *memPools, request, callback);
560 switch(prepareStatus)
561 {
562 case V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
563 return V1_0::ErrorStatus::NONE;
564 case V1_0::ErrorStatus::GENERAL_FAILURE:
565 return V1_0::ErrorStatus::GENERAL_FAILURE;
566 default:
567 {}
568 }
569
570 ALOGV("ArmnnPreparedModel_1_2::execute(...) before PostMsg");
571
572 // post the request for asynchronous execution
573 CallbackContext_1_2 cb;
574 cb.callback = callback;
575 cb.ctx = ctx;
576 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
577 ALOGV("ArmnnPreparedModel_1_2::execute(...) after PostMsg");
578 return V1_0::ErrorStatus::NONE;
579}
580
Mike Kellyb5fdf382019-06-11 16:35:25 +0100581template<typename HalVersion>
582Return<void> ArmnnPreparedModel_1_2<HalVersion>::configureExecutionBurst(
Derek Lamberti4de83c52020-03-17 13:40:18 +0000583 const sp<V1_2::IBurstCallback>& callback,
584 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
585 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
586 V1_2::IPreparedModel::configureExecutionBurst_cb cb)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100587{
588 ALOGV("ArmnnPreparedModel_1_2::configureExecutionBurst");
Mike Kelly65c42dc2019-07-22 14:06:00 +0100589 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
590 requestChannel,
591 resultChannel,
Kevin May42477c12020-03-26 13:34:14 +0000592 this);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100593
Mike Kelly44381512019-07-08 17:37:35 +0100594 if (burst == nullptr)
595 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000596 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
Mike Kelly44381512019-07-08 17:37:35 +0100597 }
598 else
599 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000600 cb(V1_0::ErrorStatus::NONE, burst);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100601 }
602 return Void();
603}
604
Kevin May42477c12020-03-26 13:34:14 +0000605#if defined(ARMNN_ANDROID_NN_V1_2) || defined(ARMNN_ANDROID_NN_V1_3)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100606template class ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>;
Derek Lamberti4de83c52020-03-17 13:40:18 +0000607template bool ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>::ExecuteGraph<CallbackContext_1_2>(
608 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
609 armnn::InputTensors& pInputTensors,
610 armnn::OutputTensors& pOutputTensors,
611 CallbackContext_1_2 cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100612#endif
613
614} // namespace armnn_driver