blob: 20b49f5da9727acfff35491a7b4fa6f5a1ad2892 [file] [log] [blame]
Kevin May42477c12020-03-26 13:34:14 +00001//
Mike Kellye2d611e2021-10-14 12:35:58 +01002// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
Kevin May42477c12020-03-26 13:34:14 +00003// SPDX-License-Identifier: MIT
4//
Sadik Armagand7be72e2020-04-23 12:56:05 +01005// Note: the ArmnnFencedExecutionCallback and code snippet in the executeFenced() function
6// in this file is based on Android code
7// under the Apache 2.0 license. See comments below for details.
8//
Kevin May42477c12020-03-26 13:34:14 +00009
10#define LOG_TAG "ArmnnDriver"
11
12#include "ArmnnPreparedModel_1_3.hpp"
13#include "Utils.hpp"
14
Narumol 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];
513
Cathal Corbette27d4e82021-10-28 12:28:35 +0100514 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
515 // inputs (of type InputTensors) is composed of a vector of ConstTensors.
516 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
517 inputTensorInfo.SetConstant();
Kevin May42477c12020-03-26 13:34:14 +0000518 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
519
520 if (inputTensor.GetMemoryArea() == nullptr)
521 {
522 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
523 return V1_3::ErrorStatus::GENERAL_FAILURE;
524 }
525
526 inputs.emplace_back(i, inputTensor);
527 }
528
529 return V1_3::ErrorStatus::NONE;
530}
531
532template<typename HalVersion>
533Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForOutputs(
534 armnn::OutputTensors& outputs,
Sadik Armagan188675f2021-02-12 17:16:42 +0000535 std::vector<V1_2::OutputShape> &outputShapes,
Kevin May42477c12020-03-26 13:34:14 +0000536 const V1_3::Request& request,
537 const std::vector<android::nn::RunTimePoolInfo>& memPools)
538{
539 outputs.reserve(request.outputs.size());
540 for (unsigned int i = 0; i < request.outputs.size(); i++)
541 {
542 const auto& outputArg = request.outputs[i];
543
Finn Williamsa4983ce2020-07-23 12:55:12 +0100544 armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
Kevin May42477c12020-03-26 13:34:14 +0000545 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
546 if (outputTensor.GetMemoryArea() == nullptr)
547 {
548 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
549 return V1_3::ErrorStatus::GENERAL_FAILURE;
550 }
551
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100552 const size_t outputSize = outputTensorInfo.GetNumBytes();
553
Finn Williamsa4983ce2020-07-23 12:55:12 +0100554 unsigned int count = 0;
555 std::for_each(outputArg.dimensions.begin(), outputArg.dimensions.end(), [&](auto dim)
556 {
557 if (dim != 0)
558 {
559 outputTensorInfo.GetShape()[count] = dim;
560 }
561 else
562 {
563 outputTensorInfo.GetShape()[count] = outputArg.dimensions.size();
564 }
565
566 count++;
567 });
568
Finn Williamsa4983ce2020-07-23 12:55:12 +0100569 outputs.emplace_back(i, outputTensor);
570 outputShapes[i] = ComputeShape(outputTensorInfo);
571
572 if (outputArg.location.length < outputSize)
573 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100574 ALOGW("ArmnnPreparedModel_1_3::Execute failed outputArg.location.length (%s) < outputSize (%s)",
575 std::to_string(outputArg.location.length).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100576 outputShapes[i].isSufficient = false;
577 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
578 }
579
Sadik Armagan188675f2021-02-12 17:16:42 +0000580 size_t bufferSize = 0;
581#if !defined(ARMNN_ANDROID_S)
582 bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
Sadik Armagan188675f2021-02-12 17:16:42 +0000583#else
Kevin Maydc873f62021-06-14 11:21:11 +0100584 bufferSize = memPools.at(outputArg.location.poolIndex).getSize();
Sadik Armagan188675f2021-02-12 17:16:42 +0000585#endif
Kevin May42477c12020-03-26 13:34:14 +0000586 if (bufferSize < outputSize)
587 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100588 ALOGW("ArmnnPreparedModel_1_3::Execute failed bufferSize (%s) < outputSize (%s)",
589 std::to_string(bufferSize).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100590 outputShapes[i].isSufficient = false;
Kevin May42477c12020-03-26 13:34:14 +0000591 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
592 }
Kevin May42477c12020-03-26 13:34:14 +0000593 }
594
595 return V1_3::ErrorStatus::NONE;
596}
597
598template<typename HalVersion>
Sadik Armagan188675f2021-02-12 17:16:42 +0000599std::tuple<V1_3::ErrorStatus, hidl_vec<V1_2::OutputShape>, V1_2::Timing, std::string>
Kevin May42477c12020-03-26 13:34:14 +0000600 ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForIO(armnn::InputTensors& inputs,
601 armnn::OutputTensors& outputs,
602 std::vector<android::nn::RunTimePoolInfo>& memPools,
603 const V1_3::Request& request)
604{
Sadik Armagan188675f2021-02-12 17:16:42 +0000605#if !defined(ARMNN_ANDROID_S)
Kevin May42477c12020-03-26 13:34:14 +0000606 if (!setRunTimePoolInfosFromMemoryPools(&memPools, request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000607#else
608 if (!setRunTimePoolInfosFromMemoryPools(&memPools, uncheckedConvert(request.pools)))
609#endif
Kevin May42477c12020-03-26 13:34:14 +0000610 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000611 return {V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000612 }
613
614 // add the inputs and outputs with their data
615 try
616 {
617 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_3::ErrorStatus::NONE)
618 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000619 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000620 }
621
Sadik Armagan188675f2021-02-12 17:16:42 +0000622 std::vector<V1_2::OutputShape> outputShapes(request.outputs.size());
Kevin May42477c12020-03-26 13:34:14 +0000623
624 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
625 if (errorStatus != V1_3::ErrorStatus::NONE)
626 {
627 return {errorStatus, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
628 }
629 }
630 catch (armnn::Exception& e)
631 {
632 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000633 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000634 }
635 catch (std::exception& e)
636 {
637 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000638 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000639 }
640
641 return {V1_3::ErrorStatus::NONE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
642}
643
644template<typename HalVersion>
645template<typename CallbackContext>
646Return<void> ArmnnPreparedModel_1_3<HalVersion>::ExecuteSynchronously(const V1_3::Request& request,
647 CallbackContext cbCtx)
648{
Sadik Armagan188675f2021-02-12 17:16:42 +0000649 if (cbCtx.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000650 {
651 cbCtx.ctx.driverStart = Now();
652 }
653
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100654 if (!m_PreparedFromCache && !android::nn::validateRequest(convertToV1_3(request), m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000655 {
656 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
657 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
658 {},
659 g_NoTiming,
660 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
661 return Void();
662 }
663
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100664 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000665 {
666 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
667 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
668 {},
669 g_NoTiming,
670 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
Sadik Armaganef8a3932020-04-09 17:21:50 +0100671 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000672 }
673
674
675 // map the memory pool into shared pointers
676 // use a shared memory pools vector on the heap, as it is passed to the request thread
677 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
678
679 // allocate the tensors on the heap, as they are passed to the request thread
680 auto inputs = std::make_shared<armnn::InputTensors>();
681 auto outputs = std::make_shared<armnn::OutputTensors>();
682
683 auto [status, outputShapes, timing, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
684 if (status != V1_3::ErrorStatus::NONE)
685 {
686 cbCtx.callback(status, outputShapes, timing, message);
Sadik Armaganef8a3932020-04-09 17:21:50 +0100687 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000688 }
689
690 ALOGV("ArmnnPreparedModel_1_3::ExecuteSynchronously() before Execution");
691
692 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
693 return Void();
694}
695
696template<typename HalVersion>
697Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000698 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000699 executeSynchronously_cb cb)
700{
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100701 if (!m_PreparedFromCache)
702 {
703 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
704 }
Kevin May42477c12020-03-26 13:34:14 +0000705 m_RequestCount++;
706
707 if (cb == nullptr)
708 {
709 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously invalid callback passed");
710 return Void();
711 }
712
713 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000714 std::vector<V1_2::OutputShape> outputShapes,
715 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000716 std::string)
717 {
718 cb(convertToV1_0(errorStatus), outputShapes, timing);
719 };
720
721 CallbackContext_1_3 cbCtx;
722 cbCtx.callback = cbWrapper;
723 cbCtx.ctx.measureTimings = measureTiming;
724
725 ExecuteSynchronously(convertToV1_3(request), cbCtx);
726 return Void();
727}
728
729template<typename HalVersion>
Kevin May352d8382020-03-31 15:03:42 +0100730Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously_1_3(
731 const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000732 V1_2::MeasureTiming measureTiming,
Kevin May352d8382020-03-31 15:03:42 +0100733 const V1_3::OptionalTimePoint& deadline,
734 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
735 executeSynchronously_1_3_cb cb)
Kevin May42477c12020-03-26 13:34:14 +0000736{
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100737 if (!m_PreparedFromCache)
738 {
739 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously_1_3(): %s", GetModelSummary(m_Model).c_str());
740 }
Kevin May42477c12020-03-26 13:34:14 +0000741 m_RequestCount++;
742
743 if (cb == nullptr)
744 {
745 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid callback passed");
746 return Void();
747 }
748
Sadik Armagan188675f2021-02-12 17:16:42 +0000749 if (deadline.getDiscriminator() != V1_3::OptionalTimePoint::hidl_discriminator::none)
Kevin May42477c12020-03-26 13:34:14 +0000750 {
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100751 ALOGW("ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter deadline is set but not supported.");
Kevin May42477c12020-03-26 13:34:14 +0000752 }
753
Sadik Armagan188675f2021-02-12 17:16:42 +0000754 if (loopTimeoutDuration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100755 {
756 ALOGW(
757 "ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter loopTimeoutDuration is set but not supported.");
Kevin May352d8382020-03-31 15:03:42 +0100758 }
759
Kevin May42477c12020-03-26 13:34:14 +0000760 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000761 std::vector<V1_2::OutputShape> outputShapes,
762 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000763 std::string)
764 {
765 cb(errorStatus, outputShapes, timing);
766 };
767
768 CallbackContext_1_3 cbCtx;
769 cbCtx.callback = cbWrapper;
770 cbCtx.ctx.measureTimings = measureTiming;
771
772 ExecuteSynchronously(request, cbCtx);
773 return Void();
774}
775
776template<typename HalVersion>
777Return<void> ArmnnPreparedModel_1_3<HalVersion>::configureExecutionBurst(
778 const sp<V1_2::IBurstCallback>& callback,
779 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
780 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
781 V1_3::IPreparedModel::configureExecutionBurst_cb cb)
782{
783 ALOGV("ArmnnPreparedModel_1_3::configureExecutionBurst");
784 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
785 requestChannel,
786 resultChannel,
787 this);
788
789 if (burst == nullptr)
790 {
791 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
792 }
793 else
794 {
795 cb(V1_0::ErrorStatus::NONE, burst);
796 }
797 return Void();
798}
799
800template<typename HalVersion>
801template<typename CallbackContext>
Sadik Armagand7be72e2020-04-23 12:56:05 +0100802Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::ExecuteGraph(
Kevin May42477c12020-03-26 13:34:14 +0000803 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
804 armnn::InputTensors& inputTensors,
805 armnn::OutputTensors& outputTensors,
806 CallbackContext cb)
807{
808 ALOGV("ArmnnPreparedModel_1_3::ExecuteGraph(...)");
Colm Donelan0fc16c62022-03-16 11:54:13 +0000809 // Capture the graph execution start time.
810 std::chrono::time_point<std::chrono::system_clock> graphExecutionStart = std::chrono::system_clock::now();
Kevin May42477c12020-03-26 13:34:14 +0000811
Kevin May42477c12020-03-26 13:34:14 +0000812 DumpTensorsIfRequired("Input", inputTensors);
813
Sadik Armagan188675f2021-02-12 17:16:42 +0000814 std::vector<V1_2::OutputShape> outputShapes(outputTensors.size());
Kevin May42477c12020-03-26 13:34:14 +0000815 for (unsigned int i = 0; i < outputTensors.size(); i++)
816 {
817 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
818 const armnn::Tensor outputTensor = outputTensorPair.second;
819 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
820
821 outputShapes[i] = ComputeShape(outputTensorInfo);
822 }
823
824 // run it
825 try
826 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000827 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000828 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100829 cb.ctx.deviceStart = Now();
Kevin May42477c12020-03-26 13:34:14 +0000830 }
Finn Williamsd8fb5402021-05-19 20:52:00 +0100831 armnn::Status status;
832 if (m_AsyncModelExecutionEnabled)
833 {
834 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled true");
835 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
836 }
837 else
838 {
839 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled false");
Narumol Prangnawaratd1a947f2022-02-07 13:12:24 +0000840 // Create a vector of Input and Output Ids which can be imported. An empty vector means all will be copied.
841 std::vector<armnn::ImportedInputId> importedInputIds;
842 if (m_EnableImport)
843 {
844 importedInputIds = m_Runtime->ImportInputs(m_NetworkId, inputTensors, armnn::MemorySource::Malloc);
845 }
846 std::vector<armnn::ImportedOutputId> importedOutputIds;
847 if (m_EnableExport)
848 {
849 importedOutputIds = m_Runtime->ImportOutputs(m_NetworkId, outputTensors, armnn::MemorySource::Malloc);
850 }
851 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors,
852 importedInputIds, importedOutputIds);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100853 }
Kevin May42477c12020-03-26 13:34:14 +0000854
Sadik Armagan188675f2021-02-12 17:16:42 +0000855 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000856 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100857 cb.ctx.deviceEnd = Now();
Kevin May42477c12020-03-26 13:34:14 +0000858 }
859 if (status != armnn::Status::Success)
860 {
Finn Williamsd8fb5402021-05-19 20:52:00 +0100861 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph EnqueueWorkload failed");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100862 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
863 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000864 }
865 }
866 catch (armnn::Exception& e)
867 {
868 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
869 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100870 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000871 }
872 catch (std::exception& e)
873 {
874 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
875 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100876 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000877 }
878
879 CommitPools(*pMemPools);
880
881 DumpTensorsIfRequired("Output", outputTensors);
882
Sadik Armagan188675f2021-02-12 17:16:42 +0000883 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000884 {
Kevin May949a69e2020-04-24 10:21:40 +0100885 cb.ctx.driverEnd = Now();
Sadik Armagan188675f2021-02-12 17:16:42 +0000886 V1_2::Timing timing;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100887 timing.timeOnDevice = MicrosecondsDuration(cb.ctx.deviceEnd, cb.ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100888 timing.timeInDriver = MicrosecondsDuration(cb.ctx.driverEnd, cb.ctx.driverStart);
Zingo Andersen7c561492022-01-25 11:09:41 +0100889 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu",
890 static_cast<unsigned long>(timing.timeOnDevice), static_cast<unsigned long>(timing.timeInDriver));
Kevin May42477c12020-03-26 13:34:14 +0000891 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100892 } else
893 {
Kevin May42477c12020-03-26 13:34:14 +0000894 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
895 }
Colm Donelan0fc16c62022-03-16 11:54:13 +0000896 // Log the total time in this call. This is a good number to compare to that printed out by
897 // RuntimeImpl::EnqueueWorkload. The difference should be the execution overhead of the driver.
898 ALOGI("ArmnnPreparedModel_1_3::ExecuteGraph Execution time = %lld µs",
899 std::chrono::duration_cast<std::chrono::microseconds>
900 (std::chrono::system_clock::now() - graphExecutionStart).count());
Sadik Armagand7be72e2020-04-23 12:56:05 +0100901 return V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000902}
903
Finn Williamsd8fb5402021-05-19 20:52:00 +0100904/// Schedule the graph prepared from the request for execution
905template<typename HalVersion>
906template<typename CallbackContext>
907void ArmnnPreparedModel_1_3<HalVersion>::ScheduleGraphForExecution(
908 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
909 std::shared_ptr<armnn::InputTensors>& inputTensors,
910 std::shared_ptr<armnn::OutputTensors>& outputTensors,
911 CallbackContext callbackContext,
912 armnn::QosExecPriority priority)
913{
914 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution(...)");
915
916 DumpTensorsIfRequired("Input", *inputTensors);
917
918 unsigned int outputTensorSize = outputTensors.get()->size();
919 std::vector<V1_2::OutputShape> outputShapes(outputTensorSize);
920 for (unsigned int i = 0; i < outputTensorSize; i++)
921 {
922 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors.get()->at(i);
923 const armnn::Tensor outputTensor = outputTensorPair.second;
924 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
925
926 outputShapes[i] = ComputeShape(outputTensorInfo);
927 }
928
929 auto tpCb = std::make_shared<
930 ArmnnThreadPoolCallback_1_3<CallbackContext_1_3>>(this,
931 pMemPools,
932 outputShapes,
933 inputTensors,
934 outputTensors,
935 callbackContext);
936
Finn Williamsca3a3e02021-06-11 15:04:02 +0100937 m_Threadpool->Schedule(m_NetworkId,
938 *tpCb->m_InputTensors,
939 *tpCb->m_OutputTensors,
940 priority,
941 tpCb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100942 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution end");
943}
944
Kevin May42477c12020-03-26 13:34:14 +0000945template<typename HalVersion>
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100946bool ArmnnPreparedModel_1_3<HalVersion>::ExecuteWithDummyInputs(unsigned int numInputs, unsigned int numOutputs)
Kevin May42477c12020-03-26 13:34:14 +0000947{
948 std::vector<std::vector<char>> storage;
949 armnn::InputTensors inputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100950 for (unsigned int i = 0; i < numInputs; i++)
Kevin May42477c12020-03-26 13:34:14 +0000951 {
Cathal Corbette27d4e82021-10-28 12:28:35 +0100952 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
953 // pInputTensors (of type InputTensors) is composed of a vector of ConstTensors.
954 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
955 inputTensorInfo.SetConstant();
956
Kevin May42477c12020-03-26 13:34:14 +0000957 storage.emplace_back(inputTensorInfo.GetNumBytes());
958 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
959
960 inputTensors.emplace_back(i, inputTensor);
961 }
962
963 armnn::OutputTensors outputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100964 for (unsigned int i = 0; i < numOutputs; i++)
Kevin May42477c12020-03-26 13:34:14 +0000965 {
966 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
967 storage.emplace_back(outputTensorInfo.GetNumBytes());
968 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
969
970 outputTensors.emplace_back(i, outputTensor);
971 }
972
Sadik Armagan188675f2021-02-12 17:16:42 +0000973 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Kevin May42477c12020-03-26 13:34:14 +0000974 CallbackContext_1_3 callbackContext;
975 callbackContext.callback = nullCallback;
Sadik Armagan188675f2021-02-12 17:16:42 +0000976 callbackContext.ctx.measureTimings = V1_2::MeasureTiming::NO;
Kevin May42477c12020-03-26 13:34:14 +0000977 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
Sadik Armagand7be72e2020-04-23 12:56:05 +0100978
979 auto errorStatus = ExecuteGraph(memPools,
980 inputTensors,
981 outputTensors,
982 callbackContext);
983 return errorStatus == V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000984}
985
986template<typename HalVersion>
987Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::Execute(const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000988 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000989 CallbackAsync_1_3 callback)
990{
991 ExecutionContext_1_3 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000992 if (measureTiming == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000993 {
994 ctx.measureTimings = measureTiming;
995 ctx.driverStart = Now();
996 }
997
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100998 if (!m_PreparedFromCache)
999 {
1000 ALOGV("ArmnnPreparedModel_1_3::execute(): %s", GetModelSummary(m_Model).c_str());
1001 }
Kevin May42477c12020-03-26 13:34:14 +00001002 m_RequestCount++;
1003
Sadik Armagan0a2dfab2021-10-06 16:41:44 +01001004 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Kevin May42477c12020-03-26 13:34:14 +00001005 {
1006 callback(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute");
1007 return V1_3::ErrorStatus::INVALID_ARGUMENT;
1008 }
1009
1010 if (!m_RequestInputsAndOutputsDumpDir.empty())
1011 {
1012 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
1013 }
1014
1015 // map the memory pool into shared pointers
1016 // use a shared memory pools vector on the heap, as it is passed to the request thread
1017 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
1018
1019 // allocate the tensors on the heap, as they are passed to the request thread
1020 auto inputTensors = std::make_shared<armnn::InputTensors>();
1021 auto outputTensors = std::make_shared<armnn::OutputTensors>();
1022
1023 auto [status, outShapes, timing, message] = PrepareMemoryForIO(*inputTensors, *outputTensors,
1024 *memPools, request);
1025 if (status != V1_3::ErrorStatus::NONE)
1026 {
1027 callback(status, outShapes, timing, message);
1028 }
1029
1030 switch(status)
1031 {
1032 case V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
1033 return V1_3::ErrorStatus::NONE;
1034 case V1_3::ErrorStatus::GENERAL_FAILURE:
1035 return V1_3::ErrorStatus::GENERAL_FAILURE;
Sadik Armagana07d2752021-05-12 20:33:58 +01001036 case V1_3::ErrorStatus::INVALID_ARGUMENT:
1037 return V1_3::ErrorStatus::INVALID_ARGUMENT;
Kevin May42477c12020-03-26 13:34:14 +00001038 default:
1039 {}
1040 }
Kevin May42477c12020-03-26 13:34:14 +00001041 CallbackContext_1_3 cb;
1042 cb.callback = callback;
1043 cb.ctx = ctx;
Finn Williamsd8fb5402021-05-19 20:52:00 +01001044
1045
1046 enum class QosExecPriority
1047 {
1048 Low = 0,
1049 Medium = 1,
1050 High = 2
1051 };
1052
1053
1054 if (m_AsyncModelExecutionEnabled)
1055 {
1056 armnn::QosExecPriority priority;
1057
1058 switch (GetModelPriority()) {
1059 case V1_3::Priority::LOW:
1060 priority = armnn::QosExecPriority::Low;
1061 break;
1062 case V1_3::Priority::MEDIUM:
1063 priority = armnn::QosExecPriority::Medium;
1064 break;
1065 case V1_3::Priority::HIGH:
1066 priority = armnn::QosExecPriority::High;
1067 break;
1068 default:
1069 priority = armnn::QosExecPriority::Medium;
1070
1071 }
1072
1073 ALOGV("ArmnnPreparedModel_1_3::execute(...) before ScheduleGraphForExecution");
1074 ScheduleGraphForExecution(memPools, inputTensors, outputTensors, cb, priority);
1075 ALOGV("ArmnnPreparedModel_1_3::execute(...) after ScheduleGraphForExecution");
1076 return V1_3::ErrorStatus::NONE;
1077 }
1078
1079 ALOGV("ArmnnPreparedModel_1_3::execute(...) before PostMsg");
1080 // post the request for asynchronous execution
Kevin May42477c12020-03-26 13:34:14 +00001081 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
1082 ALOGV("ArmnnPreparedModel_1_3::execute(...) after PostMsg");
1083 return V1_3::ErrorStatus::NONE;
1084}
1085
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +01001086template<typename HalVersion>
1087V1_3::Priority ArmnnPreparedModel_1_3<HalVersion>::GetModelPriority()
1088{
1089 return m_ModelPriority;
1090}
1091
Finn Williamsd8fb5402021-05-19 20:52:00 +01001092template<typename HalVersion>
1093template <typename CallbackContext>
1094void ArmnnPreparedModel_1_3<HalVersion>::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify(
1095 armnn::Status status, armnn::InferenceTimingPair timeTaken)
1096{
1097 ALOGV("ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify");
1098 CommitPools(*m_MemPools);
1099
1100 m_Model->DumpTensorsIfRequired("Output", *m_OutputTensors);
1101
1102 if (status != armnn::Status::Success)
1103 {
1104 ALOGW("ArmnnThreadPoolCallback_1_3::Notify EnqueueWorkload failed");
1105 m_CallbackContext.callback(V1_3::ErrorStatus::GENERAL_FAILURE,
1106 {},
1107 g_NoTiming,
1108 "ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3");
1109 return;
1110 }
1111
1112 if (m_CallbackContext.ctx.measureTimings == V1_2::MeasureTiming::YES)
1113 {
1114 m_CallbackContext.ctx.deviceStart = timeTaken.first;
1115 m_CallbackContext.ctx.deviceEnd = timeTaken.second;
1116 m_CallbackContext.ctx.driverEnd = std::chrono::steady_clock::now();
1117 V1_2::Timing timing;
1118 timing.timeOnDevice = MicrosecondsDuration(m_CallbackContext.ctx.deviceEnd, m_CallbackContext.ctx.deviceStart);
1119 timing.timeInDriver = MicrosecondsDuration(m_CallbackContext.ctx.driverEnd, m_CallbackContext.ctx.driverStart);
Zingo Andersen7c561492022-01-25 11:09:41 +01001120 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu",
1121 static_cast<unsigned long>(timing.timeOnDevice), static_cast<unsigned long>(timing.timeInDriver));
Finn Williamsd8fb5402021-05-19 20:52:00 +01001122 m_CallbackContext.callback(
1123 V1_3::ErrorStatus::NONE, m_OutputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
1124 } else
1125 {
1126 m_CallbackContext.callback(
1127 V1_3::ErrorStatus::NONE, m_OutputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
1128 }
1129 return;
1130}
1131
Kevin May42477c12020-03-26 13:34:14 +00001132#ifdef ARMNN_ANDROID_NN_V1_3
1133template class ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>;
Sadik Armagand7be72e2020-04-23 12:56:05 +01001134template Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ExecuteGraph<CallbackContext_1_3>(
Kevin May42477c12020-03-26 13:34:14 +00001135 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1136 armnn::InputTensors& pInputTensors,
1137 armnn::OutputTensors& pOutputTensors,
1138 CallbackContext_1_3 cb);
Finn Williamsd8fb5402021-05-19 20:52:00 +01001139
1140template void ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ScheduleGraphForExecution<CallbackContext_1_3>(
1141 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1142 std::shared_ptr<armnn::InputTensors>& inputTensors,
1143 std::shared_ptr<armnn::OutputTensors>& outputTensors,
1144 CallbackContext_1_3 callbackContext,
1145 armnn::QosExecPriority priority);
Kevin May42477c12020-03-26 13:34:14 +00001146#endif
1147
1148} // namespace armnn_driver