blob: 155f8b25865574c30a7ff9c074b88dee0a2e7a3d [file] [log] [blame]
Kevin May42477c12020-03-26 13:34:14 +00001//
2// Copyright © 2020 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#define LOG_TAG "ArmnnDriver"
7
8#include "ArmnnPreparedModel_1_3.hpp"
9#include "Utils.hpp"
10
11#include <Utils.h>
12#include <boost/format.hpp>
13#include <log/log.h>
14#include <OperationsUtils.h>
15#include <ExecutionBurstServer.h>
16#include <ValidateHal.h>
17
18#include <cassert>
19#include <cinttypes>
20
21using namespace android;
22using namespace android::hardware;
23
24namespace {
25
26static const Timing g_NoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX};
27using namespace armnn_driver;
28using TimePoint = std::chrono::steady_clock::time_point;
29
30TimePoint Now()
31{
32 return std::chrono::steady_clock::now();
33}
34
35unsigned long MicrosecondsDuration(TimePoint endPoint, TimePoint startPoint)
36{
37 return static_cast<unsigned long>(std::chrono::duration_cast<std::chrono::microseconds>(
38 endPoint - startPoint).count());
39}
40
41void NotifyCallbackAndCheck(const ::android::sp<V1_0::IExecutionCallback>& callback,
42 V1_3::ErrorStatus errorStatus,
43 std::vector<OutputShape>,
44 const Timing,
45 std::string callingFunction)
46{
47 Return<void> returned = callback->notify(convertToV1_0(errorStatus));
48 // This check is required, if the callback fails and it isn't checked it will bring down the service
49 if (!returned.isOk())
50 {
51 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
52 callingFunction.c_str(), returned.description().c_str());
53 }
54}
55
56void NotifyCallbackAndCheck(const ::android::sp<V1_2::IExecutionCallback>& callback,
57 V1_3::ErrorStatus errorStatus,
58 std::vector<OutputShape> outputShapes,
59 const Timing timing,
60 std::string callingFunction)
61{
62 Return<void> returned = callback->notify_1_2(convertToV1_0(errorStatus), outputShapes, timing);
63 // This check is required, if the callback fails and it isn't checked it will bring down the service
64 if (!returned.isOk())
65 {
66 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
67 callingFunction.c_str(), returned.description().c_str());
68 }
69}
70
71void NotifyCallbackAndCheck(const ::android::sp<V1_3::IExecutionCallback>& callback,
72 V1_3::ErrorStatus errorStatus,
73 std::vector<OutputShape> outputShapes,
74 const Timing timing,
75 std::string callingFunction)
76{
77 Return<void> returned = callback->notify_1_3(errorStatus, outputShapes, timing);
78 // This check is required, if the callback fails and it isn't checked it will bring down the service
79 if (!returned.isOk())
80 {
81 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
82 callingFunction.c_str(), returned.description().c_str());
83 }
84}
85
86bool ValidateRequestArgument(const RequestArgument& requestArg, const armnn::TensorInfo& tensorInfo)
87{
88 if (requestArg.dimensions.size() != 0)
89 {
90 if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
91 {
92 ALOGE("Mismatched dimensions (request argument: %zu, expected: %u)",
93 requestArg.dimensions.size(), tensorInfo.GetNumDimensions());
94 return false;
95 }
96
97 for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
98 {
99 if (requestArg.dimensions[d] != tensorInfo.GetShape()[d])
100 {
101 ALOGE("Mismatched size for dimension %d (request argument: %u, expected %u)",
102 d, requestArg.dimensions[d], tensorInfo.GetShape()[d]);
103 return false;
104 }
105 }
106 }
107
108 return true;
109}
110
111armnn::Tensor GetTensorForRequestArgument(const RequestArgument& requestArg,
112 const armnn::TensorInfo& tensorInfo,
113 const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
114{
115 if (!ValidateRequestArgument(requestArg, tensorInfo))
116 {
117 return armnn::Tensor();
118 }
119
120 return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
121}
122
123inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
124{
125 return tensorNamePrefix + std::to_string(index);
126}
127
128} // anonymous namespace
129
130using namespace android::hardware;
131
132namespace armnn_driver
133{
134
135template<typename HalVersion>
136RequestThread<ArmnnPreparedModel_1_3, HalVersion, CallbackContext_1_3>
137 ArmnnPreparedModel_1_3<HalVersion>::m_RequestThread;
138
139template<typename HalVersion>
140template<typename TensorBindingCollection>
141void ArmnnPreparedModel_1_3<HalVersion>::DumpTensorsIfRequired(char const* tensorNamePrefix,
142 const TensorBindingCollection& tensorBindings)
143{
144 if (!m_RequestInputsAndOutputsDumpDir.empty())
145 {
146 const std::string requestName = boost::str(boost::format("%1%_%2%.dump") % m_NetworkId % m_RequestCount);
147 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
148 {
149 DumpTensor(m_RequestInputsAndOutputsDumpDir,
150 requestName,
151 BuildTensorName(tensorNamePrefix, i),
152 tensorBindings[i].second);
153 }
154 }
155}
156
157template<typename HalVersion>
158ArmnnPreparedModel_1_3<HalVersion>::ArmnnPreparedModel_1_3(armnn::NetworkId networkId,
159 armnn::IRuntime* runtime,
160 const V1_3::Model& model,
161 const std::string& requestInputsAndOutputsDumpDir,
162 const bool gpuProfilingEnabled)
163 : m_NetworkId(networkId)
164 , m_Runtime(runtime)
165 , m_Model(model)
166 , m_RequestCount(0)
167 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
168 , m_GpuProfilingEnabled(gpuProfilingEnabled)
169{
170 // Enable profiling if required.
171 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
172}
173
174template<typename HalVersion>
175ArmnnPreparedModel_1_3<HalVersion>::~ArmnnPreparedModel_1_3()
176{
177 // Get a hold of the profiler used by this model.
178 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
179
180 // Unload the network associated with this model.
181 m_Runtime->UnloadNetwork(m_NetworkId);
182
183 // Dump the profiling info to a file if required.
184 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId, profiler.get());
185}
186
187template<typename HalVersion>
188Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute(const V1_0::Request& request,
189 const ::android::sp<V1_0::IExecutionCallback>& callback)
190{
191 if (callback.get() == nullptr)
192 {
193 ALOGE("ArmnnPreparedModel_1_3::execute invalid callback passed");
194 return V1_0::ErrorStatus::INVALID_ARGUMENT;
195 }
196
197 auto cb = [callback](V1_3::ErrorStatus errorStatus,
198 std::vector<OutputShape> outputShapes,
199 const Timing& timing,
200 std::string callingFunction)
201 {
202 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
203 };
204
205
206 return convertToV1_0(Execute(convertToV1_3(request), MeasureTiming::NO, cb));
207}
208
209template<typename HalVersion>
210Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute_1_2(
211 const V1_0::Request& request,
212 MeasureTiming measureTiming,
213 const sp<V1_2::IExecutionCallback>& callback)
214{
215 if (callback.get() == nullptr)
216 {
217 ALOGE("ArmnnPreparedModel_1_3::execute_1_2 invalid callback passed");
218 return V1_0::ErrorStatus::INVALID_ARGUMENT;
219 }
220
221 auto cb = [callback](V1_3::ErrorStatus errorStatus,
222 std::vector<OutputShape> outputShapes,
223 const Timing& timing,
224 std::string callingFunction)
225 {
226 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
227 };
228
229 return convertToV1_0(Execute(convertToV1_3(request), measureTiming, cb));
230}
231
232template<typename HalVersion>
233Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute_1_3(
234 const V1_3::Request& request,
235 MeasureTiming measureTiming,
236 const V1_3::OptionalTimePoint&,
237 const sp<V1_3::IExecutionCallback>& callback)
238{
239 if (callback.get() == nullptr)
240 {
241 ALOGE("ArmnnPreparedModel_1_3::execute_1_3 invalid callback passed");
242 return V1_3::ErrorStatus::INVALID_ARGUMENT;
243 }
244
245 auto cb = [callback](V1_3::ErrorStatus errorStatus,
246 std::vector<OutputShape> outputShapes,
247 const Timing& timing,
248 std::string callingFunction)
249 {
250 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
251 };
252
253 return Execute(request, measureTiming, cb);
254}
255
256template<typename HalVersion>
257Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeFenced(const V1_3::Request&,
258 const hidl_vec<hidl_handle>&,
259 MeasureTiming,
260 const OptionalTimePoint&,
261 const OptionalTimeoutDuration&,
262 executeFenced_cb cb)
263{
264 cb(ErrorStatus::DEVICE_UNAVAILABLE, hidl_handle(nullptr), nullptr);
265 return Void();
266}
267
268template<typename HalVersion>
269Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForInputs(
270 armnn::InputTensors& inputs,
271 const V1_3::Request& request,
272 const std::vector<android::nn::RunTimePoolInfo>& memPools)
273{
274 inputs.reserve(request.inputs.size());
275 for (unsigned int i = 0; i < request.inputs.size(); i++)
276 {
277 const auto& inputArg = request.inputs[i];
278
279 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
280 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
281
282 if (inputTensor.GetMemoryArea() == nullptr)
283 {
284 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
285 return V1_3::ErrorStatus::GENERAL_FAILURE;
286 }
287
288 inputs.emplace_back(i, inputTensor);
289 }
290
291 return V1_3::ErrorStatus::NONE;
292}
293
294template<typename HalVersion>
295Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForOutputs(
296 armnn::OutputTensors& outputs,
297 std::vector<OutputShape> &outputShapes,
298 const V1_3::Request& request,
299 const std::vector<android::nn::RunTimePoolInfo>& memPools)
300{
301 outputs.reserve(request.outputs.size());
302 for (unsigned int i = 0; i < request.outputs.size(); i++)
303 {
304 const auto& outputArg = request.outputs[i];
305
306 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
307 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
308 if (outputTensor.GetMemoryArea() == nullptr)
309 {
310 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
311 return V1_3::ErrorStatus::GENERAL_FAILURE;
312 }
313
314 const size_t outputSize = outputTensorInfo.GetNumBytes();
315 const size_t bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
316 if (bufferSize < outputSize)
317 {
318 ALOGW("ArmnnPreparedModel_1_3::Execute failed");
319 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
320 }
321
322 outputs.emplace_back(i, outputTensor);
323 outputShapes[i] = ComputeShape(outputTensorInfo);
324 }
325
326 return V1_3::ErrorStatus::NONE;
327}
328
329template<typename HalVersion>
330std::tuple<V1_3::ErrorStatus, hidl_vec<OutputShape>, Timing, std::string>
331 ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForIO(armnn::InputTensors& inputs,
332 armnn::OutputTensors& outputs,
333 std::vector<android::nn::RunTimePoolInfo>& memPools,
334 const V1_3::Request& request)
335{
336 if (!setRunTimePoolInfosFromMemoryPools(&memPools, request.pools))
337 {
338 return {ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
339 }
340
341 // add the inputs and outputs with their data
342 try
343 {
344 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_3::ErrorStatus::NONE)
345 {
346 return {ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
347 }
348
349 std::vector<OutputShape> outputShapes(request.outputs.size());
350
351 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
352 if (errorStatus != V1_3::ErrorStatus::NONE)
353 {
354 return {errorStatus, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
355 }
356 }
357 catch (armnn::Exception& e)
358 {
359 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
360 return {ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
361 }
362 catch (std::exception& e)
363 {
364 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
365 return {ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
366 }
367
368 return {V1_3::ErrorStatus::NONE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
369}
370
371template<typename HalVersion>
372template<typename CallbackContext>
373Return<void> ArmnnPreparedModel_1_3<HalVersion>::ExecuteSynchronously(const V1_3::Request& request,
374 CallbackContext cbCtx)
375{
376 if (cbCtx.ctx.measureTimings == MeasureTiming::YES)
377 {
378 cbCtx.ctx.driverStart = Now();
379 }
380
381 if (!android::nn::validateRequest(convertToV1_3(request), m_Model))
382 {
383 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
384 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
385 {},
386 g_NoTiming,
387 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
388 return Void();
389 }
390
391 if (!android::nn::validateRequest(request, m_Model))
392 {
393 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
394 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
395 {},
396 g_NoTiming,
397 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
398 }
399
400
401 // map the memory pool into shared pointers
402 // use a shared memory pools vector on the heap, as it is passed to the request thread
403 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
404
405 // allocate the tensors on the heap, as they are passed to the request thread
406 auto inputs = std::make_shared<armnn::InputTensors>();
407 auto outputs = std::make_shared<armnn::OutputTensors>();
408
409 auto [status, outputShapes, timing, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
410 if (status != V1_3::ErrorStatus::NONE)
411 {
412 cbCtx.callback(status, outputShapes, timing, message);
413 }
414
415 ALOGV("ArmnnPreparedModel_1_3::ExecuteSynchronously() before Execution");
416
417 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
418 return Void();
419}
420
421template<typename HalVersion>
422Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously(const V1_0::Request& request,
423 MeasureTiming measureTiming,
424 executeSynchronously_cb cb)
425{
426 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
427 m_RequestCount++;
428
429 if (cb == nullptr)
430 {
431 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously invalid callback passed");
432 return Void();
433 }
434
435 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
436 std::vector<OutputShape> outputShapes,
437 const Timing& timing,
438 std::string)
439 {
440 cb(convertToV1_0(errorStatus), outputShapes, timing);
441 };
442
443 CallbackContext_1_3 cbCtx;
444 cbCtx.callback = cbWrapper;
445 cbCtx.ctx.measureTimings = measureTiming;
446
447 ExecuteSynchronously(convertToV1_3(request), cbCtx);
448 return Void();
449}
450
451template<typename HalVersion>
452Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously_1_3(const V1_3::Request& request,
453 MeasureTiming measureTiming,
454 const V1_3::OptionalTimePoint& deadline,
455 executeSynchronously_1_3_cb cb)
456{
457 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously_1_3(): %s", GetModelSummary(m_Model).c_str());
458 m_RequestCount++;
459
460 if (cb == nullptr)
461 {
462 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid callback passed");
463 return Void();
464 }
465
466 if (deadline.getDiscriminator() != OptionalTimePoint::hidl_discriminator::none)
467 {
468 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid request model");
469 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming);
470 return Void();
471 }
472
473 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
474 std::vector<OutputShape> outputShapes,
475 const Timing& timing,
476 std::string)
477 {
478 cb(errorStatus, outputShapes, timing);
479 };
480
481 CallbackContext_1_3 cbCtx;
482 cbCtx.callback = cbWrapper;
483 cbCtx.ctx.measureTimings = measureTiming;
484
485 ExecuteSynchronously(request, cbCtx);
486 return Void();
487}
488
489template<typename HalVersion>
490Return<void> ArmnnPreparedModel_1_3<HalVersion>::configureExecutionBurst(
491 const sp<V1_2::IBurstCallback>& callback,
492 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
493 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
494 V1_3::IPreparedModel::configureExecutionBurst_cb cb)
495{
496 ALOGV("ArmnnPreparedModel_1_3::configureExecutionBurst");
497 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
498 requestChannel,
499 resultChannel,
500 this);
501
502 if (burst == nullptr)
503 {
504 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
505 }
506 else
507 {
508 cb(V1_0::ErrorStatus::NONE, burst);
509 }
510 return Void();
511}
512
513template<typename HalVersion>
514template<typename CallbackContext>
515bool ArmnnPreparedModel_1_3<HalVersion>::ExecuteGraph(
516 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
517 armnn::InputTensors& inputTensors,
518 armnn::OutputTensors& outputTensors,
519 CallbackContext cb)
520{
521 ALOGV("ArmnnPreparedModel_1_3::ExecuteGraph(...)");
522
523 TimePoint driverEnd, deviceStart, deviceEnd;
524
525 DumpTensorsIfRequired("Input", inputTensors);
526
527 std::vector<OutputShape> outputShapes(outputTensors.size());
528 for (unsigned int i = 0; i < outputTensors.size(); i++)
529 {
530 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
531 const armnn::Tensor outputTensor = outputTensorPair.second;
532 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
533
534 outputShapes[i] = ComputeShape(outputTensorInfo);
535 }
536
537 // run it
538 try
539 {
540 if (cb.ctx.measureTimings == MeasureTiming::YES)
541 {
542 deviceStart = Now();
543 }
544
545 armnn::Status status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
546
547 if (cb.ctx.measureTimings == MeasureTiming::YES)
548 {
549 deviceEnd = Now();
550 }
551 if (status != armnn::Status::Success)
552 {
553 ALOGW("EnqueueWorkload failed");
554 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming,
555 "ArmnnPreparedModel_1_3::ExecuteGraph");
556 return false;
557 }
558 }
559 catch (armnn::Exception& e)
560 {
561 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
562 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
563 return false;
564 }
565 catch (std::exception& e)
566 {
567 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
568 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
569 return false;
570 }
571
572 CommitPools(*pMemPools);
573
574 DumpTensorsIfRequired("Output", outputTensors);
575
576 if (cb.ctx.measureTimings == MeasureTiming::YES)
577 {
578 driverEnd = Now();
579 Timing timing;
580 timing.timeOnDevice = MicrosecondsDuration(deviceEnd, deviceStart);
581 timing.timeInDriver = MicrosecondsDuration(driverEnd, cb.ctx.driverStart);
582 ALOGV("ArmnnPreparedModel_1_2::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
583 timing.timeInDriver);
584 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
585 } else {
586 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
587 }
588
589 return true;
590}
591
592template<typename HalVersion>
593bool ArmnnPreparedModel_1_3<HalVersion>::ExecuteWithDummyInputs()
594{
595 std::vector<std::vector<char>> storage;
596 armnn::InputTensors inputTensors;
597 for (unsigned int i = 0; i < getMainModel(m_Model).inputIndexes.size(); i++)
598 {
599 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
600 storage.emplace_back(inputTensorInfo.GetNumBytes());
601 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
602
603 inputTensors.emplace_back(i, inputTensor);
604 }
605
606 armnn::OutputTensors outputTensors;
607 for (unsigned int i = 0; i < getMainModel(m_Model).outputIndexes.size(); i++)
608 {
609 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
610 storage.emplace_back(outputTensorInfo.GetNumBytes());
611 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
612
613 outputTensors.emplace_back(i, outputTensor);
614 }
615
616 auto nullCallback = [](V1_3::ErrorStatus, std::vector<OutputShape>, const Timing&, std::string) {};
617 CallbackContext_1_3 callbackContext;
618 callbackContext.callback = nullCallback;
619 callbackContext.ctx.measureTimings = MeasureTiming::NO;
620 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
621 return ExecuteGraph(memPools,
622 inputTensors,
623 outputTensors,
624 callbackContext);
625}
626
627template<typename HalVersion>
628Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::Execute(const V1_3::Request& request,
629 MeasureTiming measureTiming,
630 CallbackAsync_1_3 callback)
631{
632 ExecutionContext_1_3 ctx;
633 if (measureTiming == MeasureTiming::YES)
634 {
635 ctx.measureTimings = measureTiming;
636 ctx.driverStart = Now();
637 }
638
639 ALOGV("ArmnnPreparedModel_1_3::execute(): %s", GetModelSummary(m_Model).c_str());
640 m_RequestCount++;
641
642 if (!android::nn::validateRequest(request, m_Model))
643 {
644 callback(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute");
645 return V1_3::ErrorStatus::INVALID_ARGUMENT;
646 }
647
648 if (!m_RequestInputsAndOutputsDumpDir.empty())
649 {
650 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
651 }
652
653 // map the memory pool into shared pointers
654 // use a shared memory pools vector on the heap, as it is passed to the request thread
655 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
656
657 // allocate the tensors on the heap, as they are passed to the request thread
658 auto inputTensors = std::make_shared<armnn::InputTensors>();
659 auto outputTensors = std::make_shared<armnn::OutputTensors>();
660
661 auto [status, outShapes, timing, message] = PrepareMemoryForIO(*inputTensors, *outputTensors,
662 *memPools, request);
663 if (status != V1_3::ErrorStatus::NONE)
664 {
665 callback(status, outShapes, timing, message);
666 }
667
668 switch(status)
669 {
670 case V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
671 return V1_3::ErrorStatus::NONE;
672 case V1_3::ErrorStatus::GENERAL_FAILURE:
673 return V1_3::ErrorStatus::GENERAL_FAILURE;
674 default:
675 {}
676 }
677
678 ALOGV("ArmnnPreparedModel_1_3::execute(...) before PostMsg");
679
680 // post the request for asynchronous execution
681 CallbackContext_1_3 cb;
682 cb.callback = callback;
683 cb.ctx = ctx;
684 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
685 ALOGV("ArmnnPreparedModel_1_3::execute(...) after PostMsg");
686 return V1_3::ErrorStatus::NONE;
687}
688
689#ifdef ARMNN_ANDROID_NN_V1_3
690template class ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>;
691template bool ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ExecuteGraph<CallbackContext_1_3>(
692 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
693 armnn::InputTensors& pInputTensors,
694 armnn::OutputTensors& pOutputTensors,
695 CallbackContext_1_3 cb);
696#endif
697
698} // namespace armnn_driver