blob: 86c04948e0f377b41807c076f2fc98965bf864de [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&,
Kevin May352d8382020-03-31 15:03:42 +0100237 const V1_3::OptionalTimeoutDuration&,
Kevin May42477c12020-03-26 13:34:14 +0000238 const sp<V1_3::IExecutionCallback>& callback)
239{
240 if (callback.get() == nullptr)
241 {
242 ALOGE("ArmnnPreparedModel_1_3::execute_1_3 invalid callback passed");
243 return V1_3::ErrorStatus::INVALID_ARGUMENT;
244 }
245
246 auto cb = [callback](V1_3::ErrorStatus errorStatus,
247 std::vector<OutputShape> outputShapes,
248 const Timing& timing,
249 std::string callingFunction)
250 {
251 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
252 };
253
254 return Execute(request, measureTiming, cb);
255}
256
257template<typename HalVersion>
258Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeFenced(const V1_3::Request&,
259 const hidl_vec<hidl_handle>&,
260 MeasureTiming,
261 const OptionalTimePoint&,
262 const OptionalTimeoutDuration&,
Kevin May352d8382020-03-31 15:03:42 +0100263 const OptionalTimeoutDuration&,
Kevin May42477c12020-03-26 13:34:14 +0000264 executeFenced_cb cb)
265{
266 cb(ErrorStatus::DEVICE_UNAVAILABLE, hidl_handle(nullptr), nullptr);
267 return Void();
268}
269
270template<typename HalVersion>
271Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForInputs(
272 armnn::InputTensors& inputs,
273 const V1_3::Request& request,
274 const std::vector<android::nn::RunTimePoolInfo>& memPools)
275{
276 inputs.reserve(request.inputs.size());
277 for (unsigned int i = 0; i < request.inputs.size(); i++)
278 {
279 const auto& inputArg = request.inputs[i];
280
281 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
282 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
283
284 if (inputTensor.GetMemoryArea() == nullptr)
285 {
286 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
287 return V1_3::ErrorStatus::GENERAL_FAILURE;
288 }
289
290 inputs.emplace_back(i, inputTensor);
291 }
292
293 return V1_3::ErrorStatus::NONE;
294}
295
296template<typename HalVersion>
297Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForOutputs(
298 armnn::OutputTensors& outputs,
299 std::vector<OutputShape> &outputShapes,
300 const V1_3::Request& request,
301 const std::vector<android::nn::RunTimePoolInfo>& memPools)
302{
303 outputs.reserve(request.outputs.size());
304 for (unsigned int i = 0; i < request.outputs.size(); i++)
305 {
306 const auto& outputArg = request.outputs[i];
307
308 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
309 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
310 if (outputTensor.GetMemoryArea() == nullptr)
311 {
312 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
313 return V1_3::ErrorStatus::GENERAL_FAILURE;
314 }
315
316 const size_t outputSize = outputTensorInfo.GetNumBytes();
317 const size_t bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
318 if (bufferSize < outputSize)
319 {
320 ALOGW("ArmnnPreparedModel_1_3::Execute failed");
321 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
322 }
323
324 outputs.emplace_back(i, outputTensor);
325 outputShapes[i] = ComputeShape(outputTensorInfo);
326 }
327
328 return V1_3::ErrorStatus::NONE;
329}
330
331template<typename HalVersion>
332std::tuple<V1_3::ErrorStatus, hidl_vec<OutputShape>, Timing, std::string>
333 ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForIO(armnn::InputTensors& inputs,
334 armnn::OutputTensors& outputs,
335 std::vector<android::nn::RunTimePoolInfo>& memPools,
336 const V1_3::Request& request)
337{
338 if (!setRunTimePoolInfosFromMemoryPools(&memPools, request.pools))
339 {
340 return {ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
341 }
342
343 // add the inputs and outputs with their data
344 try
345 {
346 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_3::ErrorStatus::NONE)
347 {
348 return {ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
349 }
350
351 std::vector<OutputShape> outputShapes(request.outputs.size());
352
353 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
354 if (errorStatus != V1_3::ErrorStatus::NONE)
355 {
356 return {errorStatus, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
357 }
358 }
359 catch (armnn::Exception& e)
360 {
361 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
362 return {ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
363 }
364 catch (std::exception& e)
365 {
366 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
367 return {ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
368 }
369
370 return {V1_3::ErrorStatus::NONE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
371}
372
373template<typename HalVersion>
374template<typename CallbackContext>
375Return<void> ArmnnPreparedModel_1_3<HalVersion>::ExecuteSynchronously(const V1_3::Request& request,
376 CallbackContext cbCtx)
377{
378 if (cbCtx.ctx.measureTimings == MeasureTiming::YES)
379 {
380 cbCtx.ctx.driverStart = Now();
381 }
382
383 if (!android::nn::validateRequest(convertToV1_3(request), m_Model))
384 {
385 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
386 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
387 {},
388 g_NoTiming,
389 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
390 return Void();
391 }
392
393 if (!android::nn::validateRequest(request, m_Model))
394 {
395 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
396 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
397 {},
398 g_NoTiming,
399 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
400 }
401
402
403 // map the memory pool into shared pointers
404 // use a shared memory pools vector on the heap, as it is passed to the request thread
405 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
406
407 // allocate the tensors on the heap, as they are passed to the request thread
408 auto inputs = std::make_shared<armnn::InputTensors>();
409 auto outputs = std::make_shared<armnn::OutputTensors>();
410
411 auto [status, outputShapes, timing, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
412 if (status != V1_3::ErrorStatus::NONE)
413 {
414 cbCtx.callback(status, outputShapes, timing, message);
415 }
416
417 ALOGV("ArmnnPreparedModel_1_3::ExecuteSynchronously() before Execution");
418
419 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
420 return Void();
421}
422
423template<typename HalVersion>
424Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously(const V1_0::Request& request,
425 MeasureTiming measureTiming,
426 executeSynchronously_cb cb)
427{
428 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
429 m_RequestCount++;
430
431 if (cb == nullptr)
432 {
433 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously invalid callback passed");
434 return Void();
435 }
436
437 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
438 std::vector<OutputShape> outputShapes,
439 const Timing& timing,
440 std::string)
441 {
442 cb(convertToV1_0(errorStatus), outputShapes, timing);
443 };
444
445 CallbackContext_1_3 cbCtx;
446 cbCtx.callback = cbWrapper;
447 cbCtx.ctx.measureTimings = measureTiming;
448
449 ExecuteSynchronously(convertToV1_3(request), cbCtx);
450 return Void();
451}
452
453template<typename HalVersion>
Kevin May352d8382020-03-31 15:03:42 +0100454Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously_1_3(
455 const V1_3::Request& request,
456 MeasureTiming measureTiming,
457 const V1_3::OptionalTimePoint& deadline,
458 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
459 executeSynchronously_1_3_cb cb)
Kevin May42477c12020-03-26 13:34:14 +0000460{
461 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously_1_3(): %s", GetModelSummary(m_Model).c_str());
462 m_RequestCount++;
463
464 if (cb == nullptr)
465 {
466 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid callback passed");
467 return Void();
468 }
469
470 if (deadline.getDiscriminator() != OptionalTimePoint::hidl_discriminator::none)
471 {
472 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid request model");
473 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming);
474 return Void();
475 }
476
Kevin May352d8382020-03-31 15:03:42 +0100477 if (loopTimeoutDuration.getDiscriminator() != OptionalTimeoutDuration::hidl_discriminator::none)
478 {
479 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid request model");
480 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming);
481 return Void();
482 }
483
Kevin May42477c12020-03-26 13:34:14 +0000484 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
485 std::vector<OutputShape> outputShapes,
486 const Timing& timing,
487 std::string)
488 {
489 cb(errorStatus, outputShapes, timing);
490 };
491
492 CallbackContext_1_3 cbCtx;
493 cbCtx.callback = cbWrapper;
494 cbCtx.ctx.measureTimings = measureTiming;
495
496 ExecuteSynchronously(request, cbCtx);
497 return Void();
498}
499
500template<typename HalVersion>
501Return<void> ArmnnPreparedModel_1_3<HalVersion>::configureExecutionBurst(
502 const sp<V1_2::IBurstCallback>& callback,
503 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
504 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
505 V1_3::IPreparedModel::configureExecutionBurst_cb cb)
506{
507 ALOGV("ArmnnPreparedModel_1_3::configureExecutionBurst");
508 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
509 requestChannel,
510 resultChannel,
511 this);
512
513 if (burst == nullptr)
514 {
515 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
516 }
517 else
518 {
519 cb(V1_0::ErrorStatus::NONE, burst);
520 }
521 return Void();
522}
523
524template<typename HalVersion>
525template<typename CallbackContext>
526bool ArmnnPreparedModel_1_3<HalVersion>::ExecuteGraph(
527 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
528 armnn::InputTensors& inputTensors,
529 armnn::OutputTensors& outputTensors,
530 CallbackContext cb)
531{
532 ALOGV("ArmnnPreparedModel_1_3::ExecuteGraph(...)");
533
534 TimePoint driverEnd, deviceStart, deviceEnd;
535
536 DumpTensorsIfRequired("Input", inputTensors);
537
538 std::vector<OutputShape> outputShapes(outputTensors.size());
539 for (unsigned int i = 0; i < outputTensors.size(); i++)
540 {
541 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
542 const armnn::Tensor outputTensor = outputTensorPair.second;
543 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
544
545 outputShapes[i] = ComputeShape(outputTensorInfo);
546 }
547
548 // run it
549 try
550 {
551 if (cb.ctx.measureTimings == MeasureTiming::YES)
552 {
553 deviceStart = Now();
554 }
555
556 armnn::Status status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
557
558 if (cb.ctx.measureTimings == MeasureTiming::YES)
559 {
560 deviceEnd = Now();
561 }
562 if (status != armnn::Status::Success)
563 {
564 ALOGW("EnqueueWorkload failed");
565 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming,
566 "ArmnnPreparedModel_1_3::ExecuteGraph");
567 return false;
568 }
569 }
570 catch (armnn::Exception& e)
571 {
572 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
573 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
574 return false;
575 }
576 catch (std::exception& e)
577 {
578 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
579 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
580 return false;
581 }
582
583 CommitPools(*pMemPools);
584
585 DumpTensorsIfRequired("Output", outputTensors);
586
587 if (cb.ctx.measureTimings == MeasureTiming::YES)
588 {
589 driverEnd = Now();
590 Timing timing;
591 timing.timeOnDevice = MicrosecondsDuration(deviceEnd, deviceStart);
592 timing.timeInDriver = MicrosecondsDuration(driverEnd, cb.ctx.driverStart);
593 ALOGV("ArmnnPreparedModel_1_2::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
594 timing.timeInDriver);
595 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
596 } else {
597 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
598 }
599
600 return true;
601}
602
603template<typename HalVersion>
604bool ArmnnPreparedModel_1_3<HalVersion>::ExecuteWithDummyInputs()
605{
606 std::vector<std::vector<char>> storage;
607 armnn::InputTensors inputTensors;
608 for (unsigned int i = 0; i < getMainModel(m_Model).inputIndexes.size(); i++)
609 {
610 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
611 storage.emplace_back(inputTensorInfo.GetNumBytes());
612 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
613
614 inputTensors.emplace_back(i, inputTensor);
615 }
616
617 armnn::OutputTensors outputTensors;
618 for (unsigned int i = 0; i < getMainModel(m_Model).outputIndexes.size(); i++)
619 {
620 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
621 storage.emplace_back(outputTensorInfo.GetNumBytes());
622 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
623
624 outputTensors.emplace_back(i, outputTensor);
625 }
626
627 auto nullCallback = [](V1_3::ErrorStatus, std::vector<OutputShape>, const Timing&, std::string) {};
628 CallbackContext_1_3 callbackContext;
629 callbackContext.callback = nullCallback;
630 callbackContext.ctx.measureTimings = MeasureTiming::NO;
631 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
632 return ExecuteGraph(memPools,
633 inputTensors,
634 outputTensors,
635 callbackContext);
636}
637
638template<typename HalVersion>
639Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::Execute(const V1_3::Request& request,
640 MeasureTiming measureTiming,
641 CallbackAsync_1_3 callback)
642{
643 ExecutionContext_1_3 ctx;
644 if (measureTiming == MeasureTiming::YES)
645 {
646 ctx.measureTimings = measureTiming;
647 ctx.driverStart = Now();
648 }
649
650 ALOGV("ArmnnPreparedModel_1_3::execute(): %s", GetModelSummary(m_Model).c_str());
651 m_RequestCount++;
652
653 if (!android::nn::validateRequest(request, m_Model))
654 {
655 callback(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute");
656 return V1_3::ErrorStatus::INVALID_ARGUMENT;
657 }
658
659 if (!m_RequestInputsAndOutputsDumpDir.empty())
660 {
661 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
662 }
663
664 // map the memory pool into shared pointers
665 // use a shared memory pools vector on the heap, as it is passed to the request thread
666 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
667
668 // allocate the tensors on the heap, as they are passed to the request thread
669 auto inputTensors = std::make_shared<armnn::InputTensors>();
670 auto outputTensors = std::make_shared<armnn::OutputTensors>();
671
672 auto [status, outShapes, timing, message] = PrepareMemoryForIO(*inputTensors, *outputTensors,
673 *memPools, request);
674 if (status != V1_3::ErrorStatus::NONE)
675 {
676 callback(status, outShapes, timing, message);
677 }
678
679 switch(status)
680 {
681 case V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
682 return V1_3::ErrorStatus::NONE;
683 case V1_3::ErrorStatus::GENERAL_FAILURE:
684 return V1_3::ErrorStatus::GENERAL_FAILURE;
685 default:
686 {}
687 }
688
689 ALOGV("ArmnnPreparedModel_1_3::execute(...) before PostMsg");
690
691 // post the request for asynchronous execution
692 CallbackContext_1_3 cb;
693 cb.callback = callback;
694 cb.ctx = ctx;
695 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
696 ALOGV("ArmnnPreparedModel_1_3::execute(...) after PostMsg");
697 return V1_3::ErrorStatus::NONE;
698}
699
700#ifdef ARMNN_ANDROID_NN_V1_3
701template class ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>;
702template bool ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ExecuteGraph<CallbackContext_1_3>(
703 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
704 armnn::InputTensors& pInputTensors,
705 armnn::OutputTensors& pOutputTensors,
706 CallbackContext_1_3 cb);
707#endif
708
709} // namespace armnn_driver