blob: 34c42ecd688183d5d2724316529e792a9d0e4045 [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
Narumol Prangnawarat558a1d42022-02-07 13:12:24 +000015#include <armnn/Types.hpp>
16
Kevin May42477c12020-03-26 13:34:14 +000017#include <Utils.h>
Sadik Armagand7be72e2020-04-23 12:56:05 +010018#include <android/sync.h>
Kevin May42477c12020-03-26 13:34:14 +000019#include <log/log.h>
20#include <OperationsUtils.h>
21#include <ExecutionBurstServer.h>
22#include <ValidateHal.h>
23
Kevin May42477c12020-03-26 13:34:14 +000024#include <cinttypes>
25
Sadik Armagan188675f2021-02-12 17:16:42 +000026#ifdef ARMNN_ANDROID_S
27#include <LegacyUtils.h>
28#endif
29
Kevin May42477c12020-03-26 13:34:14 +000030using namespace android;
31using namespace android::hardware;
32
33namespace {
34
Sadik Armagan188675f2021-02-12 17:16:42 +000035static const V1_2::Timing g_NoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX};
Kevin May42477c12020-03-26 13:34:14 +000036using namespace armnn_driver;
37using TimePoint = std::chrono::steady_clock::time_point;
38
39TimePoint Now()
40{
41 return std::chrono::steady_clock::now();
42}
43
44unsigned long MicrosecondsDuration(TimePoint endPoint, TimePoint startPoint)
45{
46 return static_cast<unsigned long>(std::chrono::duration_cast<std::chrono::microseconds>(
47 endPoint - startPoint).count());
48}
49
50void NotifyCallbackAndCheck(const ::android::sp<V1_0::IExecutionCallback>& callback,
51 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000052 std::vector<V1_2::OutputShape>,
53 const V1_2::Timing,
Kevin May42477c12020-03-26 13:34:14 +000054 std::string callingFunction)
55{
56 Return<void> returned = callback->notify(convertToV1_0(errorStatus));
57 // This check is required, if the callback fails and it isn't checked it will bring down the service
58 if (!returned.isOk())
59 {
60 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
61 callingFunction.c_str(), returned.description().c_str());
62 }
63}
64
65void NotifyCallbackAndCheck(const ::android::sp<V1_2::IExecutionCallback>& callback,
66 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000067 std::vector<V1_2::OutputShape> outputShapes,
68 const V1_2::Timing timing,
Kevin May42477c12020-03-26 13:34:14 +000069 std::string callingFunction)
70{
71 Return<void> returned = callback->notify_1_2(convertToV1_0(errorStatus), outputShapes, timing);
72 // This check is required, if the callback fails and it isn't checked it will bring down the service
73 if (!returned.isOk())
74 {
75 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
76 callingFunction.c_str(), returned.description().c_str());
77 }
78}
79
80void NotifyCallbackAndCheck(const ::android::sp<V1_3::IExecutionCallback>& callback,
81 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000082 std::vector<V1_2::OutputShape> outputShapes,
83 const V1_2::Timing timing,
Kevin May42477c12020-03-26 13:34:14 +000084 std::string callingFunction)
85{
86 Return<void> returned = callback->notify_1_3(errorStatus, outputShapes, timing);
87 // This check is required, if the callback fails and it isn't checked it will bring down the service
88 if (!returned.isOk())
89 {
90 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
91 callingFunction.c_str(), returned.description().c_str());
92 }
93}
94
Sadik Armagan188675f2021-02-12 17:16:42 +000095bool ValidateRequestArgument(const V1_0::RequestArgument& requestArg, const armnn::TensorInfo& tensorInfo)
Kevin May42477c12020-03-26 13:34:14 +000096{
97 if (requestArg.dimensions.size() != 0)
98 {
99 if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
100 {
101 ALOGE("Mismatched dimensions (request argument: %zu, expected: %u)",
102 requestArg.dimensions.size(), tensorInfo.GetNumDimensions());
103 return false;
104 }
105
106 for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
107 {
Finn Williamsa4983ce2020-07-23 12:55:12 +0100108 if (requestArg.dimensions[d] != 0 && requestArg.dimensions[d] != tensorInfo.GetShape()[d])
Kevin May42477c12020-03-26 13:34:14 +0000109 {
110 ALOGE("Mismatched size for dimension %d (request argument: %u, expected %u)",
111 d, requestArg.dimensions[d], tensorInfo.GetShape()[d]);
112 return false;
113 }
114 }
115 }
116
117 return true;
118}
119
Sadik Armagan188675f2021-02-12 17:16:42 +0000120armnn::Tensor GetTensorForRequestArgument(const V1_0::RequestArgument& requestArg,
Kevin May42477c12020-03-26 13:34:14 +0000121 const armnn::TensorInfo& tensorInfo,
122 const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
123{
124 if (!ValidateRequestArgument(requestArg, tensorInfo))
125 {
126 return armnn::Tensor();
127 }
128
129 return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
130}
131
132inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
133{
134 return tensorNamePrefix + std::to_string(index);
135}
136
137} // anonymous namespace
138
139using namespace android::hardware;
140
141namespace armnn_driver
142{
143
144template<typename HalVersion>
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100145RequestThread_1_3<ArmnnPreparedModel_1_3, HalVersion, CallbackContext_1_3>
Kevin May42477c12020-03-26 13:34:14 +0000146 ArmnnPreparedModel_1_3<HalVersion>::m_RequestThread;
147
148template<typename HalVersion>
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100149std::unique_ptr<armnn::Threadpool> ArmnnPreparedModel_1_3<HalVersion>::m_Threadpool(nullptr);
150
151template<typename HalVersion>
Kevin May42477c12020-03-26 13:34:14 +0000152template<typename TensorBindingCollection>
153void ArmnnPreparedModel_1_3<HalVersion>::DumpTensorsIfRequired(char const* tensorNamePrefix,
154 const TensorBindingCollection& tensorBindings)
155{
156 if (!m_RequestInputsAndOutputsDumpDir.empty())
157 {
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100158 const std::string requestName = std::to_string(m_NetworkId) + "_" + std::to_string(m_RequestCount) + ".dump";
Kevin May42477c12020-03-26 13:34:14 +0000159 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
160 {
161 DumpTensor(m_RequestInputsAndOutputsDumpDir,
162 requestName,
163 BuildTensorName(tensorNamePrefix, i),
164 tensorBindings[i].second);
165 }
166 }
167}
168
169template<typename HalVersion>
170ArmnnPreparedModel_1_3<HalVersion>::ArmnnPreparedModel_1_3(armnn::NetworkId networkId,
171 armnn::IRuntime* runtime,
172 const V1_3::Model& model,
173 const std::string& requestInputsAndOutputsDumpDir,
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100174 const bool gpuProfilingEnabled,
Finn Williamsd8fb5402021-05-19 20:52:00 +0100175 V1_3::Priority priority,
Finn Williamsca3a3e02021-06-11 15:04:02 +0100176 const bool asyncModelExecutionEnabled,
Narumol Prangnawarat558a1d42022-02-07 13:12:24 +0000177 const unsigned int numberOfThreads,
178 const bool importEnabled,
179 const bool exportEnabled)
Kevin May42477c12020-03-26 13:34:14 +0000180 : m_NetworkId(networkId)
181 , m_Runtime(runtime)
182 , m_Model(model)
183 , m_RequestCount(0)
184 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
185 , m_GpuProfilingEnabled(gpuProfilingEnabled)
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100186 , m_ModelPriority(priority)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100187 , m_AsyncModelExecutionEnabled(asyncModelExecutionEnabled)
Narumol Prangnawarat558a1d42022-02-07 13:12:24 +0000188 , m_EnableImport(importEnabled)
189 , m_EnableExport(exportEnabled)
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100190 , m_PreparedFromCache(false)
191{
192 // Enable profiling if required.
193 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
194
195 if (m_AsyncModelExecutionEnabled)
196 {
197 std::vector<std::shared_ptr<armnn::IWorkingMemHandle>> memHandles;
198 for (unsigned int i=0; i < numberOfThreads; ++i)
199 {
200 memHandles.emplace_back(m_Runtime->CreateWorkingMemHandle(networkId));
201 }
202
203 if (!m_Threadpool)
204 {
205 m_Threadpool = std::make_unique<armnn::Threadpool>(numberOfThreads, runtime, memHandles);
206 }
207 else
208 {
209 m_Threadpool->LoadMemHandles(memHandles);
210 }
211
212 m_WorkingMemHandle = memHandles.back();
213 }
214}
215
216template<typename HalVersion>
217ArmnnPreparedModel_1_3<HalVersion>::ArmnnPreparedModel_1_3(armnn::NetworkId networkId,
218 armnn::IRuntime* runtime,
219 const std::string& requestInputsAndOutputsDumpDir,
220 const bool gpuProfilingEnabled,
221 V1_3::Priority priority,
222 const bool asyncModelExecutionEnabled,
223 const unsigned int numberOfThreads,
Narumol Prangnawarat558a1d42022-02-07 13:12:24 +0000224 const bool importEnabled,
225 const bool exportEnabled,
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100226 const bool preparedFromCache)
227 : m_NetworkId(networkId)
228 , m_Runtime(runtime)
229 , m_RequestCount(0)
230 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
231 , m_GpuProfilingEnabled(gpuProfilingEnabled)
232 , m_ModelPriority(priority)
233 , m_AsyncModelExecutionEnabled(asyncModelExecutionEnabled)
Narumol Prangnawarat558a1d42022-02-07 13:12:24 +0000234 , m_EnableImport(importEnabled)
235 , m_EnableExport(exportEnabled)
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100236 , m_PreparedFromCache(preparedFromCache)
Kevin May42477c12020-03-26 13:34:14 +0000237{
238 // Enable profiling if required.
239 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100240
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100241 if (m_AsyncModelExecutionEnabled)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100242 {
Finn Williamsca3a3e02021-06-11 15:04:02 +0100243 std::vector<std::shared_ptr<armnn::IWorkingMemHandle>> memHandles;
Finn Williamsd27c13b2021-06-25 10:06:09 +0100244 for (unsigned int i=0; i < numberOfThreads; ++i)
Finn Williamsca3a3e02021-06-11 15:04:02 +0100245 {
246 memHandles.emplace_back(m_Runtime->CreateWorkingMemHandle(networkId));
247 }
248
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100249 if (!m_Threadpool)
250 {
251 m_Threadpool = std::make_unique<armnn::Threadpool>(numberOfThreads, runtime, memHandles);
252 }
253 else
254 {
255 m_Threadpool->LoadMemHandles(memHandles);
256 }
257
Finn Williamsca3a3e02021-06-11 15:04:02 +0100258 m_WorkingMemHandle = memHandles.back();
Finn Williamsd8fb5402021-05-19 20:52:00 +0100259 }
Kevin May42477c12020-03-26 13:34:14 +0000260}
261
262template<typename HalVersion>
263ArmnnPreparedModel_1_3<HalVersion>::~ArmnnPreparedModel_1_3()
264{
265 // Get a hold of the profiler used by this model.
266 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
Colm Donelan12396f72022-02-15 14:59:08 +0000267 if (profiler && m_GpuProfilingEnabled)
268 {
269 // Dump the profiling info to a file if required.
270 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId,
271 profiler.get());
272 }
Kevin May42477c12020-03-26 13:34:14 +0000273
274 // Unload the network associated with this model.
275 m_Runtime->UnloadNetwork(m_NetworkId);
276
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100277 // Unload the network memhandles from the threadpool
278 if (m_AsyncModelExecutionEnabled)
279 {
280 m_Threadpool->UnloadMemHandles(m_NetworkId);
281 }
Kevin May42477c12020-03-26 13:34:14 +0000282}
283
284template<typename HalVersion>
285Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute(const V1_0::Request& request,
286 const ::android::sp<V1_0::IExecutionCallback>& callback)
287{
288 if (callback.get() == nullptr)
289 {
290 ALOGE("ArmnnPreparedModel_1_3::execute invalid callback passed");
291 return V1_0::ErrorStatus::INVALID_ARGUMENT;
292 }
293
294 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000295 std::vector<V1_2::OutputShape> outputShapes,
296 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000297 std::string callingFunction)
298 {
299 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
300 };
301
302
Sadik Armagan188675f2021-02-12 17:16:42 +0000303 return convertToV1_0(Execute(convertToV1_3(request), V1_2::MeasureTiming::NO, cb));
Kevin May42477c12020-03-26 13:34:14 +0000304}
305
306template<typename HalVersion>
307Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute_1_2(
308 const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000309 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000310 const sp<V1_2::IExecutionCallback>& callback)
311{
312 if (callback.get() == nullptr)
313 {
314 ALOGE("ArmnnPreparedModel_1_3::execute_1_2 invalid callback passed");
315 return V1_0::ErrorStatus::INVALID_ARGUMENT;
316 }
317
318 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000319 std::vector<V1_2::OutputShape> outputShapes,
320 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000321 std::string callingFunction)
322 {
323 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
324 };
325
326 return convertToV1_0(Execute(convertToV1_3(request), measureTiming, cb));
327}
328
329template<typename HalVersion>
330Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute_1_3(
331 const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000332 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000333 const V1_3::OptionalTimePoint&,
Kevin May352d8382020-03-31 15:03:42 +0100334 const V1_3::OptionalTimeoutDuration&,
Kevin May42477c12020-03-26 13:34:14 +0000335 const sp<V1_3::IExecutionCallback>& callback)
336{
337 if (callback.get() == nullptr)
338 {
339 ALOGE("ArmnnPreparedModel_1_3::execute_1_3 invalid callback passed");
340 return V1_3::ErrorStatus::INVALID_ARGUMENT;
341 }
342
343 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000344 std::vector<V1_2::OutputShape> outputShapes,
345 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000346 std::string callingFunction)
347 {
348 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
349 };
350
351 return Execute(request, measureTiming, cb);
352}
353
Sadik Armagand7be72e2020-04-23 12:56:05 +0100354/// This class is inspired by the sample implementation in Android named SampleFencedExecutionCallback.
355/// The original code is licensed under Apache-2.0 and can be found at the following link:
356/// https://android.googlesource.com/platform/frameworks/ml/+/master/nn/driver/sample/SampleDriver.h
357class ArmnnFencedExecutionCallback : public V1_3::IFencedExecutionCallback
358{
359public:
Sadik Armagan188675f2021-02-12 17:16:42 +0000360 ArmnnFencedExecutionCallback(V1_3::ErrorStatus errorStatus, V1_2::Timing timing, V1_2::Timing fenceTiming)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100361 : m_ErrorStatus(errorStatus), m_Timing(timing), m_FenceTiming(fenceTiming) {}
362 ~ArmnnFencedExecutionCallback() {}
363
364 Return<void> getExecutionInfo(getExecutionInfo_cb callback) override
365 {
366 callback(m_ErrorStatus, m_Timing, m_FenceTiming);
367 return Void();
368 }
369private:
370 V1_3::ErrorStatus m_ErrorStatus;
Sadik Armagan188675f2021-02-12 17:16:42 +0000371 V1_2::Timing m_Timing;
372 V1_2::Timing m_FenceTiming;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100373};
374
Kevin May42477c12020-03-26 13:34:14 +0000375template<typename HalVersion>
Sadik Armagand7be72e2020-04-23 12:56:05 +0100376Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeFenced(const V1_3::Request& request,
377 const hidl_vec<hidl_handle>& fenceWaitFor,
Sadik Armagan188675f2021-02-12 17:16:42 +0000378 V1_2::MeasureTiming measureTiming,
379 const V1_3::OptionalTimePoint& deadline,
380 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
381 const V1_3::OptionalTimeoutDuration&,
Kevin May42477c12020-03-26 13:34:14 +0000382 executeFenced_cb cb)
383{
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100384 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...)");
385 if (cb == nullptr)
386 {
387 ALOGE("ArmnnPreparedModel_1_3::executeFenced invalid callback passed");
Sadik Armagan188675f2021-02-12 17:16:42 +0000388 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100389 return Void();
390 }
391
Sadik Armagan188675f2021-02-12 17:16:42 +0000392 if (deadline.getDiscriminator() != V1_3::OptionalTimePoint::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100393 {
394 ALOGW("ArmnnPreparedModel_1_3::executeFenced parameter deadline is set but not supported.");
395 }
396
Sadik Armagan188675f2021-02-12 17:16:42 +0000397 if (loopTimeoutDuration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100398 {
399 ALOGW("ArmnnPreparedModel_1_3::executeFenced parameter loopTimeoutDuration is set but not supported.");
400 }
401
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100402 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model, /*allowUnspecifiedOutput=*/false))
Finn Williamsa4983ce2020-07-23 12:55:12 +0100403 {
404 ALOGV("ArmnnPreparedModel_1_3::executeFenced outputs must be specified for fenced execution ");
Sadik Armagan188675f2021-02-12 17:16:42 +0000405 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Finn Williamsa4983ce2020-07-23 12:55:12 +0100406 return Void();
407 }
408
Sadik Armagand7be72e2020-04-23 12:56:05 +0100409 ExecutionContext_1_3 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000410 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100411 {
412 ctx.measureTimings = measureTiming;
413 ctx.driverStart = Now();
414 }
415
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100416 if (!m_PreparedFromCache)
417 {
418 ALOGV("ArmnnPreparedModel_1_3::executeFenced(): %s", GetModelSummary(m_Model).c_str());
419 }
Sadik Armagand7be72e2020-04-23 12:56:05 +0100420 m_RequestCount++;
421
Sadik Armagand7be72e2020-04-23 12:56:05 +0100422 if (!m_RequestInputsAndOutputsDumpDir.empty())
423 {
424 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&cb));
425 }
426
427 // This code snippet is inspired by the sample implementation in Android named SampleDriver::executeFenced()
428 // function. The original code is licensed under Apache-2.0 and can be found at the following link:
429 // https://android.googlesource.com/platform/frameworks/ml/+/master/nn/driver/sample/SampleDriver.cpp
430 const auto fenceSize = fenceWaitFor.size();
431 for (unsigned int index = 0; index < fenceSize; ++index)
432 {
433 auto fenceNativeHandle = fenceWaitFor[index].getNativeHandle();
434 if (!fenceNativeHandle)
435 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000436 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100437 return Void();
438 }
439
440 if (sync_wait(fenceNativeHandle->data[0], -1) < 0)
441 {
442 ALOGE("ArmnnPreparedModel_1_3::executeFenced sync fence failed.");
Sadik Armagan188675f2021-02-12 17:16:42 +0000443 cb(V1_3::ErrorStatus::GENERAL_FAILURE, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100444 return Void();
445 }
446 }
447
448 TimePoint fenceExecutionStart;
Sadik Armagan188675f2021-02-12 17:16:42 +0000449 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100450 {
451 fenceExecutionStart = Now();
452 }
453
454 // map the memory pool into shared pointers
455 // use a shared memory pools vector on the heap, as it is passed to the request thread
456 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
457
458 // allocate the tensors on the heap, as they are passed to the request thread
459 auto inputs = std::make_shared<armnn::InputTensors>();
460 auto outputs = std::make_shared<armnn::OutputTensors>();
461
462 auto [status, outShapes, timings, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
463 if (status != V1_3::ErrorStatus::NONE)
464 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000465 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100466 return Void();
467 }
468
469 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...) before ExecuteGraph");
470
471 // call it with nullCallback for now as we will report the error status from here..
Sadik Armagan188675f2021-02-12 17:16:42 +0000472 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Sadik Armagand7be72e2020-04-23 12:56:05 +0100473 CallbackContext_1_3 cbCtx;
474 cbCtx.callback = nullCallback;
475 cbCtx.ctx = ctx;
476
477 auto errorStatus = ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
478 if (errorStatus != V1_3::ErrorStatus::NONE)
479 {
480 cb(errorStatus, hidl_handle(nullptr), nullptr);
481 return Void();
482 }
483 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...) after ExecuteGraph");
484
Sadik Armagan188675f2021-02-12 17:16:42 +0000485 V1_2::Timing timing = g_NoTiming;
486 V1_2::Timing fenceTiming = g_NoTiming;
487 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100488 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100489 fenceTiming.timeOnDevice = MicrosecondsDuration(ctx.deviceEnd, ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100490 fenceTiming.timeInDriver = MicrosecondsDuration(ctx.driverEnd, fenceExecutionStart);
491 ALOGV("ArmnnPreparedModel_1_3::fenceFinishExecutionTiming - Device = %lu Driver = %lu",
Zingo Andersen7c561492022-01-25 11:09:41 +0100492 static_cast<unsigned long>(fenceTiming.timeOnDevice),
493 static_cast<unsigned long>(fenceTiming.timeInDriver));
Sadik Armagand7be72e2020-04-23 12:56:05 +0100494 }
495
496 sp<ArmnnFencedExecutionCallback> armnnFencedExecutionCallback =
Sadik Armagan188675f2021-02-12 17:16:42 +0000497 new ArmnnFencedExecutionCallback(V1_3::ErrorStatus::NONE, timing, fenceTiming);
498 cb(V1_3::ErrorStatus::NONE, hidl_handle(nullptr), armnnFencedExecutionCallback);
Kevin May42477c12020-03-26 13:34:14 +0000499 return Void();
500}
501
502template<typename HalVersion>
503Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForInputs(
504 armnn::InputTensors& inputs,
505 const V1_3::Request& request,
506 const std::vector<android::nn::RunTimePoolInfo>& memPools)
507{
508 inputs.reserve(request.inputs.size());
509 for (unsigned int i = 0; i < request.inputs.size(); i++)
510 {
511 const auto& inputArg = request.inputs[i];
512
Cathal Corbette27d4e82021-10-28 12:28:35 +0100513 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
514 // inputs (of type InputTensors) is composed of a vector of ConstTensors.
515 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
516 inputTensorInfo.SetConstant();
Kevin May42477c12020-03-26 13:34:14 +0000517 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
518
519 if (inputTensor.GetMemoryArea() == nullptr)
520 {
521 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
522 return V1_3::ErrorStatus::GENERAL_FAILURE;
523 }
524
525 inputs.emplace_back(i, inputTensor);
526 }
527
528 return V1_3::ErrorStatus::NONE;
529}
530
531template<typename HalVersion>
532Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForOutputs(
533 armnn::OutputTensors& outputs,
Sadik Armagan188675f2021-02-12 17:16:42 +0000534 std::vector<V1_2::OutputShape> &outputShapes,
Kevin May42477c12020-03-26 13:34:14 +0000535 const V1_3::Request& request,
536 const std::vector<android::nn::RunTimePoolInfo>& memPools)
537{
538 outputs.reserve(request.outputs.size());
539 for (unsigned int i = 0; i < request.outputs.size(); i++)
540 {
541 const auto& outputArg = request.outputs[i];
542
Finn Williamsa4983ce2020-07-23 12:55:12 +0100543 armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
Kevin May42477c12020-03-26 13:34:14 +0000544 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
545 if (outputTensor.GetMemoryArea() == nullptr)
546 {
547 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
548 return V1_3::ErrorStatus::GENERAL_FAILURE;
549 }
550
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100551 const size_t outputSize = outputTensorInfo.GetNumBytes();
552
Finn Williamsa4983ce2020-07-23 12:55:12 +0100553 unsigned int count = 0;
554 std::for_each(outputArg.dimensions.begin(), outputArg.dimensions.end(), [&](auto dim)
555 {
556 if (dim != 0)
557 {
558 outputTensorInfo.GetShape()[count] = dim;
559 }
560 else
561 {
562 outputTensorInfo.GetShape()[count] = outputArg.dimensions.size();
563 }
564
565 count++;
566 });
567
Finn Williamsa4983ce2020-07-23 12:55:12 +0100568 outputs.emplace_back(i, outputTensor);
569 outputShapes[i] = ComputeShape(outputTensorInfo);
570
571 if (outputArg.location.length < outputSize)
572 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100573 ALOGW("ArmnnPreparedModel_1_3::Execute failed outputArg.location.length (%s) < outputSize (%s)",
574 std::to_string(outputArg.location.length).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100575 outputShapes[i].isSufficient = false;
576 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
577 }
578
Sadik Armagan188675f2021-02-12 17:16:42 +0000579 size_t bufferSize = 0;
580#if !defined(ARMNN_ANDROID_S)
581 bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
Sadik Armagan188675f2021-02-12 17:16:42 +0000582#else
Kevin Maydc873f62021-06-14 11:21:11 +0100583 bufferSize = memPools.at(outputArg.location.poolIndex).getSize();
Sadik Armagan188675f2021-02-12 17:16:42 +0000584#endif
Kevin May42477c12020-03-26 13:34:14 +0000585 if (bufferSize < outputSize)
586 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100587 ALOGW("ArmnnPreparedModel_1_3::Execute failed bufferSize (%s) < outputSize (%s)",
588 std::to_string(bufferSize).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100589 outputShapes[i].isSufficient = false;
Kevin May42477c12020-03-26 13:34:14 +0000590 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
591 }
Kevin May42477c12020-03-26 13:34:14 +0000592 }
593
594 return V1_3::ErrorStatus::NONE;
595}
596
597template<typename HalVersion>
Sadik Armagan188675f2021-02-12 17:16:42 +0000598std::tuple<V1_3::ErrorStatus, hidl_vec<V1_2::OutputShape>, V1_2::Timing, std::string>
Kevin May42477c12020-03-26 13:34:14 +0000599 ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForIO(armnn::InputTensors& inputs,
600 armnn::OutputTensors& outputs,
601 std::vector<android::nn::RunTimePoolInfo>& memPools,
602 const V1_3::Request& request)
603{
Sadik Armagan188675f2021-02-12 17:16:42 +0000604#if !defined(ARMNN_ANDROID_S)
Kevin May42477c12020-03-26 13:34:14 +0000605 if (!setRunTimePoolInfosFromMemoryPools(&memPools, request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000606#else
607 if (!setRunTimePoolInfosFromMemoryPools(&memPools, uncheckedConvert(request.pools)))
608#endif
Kevin May42477c12020-03-26 13:34:14 +0000609 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000610 return {V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000611 }
612
613 // add the inputs and outputs with their data
614 try
615 {
616 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_3::ErrorStatus::NONE)
617 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000618 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000619 }
620
Sadik Armagan188675f2021-02-12 17:16:42 +0000621 std::vector<V1_2::OutputShape> outputShapes(request.outputs.size());
Kevin May42477c12020-03-26 13:34:14 +0000622
623 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
624 if (errorStatus != V1_3::ErrorStatus::NONE)
625 {
626 return {errorStatus, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
627 }
628 }
629 catch (armnn::Exception& e)
630 {
631 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000632 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000633 }
634 catch (std::exception& e)
635 {
636 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000637 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000638 }
639
640 return {V1_3::ErrorStatus::NONE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
641}
642
643template<typename HalVersion>
644template<typename CallbackContext>
645Return<void> ArmnnPreparedModel_1_3<HalVersion>::ExecuteSynchronously(const V1_3::Request& request,
646 CallbackContext cbCtx)
647{
Sadik Armagan188675f2021-02-12 17:16:42 +0000648 if (cbCtx.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000649 {
650 cbCtx.ctx.driverStart = Now();
651 }
652
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100653 if (!m_PreparedFromCache && !android::nn::validateRequest(convertToV1_3(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");
660 return Void();
661 }
662
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100663 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000664 {
665 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
666 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
667 {},
668 g_NoTiming,
669 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
Sadik Armaganef8a3932020-04-09 17:21:50 +0100670 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000671 }
672
673
674 // map the memory pool into shared pointers
675 // use a shared memory pools vector on the heap, as it is passed to the request thread
676 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
677
678 // allocate the tensors on the heap, as they are passed to the request thread
679 auto inputs = std::make_shared<armnn::InputTensors>();
680 auto outputs = std::make_shared<armnn::OutputTensors>();
681
682 auto [status, outputShapes, timing, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
683 if (status != V1_3::ErrorStatus::NONE)
684 {
685 cbCtx.callback(status, outputShapes, timing, message);
Sadik Armaganef8a3932020-04-09 17:21:50 +0100686 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000687 }
688
689 ALOGV("ArmnnPreparedModel_1_3::ExecuteSynchronously() before Execution");
690
691 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
692 return Void();
693}
694
695template<typename HalVersion>
696Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000697 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000698 executeSynchronously_cb cb)
699{
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100700 if (!m_PreparedFromCache)
701 {
702 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
703 }
Kevin May42477c12020-03-26 13:34:14 +0000704 m_RequestCount++;
705
706 if (cb == nullptr)
707 {
708 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously invalid callback passed");
709 return Void();
710 }
711
712 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000713 std::vector<V1_2::OutputShape> outputShapes,
714 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000715 std::string)
716 {
717 cb(convertToV1_0(errorStatus), outputShapes, timing);
718 };
719
720 CallbackContext_1_3 cbCtx;
721 cbCtx.callback = cbWrapper;
722 cbCtx.ctx.measureTimings = measureTiming;
723
724 ExecuteSynchronously(convertToV1_3(request), cbCtx);
725 return Void();
726}
727
728template<typename HalVersion>
Kevin May352d8382020-03-31 15:03:42 +0100729Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously_1_3(
730 const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000731 V1_2::MeasureTiming measureTiming,
Kevin May352d8382020-03-31 15:03:42 +0100732 const V1_3::OptionalTimePoint& deadline,
733 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
734 executeSynchronously_1_3_cb cb)
Kevin May42477c12020-03-26 13:34:14 +0000735{
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100736 if (!m_PreparedFromCache)
737 {
738 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously_1_3(): %s", GetModelSummary(m_Model).c_str());
739 }
Kevin May42477c12020-03-26 13:34:14 +0000740 m_RequestCount++;
741
742 if (cb == nullptr)
743 {
744 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid callback passed");
745 return Void();
746 }
747
Sadik Armagan188675f2021-02-12 17:16:42 +0000748 if (deadline.getDiscriminator() != V1_3::OptionalTimePoint::hidl_discriminator::none)
Kevin May42477c12020-03-26 13:34:14 +0000749 {
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100750 ALOGW("ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter deadline is set but not supported.");
Kevin May42477c12020-03-26 13:34:14 +0000751 }
752
Sadik Armagan188675f2021-02-12 17:16:42 +0000753 if (loopTimeoutDuration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100754 {
755 ALOGW(
756 "ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter loopTimeoutDuration is set but not supported.");
Kevin May352d8382020-03-31 15:03:42 +0100757 }
758
Kevin May42477c12020-03-26 13:34:14 +0000759 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000760 std::vector<V1_2::OutputShape> outputShapes,
761 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000762 std::string)
763 {
764 cb(errorStatus, outputShapes, timing);
765 };
766
767 CallbackContext_1_3 cbCtx;
768 cbCtx.callback = cbWrapper;
769 cbCtx.ctx.measureTimings = measureTiming;
770
771 ExecuteSynchronously(request, cbCtx);
772 return Void();
773}
774
775template<typename HalVersion>
776Return<void> ArmnnPreparedModel_1_3<HalVersion>::configureExecutionBurst(
777 const sp<V1_2::IBurstCallback>& callback,
778 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
779 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
780 V1_3::IPreparedModel::configureExecutionBurst_cb cb)
781{
782 ALOGV("ArmnnPreparedModel_1_3::configureExecutionBurst");
783 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
784 requestChannel,
785 resultChannel,
786 this);
787
788 if (burst == nullptr)
789 {
790 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
791 }
792 else
793 {
794 cb(V1_0::ErrorStatus::NONE, burst);
795 }
796 return Void();
797}
798
799template<typename HalVersion>
800template<typename CallbackContext>
Sadik Armagand7be72e2020-04-23 12:56:05 +0100801Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::ExecuteGraph(
Kevin May42477c12020-03-26 13:34:14 +0000802 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
803 armnn::InputTensors& inputTensors,
804 armnn::OutputTensors& outputTensors,
805 CallbackContext cb)
806{
807 ALOGV("ArmnnPreparedModel_1_3::ExecuteGraph(...)");
808
Kevin May42477c12020-03-26 13:34:14 +0000809 DumpTensorsIfRequired("Input", inputTensors);
810
Sadik Armagan188675f2021-02-12 17:16:42 +0000811 std::vector<V1_2::OutputShape> outputShapes(outputTensors.size());
Kevin May42477c12020-03-26 13:34:14 +0000812 for (unsigned int i = 0; i < outputTensors.size(); i++)
813 {
814 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
815 const armnn::Tensor outputTensor = outputTensorPair.second;
816 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
817
818 outputShapes[i] = ComputeShape(outputTensorInfo);
819 }
820
821 // run it
822 try
823 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000824 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000825 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100826 cb.ctx.deviceStart = Now();
Kevin May42477c12020-03-26 13:34:14 +0000827 }
Finn Williamsd8fb5402021-05-19 20:52:00 +0100828 armnn::Status status;
829 if (m_AsyncModelExecutionEnabled)
830 {
831 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled true");
832 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
833 }
834 else
835 {
836 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled false");
Narumol Prangnawarat558a1d42022-02-07 13:12:24 +0000837 // Create a vector of Input and Output Ids which can be imported. An empty vector means all will be copied.
838 std::vector<armnn::ImportedInputId> importedInputIds;
839 if (m_EnableImport)
840 {
841 importedInputIds = m_Runtime->ImportInputs(m_NetworkId, inputTensors, armnn::MemorySource::Malloc);
842 }
843 std::vector<armnn::ImportedOutputId> importedOutputIds;
844 if (m_EnableExport)
845 {
846 importedOutputIds = m_Runtime->ImportOutputs(m_NetworkId, outputTensors, armnn::MemorySource::Malloc);
847 }
848 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors,
849 importedInputIds, importedOutputIds);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100850 }
Kevin May42477c12020-03-26 13:34:14 +0000851
Sadik Armagan188675f2021-02-12 17:16:42 +0000852 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000853 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100854 cb.ctx.deviceEnd = Now();
Kevin May42477c12020-03-26 13:34:14 +0000855 }
856 if (status != armnn::Status::Success)
857 {
Finn Williamsd8fb5402021-05-19 20:52:00 +0100858 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph EnqueueWorkload failed");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100859 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
860 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000861 }
862 }
863 catch (armnn::Exception& e)
864 {
865 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
866 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100867 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000868 }
869 catch (std::exception& e)
870 {
871 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
872 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100873 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000874 }
875
876 CommitPools(*pMemPools);
877
878 DumpTensorsIfRequired("Output", outputTensors);
879
Sadik Armagan188675f2021-02-12 17:16:42 +0000880 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000881 {
Kevin May949a69e2020-04-24 10:21:40 +0100882 cb.ctx.driverEnd = Now();
Sadik Armagan188675f2021-02-12 17:16:42 +0000883 V1_2::Timing timing;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100884 timing.timeOnDevice = MicrosecondsDuration(cb.ctx.deviceEnd, cb.ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100885 timing.timeInDriver = MicrosecondsDuration(cb.ctx.driverEnd, cb.ctx.driverStart);
Zingo Andersen7c561492022-01-25 11:09:41 +0100886 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu",
887 static_cast<unsigned long>(timing.timeOnDevice), static_cast<unsigned long>(timing.timeInDriver));
Kevin May42477c12020-03-26 13:34:14 +0000888 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100889 } else
890 {
Kevin May42477c12020-03-26 13:34:14 +0000891 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
892 }
Sadik Armagand7be72e2020-04-23 12:56:05 +0100893 return V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000894}
895
Finn Williamsd8fb5402021-05-19 20:52:00 +0100896/// Schedule the graph prepared from the request for execution
897template<typename HalVersion>
898template<typename CallbackContext>
899void ArmnnPreparedModel_1_3<HalVersion>::ScheduleGraphForExecution(
900 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
901 std::shared_ptr<armnn::InputTensors>& inputTensors,
902 std::shared_ptr<armnn::OutputTensors>& outputTensors,
903 CallbackContext callbackContext,
904 armnn::QosExecPriority priority)
905{
906 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution(...)");
907
908 DumpTensorsIfRequired("Input", *inputTensors);
909
910 unsigned int outputTensorSize = outputTensors.get()->size();
911 std::vector<V1_2::OutputShape> outputShapes(outputTensorSize);
912 for (unsigned int i = 0; i < outputTensorSize; i++)
913 {
914 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors.get()->at(i);
915 const armnn::Tensor outputTensor = outputTensorPair.second;
916 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
917
918 outputShapes[i] = ComputeShape(outputTensorInfo);
919 }
920
921 auto tpCb = std::make_shared<
922 ArmnnThreadPoolCallback_1_3<CallbackContext_1_3>>(this,
923 pMemPools,
924 outputShapes,
925 inputTensors,
926 outputTensors,
927 callbackContext);
928
Finn Williamsca3a3e02021-06-11 15:04:02 +0100929 m_Threadpool->Schedule(m_NetworkId,
930 *tpCb->m_InputTensors,
931 *tpCb->m_OutputTensors,
932 priority,
933 tpCb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100934 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution end");
935}
936
Kevin May42477c12020-03-26 13:34:14 +0000937template<typename HalVersion>
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100938bool ArmnnPreparedModel_1_3<HalVersion>::ExecuteWithDummyInputs(unsigned int numInputs, unsigned int numOutputs)
Kevin May42477c12020-03-26 13:34:14 +0000939{
940 std::vector<std::vector<char>> storage;
941 armnn::InputTensors inputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100942 for (unsigned int i = 0; i < numInputs; i++)
Kevin May42477c12020-03-26 13:34:14 +0000943 {
Cathal Corbette27d4e82021-10-28 12:28:35 +0100944 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
945 // pInputTensors (of type InputTensors) is composed of a vector of ConstTensors.
946 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
947 inputTensorInfo.SetConstant();
948
Kevin May42477c12020-03-26 13:34:14 +0000949 storage.emplace_back(inputTensorInfo.GetNumBytes());
950 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
951
952 inputTensors.emplace_back(i, inputTensor);
953 }
954
955 armnn::OutputTensors outputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100956 for (unsigned int i = 0; i < numOutputs; i++)
Kevin May42477c12020-03-26 13:34:14 +0000957 {
958 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
959 storage.emplace_back(outputTensorInfo.GetNumBytes());
960 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
961
962 outputTensors.emplace_back(i, outputTensor);
963 }
964
Sadik Armagan188675f2021-02-12 17:16:42 +0000965 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Kevin May42477c12020-03-26 13:34:14 +0000966 CallbackContext_1_3 callbackContext;
967 callbackContext.callback = nullCallback;
Sadik Armagan188675f2021-02-12 17:16:42 +0000968 callbackContext.ctx.measureTimings = V1_2::MeasureTiming::NO;
Kevin May42477c12020-03-26 13:34:14 +0000969 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
Sadik Armagand7be72e2020-04-23 12:56:05 +0100970
971 auto errorStatus = ExecuteGraph(memPools,
972 inputTensors,
973 outputTensors,
974 callbackContext);
975 return errorStatus == V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000976}
977
978template<typename HalVersion>
979Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::Execute(const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000980 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000981 CallbackAsync_1_3 callback)
982{
983 ExecutionContext_1_3 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000984 if (measureTiming == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000985 {
986 ctx.measureTimings = measureTiming;
987 ctx.driverStart = Now();
988 }
989
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100990 if (!m_PreparedFromCache)
991 {
992 ALOGV("ArmnnPreparedModel_1_3::execute(): %s", GetModelSummary(m_Model).c_str());
993 }
Kevin May42477c12020-03-26 13:34:14 +0000994 m_RequestCount++;
995
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100996 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000997 {
998 callback(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute");
999 return V1_3::ErrorStatus::INVALID_ARGUMENT;
1000 }
1001
1002 if (!m_RequestInputsAndOutputsDumpDir.empty())
1003 {
1004 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
1005 }
1006
1007 // map the memory pool into shared pointers
1008 // use a shared memory pools vector on the heap, as it is passed to the request thread
1009 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
1010
1011 // allocate the tensors on the heap, as they are passed to the request thread
1012 auto inputTensors = std::make_shared<armnn::InputTensors>();
1013 auto outputTensors = std::make_shared<armnn::OutputTensors>();
1014
1015 auto [status, outShapes, timing, message] = PrepareMemoryForIO(*inputTensors, *outputTensors,
1016 *memPools, request);
1017 if (status != V1_3::ErrorStatus::NONE)
1018 {
1019 callback(status, outShapes, timing, message);
1020 }
1021
1022 switch(status)
1023 {
1024 case V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
1025 return V1_3::ErrorStatus::NONE;
1026 case V1_3::ErrorStatus::GENERAL_FAILURE:
1027 return V1_3::ErrorStatus::GENERAL_FAILURE;
Sadik Armagana07d2752021-05-12 20:33:58 +01001028 case V1_3::ErrorStatus::INVALID_ARGUMENT:
1029 return V1_3::ErrorStatus::INVALID_ARGUMENT;
Kevin May42477c12020-03-26 13:34:14 +00001030 default:
1031 {}
1032 }
Kevin May42477c12020-03-26 13:34:14 +00001033 CallbackContext_1_3 cb;
1034 cb.callback = callback;
1035 cb.ctx = ctx;
Finn Williamsd8fb5402021-05-19 20:52:00 +01001036
1037
1038 enum class QosExecPriority
1039 {
1040 Low = 0,
1041 Medium = 1,
1042 High = 2
1043 };
1044
1045
1046 if (m_AsyncModelExecutionEnabled)
1047 {
1048 armnn::QosExecPriority priority;
1049
1050 switch (GetModelPriority()) {
1051 case V1_3::Priority::LOW:
1052 priority = armnn::QosExecPriority::Low;
1053 break;
1054 case V1_3::Priority::MEDIUM:
1055 priority = armnn::QosExecPriority::Medium;
1056 break;
1057 case V1_3::Priority::HIGH:
1058 priority = armnn::QosExecPriority::High;
1059 break;
1060 default:
1061 priority = armnn::QosExecPriority::Medium;
1062
1063 }
1064
1065 ALOGV("ArmnnPreparedModel_1_3::execute(...) before ScheduleGraphForExecution");
1066 ScheduleGraphForExecution(memPools, inputTensors, outputTensors, cb, priority);
1067 ALOGV("ArmnnPreparedModel_1_3::execute(...) after ScheduleGraphForExecution");
1068 return V1_3::ErrorStatus::NONE;
1069 }
1070
1071 ALOGV("ArmnnPreparedModel_1_3::execute(...) before PostMsg");
1072 // post the request for asynchronous execution
Kevin May42477c12020-03-26 13:34:14 +00001073 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
1074 ALOGV("ArmnnPreparedModel_1_3::execute(...) after PostMsg");
1075 return V1_3::ErrorStatus::NONE;
1076}
1077
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +01001078template<typename HalVersion>
1079V1_3::Priority ArmnnPreparedModel_1_3<HalVersion>::GetModelPriority()
1080{
1081 return m_ModelPriority;
1082}
1083
Finn Williamsd8fb5402021-05-19 20:52:00 +01001084template<typename HalVersion>
1085template <typename CallbackContext>
1086void ArmnnPreparedModel_1_3<HalVersion>::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify(
1087 armnn::Status status, armnn::InferenceTimingPair timeTaken)
1088{
1089 ALOGV("ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify");
1090 CommitPools(*m_MemPools);
1091
1092 m_Model->DumpTensorsIfRequired("Output", *m_OutputTensors);
1093
1094 if (status != armnn::Status::Success)
1095 {
1096 ALOGW("ArmnnThreadPoolCallback_1_3::Notify EnqueueWorkload failed");
1097 m_CallbackContext.callback(V1_3::ErrorStatus::GENERAL_FAILURE,
1098 {},
1099 g_NoTiming,
1100 "ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3");
1101 return;
1102 }
1103
1104 if (m_CallbackContext.ctx.measureTimings == V1_2::MeasureTiming::YES)
1105 {
1106 m_CallbackContext.ctx.deviceStart = timeTaken.first;
1107 m_CallbackContext.ctx.deviceEnd = timeTaken.second;
1108 m_CallbackContext.ctx.driverEnd = std::chrono::steady_clock::now();
1109 V1_2::Timing timing;
1110 timing.timeOnDevice = MicrosecondsDuration(m_CallbackContext.ctx.deviceEnd, m_CallbackContext.ctx.deviceStart);
1111 timing.timeInDriver = MicrosecondsDuration(m_CallbackContext.ctx.driverEnd, m_CallbackContext.ctx.driverStart);
Zingo Andersen7c561492022-01-25 11:09:41 +01001112 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu",
1113 static_cast<unsigned long>(timing.timeOnDevice), static_cast<unsigned long>(timing.timeInDriver));
Finn Williamsd8fb5402021-05-19 20:52:00 +01001114 m_CallbackContext.callback(
1115 V1_3::ErrorStatus::NONE, m_OutputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
1116 } else
1117 {
1118 m_CallbackContext.callback(
1119 V1_3::ErrorStatus::NONE, m_OutputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
1120 }
1121 return;
1122}
1123
Kevin May42477c12020-03-26 13:34:14 +00001124#ifdef ARMNN_ANDROID_NN_V1_3
1125template class ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>;
Sadik Armagand7be72e2020-04-23 12:56:05 +01001126template Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ExecuteGraph<CallbackContext_1_3>(
Kevin May42477c12020-03-26 13:34:14 +00001127 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1128 armnn::InputTensors& pInputTensors,
1129 armnn::OutputTensors& pOutputTensors,
1130 CallbackContext_1_3 cb);
Finn Williamsd8fb5402021-05-19 20:52:00 +01001131
1132template void ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ScheduleGraphForExecution<CallbackContext_1_3>(
1133 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1134 std::shared_ptr<armnn::InputTensors>& inputTensors,
1135 std::shared_ptr<armnn::OutputTensors>& outputTensors,
1136 CallbackContext_1_3 callbackContext,
1137 armnn::QosExecPriority priority);
Kevin May42477c12020-03-26 13:34:14 +00001138#endif
1139
1140} // namespace armnn_driver