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