blob: c129fd69fb2245f56301eacd1e0b621f94cdb990 [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>
128template<typename TensorBindingCollection>
129void ArmnnPreparedModel_1_2<HalVersion>::DumpTensorsIfRequired(char const* tensorNamePrefix,
130 const TensorBindingCollection& tensorBindings)
131{
132 if (!m_RequestInputsAndOutputsDumpDir.empty())
133 {
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100134 const std::string requestName = std::to_string(m_NetworkId) + "_" + std::to_string(m_RequestCount) + ".dump";
Mike Kellyb5fdf382019-06-11 16:35:25 +0100135 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
136 {
137 DumpTensor(m_RequestInputsAndOutputsDumpDir,
138 requestName,
139 BuildTensorName(tensorNamePrefix, i),
140 tensorBindings[i].second);
141 }
142 }
143}
144
145template<typename HalVersion>
146ArmnnPreparedModel_1_2<HalVersion>::ArmnnPreparedModel_1_2(armnn::NetworkId networkId,
147 armnn::IRuntime* runtime,
148 const V1_2::Model& model,
149 const std::string& requestInputsAndOutputsDumpDir,
Finn Williamsd8fb5402021-05-19 20:52:00 +0100150 const bool gpuProfilingEnabled,
151 const bool asyncModelExecutionEnabled)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100152 : m_NetworkId(networkId)
153 , m_Runtime(runtime)
154 , m_Model(model)
155 , m_RequestCount(0)
156 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
157 , m_GpuProfilingEnabled(gpuProfilingEnabled)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100158 , m_AsyncModelExecutionEnabled(asyncModelExecutionEnabled)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100159{
160 // Enable profiling if required.
161 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100162
163 if (asyncModelExecutionEnabled)
164 {
165 m_WorkingMemHandle = m_Runtime->CreateWorkingMemHandle(networkId);
166 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100167}
168
169template<typename HalVersion>
170ArmnnPreparedModel_1_2<HalVersion>::~ArmnnPreparedModel_1_2()
171{
172 // Get a hold of the profiler used by this model.
173 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
174
175 // Unload the network associated with this model.
176 m_Runtime->UnloadNetwork(m_NetworkId);
177
178 // Dump the profiling info to a file if required.
179 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId, profiler.get());
180}
181
182template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000183Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::execute(const V1_0::Request& request,
Mike Kellyb5fdf382019-06-11 16:35:25 +0100184 const ::android::sp<V1_0::IExecutionCallback>& callback)
185{
Mike Kelly65c42dc2019-07-22 14:06:00 +0100186 if (callback.get() == nullptr)
187 {
188 ALOGE("ArmnnPreparedModel_1_2::execute invalid callback passed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000189 return V1_0::ErrorStatus::INVALID_ARGUMENT;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100190 }
191
Kevin Mayec1e5b82020-02-26 17:00:39 +0000192 auto cb = [callback](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000193 std::vector<V1_2::OutputShape> outputShapes,
194 const V1_2::Timing& timing,
Mike Kelly65c42dc2019-07-22 14:06:00 +0100195 std::string callingFunction)
196 {
197 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
198 };
199
Sadik Armagan188675f2021-02-12 17:16:42 +0000200 return Execute(request, V1_2::MeasureTiming::NO, cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100201}
202
203template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000204Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::execute_1_2(
205 const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000206 V1_2::MeasureTiming measureTiming,
Kevin Mayec1e5b82020-02-26 17:00:39 +0000207 const sp<V1_2::IExecutionCallback>& callback)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100208{
Mike Kelly65c42dc2019-07-22 14:06:00 +0100209 if (callback.get() == nullptr)
210 {
211 ALOGE("ArmnnPreparedModel_1_2::execute_1_2 invalid callback passed");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000212 return V1_0::ErrorStatus::INVALID_ARGUMENT;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100213 }
214
Kevin Mayec1e5b82020-02-26 17:00:39 +0000215 auto cb = [callback](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000216 std::vector<V1_2::OutputShape> outputShapes,
217 const V1_2::Timing& timing,
Mike Kelly65c42dc2019-07-22 14:06:00 +0100218 std::string callingFunction)
219 {
220 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
221 };
222
223 return Execute(request, measureTiming, cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100224}
225
Derek Lamberti4de83c52020-03-17 13:40:18 +0000226template<typename HalVersion>
227Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForInputs(
228 armnn::InputTensors& inputs,
229 const V1_0::Request& request,
230 const std::vector<android::nn::RunTimePoolInfo>& memPools)
231{
232 inputs.reserve(request.inputs.size());
233 for (unsigned int i = 0; i < request.inputs.size(); i++)
234 {
235 const auto& inputArg = request.inputs[i];
236
237 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
238 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
239
240 if (inputTensor.GetMemoryArea() == nullptr)
241 {
242 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
243 return V1_0::ErrorStatus::GENERAL_FAILURE;
244 }
245
246 inputs.emplace_back(i, inputTensor);
247 }
248
249 return V1_0::ErrorStatus::NONE;
250}
251
252template<typename HalVersion>
253Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForOutputs(
254 armnn::OutputTensors& outputs,
Sadik Armagan188675f2021-02-12 17:16:42 +0000255 std::vector<V1_2::OutputShape> &outputShapes,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000256 const V1_0::Request& request,
257 const std::vector<android::nn::RunTimePoolInfo>& memPools)
258{
259 outputs.reserve(request.outputs.size());
260 for (unsigned int i = 0; i < request.outputs.size(); i++)
261 {
262 const auto& outputArg = request.outputs[i];
263
264 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
265 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
266 if (outputTensor.GetMemoryArea() == nullptr)
267 {
268 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
269 return V1_0::ErrorStatus::GENERAL_FAILURE;
270 }
271
272 const size_t outputSize = outputTensorInfo.GetNumBytes();
Finn Williamsa4983ce2020-07-23 12:55:12 +0100273
274 if (outputArg.location.length < outputSize)
275 {
276 ALOGW("ArmnnPreparedModel_1_2::Execute failed: outputArg.location.length < outputSize");
277 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
278 }
279
Sadik Armagan188675f2021-02-12 17:16:42 +0000280#if !defined(ARMNN_ANDROID_S)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000281 const size_t bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
282 if (bufferSize < outputSize)
283 {
Finn Williamsa4983ce2020-07-23 12:55:12 +0100284 ALOGW("ArmnnPreparedModel_1_2::Execute failed: bufferSize < outputSize");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000285 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
286 }
Sadik Armagan188675f2021-02-12 17:16:42 +0000287#else
288 const size_t bufferSize = memPools.at(outputArg.location.poolIndex).getMemory().size;
289 if (bufferSize < outputSize)
290 {
291 ALOGW("ArmnnPreparedModel_1_2::Execute failed bufferSize (%s) < outputSize (%s)",
292 std::to_string(bufferSize).c_str(), std::to_string(outputSize).c_str());
293 outputShapes[i].isSufficient = false;
294 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
295 }
296#endif
Derek Lamberti4de83c52020-03-17 13:40:18 +0000297 outputs.emplace_back(i, outputTensor);
298 outputShapes[i] = ComputeShape(outputTensorInfo);
299 }
300
301 return V1_0::ErrorStatus::NONE;
302}
303
304template<typename HalVersion>
305Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForIO(
306 armnn::InputTensors& inputs,
307 armnn::OutputTensors& outputs,
308 std::vector<android::nn::RunTimePoolInfo>& memPools,
309 const V1_0::Request& request,
310 CallbackAsync_1_2 callback)
311{
Sadik Armagan188675f2021-02-12 17:16:42 +0000312#if !defined(ARMNN_ANDROID_S)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000313 if (!setRunTimePoolInfosFromHidlMemories(&memPools, request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000314#else
315 if (!setRunTimePoolInfosFromCanonicalMemories(&memPools, uncheckedConvert(request.pools)))
316#endif
Derek Lamberti4de83c52020-03-17 13:40:18 +0000317 {
318 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
319 return V1_0::ErrorStatus::GENERAL_FAILURE;
320 }
Derek Lamberti4de83c52020-03-17 13:40:18 +0000321 // add the inputs and outputs with their data
322 try
323 {
324 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_0::ErrorStatus::NONE)
325 {
326 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
327 return V1_0::ErrorStatus::GENERAL_FAILURE;
328 }
329
Sadik Armagan188675f2021-02-12 17:16:42 +0000330 std::vector<V1_2::OutputShape> outputShapes(request.outputs.size());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000331
332 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
333 if (errorStatus != V1_0::ErrorStatus::NONE)
334 {
335 callback(errorStatus,
336 outputShapes,
337 g_NoTiming,
338 "ArmnnPreparedModel_1_2::Execute");
339 return errorStatus;
340 }
341 }
342 catch (armnn::Exception& e)
343 {
344 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
345 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
346 return V1_0::ErrorStatus::GENERAL_FAILURE;
347 }
348 catch (std::exception& e)
349 {
350 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
351 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
352 return V1_0::ErrorStatus::GENERAL_FAILURE;
353 }
354
355 return V1_0::ErrorStatus::NONE;
356}
357
Mike Kellyb5fdf382019-06-11 16:35:25 +0100358template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000359Return<void> ArmnnPreparedModel_1_2<HalVersion>::executeSynchronously(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000360 V1_2::MeasureTiming measureTiming,
Mike Kelly44381512019-07-08 17:37:35 +0100361 executeSynchronously_cb cb)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100362{
363 ALOGV("ArmnnPreparedModel_1_2::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
364 m_RequestCount++;
365
366 if (cb == nullptr)
367 {
368 ALOGE("ArmnnPreparedModel_1_2::executeSynchronously invalid callback passed");
369 return Void();
370 }
371
Derek Lamberti4de83c52020-03-17 13:40:18 +0000372 TimePoint driverStart;
Mike Kelly44381512019-07-08 17:37:35 +0100373
Sadik Armagan188675f2021-02-12 17:16:42 +0000374 if (measureTiming == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100375 {
376 driverStart = Now();
377 }
378
Mike Kellyb5fdf382019-06-11 16:35:25 +0100379 if (!android::nn::validateRequest(request, m_Model))
380 {
Mike Kelly44381512019-07-08 17:37:35 +0100381 ALOGE("ArmnnPreparedModel_1_2::executeSynchronously invalid request model");
Kevin Mayec1e5b82020-02-26 17:00:39 +0000382 cb(V1_0::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100383 return Void();
384 }
385
Derek Lamberti4de83c52020-03-17 13:40:18 +0000386 auto cbWrapper = [cb](V1_0::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000387 std::vector<V1_2::OutputShape> outputShapes,
388 const V1_2::Timing& timing,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000389 std::string)
390 {
391 cb(errorStatus, outputShapes, timing);
392 };
Mike Kellyb5fdf382019-06-11 16:35:25 +0100393
394 // map the memory pool into shared pointers
395 // use a shared memory pools vector on the heap, as it is passed to the request thread
Derek Lamberti4de83c52020-03-17 13:40:18 +0000396 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
Mike Kellyb5fdf382019-06-11 16:35:25 +0100397
Derek Lamberti4de83c52020-03-17 13:40:18 +0000398 // allocate the tensors on the heap, as they are passed to the request thread
399 auto inputs = std::make_shared<armnn::InputTensors>();
400 auto outputs = std::make_shared<armnn::OutputTensors>();
401
402 auto prepareStatus = PrepareMemoryForIO(*inputs, *outputs, *memPools, request, cbWrapper);
403 if (prepareStatus != V1_0::ErrorStatus::NONE)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100404 {
Kevin May7bdaac52020-02-10 12:10:07 +0000405 return Void();
406 }
407
Mike Kellyb5fdf382019-06-11 16:35:25 +0100408 ALOGV("ArmnnPreparedModel_1_2::executeSynchronously() before Execution");
409
Derek Lamberti4de83c52020-03-17 13:40:18 +0000410 CallbackContext_1_2 cbCtx;
411 cbCtx.callback = cbWrapper;
412 cbCtx.ctx.measureTimings = measureTiming;
413 cbCtx.ctx.driverStart = driverStart;
414 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
415
416 return Void();
417}
418
419template<typename HalVersion>
420template<typename CallbackContext>
421bool ArmnnPreparedModel_1_2<HalVersion>::ExecuteGraph(
422 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
423 armnn::InputTensors& inputTensors,
424 armnn::OutputTensors& outputTensors,
425 CallbackContext cb)
426{
427 ALOGV("ArmnnPreparedModel_1_2::ExecuteGraph(...)");
428
429 TimePoint driverEnd, deviceStart, deviceEnd;
430
431 DumpTensorsIfRequired("Input", inputTensors);
432
Sadik Armagan188675f2021-02-12 17:16:42 +0000433 std::vector<V1_2::OutputShape> outputShapes(outputTensors.size());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000434 for (unsigned int i = 0; i < outputTensors.size(); i++)
435 {
436 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
437 const armnn::Tensor outputTensor = outputTensorPair.second;
438 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
439
440 outputShapes[i] = ComputeShape(outputTensorInfo);
441 }
442
Mike Kellyb5fdf382019-06-11 16:35:25 +0100443 // run it
444 try
445 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000446 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100447 {
448 deviceStart = Now();
449 }
450
Finn Williamsd8fb5402021-05-19 20:52:00 +0100451 armnn::Status status;
452 if (m_AsyncModelExecutionEnabled)
453 {
454 ALOGW("ArmnnPreparedModel_1_2::ExecuteGraph m_AsyncModelExecutionEnabled true");
455 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
456 }
457 else
458 {
459 ALOGW("ArmnnPreparedModel_1_2::ExecuteGraph m_AsyncModelExecutionEnabled false");
460 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
461 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100462
Sadik Armagan188675f2021-02-12 17:16:42 +0000463 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100464 {
465 deviceEnd = Now();
466 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100467 if (status != armnn::Status::Success)
468 {
469 ALOGW("EnqueueWorkload failed");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000470 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming,
471 "ArmnnPreparedModel_1_2::ExecuteGraph");
472 return false;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100473 }
474 }
Kevin May7bdaac52020-02-10 12:10:07 +0000475 catch (armnn::Exception& e)
476 {
Derek Lamberti4de83c52020-03-17 13:40:18 +0000477 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
478 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
479 return false;
Kevin May7bdaac52020-02-10 12:10:07 +0000480 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000481 catch (std::exception& e)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100482 {
Kevin May7bdaac52020-02-10 12:10:07 +0000483 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000484 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
485 return false;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100486 }
487
Derek Lamberti4de83c52020-03-17 13:40:18 +0000488 CommitPools(*pMemPools);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100489
Derek Lamberti4de83c52020-03-17 13:40:18 +0000490 DumpTensorsIfRequired("Output", outputTensors);
Kevin Mayec1e5b82020-02-26 17:00:39 +0000491
Sadik Armagan188675f2021-02-12 17:16:42 +0000492 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100493 {
494 driverEnd = Now();
Sadik Armagan188675f2021-02-12 17:16:42 +0000495 V1_2::Timing timing;
Mike Kelly44381512019-07-08 17:37:35 +0100496 timing.timeOnDevice = MicrosecondsDuration(deviceEnd, deviceStart);
Derek Lamberti4de83c52020-03-17 13:40:18 +0000497 timing.timeInDriver = MicrosecondsDuration(driverEnd, cb.ctx.driverStart);
498 ALOGV("ArmnnPreparedModel_1_2::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
499 timing.timeInDriver);
500 cb.callback(V1_0::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_2::ExecuteGraph");
501 } else {
502 cb.callback(V1_0::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
Mike Kelly44381512019-07-08 17:37:35 +0100503 }
Derek Lamberti4de83c52020-03-17 13:40:18 +0000504
505 return true;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100506}
507
Derek Lamberti4de83c52020-03-17 13:40:18 +0000508template<typename HalVersion>
509bool ArmnnPreparedModel_1_2<HalVersion>::ExecuteWithDummyInputs()
510{
511 std::vector<std::vector<char>> storage;
512 armnn::InputTensors inputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000513 for (unsigned int i = 0; i < getMainModel(m_Model).inputIndexes.size(); i++)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000514 {
515 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
516 storage.emplace_back(inputTensorInfo.GetNumBytes());
517 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
518
519 inputTensors.emplace_back(i, inputTensor);
520 }
521
522 armnn::OutputTensors outputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000523 for (unsigned int i = 0; i < getMainModel(m_Model).outputIndexes.size(); i++)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000524 {
525 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
526 storage.emplace_back(outputTensorInfo.GetNumBytes());
527 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
528
529 outputTensors.emplace_back(i, outputTensor);
530 }
531
Sadik Armagan188675f2021-02-12 17:16:42 +0000532 auto nullCallback = [](V1_0::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Derek Lamberti4de83c52020-03-17 13:40:18 +0000533 CallbackContext_1_2 callbackContext;
534 callbackContext.callback = nullCallback;
Sadik Armagan188675f2021-02-12 17:16:42 +0000535 callbackContext.ctx.measureTimings = V1_2::MeasureTiming::NO;
Derek Lamberti4de83c52020-03-17 13:40:18 +0000536 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
537 return ExecuteGraph(memPools,
538 inputTensors,
539 outputTensors,
540 callbackContext);
541}
542
543template<typename HalVersion>
544Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::Execute(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000545 V1_2::MeasureTiming measureTiming,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000546 CallbackAsync_1_2 callback)
547{
548 ExecutionContext_1_2 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000549 if (measureTiming == V1_2::MeasureTiming::YES)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000550 {
551 ctx.measureTimings = measureTiming;
552 ctx.driverStart = Now();
553 }
554
555 ALOGV("ArmnnPreparedModel_1_2::execute(): %s", GetModelSummary(m_Model).c_str());
556 m_RequestCount++;
557
558 if (!android::nn::validateRequest(request, m_Model))
559 {
560 callback(V1_0::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
561 return V1_0::ErrorStatus::INVALID_ARGUMENT;
562 }
563
564 if (!m_RequestInputsAndOutputsDumpDir.empty())
565 {
566 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
567 }
568
569 // map the memory pool into shared pointers
570 // use a shared memory pools vector on the heap, as it is passed to the request thread
571 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
572
573 // allocate the tensors on the heap, as they are passed to the request thread
574 auto inputTensors = std::make_shared<armnn::InputTensors>();
575 auto outputTensors = std::make_shared<armnn::OutputTensors>();
576
577 auto prepareStatus = PrepareMemoryForIO(*inputTensors, *outputTensors, *memPools, request, callback);
578 switch(prepareStatus)
579 {
580 case V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
581 return V1_0::ErrorStatus::NONE;
582 case V1_0::ErrorStatus::GENERAL_FAILURE:
583 return V1_0::ErrorStatus::GENERAL_FAILURE;
584 default:
585 {}
586 }
587
Derek Lamberti4de83c52020-03-17 13:40:18 +0000588
589 // post the request for asynchronous execution
590 CallbackContext_1_2 cb;
591 cb.callback = callback;
592 cb.ctx = ctx;
Finn Williamsd8fb5402021-05-19 20:52:00 +0100593
594 if (m_AsyncModelExecutionEnabled)
595 {
596 ALOGV("ArmnnPreparedModel_1_2::execute(...) before ScheduleGraphForExecution");
597 ScheduleGraphForExecution(memPools, inputTensors, outputTensors, cb);
598 ALOGV("ArmnnPreparedModel_1_2::execute(...) after ScheduleGraphForExecution");
599 return V1_0::ErrorStatus::NONE;
600 }
601
602 ALOGV("ArmnnPreparedModel_1_2::execute(...) before PostMsg");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000603 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
604 ALOGV("ArmnnPreparedModel_1_2::execute(...) after PostMsg");
605 return V1_0::ErrorStatus::NONE;
606}
607
Mike Kellyb5fdf382019-06-11 16:35:25 +0100608template<typename HalVersion>
609Return<void> ArmnnPreparedModel_1_2<HalVersion>::configureExecutionBurst(
Derek Lamberti4de83c52020-03-17 13:40:18 +0000610 const sp<V1_2::IBurstCallback>& callback,
611 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
612 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
613 V1_2::IPreparedModel::configureExecutionBurst_cb cb)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100614{
615 ALOGV("ArmnnPreparedModel_1_2::configureExecutionBurst");
Mike Kelly65c42dc2019-07-22 14:06:00 +0100616 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
617 requestChannel,
618 resultChannel,
Kevin May42477c12020-03-26 13:34:14 +0000619 this);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100620
Mike Kelly44381512019-07-08 17:37:35 +0100621 if (burst == nullptr)
622 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000623 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
Mike Kelly44381512019-07-08 17:37:35 +0100624 }
625 else
626 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000627 cb(V1_0::ErrorStatus::NONE, burst);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100628 }
629 return Void();
630}
631
Finn Williamsd8fb5402021-05-19 20:52:00 +0100632/// Schedule the graph prepared from the request for execution
633template<typename HalVersion>
634template<typename CallbackContext>
635void ArmnnPreparedModel_1_2<HalVersion>::ScheduleGraphForExecution(
636 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
637 std::shared_ptr<armnn::InputTensors>& inputTensors,
638 std::shared_ptr<armnn::OutputTensors>& outputTensors,
639 CallbackContext callbackContext)
640{
641 ALOGV("ArmnnPreparedModel_1_2::ScheduleGraphForExecution(...)");
642
643 DumpTensorsIfRequired("Input", *inputTensors);
644
645 unsigned int outputTensorSize = outputTensors.get()->size();
646 std::vector<V1_2::OutputShape> outputShapes(outputTensorSize);
647 for (unsigned int i = 0; i < outputTensorSize; i++)
648 {
649 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors.get()->at(i);
650 const armnn::Tensor outputTensor = outputTensorPair.second;
651 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
652
653 outputShapes[i] = ComputeShape(outputTensorInfo);
654 }
655
656 auto tpCb = std::make_shared<
657 ArmnnThreadPoolCallback_1_2<CallbackContext_1_2>>(this,
658 pMemPools,
659 outputShapes,
660 inputTensors,
661 outputTensors,
662 callbackContext);
663
664 m_Runtime->Schedule(m_NetworkId,
665 *tpCb->m_InputTensors,
666 *tpCb->m_OutputTensors,
667 armnn::QosExecPriority::High,
668 tpCb);
669 ALOGV("ArmnnPreparedModel_1_2::ScheduleGraphForExecution end");
670}
671
672template<typename HalVersion>
673template <typename CallbackContext>
674void ArmnnPreparedModel_1_2<HalVersion>::ArmnnThreadPoolCallback_1_2<CallbackContext>::Notify(
675 armnn::Status status, armnn::InferenceTimingPair timeTaken)
676{
677 ALOGV("ArmnnPreparedModel_1_2::ArmnnThreadPoolCallback_1_2 Notify");
678
679 TimePoint driverEnd;
680
681 CommitPools(*m_MemPools);
682
683 m_Model->DumpTensorsIfRequired("Output", *m_OutputTensors);
684
685 if (status != armnn::Status::Success)
686 {
687 ALOGW("ArmnnThreadPoolCallback::Notify EnqueueWorkload failed");
688 m_CallbackContext.callback(
689 V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel::ExecuteGraph");
690 return;
691 }
692
693 if (m_CallbackContext.ctx.measureTimings == V1_2::MeasureTiming::YES)
694 {
695 driverEnd = std::chrono::steady_clock::now();
696 V1_2::Timing timing;
697 timing.timeOnDevice = MicrosecondsDuration(timeTaken.second, timeTaken.first);
698 timing.timeInDriver = MicrosecondsDuration(driverEnd, m_CallbackContext.ctx.driverStart);
699 ALOGV("ArmnnPreparedModel_1_2::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
700 timing.timeInDriver);
701 m_CallbackContext.callback(
702 V1_0::ErrorStatus::NONE, m_OutputShapes, timing, "ArmnnPreparedModel_1_2::ExecuteGraph");
703 } else {
704 m_CallbackContext.callback(
705 V1_0::ErrorStatus::NONE, m_OutputShapes, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
706 }
707 return;
708}
709
Kevin May42477c12020-03-26 13:34:14 +0000710#if defined(ARMNN_ANDROID_NN_V1_2) || defined(ARMNN_ANDROID_NN_V1_3)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100711template class ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>;
Derek Lamberti4de83c52020-03-17 13:40:18 +0000712template bool ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>::ExecuteGraph<CallbackContext_1_2>(
713 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
714 armnn::InputTensors& pInputTensors,
715 armnn::OutputTensors& pOutputTensors,
716 CallbackContext_1_2 cb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100717
718template void ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>::ScheduleGraphForExecution<CallbackContext_1_2>(
719 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
720 std::shared_ptr<armnn::InputTensors>& inputTensors,
721 std::shared_ptr<armnn::OutputTensors>& outputTensors,
722 CallbackContext_1_2 callbackContext);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100723#endif
724
725} // namespace armnn_driver