blob: ceeb3c48109d9401b9daa5089df02c89c238b3be [file] [log] [blame]
Kevin May42477c12020-03-26 13:34:14 +00001//
Mike Kellyde547162023-03-08 10:08:20 +00002// Copyright © 2020-2023 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 Prangnawaratd1a947f2022-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
Colm Donelan0fc16c62022-03-16 11:54:13 +000024#include <chrono>
Kevin May42477c12020-03-26 13:34:14 +000025#include <cinttypes>
26
Sadik Armagan188675f2021-02-12 17:16:42 +000027#ifdef ARMNN_ANDROID_S
28#include <LegacyUtils.h>
29#endif
30
Kevin May42477c12020-03-26 13:34:14 +000031using namespace android;
32using namespace android::hardware;
33
34namespace {
35
Sadik Armagan188675f2021-02-12 17:16:42 +000036static const V1_2::Timing g_NoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX};
Kevin May42477c12020-03-26 13:34:14 +000037using namespace armnn_driver;
38using TimePoint = std::chrono::steady_clock::time_point;
39
40TimePoint Now()
41{
42 return std::chrono::steady_clock::now();
43}
44
45unsigned long MicrosecondsDuration(TimePoint endPoint, TimePoint startPoint)
46{
47 return static_cast<unsigned long>(std::chrono::duration_cast<std::chrono::microseconds>(
48 endPoint - startPoint).count());
49}
50
51void NotifyCallbackAndCheck(const ::android::sp<V1_0::IExecutionCallback>& callback,
52 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000053 std::vector<V1_2::OutputShape>,
54 const V1_2::Timing,
Kevin May42477c12020-03-26 13:34:14 +000055 std::string callingFunction)
56{
57 Return<void> returned = callback->notify(convertToV1_0(errorStatus));
58 // This check is required, if the callback fails and it isn't checked it will bring down the service
59 if (!returned.isOk())
60 {
61 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
62 callingFunction.c_str(), returned.description().c_str());
63 }
64}
65
66void NotifyCallbackAndCheck(const ::android::sp<V1_2::IExecutionCallback>& callback,
67 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000068 std::vector<V1_2::OutputShape> outputShapes,
69 const V1_2::Timing timing,
Kevin May42477c12020-03-26 13:34:14 +000070 std::string callingFunction)
71{
72 Return<void> returned = callback->notify_1_2(convertToV1_0(errorStatus), outputShapes, timing);
73 // This check is required, if the callback fails and it isn't checked it will bring down the service
74 if (!returned.isOk())
75 {
76 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
77 callingFunction.c_str(), returned.description().c_str());
78 }
79}
80
81void NotifyCallbackAndCheck(const ::android::sp<V1_3::IExecutionCallback>& callback,
82 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000083 std::vector<V1_2::OutputShape> outputShapes,
84 const V1_2::Timing timing,
Kevin May42477c12020-03-26 13:34:14 +000085 std::string callingFunction)
86{
87 Return<void> returned = callback->notify_1_3(errorStatus, outputShapes, timing);
88 // This check is required, if the callback fails and it isn't checked it will bring down the service
89 if (!returned.isOk())
90 {
91 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
92 callingFunction.c_str(), returned.description().c_str());
93 }
94}
95
Sadik Armagan188675f2021-02-12 17:16:42 +000096bool ValidateRequestArgument(const V1_0::RequestArgument& requestArg, const armnn::TensorInfo& tensorInfo)
Kevin May42477c12020-03-26 13:34:14 +000097{
98 if (requestArg.dimensions.size() != 0)
99 {
100 if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
101 {
102 ALOGE("Mismatched dimensions (request argument: %zu, expected: %u)",
103 requestArg.dimensions.size(), tensorInfo.GetNumDimensions());
104 return false;
105 }
106
107 for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
108 {
Finn Williamsa4983ce2020-07-23 12:55:12 +0100109 if (requestArg.dimensions[d] != 0 && requestArg.dimensions[d] != tensorInfo.GetShape()[d])
Kevin May42477c12020-03-26 13:34:14 +0000110 {
111 ALOGE("Mismatched size for dimension %d (request argument: %u, expected %u)",
112 d, requestArg.dimensions[d], tensorInfo.GetShape()[d]);
113 return false;
114 }
115 }
116 }
117
118 return true;
119}
120
Sadik Armagan188675f2021-02-12 17:16:42 +0000121armnn::Tensor GetTensorForRequestArgument(const V1_0::RequestArgument& requestArg,
Kevin May42477c12020-03-26 13:34:14 +0000122 const armnn::TensorInfo& tensorInfo,
123 const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
124{
125 if (!ValidateRequestArgument(requestArg, tensorInfo))
126 {
127 return armnn::Tensor();
128 }
129
130 return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
131}
132
133inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
134{
135 return tensorNamePrefix + std::to_string(index);
136}
137
138} // anonymous namespace
139
140using namespace android::hardware;
141
142namespace armnn_driver
143{
144
145template<typename HalVersion>
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100146RequestThread_1_3<ArmnnPreparedModel_1_3, HalVersion, CallbackContext_1_3>
Kevin May42477c12020-03-26 13:34:14 +0000147 ArmnnPreparedModel_1_3<HalVersion>::m_RequestThread;
148
149template<typename HalVersion>
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100150std::unique_ptr<armnn::Threadpool> ArmnnPreparedModel_1_3<HalVersion>::m_Threadpool(nullptr);
151
152template<typename HalVersion>
Kevin May42477c12020-03-26 13:34:14 +0000153template<typename TensorBindingCollection>
154void ArmnnPreparedModel_1_3<HalVersion>::DumpTensorsIfRequired(char const* tensorNamePrefix,
155 const TensorBindingCollection& tensorBindings)
156{
157 if (!m_RequestInputsAndOutputsDumpDir.empty())
158 {
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100159 const std::string requestName = std::to_string(m_NetworkId) + "_" + std::to_string(m_RequestCount) + ".dump";
Kevin May42477c12020-03-26 13:34:14 +0000160 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
161 {
162 DumpTensor(m_RequestInputsAndOutputsDumpDir,
163 requestName,
164 BuildTensorName(tensorNamePrefix, i),
165 tensorBindings[i].second);
166 }
167 }
168}
169
170template<typename HalVersion>
171ArmnnPreparedModel_1_3<HalVersion>::ArmnnPreparedModel_1_3(armnn::NetworkId networkId,
172 armnn::IRuntime* runtime,
173 const V1_3::Model& model,
174 const std::string& requestInputsAndOutputsDumpDir,
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100175 const bool gpuProfilingEnabled,
Finn Williamsd8fb5402021-05-19 20:52:00 +0100176 V1_3::Priority priority,
Finn Williamsca3a3e02021-06-11 15:04:02 +0100177 const bool asyncModelExecutionEnabled,
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000178 const unsigned int numberOfThreads,
179 const bool importEnabled,
180 const bool exportEnabled)
Kevin May42477c12020-03-26 13:34:14 +0000181 : m_NetworkId(networkId)
182 , m_Runtime(runtime)
183 , m_Model(model)
184 , m_RequestCount(0)
185 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
186 , m_GpuProfilingEnabled(gpuProfilingEnabled)
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100187 , m_ModelPriority(priority)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100188 , m_AsyncModelExecutionEnabled(asyncModelExecutionEnabled)
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000189 , m_EnableImport(importEnabled)
190 , m_EnableExport(exportEnabled)
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100191 , m_PreparedFromCache(false)
192{
193 // Enable profiling if required.
194 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
195
196 if (m_AsyncModelExecutionEnabled)
197 {
198 std::vector<std::shared_ptr<armnn::IWorkingMemHandle>> memHandles;
199 for (unsigned int i=0; i < numberOfThreads; ++i)
200 {
201 memHandles.emplace_back(m_Runtime->CreateWorkingMemHandle(networkId));
202 }
203
204 if (!m_Threadpool)
205 {
206 m_Threadpool = std::make_unique<armnn::Threadpool>(numberOfThreads, runtime, memHandles);
207 }
208 else
209 {
210 m_Threadpool->LoadMemHandles(memHandles);
211 }
212
213 m_WorkingMemHandle = memHandles.back();
214 }
215}
216
217template<typename HalVersion>
218ArmnnPreparedModel_1_3<HalVersion>::ArmnnPreparedModel_1_3(armnn::NetworkId networkId,
219 armnn::IRuntime* runtime,
220 const std::string& requestInputsAndOutputsDumpDir,
221 const bool gpuProfilingEnabled,
222 V1_3::Priority priority,
223 const bool asyncModelExecutionEnabled,
224 const unsigned int numberOfThreads,
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000225 const bool importEnabled,
226 const bool exportEnabled,
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100227 const bool preparedFromCache)
228 : m_NetworkId(networkId)
229 , m_Runtime(runtime)
230 , m_RequestCount(0)
231 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
232 , m_GpuProfilingEnabled(gpuProfilingEnabled)
233 , m_ModelPriority(priority)
234 , m_AsyncModelExecutionEnabled(asyncModelExecutionEnabled)
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000235 , m_EnableImport(importEnabled)
236 , m_EnableExport(exportEnabled)
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100237 , m_PreparedFromCache(preparedFromCache)
Kevin May42477c12020-03-26 13:34:14 +0000238{
239 // Enable profiling if required.
240 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100241
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100242 if (m_AsyncModelExecutionEnabled)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100243 {
Finn Williamsca3a3e02021-06-11 15:04:02 +0100244 std::vector<std::shared_ptr<armnn::IWorkingMemHandle>> memHandles;
Finn Williamsd27c13b2021-06-25 10:06:09 +0100245 for (unsigned int i=0; i < numberOfThreads; ++i)
Finn Williamsca3a3e02021-06-11 15:04:02 +0100246 {
247 memHandles.emplace_back(m_Runtime->CreateWorkingMemHandle(networkId));
248 }
249
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100250 if (!m_Threadpool)
251 {
252 m_Threadpool = std::make_unique<armnn::Threadpool>(numberOfThreads, runtime, memHandles);
253 }
254 else
255 {
256 m_Threadpool->LoadMemHandles(memHandles);
257 }
258
Finn Williamsca3a3e02021-06-11 15:04:02 +0100259 m_WorkingMemHandle = memHandles.back();
Finn Williamsd8fb5402021-05-19 20:52:00 +0100260 }
Kevin May42477c12020-03-26 13:34:14 +0000261}
262
263template<typename HalVersion>
264ArmnnPreparedModel_1_3<HalVersion>::~ArmnnPreparedModel_1_3()
265{
266 // Get a hold of the profiler used by this model.
267 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
Colm Donelan2048b682022-02-15 14:59:08 +0000268 if (profiler && m_GpuProfilingEnabled)
269 {
270 // Dump the profiling info to a file if required.
271 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId,
272 profiler.get());
273 }
Kevin May42477c12020-03-26 13:34:14 +0000274
275 // Unload the network associated with this model.
276 m_Runtime->UnloadNetwork(m_NetworkId);
277
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100278 // Unload the network memhandles from the threadpool
279 if (m_AsyncModelExecutionEnabled)
280 {
281 m_Threadpool->UnloadMemHandles(m_NetworkId);
282 }
Kevin May42477c12020-03-26 13:34:14 +0000283}
284
285template<typename HalVersion>
286Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute(const V1_0::Request& request,
287 const ::android::sp<V1_0::IExecutionCallback>& callback)
288{
289 if (callback.get() == nullptr)
290 {
291 ALOGE("ArmnnPreparedModel_1_3::execute invalid callback passed");
292 return V1_0::ErrorStatus::INVALID_ARGUMENT;
293 }
294
295 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000296 std::vector<V1_2::OutputShape> outputShapes,
297 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000298 std::string callingFunction)
299 {
300 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
301 };
302
303
Sadik Armagan188675f2021-02-12 17:16:42 +0000304 return convertToV1_0(Execute(convertToV1_3(request), V1_2::MeasureTiming::NO, cb));
Kevin May42477c12020-03-26 13:34:14 +0000305}
306
307template<typename HalVersion>
308Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute_1_2(
309 const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000310 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000311 const sp<V1_2::IExecutionCallback>& callback)
312{
313 if (callback.get() == nullptr)
314 {
315 ALOGE("ArmnnPreparedModel_1_3::execute_1_2 invalid callback passed");
316 return V1_0::ErrorStatus::INVALID_ARGUMENT;
317 }
318
319 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000320 std::vector<V1_2::OutputShape> outputShapes,
321 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000322 std::string callingFunction)
323 {
324 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
325 };
326
327 return convertToV1_0(Execute(convertToV1_3(request), measureTiming, cb));
328}
329
330template<typename HalVersion>
331Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute_1_3(
332 const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000333 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000334 const V1_3::OptionalTimePoint&,
Kevin May352d8382020-03-31 15:03:42 +0100335 const V1_3::OptionalTimeoutDuration&,
Kevin May42477c12020-03-26 13:34:14 +0000336 const sp<V1_3::IExecutionCallback>& callback)
337{
338 if (callback.get() == nullptr)
339 {
340 ALOGE("ArmnnPreparedModel_1_3::execute_1_3 invalid callback passed");
341 return V1_3::ErrorStatus::INVALID_ARGUMENT;
342 }
343
344 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000345 std::vector<V1_2::OutputShape> outputShapes,
346 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000347 std::string callingFunction)
348 {
349 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
350 };
351
352 return Execute(request, measureTiming, cb);
353}
354
Sadik Armagand7be72e2020-04-23 12:56:05 +0100355/// This class is inspired by the sample implementation in Android named SampleFencedExecutionCallback.
356/// The original code is licensed under Apache-2.0 and can be found at the following link:
357/// https://android.googlesource.com/platform/frameworks/ml/+/master/nn/driver/sample/SampleDriver.h
358class ArmnnFencedExecutionCallback : public V1_3::IFencedExecutionCallback
359{
360public:
Sadik Armagan188675f2021-02-12 17:16:42 +0000361 ArmnnFencedExecutionCallback(V1_3::ErrorStatus errorStatus, V1_2::Timing timing, V1_2::Timing fenceTiming)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100362 : m_ErrorStatus(errorStatus), m_Timing(timing), m_FenceTiming(fenceTiming) {}
363 ~ArmnnFencedExecutionCallback() {}
364
365 Return<void> getExecutionInfo(getExecutionInfo_cb callback) override
366 {
367 callback(m_ErrorStatus, m_Timing, m_FenceTiming);
368 return Void();
369 }
370private:
371 V1_3::ErrorStatus m_ErrorStatus;
Sadik Armagan188675f2021-02-12 17:16:42 +0000372 V1_2::Timing m_Timing;
373 V1_2::Timing m_FenceTiming;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100374};
375
Kevin May42477c12020-03-26 13:34:14 +0000376template<typename HalVersion>
Sadik Armagand7be72e2020-04-23 12:56:05 +0100377Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeFenced(const V1_3::Request& request,
378 const hidl_vec<hidl_handle>& fenceWaitFor,
Sadik Armagan188675f2021-02-12 17:16:42 +0000379 V1_2::MeasureTiming measureTiming,
380 const V1_3::OptionalTimePoint& deadline,
381 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
382 const V1_3::OptionalTimeoutDuration&,
Kevin May42477c12020-03-26 13:34:14 +0000383 executeFenced_cb cb)
384{
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100385 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...)");
386 if (cb == nullptr)
387 {
388 ALOGE("ArmnnPreparedModel_1_3::executeFenced invalid callback passed");
Sadik Armagan188675f2021-02-12 17:16:42 +0000389 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100390 return Void();
391 }
392
Sadik Armagan188675f2021-02-12 17:16:42 +0000393 if (deadline.getDiscriminator() != V1_3::OptionalTimePoint::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100394 {
395 ALOGW("ArmnnPreparedModel_1_3::executeFenced parameter deadline is set but not supported.");
396 }
397
Sadik Armagan188675f2021-02-12 17:16:42 +0000398 if (loopTimeoutDuration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100399 {
400 ALOGW("ArmnnPreparedModel_1_3::executeFenced parameter loopTimeoutDuration is set but not supported.");
401 }
402
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100403 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model, /*allowUnspecifiedOutput=*/false))
Finn Williamsa4983ce2020-07-23 12:55:12 +0100404 {
405 ALOGV("ArmnnPreparedModel_1_3::executeFenced outputs must be specified for fenced execution ");
Sadik Armagan188675f2021-02-12 17:16:42 +0000406 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Finn Williamsa4983ce2020-07-23 12:55:12 +0100407 return Void();
408 }
409
Sadik Armagand7be72e2020-04-23 12:56:05 +0100410 ExecutionContext_1_3 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000411 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100412 {
413 ctx.measureTimings = measureTiming;
414 ctx.driverStart = Now();
415 }
416
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100417 if (!m_PreparedFromCache)
418 {
419 ALOGV("ArmnnPreparedModel_1_3::executeFenced(): %s", GetModelSummary(m_Model).c_str());
420 }
Sadik Armagand7be72e2020-04-23 12:56:05 +0100421 m_RequestCount++;
422
Sadik Armagand7be72e2020-04-23 12:56:05 +0100423 if (!m_RequestInputsAndOutputsDumpDir.empty())
424 {
425 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&cb));
426 }
427
428 // This code snippet is inspired by the sample implementation in Android named SampleDriver::executeFenced()
429 // function. The original code is licensed under Apache-2.0 and can be found at the following link:
430 // https://android.googlesource.com/platform/frameworks/ml/+/master/nn/driver/sample/SampleDriver.cpp
431 const auto fenceSize = fenceWaitFor.size();
432 for (unsigned int index = 0; index < fenceSize; ++index)
433 {
434 auto fenceNativeHandle = fenceWaitFor[index].getNativeHandle();
435 if (!fenceNativeHandle)
436 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000437 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100438 return Void();
439 }
440
441 if (sync_wait(fenceNativeHandle->data[0], -1) < 0)
442 {
443 ALOGE("ArmnnPreparedModel_1_3::executeFenced sync fence failed.");
Sadik Armagan188675f2021-02-12 17:16:42 +0000444 cb(V1_3::ErrorStatus::GENERAL_FAILURE, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100445 return Void();
446 }
447 }
448
449 TimePoint fenceExecutionStart;
Sadik Armagan188675f2021-02-12 17:16:42 +0000450 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100451 {
452 fenceExecutionStart = Now();
453 }
454
455 // map the memory pool into shared pointers
456 // use a shared memory pools vector on the heap, as it is passed to the request thread
457 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
458
459 // allocate the tensors on the heap, as they are passed to the request thread
460 auto inputs = std::make_shared<armnn::InputTensors>();
461 auto outputs = std::make_shared<armnn::OutputTensors>();
462
463 auto [status, outShapes, timings, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
464 if (status != V1_3::ErrorStatus::NONE)
465 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000466 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100467 return Void();
468 }
469
470 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...) before ExecuteGraph");
471
472 // call it with nullCallback for now as we will report the error status from here..
Sadik Armagan188675f2021-02-12 17:16:42 +0000473 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Sadik Armagand7be72e2020-04-23 12:56:05 +0100474 CallbackContext_1_3 cbCtx;
475 cbCtx.callback = nullCallback;
476 cbCtx.ctx = ctx;
477
478 auto errorStatus = ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
479 if (errorStatus != V1_3::ErrorStatus::NONE)
480 {
481 cb(errorStatus, hidl_handle(nullptr), nullptr);
482 return Void();
483 }
484 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...) after ExecuteGraph");
485
Sadik Armagan188675f2021-02-12 17:16:42 +0000486 V1_2::Timing timing = g_NoTiming;
487 V1_2::Timing fenceTiming = g_NoTiming;
488 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100489 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100490 fenceTiming.timeOnDevice = MicrosecondsDuration(ctx.deviceEnd, ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100491 fenceTiming.timeInDriver = MicrosecondsDuration(ctx.driverEnd, fenceExecutionStart);
492 ALOGV("ArmnnPreparedModel_1_3::fenceFinishExecutionTiming - Device = %lu Driver = %lu",
Zingo Andersen7c561492022-01-25 11:09:41 +0100493 static_cast<unsigned long>(fenceTiming.timeOnDevice),
494 static_cast<unsigned long>(fenceTiming.timeInDriver));
Sadik Armagand7be72e2020-04-23 12:56:05 +0100495 }
496
497 sp<ArmnnFencedExecutionCallback> armnnFencedExecutionCallback =
Sadik Armagan188675f2021-02-12 17:16:42 +0000498 new ArmnnFencedExecutionCallback(V1_3::ErrorStatus::NONE, timing, fenceTiming);
499 cb(V1_3::ErrorStatus::NONE, hidl_handle(nullptr), armnnFencedExecutionCallback);
Kevin May42477c12020-03-26 13:34:14 +0000500 return Void();
501}
502
503template<typename HalVersion>
504Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForInputs(
505 armnn::InputTensors& inputs,
506 const V1_3::Request& request,
507 const std::vector<android::nn::RunTimePoolInfo>& memPools)
508{
509 inputs.reserve(request.inputs.size());
510 for (unsigned int i = 0; i < request.inputs.size(); i++)
511 {
512 const auto& inputArg = request.inputs[i];
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();
Mike Kellyde547162023-03-08 10:08:20 +0000517 auto result = ValidateRequestArgument<V1_3::ErrorStatus, V1_3::Request>(request,
518 inputTensorInfo,
519 inputArg,
520 "input");
521
522 if (result != V1_3::ErrorStatus::NONE)
523 {
524 return result;
525 }
526
Kevin May42477c12020-03-26 13:34:14 +0000527 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
528
529 if (inputTensor.GetMemoryArea() == nullptr)
530 {
531 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
532 return V1_3::ErrorStatus::GENERAL_FAILURE;
533 }
534
535 inputs.emplace_back(i, inputTensor);
536 }
537
538 return V1_3::ErrorStatus::NONE;
539}
540
541template<typename HalVersion>
542Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForOutputs(
543 armnn::OutputTensors& outputs,
Sadik Armagan188675f2021-02-12 17:16:42 +0000544 std::vector<V1_2::OutputShape> &outputShapes,
Kevin May42477c12020-03-26 13:34:14 +0000545 const V1_3::Request& request,
546 const std::vector<android::nn::RunTimePoolInfo>& memPools)
547{
548 outputs.reserve(request.outputs.size());
549 for (unsigned int i = 0; i < request.outputs.size(); i++)
550 {
551 const auto& outputArg = request.outputs[i];
Finn Williamsa4983ce2020-07-23 12:55:12 +0100552 armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
Mike Kellyde547162023-03-08 10:08:20 +0000553 auto result = ValidateRequestArgument<V1_3::ErrorStatus, V1_3::Request>(request,
554 outputTensorInfo,
555 outputArg,
556 "output");
557
558 if (result != V1_3::ErrorStatus::NONE)
559 {
560 return result;
561 }
562
Kevin May42477c12020-03-26 13:34:14 +0000563 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
Mike Kellyde547162023-03-08 10:08:20 +0000564
Kevin May42477c12020-03-26 13:34:14 +0000565 if (outputTensor.GetMemoryArea() == nullptr)
566 {
567 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
568 return V1_3::ErrorStatus::GENERAL_FAILURE;
569 }
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100570 const size_t outputSize = outputTensorInfo.GetNumBytes();
571
Finn Williamsa4983ce2020-07-23 12:55:12 +0100572 unsigned int count = 0;
573 std::for_each(outputArg.dimensions.begin(), outputArg.dimensions.end(), [&](auto dim)
574 {
575 if (dim != 0)
576 {
577 outputTensorInfo.GetShape()[count] = dim;
578 }
579 else
580 {
581 outputTensorInfo.GetShape()[count] = outputArg.dimensions.size();
582 }
583
584 count++;
585 });
586
Finn Williamsa4983ce2020-07-23 12:55:12 +0100587 outputs.emplace_back(i, outputTensor);
588 outputShapes[i] = ComputeShape(outputTensorInfo);
589
590 if (outputArg.location.length < outputSize)
591 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100592 ALOGW("ArmnnPreparedModel_1_3::Execute failed outputArg.location.length (%s) < outputSize (%s)",
593 std::to_string(outputArg.location.length).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100594 outputShapes[i].isSufficient = false;
595 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
596 }
597
Sadik Armagan188675f2021-02-12 17:16:42 +0000598 size_t bufferSize = 0;
599#if !defined(ARMNN_ANDROID_S)
600 bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
Sadik Armagan188675f2021-02-12 17:16:42 +0000601#else
Kevin Maydc873f62021-06-14 11:21:11 +0100602 bufferSize = memPools.at(outputArg.location.poolIndex).getSize();
Sadik Armagan188675f2021-02-12 17:16:42 +0000603#endif
Kevin May42477c12020-03-26 13:34:14 +0000604 if (bufferSize < outputSize)
605 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100606 ALOGW("ArmnnPreparedModel_1_3::Execute failed bufferSize (%s) < outputSize (%s)",
607 std::to_string(bufferSize).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100608 outputShapes[i].isSufficient = false;
Kevin May42477c12020-03-26 13:34:14 +0000609 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
610 }
Kevin May42477c12020-03-26 13:34:14 +0000611 }
612
613 return V1_3::ErrorStatus::NONE;
614}
615
616template<typename HalVersion>
Sadik Armagan188675f2021-02-12 17:16:42 +0000617std::tuple<V1_3::ErrorStatus, hidl_vec<V1_2::OutputShape>, V1_2::Timing, std::string>
Kevin May42477c12020-03-26 13:34:14 +0000618 ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForIO(armnn::InputTensors& inputs,
619 armnn::OutputTensors& outputs,
620 std::vector<android::nn::RunTimePoolInfo>& memPools,
621 const V1_3::Request& request)
622{
Sadik Armagan188675f2021-02-12 17:16:42 +0000623#if !defined(ARMNN_ANDROID_S)
Kevin May42477c12020-03-26 13:34:14 +0000624 if (!setRunTimePoolInfosFromMemoryPools(&memPools, request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000625#else
626 if (!setRunTimePoolInfosFromMemoryPools(&memPools, uncheckedConvert(request.pools)))
627#endif
Kevin May42477c12020-03-26 13:34:14 +0000628 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000629 return {V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000630 }
631
632 // add the inputs and outputs with their data
633 try
634 {
635 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_3::ErrorStatus::NONE)
636 {
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
Sadik Armagan188675f2021-02-12 17:16:42 +0000640 std::vector<V1_2::OutputShape> outputShapes(request.outputs.size());
Kevin May42477c12020-03-26 13:34:14 +0000641
642 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
643 if (errorStatus != V1_3::ErrorStatus::NONE)
644 {
645 return {errorStatus, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
646 }
647 }
648 catch (armnn::Exception& e)
649 {
650 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000651 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000652 }
653 catch (std::exception& e)
654 {
655 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000656 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000657 }
658
659 return {V1_3::ErrorStatus::NONE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
660}
661
662template<typename HalVersion>
663template<typename CallbackContext>
664Return<void> ArmnnPreparedModel_1_3<HalVersion>::ExecuteSynchronously(const V1_3::Request& request,
665 CallbackContext cbCtx)
666{
Sadik Armagan188675f2021-02-12 17:16:42 +0000667 if (cbCtx.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000668 {
669 cbCtx.ctx.driverStart = Now();
670 }
671
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100672 if (!m_PreparedFromCache && !android::nn::validateRequest(convertToV1_3(request), m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000673 {
674 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
675 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
676 {},
677 g_NoTiming,
678 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
679 return Void();
680 }
681
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100682 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000683 {
684 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
685 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
686 {},
687 g_NoTiming,
688 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
Sadik Armaganef8a3932020-04-09 17:21:50 +0100689 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000690 }
691
692
693 // map the memory pool into shared pointers
694 // use a shared memory pools vector on the heap, as it is passed to the request thread
695 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
696
697 // allocate the tensors on the heap, as they are passed to the request thread
698 auto inputs = std::make_shared<armnn::InputTensors>();
699 auto outputs = std::make_shared<armnn::OutputTensors>();
700
701 auto [status, outputShapes, timing, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
702 if (status != V1_3::ErrorStatus::NONE)
703 {
704 cbCtx.callback(status, outputShapes, timing, message);
Sadik Armaganef8a3932020-04-09 17:21:50 +0100705 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000706 }
707
708 ALOGV("ArmnnPreparedModel_1_3::ExecuteSynchronously() before Execution");
709
710 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
711 return Void();
712}
713
714template<typename HalVersion>
715Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000716 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000717 executeSynchronously_cb cb)
718{
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100719 if (!m_PreparedFromCache)
720 {
721 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
722 }
Kevin May42477c12020-03-26 13:34:14 +0000723 m_RequestCount++;
724
725 if (cb == nullptr)
726 {
727 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously invalid callback passed");
728 return Void();
729 }
730
731 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000732 std::vector<V1_2::OutputShape> outputShapes,
733 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000734 std::string)
735 {
736 cb(convertToV1_0(errorStatus), outputShapes, timing);
737 };
738
739 CallbackContext_1_3 cbCtx;
740 cbCtx.callback = cbWrapper;
741 cbCtx.ctx.measureTimings = measureTiming;
742
743 ExecuteSynchronously(convertToV1_3(request), cbCtx);
744 return Void();
745}
746
747template<typename HalVersion>
Kevin May352d8382020-03-31 15:03:42 +0100748Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously_1_3(
749 const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000750 V1_2::MeasureTiming measureTiming,
Kevin May352d8382020-03-31 15:03:42 +0100751 const V1_3::OptionalTimePoint& deadline,
752 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
753 executeSynchronously_1_3_cb cb)
Kevin May42477c12020-03-26 13:34:14 +0000754{
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100755 if (!m_PreparedFromCache)
756 {
757 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously_1_3(): %s", GetModelSummary(m_Model).c_str());
758 }
Kevin May42477c12020-03-26 13:34:14 +0000759 m_RequestCount++;
760
761 if (cb == nullptr)
762 {
763 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid callback passed");
764 return Void();
765 }
766
Sadik Armagan188675f2021-02-12 17:16:42 +0000767 if (deadline.getDiscriminator() != V1_3::OptionalTimePoint::hidl_discriminator::none)
Kevin May42477c12020-03-26 13:34:14 +0000768 {
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100769 ALOGW("ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter deadline is set but not supported.");
Kevin May42477c12020-03-26 13:34:14 +0000770 }
771
Sadik Armagan188675f2021-02-12 17:16:42 +0000772 if (loopTimeoutDuration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100773 {
774 ALOGW(
775 "ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter loopTimeoutDuration is set but not supported.");
Kevin May352d8382020-03-31 15:03:42 +0100776 }
777
Kevin May42477c12020-03-26 13:34:14 +0000778 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000779 std::vector<V1_2::OutputShape> outputShapes,
780 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000781 std::string)
782 {
783 cb(errorStatus, outputShapes, timing);
784 };
785
786 CallbackContext_1_3 cbCtx;
787 cbCtx.callback = cbWrapper;
788 cbCtx.ctx.measureTimings = measureTiming;
789
790 ExecuteSynchronously(request, cbCtx);
791 return Void();
792}
793
794template<typename HalVersion>
795Return<void> ArmnnPreparedModel_1_3<HalVersion>::configureExecutionBurst(
796 const sp<V1_2::IBurstCallback>& callback,
797 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
798 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
799 V1_3::IPreparedModel::configureExecutionBurst_cb cb)
800{
801 ALOGV("ArmnnPreparedModel_1_3::configureExecutionBurst");
802 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
803 requestChannel,
804 resultChannel,
805 this);
806
807 if (burst == nullptr)
808 {
809 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
810 }
811 else
812 {
813 cb(V1_0::ErrorStatus::NONE, burst);
814 }
815 return Void();
816}
817
818template<typename HalVersion>
819template<typename CallbackContext>
Sadik Armagand7be72e2020-04-23 12:56:05 +0100820Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::ExecuteGraph(
Kevin May42477c12020-03-26 13:34:14 +0000821 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
822 armnn::InputTensors& inputTensors,
823 armnn::OutputTensors& outputTensors,
824 CallbackContext cb)
825{
826 ALOGV("ArmnnPreparedModel_1_3::ExecuteGraph(...)");
Colm Donelan0fc16c62022-03-16 11:54:13 +0000827 // Capture the graph execution start time.
828 std::chrono::time_point<std::chrono::system_clock> graphExecutionStart = std::chrono::system_clock::now();
Kevin May42477c12020-03-26 13:34:14 +0000829
Kevin May42477c12020-03-26 13:34:14 +0000830 DumpTensorsIfRequired("Input", inputTensors);
831
Sadik Armagan188675f2021-02-12 17:16:42 +0000832 std::vector<V1_2::OutputShape> outputShapes(outputTensors.size());
Kevin May42477c12020-03-26 13:34:14 +0000833 for (unsigned int i = 0; i < outputTensors.size(); i++)
834 {
835 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
836 const armnn::Tensor outputTensor = outputTensorPair.second;
837 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
838
839 outputShapes[i] = ComputeShape(outputTensorInfo);
840 }
841
842 // run it
843 try
844 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000845 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000846 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100847 cb.ctx.deviceStart = Now();
Kevin May42477c12020-03-26 13:34:14 +0000848 }
Finn Williamsd8fb5402021-05-19 20:52:00 +0100849 armnn::Status status;
850 if (m_AsyncModelExecutionEnabled)
851 {
852 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled true");
853 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
854 }
855 else
856 {
857 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled false");
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000858 // Create a vector of Input and Output Ids which can be imported. An empty vector means all will be copied.
859 std::vector<armnn::ImportedInputId> importedInputIds;
860 if (m_EnableImport)
861 {
862 importedInputIds = m_Runtime->ImportInputs(m_NetworkId, inputTensors, armnn::MemorySource::Malloc);
863 }
864 std::vector<armnn::ImportedOutputId> importedOutputIds;
865 if (m_EnableExport)
866 {
867 importedOutputIds = m_Runtime->ImportOutputs(m_NetworkId, outputTensors, armnn::MemorySource::Malloc);
868 }
869 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors,
870 importedInputIds, importedOutputIds);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100871 }
Kevin May42477c12020-03-26 13:34:14 +0000872
Sadik Armagan188675f2021-02-12 17:16:42 +0000873 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000874 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100875 cb.ctx.deviceEnd = Now();
Kevin May42477c12020-03-26 13:34:14 +0000876 }
877 if (status != armnn::Status::Success)
878 {
Finn Williamsd8fb5402021-05-19 20:52:00 +0100879 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph EnqueueWorkload failed");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100880 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
881 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000882 }
883 }
884 catch (armnn::Exception& e)
885 {
886 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
887 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100888 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000889 }
890 catch (std::exception& e)
891 {
892 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
893 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100894 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000895 }
896
897 CommitPools(*pMemPools);
898
899 DumpTensorsIfRequired("Output", outputTensors);
900
Sadik Armagan188675f2021-02-12 17:16:42 +0000901 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000902 {
Kevin May949a69e2020-04-24 10:21:40 +0100903 cb.ctx.driverEnd = Now();
Sadik Armagan188675f2021-02-12 17:16:42 +0000904 V1_2::Timing timing;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100905 timing.timeOnDevice = MicrosecondsDuration(cb.ctx.deviceEnd, cb.ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100906 timing.timeInDriver = MicrosecondsDuration(cb.ctx.driverEnd, cb.ctx.driverStart);
Zingo Andersen7c561492022-01-25 11:09:41 +0100907 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu",
908 static_cast<unsigned long>(timing.timeOnDevice), static_cast<unsigned long>(timing.timeInDriver));
Kevin May42477c12020-03-26 13:34:14 +0000909 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100910 } else
911 {
Kevin May42477c12020-03-26 13:34:14 +0000912 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
913 }
Colm Donelan0fc16c62022-03-16 11:54:13 +0000914 // Log the total time in this call. This is a good number to compare to that printed out by
915 // RuntimeImpl::EnqueueWorkload. The difference should be the execution overhead of the driver.
916 ALOGI("ArmnnPreparedModel_1_3::ExecuteGraph Execution time = %lld µs",
917 std::chrono::duration_cast<std::chrono::microseconds>
918 (std::chrono::system_clock::now() - graphExecutionStart).count());
Sadik Armagand7be72e2020-04-23 12:56:05 +0100919 return V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000920}
921
Finn Williamsd8fb5402021-05-19 20:52:00 +0100922/// Schedule the graph prepared from the request for execution
923template<typename HalVersion>
924template<typename CallbackContext>
925void ArmnnPreparedModel_1_3<HalVersion>::ScheduleGraphForExecution(
926 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
927 std::shared_ptr<armnn::InputTensors>& inputTensors,
928 std::shared_ptr<armnn::OutputTensors>& outputTensors,
929 CallbackContext callbackContext,
930 armnn::QosExecPriority priority)
931{
932 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution(...)");
933
934 DumpTensorsIfRequired("Input", *inputTensors);
935
936 unsigned int outputTensorSize = outputTensors.get()->size();
937 std::vector<V1_2::OutputShape> outputShapes(outputTensorSize);
938 for (unsigned int i = 0; i < outputTensorSize; i++)
939 {
940 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors.get()->at(i);
941 const armnn::Tensor outputTensor = outputTensorPair.second;
942 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
943
944 outputShapes[i] = ComputeShape(outputTensorInfo);
945 }
946
947 auto tpCb = std::make_shared<
948 ArmnnThreadPoolCallback_1_3<CallbackContext_1_3>>(this,
949 pMemPools,
950 outputShapes,
951 inputTensors,
952 outputTensors,
953 callbackContext);
954
Finn Williamsca3a3e02021-06-11 15:04:02 +0100955 m_Threadpool->Schedule(m_NetworkId,
956 *tpCb->m_InputTensors,
957 *tpCb->m_OutputTensors,
958 priority,
959 tpCb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100960 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution end");
961}
962
Kevin May42477c12020-03-26 13:34:14 +0000963template<typename HalVersion>
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100964bool ArmnnPreparedModel_1_3<HalVersion>::ExecuteWithDummyInputs(unsigned int numInputs, unsigned int numOutputs)
Kevin May42477c12020-03-26 13:34:14 +0000965{
966 std::vector<std::vector<char>> storage;
967 armnn::InputTensors inputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100968 for (unsigned int i = 0; i < numInputs; i++)
Kevin May42477c12020-03-26 13:34:14 +0000969 {
Cathal Corbette27d4e82021-10-28 12:28:35 +0100970 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
971 // pInputTensors (of type InputTensors) is composed of a vector of ConstTensors.
972 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
973 inputTensorInfo.SetConstant();
974
Kevin May42477c12020-03-26 13:34:14 +0000975 storage.emplace_back(inputTensorInfo.GetNumBytes());
976 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
977
978 inputTensors.emplace_back(i, inputTensor);
979 }
980
981 armnn::OutputTensors outputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100982 for (unsigned int i = 0; i < numOutputs; i++)
Kevin May42477c12020-03-26 13:34:14 +0000983 {
984 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
985 storage.emplace_back(outputTensorInfo.GetNumBytes());
986 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
987
988 outputTensors.emplace_back(i, outputTensor);
989 }
990
Sadik Armagan188675f2021-02-12 17:16:42 +0000991 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Kevin May42477c12020-03-26 13:34:14 +0000992 CallbackContext_1_3 callbackContext;
993 callbackContext.callback = nullCallback;
Sadik Armagan188675f2021-02-12 17:16:42 +0000994 callbackContext.ctx.measureTimings = V1_2::MeasureTiming::NO;
Kevin May42477c12020-03-26 13:34:14 +0000995 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
Sadik Armagand7be72e2020-04-23 12:56:05 +0100996
997 auto errorStatus = ExecuteGraph(memPools,
998 inputTensors,
999 outputTensors,
1000 callbackContext);
1001 return errorStatus == V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +00001002}
1003
1004template<typename HalVersion>
1005Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::Execute(const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +00001006 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +00001007 CallbackAsync_1_3 callback)
1008{
1009 ExecutionContext_1_3 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +00001010 if (measureTiming == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +00001011 {
1012 ctx.measureTimings = measureTiming;
1013 ctx.driverStart = Now();
1014 }
1015
Sadik Armagan0a2dfab2021-10-06 16:41:44 +01001016 if (!m_PreparedFromCache)
1017 {
1018 ALOGV("ArmnnPreparedModel_1_3::execute(): %s", GetModelSummary(m_Model).c_str());
1019 }
Kevin May42477c12020-03-26 13:34:14 +00001020 m_RequestCount++;
1021
Sadik Armagan0a2dfab2021-10-06 16:41:44 +01001022 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Kevin May42477c12020-03-26 13:34:14 +00001023 {
1024 callback(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute");
1025 return V1_3::ErrorStatus::INVALID_ARGUMENT;
1026 }
1027
1028 if (!m_RequestInputsAndOutputsDumpDir.empty())
1029 {
1030 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
1031 }
1032
1033 // map the memory pool into shared pointers
1034 // use a shared memory pools vector on the heap, as it is passed to the request thread
1035 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
1036
1037 // allocate the tensors on the heap, as they are passed to the request thread
1038 auto inputTensors = std::make_shared<armnn::InputTensors>();
1039 auto outputTensors = std::make_shared<armnn::OutputTensors>();
1040
1041 auto [status, outShapes, timing, message] = PrepareMemoryForIO(*inputTensors, *outputTensors,
1042 *memPools, request);
1043 if (status != V1_3::ErrorStatus::NONE)
1044 {
1045 callback(status, outShapes, timing, message);
1046 }
1047
1048 switch(status)
1049 {
1050 case V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
1051 return V1_3::ErrorStatus::NONE;
1052 case V1_3::ErrorStatus::GENERAL_FAILURE:
1053 return V1_3::ErrorStatus::GENERAL_FAILURE;
Sadik Armagana07d2752021-05-12 20:33:58 +01001054 case V1_3::ErrorStatus::INVALID_ARGUMENT:
1055 return V1_3::ErrorStatus::INVALID_ARGUMENT;
Kevin May42477c12020-03-26 13:34:14 +00001056 default:
1057 {}
1058 }
Kevin May42477c12020-03-26 13:34:14 +00001059 CallbackContext_1_3 cb;
1060 cb.callback = callback;
1061 cb.ctx = ctx;
Finn Williamsd8fb5402021-05-19 20:52:00 +01001062
1063
1064 enum class QosExecPriority
1065 {
1066 Low = 0,
1067 Medium = 1,
1068 High = 2
1069 };
1070
1071
1072 if (m_AsyncModelExecutionEnabled)
1073 {
1074 armnn::QosExecPriority priority;
1075
1076 switch (GetModelPriority()) {
1077 case V1_3::Priority::LOW:
1078 priority = armnn::QosExecPriority::Low;
1079 break;
1080 case V1_3::Priority::MEDIUM:
1081 priority = armnn::QosExecPriority::Medium;
1082 break;
1083 case V1_3::Priority::HIGH:
1084 priority = armnn::QosExecPriority::High;
1085 break;
1086 default:
1087 priority = armnn::QosExecPriority::Medium;
1088
1089 }
1090
1091 ALOGV("ArmnnPreparedModel_1_3::execute(...) before ScheduleGraphForExecution");
1092 ScheduleGraphForExecution(memPools, inputTensors, outputTensors, cb, priority);
1093 ALOGV("ArmnnPreparedModel_1_3::execute(...) after ScheduleGraphForExecution");
1094 return V1_3::ErrorStatus::NONE;
1095 }
1096
1097 ALOGV("ArmnnPreparedModel_1_3::execute(...) before PostMsg");
1098 // post the request for asynchronous execution
Kevin May42477c12020-03-26 13:34:14 +00001099 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
1100 ALOGV("ArmnnPreparedModel_1_3::execute(...) after PostMsg");
1101 return V1_3::ErrorStatus::NONE;
1102}
1103
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +01001104template<typename HalVersion>
1105V1_3::Priority ArmnnPreparedModel_1_3<HalVersion>::GetModelPriority()
1106{
1107 return m_ModelPriority;
1108}
1109
Finn Williamsd8fb5402021-05-19 20:52:00 +01001110template<typename HalVersion>
1111template <typename CallbackContext>
1112void ArmnnPreparedModel_1_3<HalVersion>::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify(
1113 armnn::Status status, armnn::InferenceTimingPair timeTaken)
1114{
1115 ALOGV("ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify");
1116 CommitPools(*m_MemPools);
1117
1118 m_Model->DumpTensorsIfRequired("Output", *m_OutputTensors);
1119
1120 if (status != armnn::Status::Success)
1121 {
1122 ALOGW("ArmnnThreadPoolCallback_1_3::Notify EnqueueWorkload failed");
1123 m_CallbackContext.callback(V1_3::ErrorStatus::GENERAL_FAILURE,
1124 {},
1125 g_NoTiming,
1126 "ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3");
1127 return;
1128 }
1129
1130 if (m_CallbackContext.ctx.measureTimings == V1_2::MeasureTiming::YES)
1131 {
1132 m_CallbackContext.ctx.deviceStart = timeTaken.first;
1133 m_CallbackContext.ctx.deviceEnd = timeTaken.second;
1134 m_CallbackContext.ctx.driverEnd = std::chrono::steady_clock::now();
1135 V1_2::Timing timing;
1136 timing.timeOnDevice = MicrosecondsDuration(m_CallbackContext.ctx.deviceEnd, m_CallbackContext.ctx.deviceStart);
1137 timing.timeInDriver = MicrosecondsDuration(m_CallbackContext.ctx.driverEnd, m_CallbackContext.ctx.driverStart);
Zingo Andersen7c561492022-01-25 11:09:41 +01001138 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu",
1139 static_cast<unsigned long>(timing.timeOnDevice), static_cast<unsigned long>(timing.timeInDriver));
Finn Williamsd8fb5402021-05-19 20:52:00 +01001140 m_CallbackContext.callback(
1141 V1_3::ErrorStatus::NONE, m_OutputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
1142 } else
1143 {
1144 m_CallbackContext.callback(
1145 V1_3::ErrorStatus::NONE, m_OutputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
1146 }
1147 return;
1148}
1149
Kevin May42477c12020-03-26 13:34:14 +00001150#ifdef ARMNN_ANDROID_NN_V1_3
1151template class ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>;
Sadik Armagand7be72e2020-04-23 12:56:05 +01001152template Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ExecuteGraph<CallbackContext_1_3>(
Kevin May42477c12020-03-26 13:34:14 +00001153 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1154 armnn::InputTensors& pInputTensors,
1155 armnn::OutputTensors& pOutputTensors,
1156 CallbackContext_1_3 cb);
Finn Williamsd8fb5402021-05-19 20:52:00 +01001157
1158template void ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ScheduleGraphForExecution<CallbackContext_1_3>(
1159 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1160 std::shared_ptr<armnn::InputTensors>& inputTensors,
1161 std::shared_ptr<armnn::OutputTensors>& outputTensors,
1162 CallbackContext_1_3 callbackContext,
1163 armnn::QosExecPriority priority);
Kevin May42477c12020-03-26 13:34:14 +00001164#endif
1165
1166} // namespace armnn_driver