blob: bde646de13a8e0eb66a9b7256cbe3fe2b0bd62a5 [file] [log] [blame]
Kevin May42477c12020-03-26 13:34:14 +00001//
Mike Kellye2d611e2021-10-14 12:35:58 +01002// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
Kevin May42477c12020-03-26 13:34:14 +00003// SPDX-License-Identifier: MIT
4//
Sadik Armagand7be72e2020-04-23 12:56:05 +01005// Note: the ArmnnFencedExecutionCallback and code snippet in the executeFenced() function
6// in this file is based on Android code
7// under the Apache 2.0 license. See comments below for details.
8//
Kevin May42477c12020-03-26 13:34:14 +00009
10#define LOG_TAG "ArmnnDriver"
11
12#include "ArmnnPreparedModel_1_3.hpp"
13#include "Utils.hpp"
14
15#include <Utils.h>
Sadik Armagand7be72e2020-04-23 12:56:05 +010016#include <android/sync.h>
Kevin May42477c12020-03-26 13:34:14 +000017#include <log/log.h>
18#include <OperationsUtils.h>
19#include <ExecutionBurstServer.h>
20#include <ValidateHal.h>
21
Kevin May42477c12020-03-26 13:34:14 +000022#include <cinttypes>
23
Sadik Armagan188675f2021-02-12 17:16:42 +000024#ifdef ARMNN_ANDROID_S
25#include <LegacyUtils.h>
26#endif
27
Kevin May42477c12020-03-26 13:34:14 +000028using namespace android;
29using namespace android::hardware;
30
31namespace {
32
Sadik Armagan188675f2021-02-12 17:16:42 +000033static const V1_2::Timing g_NoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX};
Kevin May42477c12020-03-26 13:34:14 +000034using namespace armnn_driver;
35using TimePoint = std::chrono::steady_clock::time_point;
36
37TimePoint Now()
38{
39 return std::chrono::steady_clock::now();
40}
41
42unsigned long MicrosecondsDuration(TimePoint endPoint, TimePoint startPoint)
43{
44 return static_cast<unsigned long>(std::chrono::duration_cast<std::chrono::microseconds>(
45 endPoint - startPoint).count());
46}
47
48void NotifyCallbackAndCheck(const ::android::sp<V1_0::IExecutionCallback>& callback,
49 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000050 std::vector<V1_2::OutputShape>,
51 const V1_2::Timing,
Kevin May42477c12020-03-26 13:34:14 +000052 std::string callingFunction)
53{
54 Return<void> returned = callback->notify(convertToV1_0(errorStatus));
55 // This check is required, if the callback fails and it isn't checked it will bring down the service
56 if (!returned.isOk())
57 {
58 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
59 callingFunction.c_str(), returned.description().c_str());
60 }
61}
62
63void NotifyCallbackAndCheck(const ::android::sp<V1_2::IExecutionCallback>& callback,
64 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000065 std::vector<V1_2::OutputShape> outputShapes,
66 const V1_2::Timing timing,
Kevin May42477c12020-03-26 13:34:14 +000067 std::string callingFunction)
68{
69 Return<void> returned = callback->notify_1_2(convertToV1_0(errorStatus), outputShapes, timing);
70 // This check is required, if the callback fails and it isn't checked it will bring down the service
71 if (!returned.isOk())
72 {
73 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
74 callingFunction.c_str(), returned.description().c_str());
75 }
76}
77
78void NotifyCallbackAndCheck(const ::android::sp<V1_3::IExecutionCallback>& callback,
79 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000080 std::vector<V1_2::OutputShape> outputShapes,
81 const V1_2::Timing timing,
Kevin May42477c12020-03-26 13:34:14 +000082 std::string callingFunction)
83{
84 Return<void> returned = callback->notify_1_3(errorStatus, outputShapes, timing);
85 // This check is required, if the callback fails and it isn't checked it will bring down the service
86 if (!returned.isOk())
87 {
88 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
89 callingFunction.c_str(), returned.description().c_str());
90 }
91}
92
Sadik Armagan188675f2021-02-12 17:16:42 +000093bool ValidateRequestArgument(const V1_0::RequestArgument& requestArg, const armnn::TensorInfo& tensorInfo)
Kevin May42477c12020-03-26 13:34:14 +000094{
95 if (requestArg.dimensions.size() != 0)
96 {
97 if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
98 {
99 ALOGE("Mismatched dimensions (request argument: %zu, expected: %u)",
100 requestArg.dimensions.size(), tensorInfo.GetNumDimensions());
101 return false;
102 }
103
104 for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
105 {
Finn Williamsa4983ce2020-07-23 12:55:12 +0100106 if (requestArg.dimensions[d] != 0 && requestArg.dimensions[d] != tensorInfo.GetShape()[d])
Kevin May42477c12020-03-26 13:34:14 +0000107 {
108 ALOGE("Mismatched size for dimension %d (request argument: %u, expected %u)",
109 d, requestArg.dimensions[d], tensorInfo.GetShape()[d]);
110 return false;
111 }
112 }
113 }
114
115 return true;
116}
117
Sadik Armagan188675f2021-02-12 17:16:42 +0000118armnn::Tensor GetTensorForRequestArgument(const V1_0::RequestArgument& requestArg,
Kevin May42477c12020-03-26 13:34:14 +0000119 const armnn::TensorInfo& tensorInfo,
120 const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
121{
122 if (!ValidateRequestArgument(requestArg, tensorInfo))
123 {
124 return armnn::Tensor();
125 }
126
127 return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
128}
129
130inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
131{
132 return tensorNamePrefix + std::to_string(index);
133}
134
135} // anonymous namespace
136
137using namespace android::hardware;
138
139namespace armnn_driver
140{
141
142template<typename HalVersion>
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100143RequestThread_1_3<ArmnnPreparedModel_1_3, HalVersion, CallbackContext_1_3>
Kevin May42477c12020-03-26 13:34:14 +0000144 ArmnnPreparedModel_1_3<HalVersion>::m_RequestThread;
145
146template<typename HalVersion>
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100147std::unique_ptr<armnn::Threadpool> ArmnnPreparedModel_1_3<HalVersion>::m_Threadpool(nullptr);
148
149template<typename HalVersion>
Kevin May42477c12020-03-26 13:34:14 +0000150template<typename TensorBindingCollection>
151void ArmnnPreparedModel_1_3<HalVersion>::DumpTensorsIfRequired(char const* tensorNamePrefix,
152 const TensorBindingCollection& tensorBindings)
153{
154 if (!m_RequestInputsAndOutputsDumpDir.empty())
155 {
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100156 const std::string requestName = std::to_string(m_NetworkId) + "_" + std::to_string(m_RequestCount) + ".dump";
Kevin May42477c12020-03-26 13:34:14 +0000157 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
158 {
159 DumpTensor(m_RequestInputsAndOutputsDumpDir,
160 requestName,
161 BuildTensorName(tensorNamePrefix, i),
162 tensorBindings[i].second);
163 }
164 }
165}
166
167template<typename HalVersion>
168ArmnnPreparedModel_1_3<HalVersion>::ArmnnPreparedModel_1_3(armnn::NetworkId networkId,
169 armnn::IRuntime* runtime,
170 const V1_3::Model& model,
171 const std::string& requestInputsAndOutputsDumpDir,
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100172 const bool gpuProfilingEnabled,
Finn Williamsd8fb5402021-05-19 20:52:00 +0100173 V1_3::Priority priority,
Finn Williamsca3a3e02021-06-11 15:04:02 +0100174 const bool asyncModelExecutionEnabled,
175 const unsigned int numberOfThreads)
Kevin May42477c12020-03-26 13:34:14 +0000176 : m_NetworkId(networkId)
177 , m_Runtime(runtime)
178 , m_Model(model)
179 , m_RequestCount(0)
180 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
181 , m_GpuProfilingEnabled(gpuProfilingEnabled)
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100182 , m_ModelPriority(priority)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100183 , m_AsyncModelExecutionEnabled(asyncModelExecutionEnabled)
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100184 , m_PreparedFromCache(false)
185{
186 // Enable profiling if required.
187 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
188
189 if (m_AsyncModelExecutionEnabled)
190 {
191 std::vector<std::shared_ptr<armnn::IWorkingMemHandle>> memHandles;
192 for (unsigned int i=0; i < numberOfThreads; ++i)
193 {
194 memHandles.emplace_back(m_Runtime->CreateWorkingMemHandle(networkId));
195 }
196
197 if (!m_Threadpool)
198 {
199 m_Threadpool = std::make_unique<armnn::Threadpool>(numberOfThreads, runtime, memHandles);
200 }
201 else
202 {
203 m_Threadpool->LoadMemHandles(memHandles);
204 }
205
206 m_WorkingMemHandle = memHandles.back();
207 }
208}
209
210template<typename HalVersion>
211ArmnnPreparedModel_1_3<HalVersion>::ArmnnPreparedModel_1_3(armnn::NetworkId networkId,
212 armnn::IRuntime* runtime,
213 const std::string& requestInputsAndOutputsDumpDir,
214 const bool gpuProfilingEnabled,
215 V1_3::Priority priority,
216 const bool asyncModelExecutionEnabled,
217 const unsigned int numberOfThreads,
218 const bool preparedFromCache)
219 : m_NetworkId(networkId)
220 , m_Runtime(runtime)
221 , m_RequestCount(0)
222 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
223 , m_GpuProfilingEnabled(gpuProfilingEnabled)
224 , m_ModelPriority(priority)
225 , m_AsyncModelExecutionEnabled(asyncModelExecutionEnabled)
226 , m_PreparedFromCache(preparedFromCache)
Kevin May42477c12020-03-26 13:34:14 +0000227{
228 // Enable profiling if required.
229 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100230
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100231 if (m_AsyncModelExecutionEnabled)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100232 {
Finn Williamsca3a3e02021-06-11 15:04:02 +0100233 std::vector<std::shared_ptr<armnn::IWorkingMemHandle>> memHandles;
Finn Williamsd27c13b2021-06-25 10:06:09 +0100234 for (unsigned int i=0; i < numberOfThreads; ++i)
Finn Williamsca3a3e02021-06-11 15:04:02 +0100235 {
236 memHandles.emplace_back(m_Runtime->CreateWorkingMemHandle(networkId));
237 }
238
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100239 if (!m_Threadpool)
240 {
241 m_Threadpool = std::make_unique<armnn::Threadpool>(numberOfThreads, runtime, memHandles);
242 }
243 else
244 {
245 m_Threadpool->LoadMemHandles(memHandles);
246 }
247
Finn Williamsca3a3e02021-06-11 15:04:02 +0100248 m_WorkingMemHandle = memHandles.back();
Finn Williamsd8fb5402021-05-19 20:52:00 +0100249 }
Kevin May42477c12020-03-26 13:34:14 +0000250}
251
252template<typename HalVersion>
253ArmnnPreparedModel_1_3<HalVersion>::~ArmnnPreparedModel_1_3()
254{
255 // Get a hold of the profiler used by this model.
256 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
257
258 // Unload the network associated with this model.
259 m_Runtime->UnloadNetwork(m_NetworkId);
260
Finn Williamsfdf2eae2021-07-08 13:07:19 +0100261 // Unload the network memhandles from the threadpool
262 if (m_AsyncModelExecutionEnabled)
263 {
264 m_Threadpool->UnloadMemHandles(m_NetworkId);
265 }
266
Kevin May42477c12020-03-26 13:34:14 +0000267 // Dump the profiling info to a file if required.
268 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId, profiler.get());
269}
270
271template<typename HalVersion>
272Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute(const V1_0::Request& request,
273 const ::android::sp<V1_0::IExecutionCallback>& callback)
274{
275 if (callback.get() == nullptr)
276 {
277 ALOGE("ArmnnPreparedModel_1_3::execute invalid callback passed");
278 return V1_0::ErrorStatus::INVALID_ARGUMENT;
279 }
280
281 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000282 std::vector<V1_2::OutputShape> outputShapes,
283 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000284 std::string callingFunction)
285 {
286 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
287 };
288
289
Sadik Armagan188675f2021-02-12 17:16:42 +0000290 return convertToV1_0(Execute(convertToV1_3(request), V1_2::MeasureTiming::NO, cb));
Kevin May42477c12020-03-26 13:34:14 +0000291}
292
293template<typename HalVersion>
294Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute_1_2(
295 const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000296 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000297 const sp<V1_2::IExecutionCallback>& callback)
298{
299 if (callback.get() == nullptr)
300 {
301 ALOGE("ArmnnPreparedModel_1_3::execute_1_2 invalid callback passed");
302 return V1_0::ErrorStatus::INVALID_ARGUMENT;
303 }
304
305 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000306 std::vector<V1_2::OutputShape> outputShapes,
307 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000308 std::string callingFunction)
309 {
310 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
311 };
312
313 return convertToV1_0(Execute(convertToV1_3(request), measureTiming, cb));
314}
315
316template<typename HalVersion>
317Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute_1_3(
318 const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000319 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000320 const V1_3::OptionalTimePoint&,
Kevin May352d8382020-03-31 15:03:42 +0100321 const V1_3::OptionalTimeoutDuration&,
Kevin May42477c12020-03-26 13:34:14 +0000322 const sp<V1_3::IExecutionCallback>& callback)
323{
324 if (callback.get() == nullptr)
325 {
326 ALOGE("ArmnnPreparedModel_1_3::execute_1_3 invalid callback passed");
327 return V1_3::ErrorStatus::INVALID_ARGUMENT;
328 }
329
330 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000331 std::vector<V1_2::OutputShape> outputShapes,
332 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000333 std::string callingFunction)
334 {
335 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
336 };
337
338 return Execute(request, measureTiming, cb);
339}
340
Sadik Armagand7be72e2020-04-23 12:56:05 +0100341/// This class is inspired by the sample implementation in Android named SampleFencedExecutionCallback.
342/// The original code is licensed under Apache-2.0 and can be found at the following link:
343/// https://android.googlesource.com/platform/frameworks/ml/+/master/nn/driver/sample/SampleDriver.h
344class ArmnnFencedExecutionCallback : public V1_3::IFencedExecutionCallback
345{
346public:
Sadik Armagan188675f2021-02-12 17:16:42 +0000347 ArmnnFencedExecutionCallback(V1_3::ErrorStatus errorStatus, V1_2::Timing timing, V1_2::Timing fenceTiming)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100348 : m_ErrorStatus(errorStatus), m_Timing(timing), m_FenceTiming(fenceTiming) {}
349 ~ArmnnFencedExecutionCallback() {}
350
351 Return<void> getExecutionInfo(getExecutionInfo_cb callback) override
352 {
353 callback(m_ErrorStatus, m_Timing, m_FenceTiming);
354 return Void();
355 }
356private:
357 V1_3::ErrorStatus m_ErrorStatus;
Sadik Armagan188675f2021-02-12 17:16:42 +0000358 V1_2::Timing m_Timing;
359 V1_2::Timing m_FenceTiming;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100360};
361
Kevin May42477c12020-03-26 13:34:14 +0000362template<typename HalVersion>
Sadik Armagand7be72e2020-04-23 12:56:05 +0100363Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeFenced(const V1_3::Request& request,
364 const hidl_vec<hidl_handle>& fenceWaitFor,
Sadik Armagan188675f2021-02-12 17:16:42 +0000365 V1_2::MeasureTiming measureTiming,
366 const V1_3::OptionalTimePoint& deadline,
367 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
368 const V1_3::OptionalTimeoutDuration&,
Kevin May42477c12020-03-26 13:34:14 +0000369 executeFenced_cb cb)
370{
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100371 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...)");
372 if (cb == nullptr)
373 {
374 ALOGE("ArmnnPreparedModel_1_3::executeFenced invalid callback passed");
Sadik Armagan188675f2021-02-12 17:16:42 +0000375 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100376 return Void();
377 }
378
Sadik Armagan188675f2021-02-12 17:16:42 +0000379 if (deadline.getDiscriminator() != V1_3::OptionalTimePoint::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100380 {
381 ALOGW("ArmnnPreparedModel_1_3::executeFenced parameter deadline is set but not supported.");
382 }
383
Sadik Armagan188675f2021-02-12 17:16:42 +0000384 if (loopTimeoutDuration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100385 {
386 ALOGW("ArmnnPreparedModel_1_3::executeFenced parameter loopTimeoutDuration is set but not supported.");
387 }
388
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100389 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model, /*allowUnspecifiedOutput=*/false))
Finn Williamsa4983ce2020-07-23 12:55:12 +0100390 {
391 ALOGV("ArmnnPreparedModel_1_3::executeFenced outputs must be specified for fenced execution ");
Sadik Armagan188675f2021-02-12 17:16:42 +0000392 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Finn Williamsa4983ce2020-07-23 12:55:12 +0100393 return Void();
394 }
395
Sadik Armagand7be72e2020-04-23 12:56:05 +0100396 ExecutionContext_1_3 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000397 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100398 {
399 ctx.measureTimings = measureTiming;
400 ctx.driverStart = Now();
401 }
402
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100403 if (!m_PreparedFromCache)
404 {
405 ALOGV("ArmnnPreparedModel_1_3::executeFenced(): %s", GetModelSummary(m_Model).c_str());
406 }
Sadik Armagand7be72e2020-04-23 12:56:05 +0100407 m_RequestCount++;
408
Sadik Armagand7be72e2020-04-23 12:56:05 +0100409 if (!m_RequestInputsAndOutputsDumpDir.empty())
410 {
411 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&cb));
412 }
413
414 // This code snippet is inspired by the sample implementation in Android named SampleDriver::executeFenced()
415 // function. The original code is licensed under Apache-2.0 and can be found at the following link:
416 // https://android.googlesource.com/platform/frameworks/ml/+/master/nn/driver/sample/SampleDriver.cpp
417 const auto fenceSize = fenceWaitFor.size();
418 for (unsigned int index = 0; index < fenceSize; ++index)
419 {
420 auto fenceNativeHandle = fenceWaitFor[index].getNativeHandle();
421 if (!fenceNativeHandle)
422 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000423 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100424 return Void();
425 }
426
427 if (sync_wait(fenceNativeHandle->data[0], -1) < 0)
428 {
429 ALOGE("ArmnnPreparedModel_1_3::executeFenced sync fence failed.");
Sadik Armagan188675f2021-02-12 17:16:42 +0000430 cb(V1_3::ErrorStatus::GENERAL_FAILURE, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100431 return Void();
432 }
433 }
434
435 TimePoint fenceExecutionStart;
Sadik Armagan188675f2021-02-12 17:16:42 +0000436 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100437 {
438 fenceExecutionStart = Now();
439 }
440
441 // map the memory pool into shared pointers
442 // use a shared memory pools vector on the heap, as it is passed to the request thread
443 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
444
445 // allocate the tensors on the heap, as they are passed to the request thread
446 auto inputs = std::make_shared<armnn::InputTensors>();
447 auto outputs = std::make_shared<armnn::OutputTensors>();
448
449 auto [status, outShapes, timings, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
450 if (status != V1_3::ErrorStatus::NONE)
451 {
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 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...) before ExecuteGraph");
457
458 // call it with nullCallback for now as we will report the error status from here..
Sadik Armagan188675f2021-02-12 17:16:42 +0000459 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Sadik Armagand7be72e2020-04-23 12:56:05 +0100460 CallbackContext_1_3 cbCtx;
461 cbCtx.callback = nullCallback;
462 cbCtx.ctx = ctx;
463
464 auto errorStatus = ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
465 if (errorStatus != V1_3::ErrorStatus::NONE)
466 {
467 cb(errorStatus, hidl_handle(nullptr), nullptr);
468 return Void();
469 }
470 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...) after ExecuteGraph");
471
Sadik Armagan188675f2021-02-12 17:16:42 +0000472 V1_2::Timing timing = g_NoTiming;
473 V1_2::Timing fenceTiming = g_NoTiming;
474 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100475 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100476 fenceTiming.timeOnDevice = MicrosecondsDuration(ctx.deviceEnd, ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100477 fenceTiming.timeInDriver = MicrosecondsDuration(ctx.driverEnd, fenceExecutionStart);
478 ALOGV("ArmnnPreparedModel_1_3::fenceFinishExecutionTiming - Device = %lu Driver = %lu",
Sadik Armagand7be72e2020-04-23 12:56:05 +0100479 fenceTiming.timeOnDevice, fenceTiming.timeInDriver);
480 }
481
482 sp<ArmnnFencedExecutionCallback> armnnFencedExecutionCallback =
Sadik Armagan188675f2021-02-12 17:16:42 +0000483 new ArmnnFencedExecutionCallback(V1_3::ErrorStatus::NONE, timing, fenceTiming);
484 cb(V1_3::ErrorStatus::NONE, hidl_handle(nullptr), armnnFencedExecutionCallback);
Kevin May42477c12020-03-26 13:34:14 +0000485 return Void();
486}
487
488template<typename HalVersion>
489Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForInputs(
490 armnn::InputTensors& inputs,
491 const V1_3::Request& request,
492 const std::vector<android::nn::RunTimePoolInfo>& memPools)
493{
494 inputs.reserve(request.inputs.size());
495 for (unsigned int i = 0; i < request.inputs.size(); i++)
496 {
497 const auto& inputArg = request.inputs[i];
498
Cathal Corbette27d4e82021-10-28 12:28:35 +0100499 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
500 // inputs (of type InputTensors) is composed of a vector of ConstTensors.
501 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
502 inputTensorInfo.SetConstant();
Kevin May42477c12020-03-26 13:34:14 +0000503 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
504
505 if (inputTensor.GetMemoryArea() == nullptr)
506 {
507 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
508 return V1_3::ErrorStatus::GENERAL_FAILURE;
509 }
510
511 inputs.emplace_back(i, inputTensor);
512 }
513
514 return V1_3::ErrorStatus::NONE;
515}
516
517template<typename HalVersion>
518Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForOutputs(
519 armnn::OutputTensors& outputs,
Sadik Armagan188675f2021-02-12 17:16:42 +0000520 std::vector<V1_2::OutputShape> &outputShapes,
Kevin May42477c12020-03-26 13:34:14 +0000521 const V1_3::Request& request,
522 const std::vector<android::nn::RunTimePoolInfo>& memPools)
523{
524 outputs.reserve(request.outputs.size());
525 for (unsigned int i = 0; i < request.outputs.size(); i++)
526 {
527 const auto& outputArg = request.outputs[i];
528
Finn Williamsa4983ce2020-07-23 12:55:12 +0100529 armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
Kevin May42477c12020-03-26 13:34:14 +0000530 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
531 if (outputTensor.GetMemoryArea() == nullptr)
532 {
533 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
534 return V1_3::ErrorStatus::GENERAL_FAILURE;
535 }
536
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100537 const size_t outputSize = outputTensorInfo.GetNumBytes();
538
Finn Williamsa4983ce2020-07-23 12:55:12 +0100539 unsigned int count = 0;
540 std::for_each(outputArg.dimensions.begin(), outputArg.dimensions.end(), [&](auto dim)
541 {
542 if (dim != 0)
543 {
544 outputTensorInfo.GetShape()[count] = dim;
545 }
546 else
547 {
548 outputTensorInfo.GetShape()[count] = outputArg.dimensions.size();
549 }
550
551 count++;
552 });
553
Finn Williamsa4983ce2020-07-23 12:55:12 +0100554 outputs.emplace_back(i, outputTensor);
555 outputShapes[i] = ComputeShape(outputTensorInfo);
556
557 if (outputArg.location.length < outputSize)
558 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100559 ALOGW("ArmnnPreparedModel_1_3::Execute failed outputArg.location.length (%s) < outputSize (%s)",
560 std::to_string(outputArg.location.length).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100561 outputShapes[i].isSufficient = false;
562 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
563 }
564
Sadik Armagan188675f2021-02-12 17:16:42 +0000565 size_t bufferSize = 0;
566#if !defined(ARMNN_ANDROID_S)
567 bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
Sadik Armagan188675f2021-02-12 17:16:42 +0000568#else
Kevin Maydc873f62021-06-14 11:21:11 +0100569 bufferSize = memPools.at(outputArg.location.poolIndex).getSize();
Sadik Armagan188675f2021-02-12 17:16:42 +0000570#endif
Kevin May42477c12020-03-26 13:34:14 +0000571 if (bufferSize < outputSize)
572 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100573 ALOGW("ArmnnPreparedModel_1_3::Execute failed bufferSize (%s) < outputSize (%s)",
574 std::to_string(bufferSize).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100575 outputShapes[i].isSufficient = false;
Kevin May42477c12020-03-26 13:34:14 +0000576 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
577 }
Kevin May42477c12020-03-26 13:34:14 +0000578 }
579
580 return V1_3::ErrorStatus::NONE;
581}
582
583template<typename HalVersion>
Sadik Armagan188675f2021-02-12 17:16:42 +0000584std::tuple<V1_3::ErrorStatus, hidl_vec<V1_2::OutputShape>, V1_2::Timing, std::string>
Kevin May42477c12020-03-26 13:34:14 +0000585 ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForIO(armnn::InputTensors& inputs,
586 armnn::OutputTensors& outputs,
587 std::vector<android::nn::RunTimePoolInfo>& memPools,
588 const V1_3::Request& request)
589{
Sadik Armagan188675f2021-02-12 17:16:42 +0000590#if !defined(ARMNN_ANDROID_S)
Kevin May42477c12020-03-26 13:34:14 +0000591 if (!setRunTimePoolInfosFromMemoryPools(&memPools, request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000592#else
593 if (!setRunTimePoolInfosFromMemoryPools(&memPools, uncheckedConvert(request.pools)))
594#endif
Kevin May42477c12020-03-26 13:34:14 +0000595 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000596 return {V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000597 }
598
599 // add the inputs and outputs with their data
600 try
601 {
602 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_3::ErrorStatus::NONE)
603 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000604 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000605 }
606
Sadik Armagan188675f2021-02-12 17:16:42 +0000607 std::vector<V1_2::OutputShape> outputShapes(request.outputs.size());
Kevin May42477c12020-03-26 13:34:14 +0000608
609 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
610 if (errorStatus != V1_3::ErrorStatus::NONE)
611 {
612 return {errorStatus, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
613 }
614 }
615 catch (armnn::Exception& e)
616 {
617 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000618 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000619 }
620 catch (std::exception& e)
621 {
622 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000623 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000624 }
625
626 return {V1_3::ErrorStatus::NONE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
627}
628
629template<typename HalVersion>
630template<typename CallbackContext>
631Return<void> ArmnnPreparedModel_1_3<HalVersion>::ExecuteSynchronously(const V1_3::Request& request,
632 CallbackContext cbCtx)
633{
Sadik Armagan188675f2021-02-12 17:16:42 +0000634 if (cbCtx.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000635 {
636 cbCtx.ctx.driverStart = Now();
637 }
638
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100639 if (!m_PreparedFromCache && !android::nn::validateRequest(convertToV1_3(request), m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000640 {
641 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
642 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
643 {},
644 g_NoTiming,
645 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
646 return Void();
647 }
648
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100649 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000650 {
651 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
652 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
653 {},
654 g_NoTiming,
655 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
Sadik Armaganef8a3932020-04-09 17:21:50 +0100656 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000657 }
658
659
660 // map the memory pool into shared pointers
661 // use a shared memory pools vector on the heap, as it is passed to the request thread
662 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
663
664 // allocate the tensors on the heap, as they are passed to the request thread
665 auto inputs = std::make_shared<armnn::InputTensors>();
666 auto outputs = std::make_shared<armnn::OutputTensors>();
667
668 auto [status, outputShapes, timing, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
669 if (status != V1_3::ErrorStatus::NONE)
670 {
671 cbCtx.callback(status, outputShapes, timing, message);
Sadik Armaganef8a3932020-04-09 17:21:50 +0100672 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000673 }
674
675 ALOGV("ArmnnPreparedModel_1_3::ExecuteSynchronously() before Execution");
676
677 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
678 return Void();
679}
680
681template<typename HalVersion>
682Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000683 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000684 executeSynchronously_cb cb)
685{
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100686 if (!m_PreparedFromCache)
687 {
688 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
689 }
Kevin May42477c12020-03-26 13:34:14 +0000690 m_RequestCount++;
691
692 if (cb == nullptr)
693 {
694 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously invalid callback passed");
695 return Void();
696 }
697
698 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000699 std::vector<V1_2::OutputShape> outputShapes,
700 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000701 std::string)
702 {
703 cb(convertToV1_0(errorStatus), outputShapes, timing);
704 };
705
706 CallbackContext_1_3 cbCtx;
707 cbCtx.callback = cbWrapper;
708 cbCtx.ctx.measureTimings = measureTiming;
709
710 ExecuteSynchronously(convertToV1_3(request), cbCtx);
711 return Void();
712}
713
714template<typename HalVersion>
Kevin May352d8382020-03-31 15:03:42 +0100715Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously_1_3(
716 const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000717 V1_2::MeasureTiming measureTiming,
Kevin May352d8382020-03-31 15:03:42 +0100718 const V1_3::OptionalTimePoint& deadline,
719 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
720 executeSynchronously_1_3_cb cb)
Kevin May42477c12020-03-26 13:34:14 +0000721{
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100722 if (!m_PreparedFromCache)
723 {
724 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously_1_3(): %s", GetModelSummary(m_Model).c_str());
725 }
Kevin May42477c12020-03-26 13:34:14 +0000726 m_RequestCount++;
727
728 if (cb == nullptr)
729 {
730 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid callback passed");
731 return Void();
732 }
733
Sadik Armagan188675f2021-02-12 17:16:42 +0000734 if (deadline.getDiscriminator() != V1_3::OptionalTimePoint::hidl_discriminator::none)
Kevin May42477c12020-03-26 13:34:14 +0000735 {
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100736 ALOGW("ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter deadline is set but not supported.");
Kevin May42477c12020-03-26 13:34:14 +0000737 }
738
Sadik Armagan188675f2021-02-12 17:16:42 +0000739 if (loopTimeoutDuration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100740 {
741 ALOGW(
742 "ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter loopTimeoutDuration is set but not supported.");
Kevin May352d8382020-03-31 15:03:42 +0100743 }
744
Kevin May42477c12020-03-26 13:34:14 +0000745 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000746 std::vector<V1_2::OutputShape> outputShapes,
747 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000748 std::string)
749 {
750 cb(errorStatus, outputShapes, timing);
751 };
752
753 CallbackContext_1_3 cbCtx;
754 cbCtx.callback = cbWrapper;
755 cbCtx.ctx.measureTimings = measureTiming;
756
757 ExecuteSynchronously(request, cbCtx);
758 return Void();
759}
760
761template<typename HalVersion>
762Return<void> ArmnnPreparedModel_1_3<HalVersion>::configureExecutionBurst(
763 const sp<V1_2::IBurstCallback>& callback,
764 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
765 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
766 V1_3::IPreparedModel::configureExecutionBurst_cb cb)
767{
768 ALOGV("ArmnnPreparedModel_1_3::configureExecutionBurst");
769 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
770 requestChannel,
771 resultChannel,
772 this);
773
774 if (burst == nullptr)
775 {
776 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
777 }
778 else
779 {
780 cb(V1_0::ErrorStatus::NONE, burst);
781 }
782 return Void();
783}
784
785template<typename HalVersion>
786template<typename CallbackContext>
Sadik Armagand7be72e2020-04-23 12:56:05 +0100787Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::ExecuteGraph(
Kevin May42477c12020-03-26 13:34:14 +0000788 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
789 armnn::InputTensors& inputTensors,
790 armnn::OutputTensors& outputTensors,
791 CallbackContext cb)
792{
793 ALOGV("ArmnnPreparedModel_1_3::ExecuteGraph(...)");
794
Kevin May42477c12020-03-26 13:34:14 +0000795 DumpTensorsIfRequired("Input", inputTensors);
796
Sadik Armagan188675f2021-02-12 17:16:42 +0000797 std::vector<V1_2::OutputShape> outputShapes(outputTensors.size());
Kevin May42477c12020-03-26 13:34:14 +0000798 for (unsigned int i = 0; i < outputTensors.size(); i++)
799 {
800 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
801 const armnn::Tensor outputTensor = outputTensorPair.second;
802 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
803
804 outputShapes[i] = ComputeShape(outputTensorInfo);
805 }
806
807 // run it
808 try
809 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000810 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000811 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100812 cb.ctx.deviceStart = Now();
Kevin May42477c12020-03-26 13:34:14 +0000813 }
Finn Williamsd8fb5402021-05-19 20:52:00 +0100814 armnn::Status status;
815 if (m_AsyncModelExecutionEnabled)
816 {
817 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled true");
818 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
819 }
820 else
821 {
822 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled false");
823 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
824 }
Kevin May42477c12020-03-26 13:34:14 +0000825
Sadik Armagan188675f2021-02-12 17:16:42 +0000826 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000827 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100828 cb.ctx.deviceEnd = Now();
Kevin May42477c12020-03-26 13:34:14 +0000829 }
830 if (status != armnn::Status::Success)
831 {
Finn Williamsd8fb5402021-05-19 20:52:00 +0100832 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph EnqueueWorkload failed");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100833 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
834 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000835 }
836 }
837 catch (armnn::Exception& e)
838 {
839 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
840 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100841 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000842 }
843 catch (std::exception& e)
844 {
845 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
846 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100847 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000848 }
849
850 CommitPools(*pMemPools);
851
852 DumpTensorsIfRequired("Output", outputTensors);
853
Sadik Armagan188675f2021-02-12 17:16:42 +0000854 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000855 {
Kevin May949a69e2020-04-24 10:21:40 +0100856 cb.ctx.driverEnd = Now();
Sadik Armagan188675f2021-02-12 17:16:42 +0000857 V1_2::Timing timing;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100858 timing.timeOnDevice = MicrosecondsDuration(cb.ctx.deviceEnd, cb.ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100859 timing.timeInDriver = MicrosecondsDuration(cb.ctx.driverEnd, cb.ctx.driverStart);
860 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
Kevin May42477c12020-03-26 13:34:14 +0000861 timing.timeInDriver);
862 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100863 } else
864 {
Kevin May42477c12020-03-26 13:34:14 +0000865 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
866 }
Sadik Armagand7be72e2020-04-23 12:56:05 +0100867 return V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000868}
869
Finn Williamsd8fb5402021-05-19 20:52:00 +0100870/// Schedule the graph prepared from the request for execution
871template<typename HalVersion>
872template<typename CallbackContext>
873void ArmnnPreparedModel_1_3<HalVersion>::ScheduleGraphForExecution(
874 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
875 std::shared_ptr<armnn::InputTensors>& inputTensors,
876 std::shared_ptr<armnn::OutputTensors>& outputTensors,
877 CallbackContext callbackContext,
878 armnn::QosExecPriority priority)
879{
880 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution(...)");
881
882 DumpTensorsIfRequired("Input", *inputTensors);
883
884 unsigned int outputTensorSize = outputTensors.get()->size();
885 std::vector<V1_2::OutputShape> outputShapes(outputTensorSize);
886 for (unsigned int i = 0; i < outputTensorSize; i++)
887 {
888 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors.get()->at(i);
889 const armnn::Tensor outputTensor = outputTensorPair.second;
890 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
891
892 outputShapes[i] = ComputeShape(outputTensorInfo);
893 }
894
895 auto tpCb = std::make_shared<
896 ArmnnThreadPoolCallback_1_3<CallbackContext_1_3>>(this,
897 pMemPools,
898 outputShapes,
899 inputTensors,
900 outputTensors,
901 callbackContext);
902
Finn Williamsca3a3e02021-06-11 15:04:02 +0100903 m_Threadpool->Schedule(m_NetworkId,
904 *tpCb->m_InputTensors,
905 *tpCb->m_OutputTensors,
906 priority,
907 tpCb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100908 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution end");
909}
910
Kevin May42477c12020-03-26 13:34:14 +0000911template<typename HalVersion>
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100912bool ArmnnPreparedModel_1_3<HalVersion>::ExecuteWithDummyInputs(unsigned int numInputs, unsigned int numOutputs)
Kevin May42477c12020-03-26 13:34:14 +0000913{
914 std::vector<std::vector<char>> storage;
915 armnn::InputTensors inputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100916 for (unsigned int i = 0; i < numInputs; i++)
Kevin May42477c12020-03-26 13:34:14 +0000917 {
Cathal Corbette27d4e82021-10-28 12:28:35 +0100918 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
919 // pInputTensors (of type InputTensors) is composed of a vector of ConstTensors.
920 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
921 inputTensorInfo.SetConstant();
922
Kevin May42477c12020-03-26 13:34:14 +0000923 storage.emplace_back(inputTensorInfo.GetNumBytes());
924 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
925
926 inputTensors.emplace_back(i, inputTensor);
927 }
928
929 armnn::OutputTensors outputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100930 for (unsigned int i = 0; i < numOutputs; i++)
Kevin May42477c12020-03-26 13:34:14 +0000931 {
932 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
933 storage.emplace_back(outputTensorInfo.GetNumBytes());
934 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
935
936 outputTensors.emplace_back(i, outputTensor);
937 }
938
Sadik Armagan188675f2021-02-12 17:16:42 +0000939 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Kevin May42477c12020-03-26 13:34:14 +0000940 CallbackContext_1_3 callbackContext;
941 callbackContext.callback = nullCallback;
Sadik Armagan188675f2021-02-12 17:16:42 +0000942 callbackContext.ctx.measureTimings = V1_2::MeasureTiming::NO;
Kevin May42477c12020-03-26 13:34:14 +0000943 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
Sadik Armagand7be72e2020-04-23 12:56:05 +0100944
945 auto errorStatus = ExecuteGraph(memPools,
946 inputTensors,
947 outputTensors,
948 callbackContext);
949 return errorStatus == V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000950}
951
952template<typename HalVersion>
953Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::Execute(const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000954 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000955 CallbackAsync_1_3 callback)
956{
957 ExecutionContext_1_3 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000958 if (measureTiming == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000959 {
960 ctx.measureTimings = measureTiming;
961 ctx.driverStart = Now();
962 }
963
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100964 if (!m_PreparedFromCache)
965 {
966 ALOGV("ArmnnPreparedModel_1_3::execute(): %s", GetModelSummary(m_Model).c_str());
967 }
Kevin May42477c12020-03-26 13:34:14 +0000968 m_RequestCount++;
969
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100970 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000971 {
972 callback(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute");
973 return V1_3::ErrorStatus::INVALID_ARGUMENT;
974 }
975
976 if (!m_RequestInputsAndOutputsDumpDir.empty())
977 {
978 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
979 }
980
981 // map the memory pool into shared pointers
982 // use a shared memory pools vector on the heap, as it is passed to the request thread
983 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
984
985 // allocate the tensors on the heap, as they are passed to the request thread
986 auto inputTensors = std::make_shared<armnn::InputTensors>();
987 auto outputTensors = std::make_shared<armnn::OutputTensors>();
988
989 auto [status, outShapes, timing, message] = PrepareMemoryForIO(*inputTensors, *outputTensors,
990 *memPools, request);
991 if (status != V1_3::ErrorStatus::NONE)
992 {
993 callback(status, outShapes, timing, message);
994 }
995
996 switch(status)
997 {
998 case V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
999 return V1_3::ErrorStatus::NONE;
1000 case V1_3::ErrorStatus::GENERAL_FAILURE:
1001 return V1_3::ErrorStatus::GENERAL_FAILURE;
Sadik Armagana07d2752021-05-12 20:33:58 +01001002 case V1_3::ErrorStatus::INVALID_ARGUMENT:
1003 return V1_3::ErrorStatus::INVALID_ARGUMENT;
Kevin May42477c12020-03-26 13:34:14 +00001004 default:
1005 {}
1006 }
Kevin May42477c12020-03-26 13:34:14 +00001007 CallbackContext_1_3 cb;
1008 cb.callback = callback;
1009 cb.ctx = ctx;
Finn Williamsd8fb5402021-05-19 20:52:00 +01001010
1011
1012 enum class QosExecPriority
1013 {
1014 Low = 0,
1015 Medium = 1,
1016 High = 2
1017 };
1018
1019
1020 if (m_AsyncModelExecutionEnabled)
1021 {
1022 armnn::QosExecPriority priority;
1023
1024 switch (GetModelPriority()) {
1025 case V1_3::Priority::LOW:
1026 priority = armnn::QosExecPriority::Low;
1027 break;
1028 case V1_3::Priority::MEDIUM:
1029 priority = armnn::QosExecPriority::Medium;
1030 break;
1031 case V1_3::Priority::HIGH:
1032 priority = armnn::QosExecPriority::High;
1033 break;
1034 default:
1035 priority = armnn::QosExecPriority::Medium;
1036
1037 }
1038
1039 ALOGV("ArmnnPreparedModel_1_3::execute(...) before ScheduleGraphForExecution");
1040 ScheduleGraphForExecution(memPools, inputTensors, outputTensors, cb, priority);
1041 ALOGV("ArmnnPreparedModel_1_3::execute(...) after ScheduleGraphForExecution");
1042 return V1_3::ErrorStatus::NONE;
1043 }
1044
1045 ALOGV("ArmnnPreparedModel_1_3::execute(...) before PostMsg");
1046 // post the request for asynchronous execution
Kevin May42477c12020-03-26 13:34:14 +00001047 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
1048 ALOGV("ArmnnPreparedModel_1_3::execute(...) after PostMsg");
1049 return V1_3::ErrorStatus::NONE;
1050}
1051
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +01001052template<typename HalVersion>
1053V1_3::Priority ArmnnPreparedModel_1_3<HalVersion>::GetModelPriority()
1054{
1055 return m_ModelPriority;
1056}
1057
Finn Williamsd8fb5402021-05-19 20:52:00 +01001058template<typename HalVersion>
1059template <typename CallbackContext>
1060void ArmnnPreparedModel_1_3<HalVersion>::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify(
1061 armnn::Status status, armnn::InferenceTimingPair timeTaken)
1062{
1063 ALOGV("ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify");
1064 CommitPools(*m_MemPools);
1065
1066 m_Model->DumpTensorsIfRequired("Output", *m_OutputTensors);
1067
1068 if (status != armnn::Status::Success)
1069 {
1070 ALOGW("ArmnnThreadPoolCallback_1_3::Notify EnqueueWorkload failed");
1071 m_CallbackContext.callback(V1_3::ErrorStatus::GENERAL_FAILURE,
1072 {},
1073 g_NoTiming,
1074 "ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3");
1075 return;
1076 }
1077
1078 if (m_CallbackContext.ctx.measureTimings == V1_2::MeasureTiming::YES)
1079 {
1080 m_CallbackContext.ctx.deviceStart = timeTaken.first;
1081 m_CallbackContext.ctx.deviceEnd = timeTaken.second;
1082 m_CallbackContext.ctx.driverEnd = std::chrono::steady_clock::now();
1083 V1_2::Timing timing;
1084 timing.timeOnDevice = MicrosecondsDuration(m_CallbackContext.ctx.deviceEnd, m_CallbackContext.ctx.deviceStart);
1085 timing.timeInDriver = MicrosecondsDuration(m_CallbackContext.ctx.driverEnd, m_CallbackContext.ctx.driverStart);
1086 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
1087 timing.timeInDriver);
1088 m_CallbackContext.callback(
1089 V1_3::ErrorStatus::NONE, m_OutputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
1090 } else
1091 {
1092 m_CallbackContext.callback(
1093 V1_3::ErrorStatus::NONE, m_OutputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
1094 }
1095 return;
1096}
1097
Kevin May42477c12020-03-26 13:34:14 +00001098#ifdef ARMNN_ANDROID_NN_V1_3
1099template class ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>;
Sadik Armagand7be72e2020-04-23 12:56:05 +01001100template Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ExecuteGraph<CallbackContext_1_3>(
Kevin May42477c12020-03-26 13:34:14 +00001101 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1102 armnn::InputTensors& pInputTensors,
1103 armnn::OutputTensors& pOutputTensors,
1104 CallbackContext_1_3 cb);
Finn Williamsd8fb5402021-05-19 20:52:00 +01001105
1106template void ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ScheduleGraphForExecution<CallbackContext_1_3>(
1107 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1108 std::shared_ptr<armnn::InputTensors>& inputTensors,
1109 std::shared_ptr<armnn::OutputTensors>& outputTensors,
1110 CallbackContext_1_3 callbackContext,
1111 armnn::QosExecPriority priority);
Kevin May42477c12020-03-26 13:34:14 +00001112#endif
1113
1114} // namespace armnn_driver