blob: 1827d90005756e7820b86308309a57f4287798a5 [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 {
Mike Kellya92b3f32023-07-31 12:48:53 +0100437 ALOGE("ArmnnPreparedModel_1_3::executeFenced null native handle.");
438 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
439 return Void();
440 }
441
442 if (fenceNativeHandle->numFds != 1)
443 {
444 ALOGE("ArmnnPreparedModel_1_3::executeFenced invalid fenceHandle numFds.");
445 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
446 return Void();
447 }
448
449 if (fenceNativeHandle->numInts != 0)
450 {
451 ALOGE("ArmnnPreparedModel_1_3::executeFenced invalid fenceHandle numInts.");
Sadik Armagan188675f2021-02-12 17:16:42 +0000452 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100453 return Void();
454 }
455
456 if (sync_wait(fenceNativeHandle->data[0], -1) < 0)
457 {
458 ALOGE("ArmnnPreparedModel_1_3::executeFenced sync fence failed.");
Sadik Armagan188675f2021-02-12 17:16:42 +0000459 cb(V1_3::ErrorStatus::GENERAL_FAILURE, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100460 return Void();
461 }
462 }
463
464 TimePoint fenceExecutionStart;
Sadik Armagan188675f2021-02-12 17:16:42 +0000465 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100466 {
467 fenceExecutionStart = Now();
468 }
469
470 // map the memory pool into shared pointers
471 // use a shared memory pools vector on the heap, as it is passed to the request thread
472 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
473
474 // allocate the tensors on the heap, as they are passed to the request thread
475 auto inputs = std::make_shared<armnn::InputTensors>();
476 auto outputs = std::make_shared<armnn::OutputTensors>();
477
478 auto [status, outShapes, timings, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
479 if (status != V1_3::ErrorStatus::NONE)
480 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000481 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100482 return Void();
483 }
484
485 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...) before ExecuteGraph");
486
487 // call it with nullCallback for now as we will report the error status from here..
Sadik Armagan188675f2021-02-12 17:16:42 +0000488 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Sadik Armagand7be72e2020-04-23 12:56:05 +0100489 CallbackContext_1_3 cbCtx;
490 cbCtx.callback = nullCallback;
491 cbCtx.ctx = ctx;
492
493 auto errorStatus = ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
494 if (errorStatus != V1_3::ErrorStatus::NONE)
495 {
496 cb(errorStatus, hidl_handle(nullptr), nullptr);
497 return Void();
498 }
499 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...) after ExecuteGraph");
500
Sadik Armagan188675f2021-02-12 17:16:42 +0000501 V1_2::Timing timing = g_NoTiming;
502 V1_2::Timing fenceTiming = g_NoTiming;
503 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100504 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100505 fenceTiming.timeOnDevice = MicrosecondsDuration(ctx.deviceEnd, ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100506 fenceTiming.timeInDriver = MicrosecondsDuration(ctx.driverEnd, fenceExecutionStart);
507 ALOGV("ArmnnPreparedModel_1_3::fenceFinishExecutionTiming - Device = %lu Driver = %lu",
Zingo Andersen7c561492022-01-25 11:09:41 +0100508 static_cast<unsigned long>(fenceTiming.timeOnDevice),
509 static_cast<unsigned long>(fenceTiming.timeInDriver));
Sadik Armagand7be72e2020-04-23 12:56:05 +0100510 }
511
512 sp<ArmnnFencedExecutionCallback> armnnFencedExecutionCallback =
Sadik Armagan188675f2021-02-12 17:16:42 +0000513 new ArmnnFencedExecutionCallback(V1_3::ErrorStatus::NONE, timing, fenceTiming);
514 cb(V1_3::ErrorStatus::NONE, hidl_handle(nullptr), armnnFencedExecutionCallback);
Kevin May42477c12020-03-26 13:34:14 +0000515 return Void();
516}
517
518template<typename HalVersion>
519Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForInputs(
520 armnn::InputTensors& inputs,
521 const V1_3::Request& request,
522 const std::vector<android::nn::RunTimePoolInfo>& memPools)
523{
524 inputs.reserve(request.inputs.size());
525 for (unsigned int i = 0; i < request.inputs.size(); i++)
526 {
527 const auto& inputArg = request.inputs[i];
Cathal Corbette27d4e82021-10-28 12:28:35 +0100528 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
529 // inputs (of type InputTensors) is composed of a vector of ConstTensors.
530 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
531 inputTensorInfo.SetConstant();
Mike Kellyde547162023-03-08 10:08:20 +0000532 auto result = ValidateRequestArgument<V1_3::ErrorStatus, V1_3::Request>(request,
533 inputTensorInfo,
534 inputArg,
535 "input");
536
537 if (result != V1_3::ErrorStatus::NONE)
538 {
539 return result;
540 }
541
Kevin May42477c12020-03-26 13:34:14 +0000542 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
543
544 if (inputTensor.GetMemoryArea() == nullptr)
545 {
546 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
547 return V1_3::ErrorStatus::GENERAL_FAILURE;
548 }
549
550 inputs.emplace_back(i, inputTensor);
551 }
552
553 return V1_3::ErrorStatus::NONE;
554}
555
556template<typename HalVersion>
557Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForOutputs(
558 armnn::OutputTensors& outputs,
Sadik Armagan188675f2021-02-12 17:16:42 +0000559 std::vector<V1_2::OutputShape> &outputShapes,
Kevin May42477c12020-03-26 13:34:14 +0000560 const V1_3::Request& request,
561 const std::vector<android::nn::RunTimePoolInfo>& memPools)
562{
563 outputs.reserve(request.outputs.size());
564 for (unsigned int i = 0; i < request.outputs.size(); i++)
565 {
566 const auto& outputArg = request.outputs[i];
Finn Williamsa4983ce2020-07-23 12:55:12 +0100567 armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
Mike Kellyde547162023-03-08 10:08:20 +0000568 auto result = ValidateRequestArgument<V1_3::ErrorStatus, V1_3::Request>(request,
569 outputTensorInfo,
570 outputArg,
571 "output");
572
573 if (result != V1_3::ErrorStatus::NONE)
574 {
575 return result;
576 }
577
Kevin May42477c12020-03-26 13:34:14 +0000578 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
Mike Kellyde547162023-03-08 10:08:20 +0000579
Kevin May42477c12020-03-26 13:34:14 +0000580 if (outputTensor.GetMemoryArea() == nullptr)
581 {
582 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
583 return V1_3::ErrorStatus::GENERAL_FAILURE;
584 }
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100585 const size_t outputSize = outputTensorInfo.GetNumBytes();
586
Finn Williamsa4983ce2020-07-23 12:55:12 +0100587 unsigned int count = 0;
588 std::for_each(outputArg.dimensions.begin(), outputArg.dimensions.end(), [&](auto dim)
589 {
590 if (dim != 0)
591 {
592 outputTensorInfo.GetShape()[count] = dim;
593 }
594 else
595 {
596 outputTensorInfo.GetShape()[count] = outputArg.dimensions.size();
597 }
598
599 count++;
600 });
601
Finn Williamsa4983ce2020-07-23 12:55:12 +0100602 outputs.emplace_back(i, outputTensor);
603 outputShapes[i] = ComputeShape(outputTensorInfo);
604
605 if (outputArg.location.length < outputSize)
606 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100607 ALOGW("ArmnnPreparedModel_1_3::Execute failed outputArg.location.length (%s) < outputSize (%s)",
608 std::to_string(outputArg.location.length).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100609 outputShapes[i].isSufficient = false;
610 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
611 }
612
Sadik Armagan188675f2021-02-12 17:16:42 +0000613 size_t bufferSize = 0;
614#if !defined(ARMNN_ANDROID_S)
615 bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
Sadik Armagan188675f2021-02-12 17:16:42 +0000616#else
Kevin Maydc873f62021-06-14 11:21:11 +0100617 bufferSize = memPools.at(outputArg.location.poolIndex).getSize();
Sadik Armagan188675f2021-02-12 17:16:42 +0000618#endif
Kevin May42477c12020-03-26 13:34:14 +0000619 if (bufferSize < outputSize)
620 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100621 ALOGW("ArmnnPreparedModel_1_3::Execute failed bufferSize (%s) < outputSize (%s)",
622 std::to_string(bufferSize).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100623 outputShapes[i].isSufficient = false;
Kevin May42477c12020-03-26 13:34:14 +0000624 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
625 }
Kevin May42477c12020-03-26 13:34:14 +0000626 }
627
628 return V1_3::ErrorStatus::NONE;
629}
630
631template<typename HalVersion>
Sadik Armagan188675f2021-02-12 17:16:42 +0000632std::tuple<V1_3::ErrorStatus, hidl_vec<V1_2::OutputShape>, V1_2::Timing, std::string>
Kevin May42477c12020-03-26 13:34:14 +0000633 ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForIO(armnn::InputTensors& inputs,
634 armnn::OutputTensors& outputs,
635 std::vector<android::nn::RunTimePoolInfo>& memPools,
636 const V1_3::Request& request)
637{
Sadik Armagan188675f2021-02-12 17:16:42 +0000638#if !defined(ARMNN_ANDROID_S)
Kevin May42477c12020-03-26 13:34:14 +0000639 if (!setRunTimePoolInfosFromMemoryPools(&memPools, request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000640#else
641 if (!setRunTimePoolInfosFromMemoryPools(&memPools, uncheckedConvert(request.pools)))
642#endif
Kevin May42477c12020-03-26 13:34:14 +0000643 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000644 return {V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000645 }
646
647 // add the inputs and outputs with their data
648 try
649 {
650 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_3::ErrorStatus::NONE)
651 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000652 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000653 }
654
Sadik Armagan188675f2021-02-12 17:16:42 +0000655 std::vector<V1_2::OutputShape> outputShapes(request.outputs.size());
Kevin May42477c12020-03-26 13:34:14 +0000656
657 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
658 if (errorStatus != V1_3::ErrorStatus::NONE)
659 {
660 return {errorStatus, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
661 }
662 }
663 catch (armnn::Exception& e)
664 {
665 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000666 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000667 }
668 catch (std::exception& e)
669 {
670 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000671 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000672 }
673
674 return {V1_3::ErrorStatus::NONE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
675}
676
677template<typename HalVersion>
678template<typename CallbackContext>
679Return<void> ArmnnPreparedModel_1_3<HalVersion>::ExecuteSynchronously(const V1_3::Request& request,
680 CallbackContext cbCtx)
681{
Sadik Armagan188675f2021-02-12 17:16:42 +0000682 if (cbCtx.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000683 {
684 cbCtx.ctx.driverStart = Now();
685 }
686
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100687 if (!m_PreparedFromCache && !android::nn::validateRequest(convertToV1_3(request), m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000688 {
689 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
690 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
691 {},
692 g_NoTiming,
693 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
694 return Void();
695 }
696
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100697 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000698 {
699 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
700 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
701 {},
702 g_NoTiming,
703 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
Sadik Armaganef8a3932020-04-09 17:21:50 +0100704 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000705 }
706
707
708 // map the memory pool into shared pointers
709 // use a shared memory pools vector on the heap, as it is passed to the request thread
710 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
711
712 // allocate the tensors on the heap, as they are passed to the request thread
713 auto inputs = std::make_shared<armnn::InputTensors>();
714 auto outputs = std::make_shared<armnn::OutputTensors>();
715
716 auto [status, outputShapes, timing, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
717 if (status != V1_3::ErrorStatus::NONE)
718 {
719 cbCtx.callback(status, outputShapes, timing, message);
Sadik Armaganef8a3932020-04-09 17:21:50 +0100720 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000721 }
722
723 ALOGV("ArmnnPreparedModel_1_3::ExecuteSynchronously() before Execution");
724
725 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
726 return Void();
727}
728
729template<typename HalVersion>
730Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000731 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000732 executeSynchronously_cb cb)
733{
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100734 if (!m_PreparedFromCache)
735 {
736 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
737 }
Kevin May42477c12020-03-26 13:34:14 +0000738 m_RequestCount++;
739
740 if (cb == nullptr)
741 {
742 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously invalid callback passed");
743 return Void();
744 }
745
746 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000747 std::vector<V1_2::OutputShape> outputShapes,
748 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000749 std::string)
750 {
751 cb(convertToV1_0(errorStatus), outputShapes, timing);
752 };
753
754 CallbackContext_1_3 cbCtx;
755 cbCtx.callback = cbWrapper;
756 cbCtx.ctx.measureTimings = measureTiming;
757
758 ExecuteSynchronously(convertToV1_3(request), cbCtx);
759 return Void();
760}
761
762template<typename HalVersion>
Kevin May352d8382020-03-31 15:03:42 +0100763Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously_1_3(
764 const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000765 V1_2::MeasureTiming measureTiming,
Kevin May352d8382020-03-31 15:03:42 +0100766 const V1_3::OptionalTimePoint& deadline,
767 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
768 executeSynchronously_1_3_cb cb)
Kevin May42477c12020-03-26 13:34:14 +0000769{
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100770 if (!m_PreparedFromCache)
771 {
772 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously_1_3(): %s", GetModelSummary(m_Model).c_str());
773 }
Kevin May42477c12020-03-26 13:34:14 +0000774 m_RequestCount++;
775
776 if (cb == nullptr)
777 {
778 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid callback passed");
779 return Void();
780 }
781
Sadik Armagan188675f2021-02-12 17:16:42 +0000782 if (deadline.getDiscriminator() != V1_3::OptionalTimePoint::hidl_discriminator::none)
Kevin May42477c12020-03-26 13:34:14 +0000783 {
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100784 ALOGW("ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter deadline is set but not supported.");
Kevin May42477c12020-03-26 13:34:14 +0000785 }
786
Sadik Armagan188675f2021-02-12 17:16:42 +0000787 if (loopTimeoutDuration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100788 {
789 ALOGW(
790 "ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter loopTimeoutDuration is set but not supported.");
Kevin May352d8382020-03-31 15:03:42 +0100791 }
792
Kevin May42477c12020-03-26 13:34:14 +0000793 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000794 std::vector<V1_2::OutputShape> outputShapes,
795 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000796 std::string)
797 {
798 cb(errorStatus, outputShapes, timing);
799 };
800
801 CallbackContext_1_3 cbCtx;
802 cbCtx.callback = cbWrapper;
803 cbCtx.ctx.measureTimings = measureTiming;
804
805 ExecuteSynchronously(request, cbCtx);
806 return Void();
807}
808
809template<typename HalVersion>
810Return<void> ArmnnPreparedModel_1_3<HalVersion>::configureExecutionBurst(
811 const sp<V1_2::IBurstCallback>& callback,
812 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
813 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
814 V1_3::IPreparedModel::configureExecutionBurst_cb cb)
815{
816 ALOGV("ArmnnPreparedModel_1_3::configureExecutionBurst");
817 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
818 requestChannel,
819 resultChannel,
820 this);
821
822 if (burst == nullptr)
823 {
824 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
825 }
826 else
827 {
828 cb(V1_0::ErrorStatus::NONE, burst);
829 }
830 return Void();
831}
832
833template<typename HalVersion>
834template<typename CallbackContext>
Sadik Armagand7be72e2020-04-23 12:56:05 +0100835Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::ExecuteGraph(
Kevin May42477c12020-03-26 13:34:14 +0000836 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
837 armnn::InputTensors& inputTensors,
838 armnn::OutputTensors& outputTensors,
839 CallbackContext cb)
840{
841 ALOGV("ArmnnPreparedModel_1_3::ExecuteGraph(...)");
Colm Donelan0fc16c62022-03-16 11:54:13 +0000842 // Capture the graph execution start time.
843 std::chrono::time_point<std::chrono::system_clock> graphExecutionStart = std::chrono::system_clock::now();
Kevin May42477c12020-03-26 13:34:14 +0000844
Kevin May42477c12020-03-26 13:34:14 +0000845 DumpTensorsIfRequired("Input", inputTensors);
846
Sadik Armagan188675f2021-02-12 17:16:42 +0000847 std::vector<V1_2::OutputShape> outputShapes(outputTensors.size());
Kevin May42477c12020-03-26 13:34:14 +0000848 for (unsigned int i = 0; i < outputTensors.size(); i++)
849 {
850 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
851 const armnn::Tensor outputTensor = outputTensorPair.second;
852 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
853
854 outputShapes[i] = ComputeShape(outputTensorInfo);
855 }
856
857 // run it
858 try
859 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000860 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000861 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100862 cb.ctx.deviceStart = Now();
Kevin May42477c12020-03-26 13:34:14 +0000863 }
Finn Williamsd8fb5402021-05-19 20:52:00 +0100864 armnn::Status status;
865 if (m_AsyncModelExecutionEnabled)
866 {
867 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled true");
868 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
869 }
870 else
871 {
872 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled false");
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000873 // Create a vector of Input and Output Ids which can be imported. An empty vector means all will be copied.
874 std::vector<armnn::ImportedInputId> importedInputIds;
875 if (m_EnableImport)
876 {
877 importedInputIds = m_Runtime->ImportInputs(m_NetworkId, inputTensors, armnn::MemorySource::Malloc);
878 }
879 std::vector<armnn::ImportedOutputId> importedOutputIds;
880 if (m_EnableExport)
881 {
882 importedOutputIds = m_Runtime->ImportOutputs(m_NetworkId, outputTensors, armnn::MemorySource::Malloc);
883 }
884 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors,
885 importedInputIds, importedOutputIds);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100886 }
Kevin May42477c12020-03-26 13:34:14 +0000887
Sadik Armagan188675f2021-02-12 17:16:42 +0000888 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000889 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100890 cb.ctx.deviceEnd = Now();
Kevin May42477c12020-03-26 13:34:14 +0000891 }
892 if (status != armnn::Status::Success)
893 {
Finn Williamsd8fb5402021-05-19 20:52:00 +0100894 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph EnqueueWorkload failed");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100895 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
896 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000897 }
898 }
899 catch (armnn::Exception& e)
900 {
901 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
902 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100903 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000904 }
905 catch (std::exception& e)
906 {
907 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
908 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100909 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000910 }
911
912 CommitPools(*pMemPools);
913
914 DumpTensorsIfRequired("Output", outputTensors);
915
Sadik Armagan188675f2021-02-12 17:16:42 +0000916 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000917 {
Kevin May949a69e2020-04-24 10:21:40 +0100918 cb.ctx.driverEnd = Now();
Sadik Armagan188675f2021-02-12 17:16:42 +0000919 V1_2::Timing timing;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100920 timing.timeOnDevice = MicrosecondsDuration(cb.ctx.deviceEnd, cb.ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100921 timing.timeInDriver = MicrosecondsDuration(cb.ctx.driverEnd, cb.ctx.driverStart);
Zingo Andersen7c561492022-01-25 11:09:41 +0100922 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu",
923 static_cast<unsigned long>(timing.timeOnDevice), static_cast<unsigned long>(timing.timeInDriver));
Kevin May42477c12020-03-26 13:34:14 +0000924 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100925 } else
926 {
Kevin May42477c12020-03-26 13:34:14 +0000927 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
928 }
Colm Donelan0fc16c62022-03-16 11:54:13 +0000929 // Log the total time in this call. This is a good number to compare to that printed out by
930 // RuntimeImpl::EnqueueWorkload. The difference should be the execution overhead of the driver.
931 ALOGI("ArmnnPreparedModel_1_3::ExecuteGraph Execution time = %lld µs",
932 std::chrono::duration_cast<std::chrono::microseconds>
933 (std::chrono::system_clock::now() - graphExecutionStart).count());
Sadik Armagand7be72e2020-04-23 12:56:05 +0100934 return V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000935}
936
Finn Williamsd8fb5402021-05-19 20:52:00 +0100937/// Schedule the graph prepared from the request for execution
938template<typename HalVersion>
939template<typename CallbackContext>
940void ArmnnPreparedModel_1_3<HalVersion>::ScheduleGraphForExecution(
941 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
942 std::shared_ptr<armnn::InputTensors>& inputTensors,
943 std::shared_ptr<armnn::OutputTensors>& outputTensors,
944 CallbackContext callbackContext,
945 armnn::QosExecPriority priority)
946{
947 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution(...)");
948
949 DumpTensorsIfRequired("Input", *inputTensors);
950
951 unsigned int outputTensorSize = outputTensors.get()->size();
952 std::vector<V1_2::OutputShape> outputShapes(outputTensorSize);
953 for (unsigned int i = 0; i < outputTensorSize; i++)
954 {
955 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors.get()->at(i);
956 const armnn::Tensor outputTensor = outputTensorPair.second;
957 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
958
959 outputShapes[i] = ComputeShape(outputTensorInfo);
960 }
961
962 auto tpCb = std::make_shared<
963 ArmnnThreadPoolCallback_1_3<CallbackContext_1_3>>(this,
964 pMemPools,
965 outputShapes,
966 inputTensors,
967 outputTensors,
968 callbackContext);
969
Finn Williamsca3a3e02021-06-11 15:04:02 +0100970 m_Threadpool->Schedule(m_NetworkId,
971 *tpCb->m_InputTensors,
972 *tpCb->m_OutputTensors,
973 priority,
974 tpCb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100975 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution end");
976}
977
Kevin May42477c12020-03-26 13:34:14 +0000978template<typename HalVersion>
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100979bool ArmnnPreparedModel_1_3<HalVersion>::ExecuteWithDummyInputs(unsigned int numInputs, unsigned int numOutputs)
Kevin May42477c12020-03-26 13:34:14 +0000980{
981 std::vector<std::vector<char>> storage;
982 armnn::InputTensors inputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100983 for (unsigned int i = 0; i < numInputs; i++)
Kevin May42477c12020-03-26 13:34:14 +0000984 {
Cathal Corbette27d4e82021-10-28 12:28:35 +0100985 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
986 // pInputTensors (of type InputTensors) is composed of a vector of ConstTensors.
987 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
988 inputTensorInfo.SetConstant();
989
Kevin May42477c12020-03-26 13:34:14 +0000990 storage.emplace_back(inputTensorInfo.GetNumBytes());
991 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
992
993 inputTensors.emplace_back(i, inputTensor);
994 }
995
996 armnn::OutputTensors outputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100997 for (unsigned int i = 0; i < numOutputs; i++)
Kevin May42477c12020-03-26 13:34:14 +0000998 {
999 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
1000 storage.emplace_back(outputTensorInfo.GetNumBytes());
1001 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
1002
1003 outputTensors.emplace_back(i, outputTensor);
1004 }
1005
Sadik Armagan188675f2021-02-12 17:16:42 +00001006 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Kevin May42477c12020-03-26 13:34:14 +00001007 CallbackContext_1_3 callbackContext;
1008 callbackContext.callback = nullCallback;
Sadik Armagan188675f2021-02-12 17:16:42 +00001009 callbackContext.ctx.measureTimings = V1_2::MeasureTiming::NO;
Kevin May42477c12020-03-26 13:34:14 +00001010 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
Sadik Armagand7be72e2020-04-23 12:56:05 +01001011
1012 auto errorStatus = ExecuteGraph(memPools,
1013 inputTensors,
1014 outputTensors,
1015 callbackContext);
1016 return errorStatus == V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +00001017}
1018
1019template<typename HalVersion>
1020Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::Execute(const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +00001021 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +00001022 CallbackAsync_1_3 callback)
1023{
1024 ExecutionContext_1_3 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +00001025 if (measureTiming == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +00001026 {
1027 ctx.measureTimings = measureTiming;
1028 ctx.driverStart = Now();
1029 }
1030
Sadik Armagan0a2dfab2021-10-06 16:41:44 +01001031 if (!m_PreparedFromCache)
1032 {
1033 ALOGV("ArmnnPreparedModel_1_3::execute(): %s", GetModelSummary(m_Model).c_str());
1034 }
Kevin May42477c12020-03-26 13:34:14 +00001035 m_RequestCount++;
1036
Sadik Armagan0a2dfab2021-10-06 16:41:44 +01001037 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Kevin May42477c12020-03-26 13:34:14 +00001038 {
1039 callback(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute");
1040 return V1_3::ErrorStatus::INVALID_ARGUMENT;
1041 }
1042
1043 if (!m_RequestInputsAndOutputsDumpDir.empty())
1044 {
1045 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
1046 }
1047
1048 // map the memory pool into shared pointers
1049 // use a shared memory pools vector on the heap, as it is passed to the request thread
1050 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
1051
1052 // allocate the tensors on the heap, as they are passed to the request thread
1053 auto inputTensors = std::make_shared<armnn::InputTensors>();
1054 auto outputTensors = std::make_shared<armnn::OutputTensors>();
1055
1056 auto [status, outShapes, timing, message] = PrepareMemoryForIO(*inputTensors, *outputTensors,
1057 *memPools, request);
1058 if (status != V1_3::ErrorStatus::NONE)
1059 {
1060 callback(status, outShapes, timing, message);
1061 }
1062
1063 switch(status)
1064 {
1065 case V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
1066 return V1_3::ErrorStatus::NONE;
1067 case V1_3::ErrorStatus::GENERAL_FAILURE:
1068 return V1_3::ErrorStatus::GENERAL_FAILURE;
Sadik Armagana07d2752021-05-12 20:33:58 +01001069 case V1_3::ErrorStatus::INVALID_ARGUMENT:
1070 return V1_3::ErrorStatus::INVALID_ARGUMENT;
Kevin May42477c12020-03-26 13:34:14 +00001071 default:
1072 {}
1073 }
Kevin May42477c12020-03-26 13:34:14 +00001074 CallbackContext_1_3 cb;
1075 cb.callback = callback;
1076 cb.ctx = ctx;
Finn Williamsd8fb5402021-05-19 20:52:00 +01001077
1078
1079 enum class QosExecPriority
1080 {
1081 Low = 0,
1082 Medium = 1,
1083 High = 2
1084 };
1085
1086
1087 if (m_AsyncModelExecutionEnabled)
1088 {
1089 armnn::QosExecPriority priority;
1090
1091 switch (GetModelPriority()) {
1092 case V1_3::Priority::LOW:
1093 priority = armnn::QosExecPriority::Low;
1094 break;
1095 case V1_3::Priority::MEDIUM:
1096 priority = armnn::QosExecPriority::Medium;
1097 break;
1098 case V1_3::Priority::HIGH:
1099 priority = armnn::QosExecPriority::High;
1100 break;
1101 default:
1102 priority = armnn::QosExecPriority::Medium;
1103
1104 }
1105
1106 ALOGV("ArmnnPreparedModel_1_3::execute(...) before ScheduleGraphForExecution");
1107 ScheduleGraphForExecution(memPools, inputTensors, outputTensors, cb, priority);
1108 ALOGV("ArmnnPreparedModel_1_3::execute(...) after ScheduleGraphForExecution");
1109 return V1_3::ErrorStatus::NONE;
1110 }
1111
1112 ALOGV("ArmnnPreparedModel_1_3::execute(...) before PostMsg");
1113 // post the request for asynchronous execution
Kevin May42477c12020-03-26 13:34:14 +00001114 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
1115 ALOGV("ArmnnPreparedModel_1_3::execute(...) after PostMsg");
1116 return V1_3::ErrorStatus::NONE;
1117}
1118
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +01001119template<typename HalVersion>
1120V1_3::Priority ArmnnPreparedModel_1_3<HalVersion>::GetModelPriority()
1121{
1122 return m_ModelPriority;
1123}
1124
Finn Williamsd8fb5402021-05-19 20:52:00 +01001125template<typename HalVersion>
1126template <typename CallbackContext>
1127void ArmnnPreparedModel_1_3<HalVersion>::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify(
1128 armnn::Status status, armnn::InferenceTimingPair timeTaken)
1129{
1130 ALOGV("ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify");
1131 CommitPools(*m_MemPools);
1132
1133 m_Model->DumpTensorsIfRequired("Output", *m_OutputTensors);
1134
1135 if (status != armnn::Status::Success)
1136 {
1137 ALOGW("ArmnnThreadPoolCallback_1_3::Notify EnqueueWorkload failed");
1138 m_CallbackContext.callback(V1_3::ErrorStatus::GENERAL_FAILURE,
1139 {},
1140 g_NoTiming,
1141 "ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3");
1142 return;
1143 }
1144
1145 if (m_CallbackContext.ctx.measureTimings == V1_2::MeasureTiming::YES)
1146 {
1147 m_CallbackContext.ctx.deviceStart = timeTaken.first;
1148 m_CallbackContext.ctx.deviceEnd = timeTaken.second;
1149 m_CallbackContext.ctx.driverEnd = std::chrono::steady_clock::now();
1150 V1_2::Timing timing;
1151 timing.timeOnDevice = MicrosecondsDuration(m_CallbackContext.ctx.deviceEnd, m_CallbackContext.ctx.deviceStart);
1152 timing.timeInDriver = MicrosecondsDuration(m_CallbackContext.ctx.driverEnd, m_CallbackContext.ctx.driverStart);
Zingo Andersen7c561492022-01-25 11:09:41 +01001153 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu",
1154 static_cast<unsigned long>(timing.timeOnDevice), static_cast<unsigned long>(timing.timeInDriver));
Finn Williamsd8fb5402021-05-19 20:52:00 +01001155 m_CallbackContext.callback(
1156 V1_3::ErrorStatus::NONE, m_OutputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
1157 } else
1158 {
1159 m_CallbackContext.callback(
1160 V1_3::ErrorStatus::NONE, m_OutputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
1161 }
1162 return;
1163}
1164
Kevin May42477c12020-03-26 13:34:14 +00001165#ifdef ARMNN_ANDROID_NN_V1_3
1166template class ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>;
Sadik Armagand7be72e2020-04-23 12:56:05 +01001167template Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ExecuteGraph<CallbackContext_1_3>(
Kevin May42477c12020-03-26 13:34:14 +00001168 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1169 armnn::InputTensors& pInputTensors,
1170 armnn::OutputTensors& pOutputTensors,
1171 CallbackContext_1_3 cb);
Finn Williamsd8fb5402021-05-19 20:52:00 +01001172
1173template void ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ScheduleGraphForExecution<CallbackContext_1_3>(
1174 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1175 std::shared_ptr<armnn::InputTensors>& inputTensors,
1176 std::shared_ptr<armnn::OutputTensors>& outputTensors,
1177 CallbackContext_1_3 callbackContext,
1178 armnn::QosExecPriority priority);
Kevin May42477c12020-03-26 13:34:14 +00001179#endif
1180
1181} // namespace armnn_driver