blob: 36575b860e55069cb715791585a4ca9d9defbc19 [file] [log] [blame]
Kevin May42477c12020-03-26 13:34:14 +00001//
Mike Kellye2d611e2021-10-14 12:35:58 +01002// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
Kevin May42477c12020-03-26 13:34:14 +00003// SPDX-License-Identifier: MIT
4//
Sadik Armagand7be72e2020-04-23 12:56:05 +01005// Note: the ArmnnFencedExecutionCallback and code snippet in the executeFenced() function
6// in this file is based on Android code
7// under the Apache 2.0 license. See comments below for details.
8//
Kevin May42477c12020-03-26 13:34:14 +00009
10#define LOG_TAG "ArmnnDriver"
11
12#include "ArmnnPreparedModel_1_3.hpp"
13#include "Utils.hpp"
14
15#include <Utils.h>
Sadik Armagand7be72e2020-04-23 12:56:05 +010016#include <android/sync.h>
Kevin May42477c12020-03-26 13:34:14 +000017#include <log/log.h>
18#include <OperationsUtils.h>
19#include <ExecutionBurstServer.h>
20#include <ValidateHal.h>
21
Kevin May42477c12020-03-26 13:34:14 +000022#include <cinttypes>
23
Sadik Armagan188675f2021-02-12 17:16:42 +000024#ifdef ARMNN_ANDROID_S
25#include <LegacyUtils.h>
26#endif
27
Kevin May42477c12020-03-26 13:34:14 +000028using namespace android;
29using namespace android::hardware;
30
31namespace {
32
Sadik Armagan188675f2021-02-12 17:16:42 +000033static const V1_2::Timing g_NoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX};
Kevin May42477c12020-03-26 13:34:14 +000034using namespace armnn_driver;
35using TimePoint = std::chrono::steady_clock::time_point;
36
37TimePoint Now()
38{
39 return std::chrono::steady_clock::now();
40}
41
42unsigned long MicrosecondsDuration(TimePoint endPoint, TimePoint startPoint)
43{
44 return static_cast<unsigned long>(std::chrono::duration_cast<std::chrono::microseconds>(
45 endPoint - startPoint).count());
46}
47
48void NotifyCallbackAndCheck(const ::android::sp<V1_0::IExecutionCallback>& callback,
49 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000050 std::vector<V1_2::OutputShape>,
51 const V1_2::Timing,
Kevin May42477c12020-03-26 13:34:14 +000052 std::string callingFunction)
53{
54 Return<void> returned = callback->notify(convertToV1_0(errorStatus));
55 // This check is required, if the callback fails and it isn't checked it will bring down the service
56 if (!returned.isOk())
57 {
58 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
59 callingFunction.c_str(), returned.description().c_str());
60 }
61}
62
63void NotifyCallbackAndCheck(const ::android::sp<V1_2::IExecutionCallback>& callback,
64 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000065 std::vector<V1_2::OutputShape> outputShapes,
66 const V1_2::Timing timing,
Kevin May42477c12020-03-26 13:34:14 +000067 std::string callingFunction)
68{
69 Return<void> returned = callback->notify_1_2(convertToV1_0(errorStatus), outputShapes, timing);
70 // This check is required, if the callback fails and it isn't checked it will bring down the service
71 if (!returned.isOk())
72 {
73 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
74 callingFunction.c_str(), returned.description().c_str());
75 }
76}
77
78void NotifyCallbackAndCheck(const ::android::sp<V1_3::IExecutionCallback>& callback,
79 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000080 std::vector<V1_2::OutputShape> outputShapes,
81 const V1_2::Timing timing,
Kevin May42477c12020-03-26 13:34:14 +000082 std::string callingFunction)
83{
84 Return<void> returned = callback->notify_1_3(errorStatus, outputShapes, timing);
85 // This check is required, if the callback fails and it isn't checked it will bring down the service
86 if (!returned.isOk())
87 {
88 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
89 callingFunction.c_str(), returned.description().c_str());
90 }
91}
92
Sadik Armagan188675f2021-02-12 17:16:42 +000093bool ValidateRequestArgument(const V1_0::RequestArgument& requestArg, const armnn::TensorInfo& tensorInfo)
Kevin May42477c12020-03-26 13:34:14 +000094{
95 if (requestArg.dimensions.size() != 0)
96 {
97 if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
98 {
99 ALOGE("Mismatched dimensions (request argument: %zu, expected: %u)",
100 requestArg.dimensions.size(), tensorInfo.GetNumDimensions());
101 return false;
102 }
103
104 for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
105 {
Finn Williamsa4983ce2020-07-23 12:55:12 +0100106 if (requestArg.dimensions[d] != 0 && requestArg.dimensions[d] != tensorInfo.GetShape()[d])
Kevin May42477c12020-03-26 13:34:14 +0000107 {
108 ALOGE("Mismatched size for dimension %d (request argument: %u, expected %u)",
109 d, requestArg.dimensions[d], tensorInfo.GetShape()[d]);
110 return false;
111 }
112 }
113 }
114
115 return true;
116}
117
Sadik Armagan188675f2021-02-12 17:16:42 +0000118armnn::Tensor GetTensorForRequestArgument(const V1_0::RequestArgument& requestArg,
Kevin May42477c12020-03-26 13:34:14 +0000119 const armnn::TensorInfo& tensorInfo,
120 const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
121{
122 if (!ValidateRequestArgument(requestArg, tensorInfo))
123 {
124 return armnn::Tensor();
125 }
126
127 return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
128}
129
130inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
131{
132 return tensorNamePrefix + std::to_string(index);
133}
134
135} // anonymous namespace
136
137using namespace android::hardware;
138
139namespace armnn_driver
140{
141
142template<typename HalVersion>
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100143RequestThread_1_3<ArmnnPreparedModel_1_3, HalVersion, CallbackContext_1_3>
Kevin May42477c12020-03-26 13:34:14 +0000144 ArmnnPreparedModel_1_3<HalVersion>::m_RequestThread;
145
146template<typename HalVersion>
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100147std::unique_ptr<armnn::Threadpool> ArmnnPreparedModel_1_3<HalVersion>::m_Threadpool(nullptr);
148
149template<typename HalVersion>
Kevin May42477c12020-03-26 13:34:14 +0000150template<typename TensorBindingCollection>
151void ArmnnPreparedModel_1_3<HalVersion>::DumpTensorsIfRequired(char const* tensorNamePrefix,
152 const TensorBindingCollection& tensorBindings)
153{
154 if (!m_RequestInputsAndOutputsDumpDir.empty())
155 {
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100156 const std::string requestName = std::to_string(m_NetworkId) + "_" + std::to_string(m_RequestCount) + ".dump";
Kevin May42477c12020-03-26 13:34:14 +0000157 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
158 {
159 DumpTensor(m_RequestInputsAndOutputsDumpDir,
160 requestName,
161 BuildTensorName(tensorNamePrefix, i),
162 tensorBindings[i].second);
163 }
164 }
165}
166
167template<typename HalVersion>
168ArmnnPreparedModel_1_3<HalVersion>::ArmnnPreparedModel_1_3(armnn::NetworkId networkId,
169 armnn::IRuntime* runtime,
170 const V1_3::Model& model,
171 const std::string& requestInputsAndOutputsDumpDir,
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100172 const bool gpuProfilingEnabled,
Finn Williamsd8fb5402021-05-19 20:52:00 +0100173 V1_3::Priority priority,
Finn Williamsca3a3e02021-06-11 15:04:02 +0100174 const bool asyncModelExecutionEnabled,
175 const unsigned int numberOfThreads)
Kevin May42477c12020-03-26 13:34:14 +0000176 : m_NetworkId(networkId)
177 , m_Runtime(runtime)
178 , m_Model(model)
179 , m_RequestCount(0)
180 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
181 , m_GpuProfilingEnabled(gpuProfilingEnabled)
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100182 , m_ModelPriority(priority)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100183 , m_AsyncModelExecutionEnabled(asyncModelExecutionEnabled)
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100184 , m_PreparedFromCache(false)
185{
186 // Enable profiling if required.
187 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
188
189 if (m_AsyncModelExecutionEnabled)
190 {
191 std::vector<std::shared_ptr<armnn::IWorkingMemHandle>> memHandles;
192 for (unsigned int i=0; i < numberOfThreads; ++i)
193 {
194 memHandles.emplace_back(m_Runtime->CreateWorkingMemHandle(networkId));
195 }
196
197 if (!m_Threadpool)
198 {
199 m_Threadpool = std::make_unique<armnn::Threadpool>(numberOfThreads, runtime, memHandles);
200 }
201 else
202 {
203 m_Threadpool->LoadMemHandles(memHandles);
204 }
205
206 m_WorkingMemHandle = memHandles.back();
207 }
208}
209
210template<typename HalVersion>
211ArmnnPreparedModel_1_3<HalVersion>::ArmnnPreparedModel_1_3(armnn::NetworkId networkId,
212 armnn::IRuntime* runtime,
213 const std::string& requestInputsAndOutputsDumpDir,
214 const bool gpuProfilingEnabled,
215 V1_3::Priority priority,
216 const bool asyncModelExecutionEnabled,
217 const unsigned int numberOfThreads,
218 const bool preparedFromCache)
219 : m_NetworkId(networkId)
220 , m_Runtime(runtime)
221 , m_RequestCount(0)
222 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
223 , m_GpuProfilingEnabled(gpuProfilingEnabled)
224 , m_ModelPriority(priority)
225 , m_AsyncModelExecutionEnabled(asyncModelExecutionEnabled)
226 , m_PreparedFromCache(preparedFromCache)
Kevin May42477c12020-03-26 13:34:14 +0000227{
228 // Enable profiling if required.
229 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100230
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100231 if (m_AsyncModelExecutionEnabled)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100232 {
Finn Williamsca3a3e02021-06-11 15:04:02 +0100233 std::vector<std::shared_ptr<armnn::IWorkingMemHandle>> memHandles;
Finn Williamsd27c13b2021-06-25 10:06:09 +0100234 for (unsigned int i=0; i < numberOfThreads; ++i)
Finn Williamsca3a3e02021-06-11 15:04:02 +0100235 {
236 memHandles.emplace_back(m_Runtime->CreateWorkingMemHandle(networkId));
237 }
238
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100239 if (!m_Threadpool)
240 {
241 m_Threadpool = std::make_unique<armnn::Threadpool>(numberOfThreads, runtime, memHandles);
242 }
243 else
244 {
245 m_Threadpool->LoadMemHandles(memHandles);
246 }
247
Finn Williamsca3a3e02021-06-11 15:04:02 +0100248 m_WorkingMemHandle = memHandles.back();
Finn Williamsd8fb5402021-05-19 20:52:00 +0100249 }
Kevin May42477c12020-03-26 13:34:14 +0000250}
251
252template<typename HalVersion>
253ArmnnPreparedModel_1_3<HalVersion>::~ArmnnPreparedModel_1_3()
254{
255 // Get a hold of the profiler used by this model.
256 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
Colm Donelan2048b682022-02-15 14:59:08 +0000257 if (profiler && m_GpuProfilingEnabled)
258 {
259 // Dump the profiling info to a file if required.
260 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId,
261 profiler.get());
262 }
Kevin May42477c12020-03-26 13:34:14 +0000263
264 // Unload the network associated with this model.
265 m_Runtime->UnloadNetwork(m_NetworkId);
266
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100267 // Unload the network memhandles from the threadpool
268 if (m_AsyncModelExecutionEnabled)
269 {
270 m_Threadpool->UnloadMemHandles(m_NetworkId);
271 }
Kevin May42477c12020-03-26 13:34:14 +0000272}
273
274template<typename HalVersion>
275Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute(const V1_0::Request& request,
276 const ::android::sp<V1_0::IExecutionCallback>& callback)
277{
278 if (callback.get() == nullptr)
279 {
280 ALOGE("ArmnnPreparedModel_1_3::execute invalid callback passed");
281 return V1_0::ErrorStatus::INVALID_ARGUMENT;
282 }
283
284 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000285 std::vector<V1_2::OutputShape> outputShapes,
286 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000287 std::string callingFunction)
288 {
289 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
290 };
291
292
Sadik Armagan188675f2021-02-12 17:16:42 +0000293 return convertToV1_0(Execute(convertToV1_3(request), V1_2::MeasureTiming::NO, cb));
Kevin May42477c12020-03-26 13:34:14 +0000294}
295
296template<typename HalVersion>
297Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute_1_2(
298 const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000299 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000300 const sp<V1_2::IExecutionCallback>& callback)
301{
302 if (callback.get() == nullptr)
303 {
304 ALOGE("ArmnnPreparedModel_1_3::execute_1_2 invalid callback passed");
305 return V1_0::ErrorStatus::INVALID_ARGUMENT;
306 }
307
308 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000309 std::vector<V1_2::OutputShape> outputShapes,
310 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000311 std::string callingFunction)
312 {
313 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
314 };
315
316 return convertToV1_0(Execute(convertToV1_3(request), measureTiming, cb));
317}
318
319template<typename HalVersion>
320Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute_1_3(
321 const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000322 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000323 const V1_3::OptionalTimePoint&,
Kevin May352d8382020-03-31 15:03:42 +0100324 const V1_3::OptionalTimeoutDuration&,
Kevin May42477c12020-03-26 13:34:14 +0000325 const sp<V1_3::IExecutionCallback>& callback)
326{
327 if (callback.get() == nullptr)
328 {
329 ALOGE("ArmnnPreparedModel_1_3::execute_1_3 invalid callback passed");
330 return V1_3::ErrorStatus::INVALID_ARGUMENT;
331 }
332
333 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000334 std::vector<V1_2::OutputShape> outputShapes,
335 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000336 std::string callingFunction)
337 {
338 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
339 };
340
341 return Execute(request, measureTiming, cb);
342}
343
Sadik Armagand7be72e2020-04-23 12:56:05 +0100344/// This class is inspired by the sample implementation in Android named SampleFencedExecutionCallback.
345/// The original code is licensed under Apache-2.0 and can be found at the following link:
346/// https://android.googlesource.com/platform/frameworks/ml/+/master/nn/driver/sample/SampleDriver.h
347class ArmnnFencedExecutionCallback : public V1_3::IFencedExecutionCallback
348{
349public:
Sadik Armagan188675f2021-02-12 17:16:42 +0000350 ArmnnFencedExecutionCallback(V1_3::ErrorStatus errorStatus, V1_2::Timing timing, V1_2::Timing fenceTiming)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100351 : m_ErrorStatus(errorStatus), m_Timing(timing), m_FenceTiming(fenceTiming) {}
352 ~ArmnnFencedExecutionCallback() {}
353
354 Return<void> getExecutionInfo(getExecutionInfo_cb callback) override
355 {
356 callback(m_ErrorStatus, m_Timing, m_FenceTiming);
357 return Void();
358 }
359private:
360 V1_3::ErrorStatus m_ErrorStatus;
Sadik Armagan188675f2021-02-12 17:16:42 +0000361 V1_2::Timing m_Timing;
362 V1_2::Timing m_FenceTiming;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100363};
364
Kevin May42477c12020-03-26 13:34:14 +0000365template<typename HalVersion>
Sadik Armagand7be72e2020-04-23 12:56:05 +0100366Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeFenced(const V1_3::Request& request,
367 const hidl_vec<hidl_handle>& fenceWaitFor,
Sadik Armagan188675f2021-02-12 17:16:42 +0000368 V1_2::MeasureTiming measureTiming,
369 const V1_3::OptionalTimePoint& deadline,
370 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
371 const V1_3::OptionalTimeoutDuration&,
Kevin May42477c12020-03-26 13:34:14 +0000372 executeFenced_cb cb)
373{
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100374 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...)");
375 if (cb == nullptr)
376 {
377 ALOGE("ArmnnPreparedModel_1_3::executeFenced invalid callback passed");
Sadik Armagan188675f2021-02-12 17:16:42 +0000378 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100379 return Void();
380 }
381
Sadik Armagan188675f2021-02-12 17:16:42 +0000382 if (deadline.getDiscriminator() != V1_3::OptionalTimePoint::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100383 {
384 ALOGW("ArmnnPreparedModel_1_3::executeFenced parameter deadline is set but not supported.");
385 }
386
Sadik Armagan188675f2021-02-12 17:16:42 +0000387 if (loopTimeoutDuration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100388 {
389 ALOGW("ArmnnPreparedModel_1_3::executeFenced parameter loopTimeoutDuration is set but not supported.");
390 }
391
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100392 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model, /*allowUnspecifiedOutput=*/false))
Finn Williamsa4983ce2020-07-23 12:55:12 +0100393 {
394 ALOGV("ArmnnPreparedModel_1_3::executeFenced outputs must be specified for fenced execution ");
Sadik Armagan188675f2021-02-12 17:16:42 +0000395 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Finn Williamsa4983ce2020-07-23 12:55:12 +0100396 return Void();
397 }
398
Sadik Armagand7be72e2020-04-23 12:56:05 +0100399 ExecutionContext_1_3 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000400 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100401 {
402 ctx.measureTimings = measureTiming;
403 ctx.driverStart = Now();
404 }
405
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100406 if (!m_PreparedFromCache)
407 {
408 ALOGV("ArmnnPreparedModel_1_3::executeFenced(): %s", GetModelSummary(m_Model).c_str());
409 }
Sadik Armagand7be72e2020-04-23 12:56:05 +0100410 m_RequestCount++;
411
Sadik Armagand7be72e2020-04-23 12:56:05 +0100412 if (!m_RequestInputsAndOutputsDumpDir.empty())
413 {
414 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&cb));
415 }
416
417 // This code snippet is inspired by the sample implementation in Android named SampleDriver::executeFenced()
418 // function. The original code is licensed under Apache-2.0 and can be found at the following link:
419 // https://android.googlesource.com/platform/frameworks/ml/+/master/nn/driver/sample/SampleDriver.cpp
420 const auto fenceSize = fenceWaitFor.size();
421 for (unsigned int index = 0; index < fenceSize; ++index)
422 {
423 auto fenceNativeHandle = fenceWaitFor[index].getNativeHandle();
424 if (!fenceNativeHandle)
425 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000426 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100427 return Void();
428 }
429
430 if (sync_wait(fenceNativeHandle->data[0], -1) < 0)
431 {
432 ALOGE("ArmnnPreparedModel_1_3::executeFenced sync fence failed.");
Sadik Armagan188675f2021-02-12 17:16:42 +0000433 cb(V1_3::ErrorStatus::GENERAL_FAILURE, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100434 return Void();
435 }
436 }
437
438 TimePoint fenceExecutionStart;
Sadik Armagan188675f2021-02-12 17:16:42 +0000439 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100440 {
441 fenceExecutionStart = Now();
442 }
443
444 // map the memory pool into shared pointers
445 // use a shared memory pools vector on the heap, as it is passed to the request thread
446 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
447
448 // allocate the tensors on the heap, as they are passed to the request thread
449 auto inputs = std::make_shared<armnn::InputTensors>();
450 auto outputs = std::make_shared<armnn::OutputTensors>();
451
452 auto [status, outShapes, timings, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
453 if (status != V1_3::ErrorStatus::NONE)
454 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000455 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100456 return Void();
457 }
458
459 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...) before ExecuteGraph");
460
461 // call it with nullCallback for now as we will report the error status from here..
Sadik Armagan188675f2021-02-12 17:16:42 +0000462 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Sadik Armagand7be72e2020-04-23 12:56:05 +0100463 CallbackContext_1_3 cbCtx;
464 cbCtx.callback = nullCallback;
465 cbCtx.ctx = ctx;
466
467 auto errorStatus = ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
468 if (errorStatus != V1_3::ErrorStatus::NONE)
469 {
470 cb(errorStatus, hidl_handle(nullptr), nullptr);
471 return Void();
472 }
473 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...) after ExecuteGraph");
474
Sadik Armagan188675f2021-02-12 17:16:42 +0000475 V1_2::Timing timing = g_NoTiming;
476 V1_2::Timing fenceTiming = g_NoTiming;
477 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100478 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100479 fenceTiming.timeOnDevice = MicrosecondsDuration(ctx.deviceEnd, ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100480 fenceTiming.timeInDriver = MicrosecondsDuration(ctx.driverEnd, fenceExecutionStart);
481 ALOGV("ArmnnPreparedModel_1_3::fenceFinishExecutionTiming - Device = %lu Driver = %lu",
Zingo Andersen7c561492022-01-25 11:09:41 +0100482 static_cast<unsigned long>(fenceTiming.timeOnDevice),
483 static_cast<unsigned long>(fenceTiming.timeInDriver));
Sadik Armagand7be72e2020-04-23 12:56:05 +0100484 }
485
486 sp<ArmnnFencedExecutionCallback> armnnFencedExecutionCallback =
Sadik Armagan188675f2021-02-12 17:16:42 +0000487 new ArmnnFencedExecutionCallback(V1_3::ErrorStatus::NONE, timing, fenceTiming);
488 cb(V1_3::ErrorStatus::NONE, hidl_handle(nullptr), armnnFencedExecutionCallback);
Kevin May42477c12020-03-26 13:34:14 +0000489 return Void();
490}
491
492template<typename HalVersion>
493Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForInputs(
494 armnn::InputTensors& inputs,
495 const V1_3::Request& request,
496 const std::vector<android::nn::RunTimePoolInfo>& memPools)
497{
498 inputs.reserve(request.inputs.size());
499 for (unsigned int i = 0; i < request.inputs.size(); i++)
500 {
501 const auto& inputArg = request.inputs[i];
502
Cathal Corbette27d4e82021-10-28 12:28:35 +0100503 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
504 // inputs (of type InputTensors) is composed of a vector of ConstTensors.
505 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
506 inputTensorInfo.SetConstant();
Kevin May42477c12020-03-26 13:34:14 +0000507 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
508
509 if (inputTensor.GetMemoryArea() == nullptr)
510 {
511 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
512 return V1_3::ErrorStatus::GENERAL_FAILURE;
513 }
514
515 inputs.emplace_back(i, inputTensor);
516 }
517
518 return V1_3::ErrorStatus::NONE;
519}
520
521template<typename HalVersion>
522Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForOutputs(
523 armnn::OutputTensors& outputs,
Sadik Armagan188675f2021-02-12 17:16:42 +0000524 std::vector<V1_2::OutputShape> &outputShapes,
Kevin May42477c12020-03-26 13:34:14 +0000525 const V1_3::Request& request,
526 const std::vector<android::nn::RunTimePoolInfo>& memPools)
527{
528 outputs.reserve(request.outputs.size());
529 for (unsigned int i = 0; i < request.outputs.size(); i++)
530 {
531 const auto& outputArg = request.outputs[i];
532
Finn Williamsa4983ce2020-07-23 12:55:12 +0100533 armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
Kevin May42477c12020-03-26 13:34:14 +0000534 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
535 if (outputTensor.GetMemoryArea() == nullptr)
536 {
537 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
538 return V1_3::ErrorStatus::GENERAL_FAILURE;
539 }
540
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100541 const size_t outputSize = outputTensorInfo.GetNumBytes();
542
Finn Williamsa4983ce2020-07-23 12:55:12 +0100543 unsigned int count = 0;
544 std::for_each(outputArg.dimensions.begin(), outputArg.dimensions.end(), [&](auto dim)
545 {
546 if (dim != 0)
547 {
548 outputTensorInfo.GetShape()[count] = dim;
549 }
550 else
551 {
552 outputTensorInfo.GetShape()[count] = outputArg.dimensions.size();
553 }
554
555 count++;
556 });
557
Finn Williamsa4983ce2020-07-23 12:55:12 +0100558 outputs.emplace_back(i, outputTensor);
559 outputShapes[i] = ComputeShape(outputTensorInfo);
560
561 if (outputArg.location.length < outputSize)
562 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100563 ALOGW("ArmnnPreparedModel_1_3::Execute failed outputArg.location.length (%s) < outputSize (%s)",
564 std::to_string(outputArg.location.length).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100565 outputShapes[i].isSufficient = false;
566 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
567 }
568
Sadik Armagan188675f2021-02-12 17:16:42 +0000569 size_t bufferSize = 0;
570#if !defined(ARMNN_ANDROID_S)
571 bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
Sadik Armagan188675f2021-02-12 17:16:42 +0000572#else
Kevin Maydc873f62021-06-14 11:21:11 +0100573 bufferSize = memPools.at(outputArg.location.poolIndex).getSize();
Sadik Armagan188675f2021-02-12 17:16:42 +0000574#endif
Kevin May42477c12020-03-26 13:34:14 +0000575 if (bufferSize < outputSize)
576 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100577 ALOGW("ArmnnPreparedModel_1_3::Execute failed bufferSize (%s) < outputSize (%s)",
578 std::to_string(bufferSize).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100579 outputShapes[i].isSufficient = false;
Kevin May42477c12020-03-26 13:34:14 +0000580 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
581 }
Kevin May42477c12020-03-26 13:34:14 +0000582 }
583
584 return V1_3::ErrorStatus::NONE;
585}
586
587template<typename HalVersion>
Sadik Armagan188675f2021-02-12 17:16:42 +0000588std::tuple<V1_3::ErrorStatus, hidl_vec<V1_2::OutputShape>, V1_2::Timing, std::string>
Kevin May42477c12020-03-26 13:34:14 +0000589 ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForIO(armnn::InputTensors& inputs,
590 armnn::OutputTensors& outputs,
591 std::vector<android::nn::RunTimePoolInfo>& memPools,
592 const V1_3::Request& request)
593{
Sadik Armagan188675f2021-02-12 17:16:42 +0000594#if !defined(ARMNN_ANDROID_S)
Kevin May42477c12020-03-26 13:34:14 +0000595 if (!setRunTimePoolInfosFromMemoryPools(&memPools, request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000596#else
597 if (!setRunTimePoolInfosFromMemoryPools(&memPools, uncheckedConvert(request.pools)))
598#endif
Kevin May42477c12020-03-26 13:34:14 +0000599 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000600 return {V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000601 }
602
603 // add the inputs and outputs with their data
604 try
605 {
606 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_3::ErrorStatus::NONE)
607 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000608 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000609 }
610
Sadik Armagan188675f2021-02-12 17:16:42 +0000611 std::vector<V1_2::OutputShape> outputShapes(request.outputs.size());
Kevin May42477c12020-03-26 13:34:14 +0000612
613 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
614 if (errorStatus != V1_3::ErrorStatus::NONE)
615 {
616 return {errorStatus, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
617 }
618 }
619 catch (armnn::Exception& e)
620 {
621 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000622 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000623 }
624 catch (std::exception& e)
625 {
626 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000627 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000628 }
629
630 return {V1_3::ErrorStatus::NONE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
631}
632
633template<typename HalVersion>
634template<typename CallbackContext>
635Return<void> ArmnnPreparedModel_1_3<HalVersion>::ExecuteSynchronously(const V1_3::Request& request,
636 CallbackContext cbCtx)
637{
Sadik Armagan188675f2021-02-12 17:16:42 +0000638 if (cbCtx.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000639 {
640 cbCtx.ctx.driverStart = Now();
641 }
642
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100643 if (!m_PreparedFromCache && !android::nn::validateRequest(convertToV1_3(request), m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000644 {
645 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
646 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
647 {},
648 g_NoTiming,
649 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
650 return Void();
651 }
652
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100653 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000654 {
655 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
656 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
657 {},
658 g_NoTiming,
659 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
Sadik Armaganef8a3932020-04-09 17:21:50 +0100660 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000661 }
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 inputs = std::make_shared<armnn::InputTensors>();
670 auto outputs = std::make_shared<armnn::OutputTensors>();
671
672 auto [status, outputShapes, timing, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
673 if (status != V1_3::ErrorStatus::NONE)
674 {
675 cbCtx.callback(status, outputShapes, timing, message);
Sadik Armaganef8a3932020-04-09 17:21:50 +0100676 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000677 }
678
679 ALOGV("ArmnnPreparedModel_1_3::ExecuteSynchronously() before Execution");
680
681 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
682 return Void();
683}
684
685template<typename HalVersion>
686Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000687 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000688 executeSynchronously_cb cb)
689{
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100690 if (!m_PreparedFromCache)
691 {
692 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
693 }
Kevin May42477c12020-03-26 13:34:14 +0000694 m_RequestCount++;
695
696 if (cb == nullptr)
697 {
698 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously invalid callback passed");
699 return Void();
700 }
701
702 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000703 std::vector<V1_2::OutputShape> outputShapes,
704 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000705 std::string)
706 {
707 cb(convertToV1_0(errorStatus), outputShapes, timing);
708 };
709
710 CallbackContext_1_3 cbCtx;
711 cbCtx.callback = cbWrapper;
712 cbCtx.ctx.measureTimings = measureTiming;
713
714 ExecuteSynchronously(convertToV1_3(request), cbCtx);
715 return Void();
716}
717
718template<typename HalVersion>
Kevin May352d8382020-03-31 15:03:42 +0100719Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously_1_3(
720 const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000721 V1_2::MeasureTiming measureTiming,
Kevin May352d8382020-03-31 15:03:42 +0100722 const V1_3::OptionalTimePoint& deadline,
723 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
724 executeSynchronously_1_3_cb cb)
Kevin May42477c12020-03-26 13:34:14 +0000725{
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100726 if (!m_PreparedFromCache)
727 {
728 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously_1_3(): %s", GetModelSummary(m_Model).c_str());
729 }
Kevin May42477c12020-03-26 13:34:14 +0000730 m_RequestCount++;
731
732 if (cb == nullptr)
733 {
734 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid callback passed");
735 return Void();
736 }
737
Sadik Armagan188675f2021-02-12 17:16:42 +0000738 if (deadline.getDiscriminator() != V1_3::OptionalTimePoint::hidl_discriminator::none)
Kevin May42477c12020-03-26 13:34:14 +0000739 {
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100740 ALOGW("ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter deadline is set but not supported.");
Kevin May42477c12020-03-26 13:34:14 +0000741 }
742
Sadik Armagan188675f2021-02-12 17:16:42 +0000743 if (loopTimeoutDuration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100744 {
745 ALOGW(
746 "ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter loopTimeoutDuration is set but not supported.");
Kevin May352d8382020-03-31 15:03:42 +0100747 }
748
Kevin May42477c12020-03-26 13:34:14 +0000749 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000750 std::vector<V1_2::OutputShape> outputShapes,
751 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000752 std::string)
753 {
754 cb(errorStatus, outputShapes, timing);
755 };
756
757 CallbackContext_1_3 cbCtx;
758 cbCtx.callback = cbWrapper;
759 cbCtx.ctx.measureTimings = measureTiming;
760
761 ExecuteSynchronously(request, cbCtx);
762 return Void();
763}
764
765template<typename HalVersion>
766Return<void> ArmnnPreparedModel_1_3<HalVersion>::configureExecutionBurst(
767 const sp<V1_2::IBurstCallback>& callback,
768 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
769 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
770 V1_3::IPreparedModel::configureExecutionBurst_cb cb)
771{
772 ALOGV("ArmnnPreparedModel_1_3::configureExecutionBurst");
773 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
774 requestChannel,
775 resultChannel,
776 this);
777
778 if (burst == nullptr)
779 {
780 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
781 }
782 else
783 {
784 cb(V1_0::ErrorStatus::NONE, burst);
785 }
786 return Void();
787}
788
789template<typename HalVersion>
790template<typename CallbackContext>
Sadik Armagand7be72e2020-04-23 12:56:05 +0100791Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::ExecuteGraph(
Kevin May42477c12020-03-26 13:34:14 +0000792 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
793 armnn::InputTensors& inputTensors,
794 armnn::OutputTensors& outputTensors,
795 CallbackContext cb)
796{
797 ALOGV("ArmnnPreparedModel_1_3::ExecuteGraph(...)");
798
Kevin May42477c12020-03-26 13:34:14 +0000799 DumpTensorsIfRequired("Input", inputTensors);
800
Sadik Armagan188675f2021-02-12 17:16:42 +0000801 std::vector<V1_2::OutputShape> outputShapes(outputTensors.size());
Kevin May42477c12020-03-26 13:34:14 +0000802 for (unsigned int i = 0; i < outputTensors.size(); i++)
803 {
804 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
805 const armnn::Tensor outputTensor = outputTensorPair.second;
806 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
807
808 outputShapes[i] = ComputeShape(outputTensorInfo);
809 }
810
811 // run it
812 try
813 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000814 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000815 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100816 cb.ctx.deviceStart = Now();
Kevin May42477c12020-03-26 13:34:14 +0000817 }
Finn Williamsd8fb5402021-05-19 20:52:00 +0100818 armnn::Status status;
819 if (m_AsyncModelExecutionEnabled)
820 {
821 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled true");
822 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
823 }
824 else
825 {
826 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled false");
David Monahan80696032022-02-02 12:17:46 +0000827 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100828 }
Kevin May42477c12020-03-26 13:34:14 +0000829
Sadik Armagan188675f2021-02-12 17:16:42 +0000830 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000831 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100832 cb.ctx.deviceEnd = Now();
Kevin May42477c12020-03-26 13:34:14 +0000833 }
834 if (status != armnn::Status::Success)
835 {
Finn Williamsd8fb5402021-05-19 20:52:00 +0100836 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph EnqueueWorkload failed");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100837 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
838 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000839 }
840 }
841 catch (armnn::Exception& e)
842 {
843 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
844 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100845 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000846 }
847 catch (std::exception& e)
848 {
849 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
850 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100851 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000852 }
853
854 CommitPools(*pMemPools);
855
856 DumpTensorsIfRequired("Output", outputTensors);
857
Sadik Armagan188675f2021-02-12 17:16:42 +0000858 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000859 {
Kevin May949a69e2020-04-24 10:21:40 +0100860 cb.ctx.driverEnd = Now();
Sadik Armagan188675f2021-02-12 17:16:42 +0000861 V1_2::Timing timing;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100862 timing.timeOnDevice = MicrosecondsDuration(cb.ctx.deviceEnd, cb.ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100863 timing.timeInDriver = MicrosecondsDuration(cb.ctx.driverEnd, cb.ctx.driverStart);
Zingo Andersen7c561492022-01-25 11:09:41 +0100864 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu",
865 static_cast<unsigned long>(timing.timeOnDevice), static_cast<unsigned long>(timing.timeInDriver));
Kevin May42477c12020-03-26 13:34:14 +0000866 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100867 } else
868 {
Kevin May42477c12020-03-26 13:34:14 +0000869 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
870 }
Sadik Armagand7be72e2020-04-23 12:56:05 +0100871 return V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000872}
873
Finn Williamsd8fb5402021-05-19 20:52:00 +0100874/// Schedule the graph prepared from the request for execution
875template<typename HalVersion>
876template<typename CallbackContext>
877void ArmnnPreparedModel_1_3<HalVersion>::ScheduleGraphForExecution(
878 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
879 std::shared_ptr<armnn::InputTensors>& inputTensors,
880 std::shared_ptr<armnn::OutputTensors>& outputTensors,
881 CallbackContext callbackContext,
882 armnn::QosExecPriority priority)
883{
884 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution(...)");
885
886 DumpTensorsIfRequired("Input", *inputTensors);
887
888 unsigned int outputTensorSize = outputTensors.get()->size();
889 std::vector<V1_2::OutputShape> outputShapes(outputTensorSize);
890 for (unsigned int i = 0; i < outputTensorSize; i++)
891 {
892 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors.get()->at(i);
893 const armnn::Tensor outputTensor = outputTensorPair.second;
894 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
895
896 outputShapes[i] = ComputeShape(outputTensorInfo);
897 }
898
899 auto tpCb = std::make_shared<
900 ArmnnThreadPoolCallback_1_3<CallbackContext_1_3>>(this,
901 pMemPools,
902 outputShapes,
903 inputTensors,
904 outputTensors,
905 callbackContext);
906
Finn Williamsca3a3e02021-06-11 15:04:02 +0100907 m_Threadpool->Schedule(m_NetworkId,
908 *tpCb->m_InputTensors,
909 *tpCb->m_OutputTensors,
910 priority,
911 tpCb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100912 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution end");
913}
914
Kevin May42477c12020-03-26 13:34:14 +0000915template<typename HalVersion>
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100916bool ArmnnPreparedModel_1_3<HalVersion>::ExecuteWithDummyInputs(unsigned int numInputs, unsigned int numOutputs)
Kevin May42477c12020-03-26 13:34:14 +0000917{
918 std::vector<std::vector<char>> storage;
919 armnn::InputTensors inputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100920 for (unsigned int i = 0; i < numInputs; i++)
Kevin May42477c12020-03-26 13:34:14 +0000921 {
Cathal Corbette27d4e82021-10-28 12:28:35 +0100922 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
923 // pInputTensors (of type InputTensors) is composed of a vector of ConstTensors.
924 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
925 inputTensorInfo.SetConstant();
926
Kevin May42477c12020-03-26 13:34:14 +0000927 storage.emplace_back(inputTensorInfo.GetNumBytes());
928 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
929
930 inputTensors.emplace_back(i, inputTensor);
931 }
932
933 armnn::OutputTensors outputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100934 for (unsigned int i = 0; i < numOutputs; i++)
Kevin May42477c12020-03-26 13:34:14 +0000935 {
936 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
937 storage.emplace_back(outputTensorInfo.GetNumBytes());
938 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
939
940 outputTensors.emplace_back(i, outputTensor);
941 }
942
Sadik Armagan188675f2021-02-12 17:16:42 +0000943 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Kevin May42477c12020-03-26 13:34:14 +0000944 CallbackContext_1_3 callbackContext;
945 callbackContext.callback = nullCallback;
Sadik Armagan188675f2021-02-12 17:16:42 +0000946 callbackContext.ctx.measureTimings = V1_2::MeasureTiming::NO;
Kevin May42477c12020-03-26 13:34:14 +0000947 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
Sadik Armagand7be72e2020-04-23 12:56:05 +0100948
949 auto errorStatus = ExecuteGraph(memPools,
950 inputTensors,
951 outputTensors,
952 callbackContext);
953 return errorStatus == V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000954}
955
956template<typename HalVersion>
957Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::Execute(const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000958 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000959 CallbackAsync_1_3 callback)
960{
961 ExecutionContext_1_3 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000962 if (measureTiming == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000963 {
964 ctx.measureTimings = measureTiming;
965 ctx.driverStart = Now();
966 }
967
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100968 if (!m_PreparedFromCache)
969 {
970 ALOGV("ArmnnPreparedModel_1_3::execute(): %s", GetModelSummary(m_Model).c_str());
971 }
Kevin May42477c12020-03-26 13:34:14 +0000972 m_RequestCount++;
973
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100974 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000975 {
976 callback(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute");
977 return V1_3::ErrorStatus::INVALID_ARGUMENT;
978 }
979
980 if (!m_RequestInputsAndOutputsDumpDir.empty())
981 {
982 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
983 }
984
985 // map the memory pool into shared pointers
986 // use a shared memory pools vector on the heap, as it is passed to the request thread
987 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
988
989 // allocate the tensors on the heap, as they are passed to the request thread
990 auto inputTensors = std::make_shared<armnn::InputTensors>();
991 auto outputTensors = std::make_shared<armnn::OutputTensors>();
992
993 auto [status, outShapes, timing, message] = PrepareMemoryForIO(*inputTensors, *outputTensors,
994 *memPools, request);
995 if (status != V1_3::ErrorStatus::NONE)
996 {
997 callback(status, outShapes, timing, message);
998 }
999
1000 switch(status)
1001 {
1002 case V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
1003 return V1_3::ErrorStatus::NONE;
1004 case V1_3::ErrorStatus::GENERAL_FAILURE:
1005 return V1_3::ErrorStatus::GENERAL_FAILURE;
Sadik Armagana07d2752021-05-12 20:33:58 +01001006 case V1_3::ErrorStatus::INVALID_ARGUMENT:
1007 return V1_3::ErrorStatus::INVALID_ARGUMENT;
Kevin May42477c12020-03-26 13:34:14 +00001008 default:
1009 {}
1010 }
Kevin May42477c12020-03-26 13:34:14 +00001011 CallbackContext_1_3 cb;
1012 cb.callback = callback;
1013 cb.ctx = ctx;
Finn Williamsd8fb5402021-05-19 20:52:00 +01001014
1015
1016 enum class QosExecPriority
1017 {
1018 Low = 0,
1019 Medium = 1,
1020 High = 2
1021 };
1022
1023
1024 if (m_AsyncModelExecutionEnabled)
1025 {
1026 armnn::QosExecPriority priority;
1027
1028 switch (GetModelPriority()) {
1029 case V1_3::Priority::LOW:
1030 priority = armnn::QosExecPriority::Low;
1031 break;
1032 case V1_3::Priority::MEDIUM:
1033 priority = armnn::QosExecPriority::Medium;
1034 break;
1035 case V1_3::Priority::HIGH:
1036 priority = armnn::QosExecPriority::High;
1037 break;
1038 default:
1039 priority = armnn::QosExecPriority::Medium;
1040
1041 }
1042
1043 ALOGV("ArmnnPreparedModel_1_3::execute(...) before ScheduleGraphForExecution");
1044 ScheduleGraphForExecution(memPools, inputTensors, outputTensors, cb, priority);
1045 ALOGV("ArmnnPreparedModel_1_3::execute(...) after ScheduleGraphForExecution");
1046 return V1_3::ErrorStatus::NONE;
1047 }
1048
1049 ALOGV("ArmnnPreparedModel_1_3::execute(...) before PostMsg");
1050 // post the request for asynchronous execution
Kevin May42477c12020-03-26 13:34:14 +00001051 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
1052 ALOGV("ArmnnPreparedModel_1_3::execute(...) after PostMsg");
1053 return V1_3::ErrorStatus::NONE;
1054}
1055
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +01001056template<typename HalVersion>
1057V1_3::Priority ArmnnPreparedModel_1_3<HalVersion>::GetModelPriority()
1058{
1059 return m_ModelPriority;
1060}
1061
Finn Williamsd8fb5402021-05-19 20:52:00 +01001062template<typename HalVersion>
1063template <typename CallbackContext>
1064void ArmnnPreparedModel_1_3<HalVersion>::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify(
1065 armnn::Status status, armnn::InferenceTimingPair timeTaken)
1066{
1067 ALOGV("ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify");
1068 CommitPools(*m_MemPools);
1069
1070 m_Model->DumpTensorsIfRequired("Output", *m_OutputTensors);
1071
1072 if (status != armnn::Status::Success)
1073 {
1074 ALOGW("ArmnnThreadPoolCallback_1_3::Notify EnqueueWorkload failed");
1075 m_CallbackContext.callback(V1_3::ErrorStatus::GENERAL_FAILURE,
1076 {},
1077 g_NoTiming,
1078 "ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3");
1079 return;
1080 }
1081
1082 if (m_CallbackContext.ctx.measureTimings == V1_2::MeasureTiming::YES)
1083 {
1084 m_CallbackContext.ctx.deviceStart = timeTaken.first;
1085 m_CallbackContext.ctx.deviceEnd = timeTaken.second;
1086 m_CallbackContext.ctx.driverEnd = std::chrono::steady_clock::now();
1087 V1_2::Timing timing;
1088 timing.timeOnDevice = MicrosecondsDuration(m_CallbackContext.ctx.deviceEnd, m_CallbackContext.ctx.deviceStart);
1089 timing.timeInDriver = MicrosecondsDuration(m_CallbackContext.ctx.driverEnd, m_CallbackContext.ctx.driverStart);
Zingo Andersen7c561492022-01-25 11:09:41 +01001090 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu",
1091 static_cast<unsigned long>(timing.timeOnDevice), static_cast<unsigned long>(timing.timeInDriver));
Finn Williamsd8fb5402021-05-19 20:52:00 +01001092 m_CallbackContext.callback(
1093 V1_3::ErrorStatus::NONE, m_OutputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
1094 } else
1095 {
1096 m_CallbackContext.callback(
1097 V1_3::ErrorStatus::NONE, m_OutputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
1098 }
1099 return;
1100}
1101
Kevin May42477c12020-03-26 13:34:14 +00001102#ifdef ARMNN_ANDROID_NN_V1_3
1103template class ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>;
Sadik Armagand7be72e2020-04-23 12:56:05 +01001104template Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ExecuteGraph<CallbackContext_1_3>(
Kevin May42477c12020-03-26 13:34:14 +00001105 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1106 armnn::InputTensors& pInputTensors,
1107 armnn::OutputTensors& pOutputTensors,
1108 CallbackContext_1_3 cb);
Finn Williamsd8fb5402021-05-19 20:52:00 +01001109
1110template void ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ScheduleGraphForExecution<CallbackContext_1_3>(
1111 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1112 std::shared_ptr<armnn::InputTensors>& inputTensors,
1113 std::shared_ptr<armnn::OutputTensors>& outputTensors,
1114 CallbackContext_1_3 callbackContext,
1115 armnn::QosExecPriority priority);
Kevin May42477c12020-03-26 13:34:14 +00001116#endif
1117
1118} // namespace armnn_driver