blob: 68156cab013e11752ff11fd17acd21865a66be0b [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{
Sadik Armagan871fe6d2020-04-03 15:32:39 +0100266 cb(ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Kevin May42477c12020-03-26 13:34:14 +0000267 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 {
Sadik Armaganef8a3932020-04-09 17:21:50 +0100340 return {ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000341 }
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");
Sadik Armaganef8a3932020-04-09 17:21:50 +0100400 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000401 }
402
403
404 // map the memory pool into shared pointers
405 // use a shared memory pools vector on the heap, as it is passed to the request thread
406 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
407
408 // allocate the tensors on the heap, as they are passed to the request thread
409 auto inputs = std::make_shared<armnn::InputTensors>();
410 auto outputs = std::make_shared<armnn::OutputTensors>();
411
412 auto [status, outputShapes, timing, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
413 if (status != V1_3::ErrorStatus::NONE)
414 {
415 cbCtx.callback(status, outputShapes, timing, message);
Sadik Armaganef8a3932020-04-09 17:21:50 +0100416 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000417 }
418
419 ALOGV("ArmnnPreparedModel_1_3::ExecuteSynchronously() before Execution");
420
421 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
422 return Void();
423}
424
425template<typename HalVersion>
426Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously(const V1_0::Request& request,
427 MeasureTiming measureTiming,
428 executeSynchronously_cb cb)
429{
430 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
431 m_RequestCount++;
432
433 if (cb == nullptr)
434 {
435 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously invalid callback passed");
436 return Void();
437 }
438
439 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
440 std::vector<OutputShape> outputShapes,
441 const Timing& timing,
442 std::string)
443 {
444 cb(convertToV1_0(errorStatus), outputShapes, timing);
445 };
446
447 CallbackContext_1_3 cbCtx;
448 cbCtx.callback = cbWrapper;
449 cbCtx.ctx.measureTimings = measureTiming;
450
451 ExecuteSynchronously(convertToV1_3(request), cbCtx);
452 return Void();
453}
454
455template<typename HalVersion>
Kevin May352d8382020-03-31 15:03:42 +0100456Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously_1_3(
457 const V1_3::Request& request,
458 MeasureTiming measureTiming,
459 const V1_3::OptionalTimePoint& deadline,
460 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
461 executeSynchronously_1_3_cb cb)
Kevin May42477c12020-03-26 13:34:14 +0000462{
463 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously_1_3(): %s", GetModelSummary(m_Model).c_str());
464 m_RequestCount++;
465
466 if (cb == nullptr)
467 {
468 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid callback passed");
469 return Void();
470 }
471
472 if (deadline.getDiscriminator() != OptionalTimePoint::hidl_discriminator::none)
473 {
474 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid request model");
475 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming);
476 return Void();
477 }
478
Kevin May352d8382020-03-31 15:03:42 +0100479 if (loopTimeoutDuration.getDiscriminator() != OptionalTimeoutDuration::hidl_discriminator::none)
480 {
481 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid request model");
482 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming);
483 return Void();
484 }
485
Kevin May42477c12020-03-26 13:34:14 +0000486 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
487 std::vector<OutputShape> outputShapes,
488 const Timing& timing,
489 std::string)
490 {
491 cb(errorStatus, outputShapes, timing);
492 };
493
494 CallbackContext_1_3 cbCtx;
495 cbCtx.callback = cbWrapper;
496 cbCtx.ctx.measureTimings = measureTiming;
497
498 ExecuteSynchronously(request, cbCtx);
499 return Void();
500}
501
502template<typename HalVersion>
503Return<void> ArmnnPreparedModel_1_3<HalVersion>::configureExecutionBurst(
504 const sp<V1_2::IBurstCallback>& callback,
505 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
506 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
507 V1_3::IPreparedModel::configureExecutionBurst_cb cb)
508{
509 ALOGV("ArmnnPreparedModel_1_3::configureExecutionBurst");
510 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
511 requestChannel,
512 resultChannel,
513 this);
514
515 if (burst == nullptr)
516 {
517 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
518 }
519 else
520 {
521 cb(V1_0::ErrorStatus::NONE, burst);
522 }
523 return Void();
524}
525
526template<typename HalVersion>
527template<typename CallbackContext>
528bool ArmnnPreparedModel_1_3<HalVersion>::ExecuteGraph(
529 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
530 armnn::InputTensors& inputTensors,
531 armnn::OutputTensors& outputTensors,
532 CallbackContext cb)
533{
534 ALOGV("ArmnnPreparedModel_1_3::ExecuteGraph(...)");
535
536 TimePoint driverEnd, deviceStart, deviceEnd;
537
538 DumpTensorsIfRequired("Input", inputTensors);
539
540 std::vector<OutputShape> outputShapes(outputTensors.size());
541 for (unsigned int i = 0; i < outputTensors.size(); i++)
542 {
543 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
544 const armnn::Tensor outputTensor = outputTensorPair.second;
545 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
546
547 outputShapes[i] = ComputeShape(outputTensorInfo);
548 }
549
550 // run it
551 try
552 {
553 if (cb.ctx.measureTimings == MeasureTiming::YES)
554 {
555 deviceStart = Now();
556 }
557
558 armnn::Status status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
559
560 if (cb.ctx.measureTimings == MeasureTiming::YES)
561 {
562 deviceEnd = Now();
563 }
564 if (status != armnn::Status::Success)
565 {
566 ALOGW("EnqueueWorkload failed");
567 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming,
568 "ArmnnPreparedModel_1_3::ExecuteGraph");
569 return false;
570 }
571 }
572 catch (armnn::Exception& e)
573 {
574 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
575 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
576 return false;
577 }
578 catch (std::exception& e)
579 {
580 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
581 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
582 return false;
583 }
584
585 CommitPools(*pMemPools);
586
587 DumpTensorsIfRequired("Output", outputTensors);
588
589 if (cb.ctx.measureTimings == MeasureTiming::YES)
590 {
591 driverEnd = Now();
592 Timing timing;
593 timing.timeOnDevice = MicrosecondsDuration(deviceEnd, deviceStart);
594 timing.timeInDriver = MicrosecondsDuration(driverEnd, cb.ctx.driverStart);
595 ALOGV("ArmnnPreparedModel_1_2::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
596 timing.timeInDriver);
597 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
598 } else {
599 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
600 }
601
602 return true;
603}
604
605template<typename HalVersion>
606bool ArmnnPreparedModel_1_3<HalVersion>::ExecuteWithDummyInputs()
607{
608 std::vector<std::vector<char>> storage;
609 armnn::InputTensors inputTensors;
610 for (unsigned int i = 0; i < getMainModel(m_Model).inputIndexes.size(); i++)
611 {
612 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
613 storage.emplace_back(inputTensorInfo.GetNumBytes());
614 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
615
616 inputTensors.emplace_back(i, inputTensor);
617 }
618
619 armnn::OutputTensors outputTensors;
620 for (unsigned int i = 0; i < getMainModel(m_Model).outputIndexes.size(); i++)
621 {
622 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
623 storage.emplace_back(outputTensorInfo.GetNumBytes());
624 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
625
626 outputTensors.emplace_back(i, outputTensor);
627 }
628
629 auto nullCallback = [](V1_3::ErrorStatus, std::vector<OutputShape>, const Timing&, std::string) {};
630 CallbackContext_1_3 callbackContext;
631 callbackContext.callback = nullCallback;
632 callbackContext.ctx.measureTimings = MeasureTiming::NO;
633 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
634 return ExecuteGraph(memPools,
635 inputTensors,
636 outputTensors,
637 callbackContext);
638}
639
640template<typename HalVersion>
641Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::Execute(const V1_3::Request& request,
642 MeasureTiming measureTiming,
643 CallbackAsync_1_3 callback)
644{
645 ExecutionContext_1_3 ctx;
646 if (measureTiming == MeasureTiming::YES)
647 {
648 ctx.measureTimings = measureTiming;
649 ctx.driverStart = Now();
650 }
651
652 ALOGV("ArmnnPreparedModel_1_3::execute(): %s", GetModelSummary(m_Model).c_str());
653 m_RequestCount++;
654
655 if (!android::nn::validateRequest(request, m_Model))
656 {
657 callback(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute");
658 return V1_3::ErrorStatus::INVALID_ARGUMENT;
659 }
660
661 if (!m_RequestInputsAndOutputsDumpDir.empty())
662 {
663 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
664 }
665
666 // map the memory pool into shared pointers
667 // use a shared memory pools vector on the heap, as it is passed to the request thread
668 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
669
670 // allocate the tensors on the heap, as they are passed to the request thread
671 auto inputTensors = std::make_shared<armnn::InputTensors>();
672 auto outputTensors = std::make_shared<armnn::OutputTensors>();
673
674 auto [status, outShapes, timing, message] = PrepareMemoryForIO(*inputTensors, *outputTensors,
675 *memPools, request);
676 if (status != V1_3::ErrorStatus::NONE)
677 {
678 callback(status, outShapes, timing, message);
679 }
680
681 switch(status)
682 {
683 case V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
684 return V1_3::ErrorStatus::NONE;
685 case V1_3::ErrorStatus::GENERAL_FAILURE:
686 return V1_3::ErrorStatus::GENERAL_FAILURE;
687 default:
688 {}
689 }
690
691 ALOGV("ArmnnPreparedModel_1_3::execute(...) before PostMsg");
692
693 // post the request for asynchronous execution
694 CallbackContext_1_3 cb;
695 cb.callback = callback;
696 cb.ctx = ctx;
697 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
698 ALOGV("ArmnnPreparedModel_1_3::execute(...) after PostMsg");
699 return V1_3::ErrorStatus::NONE;
700}
701
702#ifdef ARMNN_ANDROID_NN_V1_3
703template class ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>;
704template bool ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ExecuteGraph<CallbackContext_1_3>(
705 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
706 armnn::InputTensors& pInputTensors,
707 armnn::OutputTensors& pOutputTensors,
708 CallbackContext_1_3 cb);
709#endif
710
711} // namespace armnn_driver