blob: e963d4e4377e7255ff062721eff036db1e992c7f [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
499 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
500 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
501
502 if (inputTensor.GetMemoryArea() == nullptr)
503 {
504 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
505 return V1_3::ErrorStatus::GENERAL_FAILURE;
506 }
507
508 inputs.emplace_back(i, inputTensor);
509 }
510
511 return V1_3::ErrorStatus::NONE;
512}
513
514template<typename HalVersion>
515Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForOutputs(
516 armnn::OutputTensors& outputs,
Sadik Armagan188675f2021-02-12 17:16:42 +0000517 std::vector<V1_2::OutputShape> &outputShapes,
Kevin May42477c12020-03-26 13:34:14 +0000518 const V1_3::Request& request,
519 const std::vector<android::nn::RunTimePoolInfo>& memPools)
520{
521 outputs.reserve(request.outputs.size());
522 for (unsigned int i = 0; i < request.outputs.size(); i++)
523 {
524 const auto& outputArg = request.outputs[i];
525
Finn Williamsa4983ce2020-07-23 12:55:12 +0100526 armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
Kevin May42477c12020-03-26 13:34:14 +0000527 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
528 if (outputTensor.GetMemoryArea() == nullptr)
529 {
530 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
531 return V1_3::ErrorStatus::GENERAL_FAILURE;
532 }
533
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100534 const size_t outputSize = outputTensorInfo.GetNumBytes();
535
Finn Williamsa4983ce2020-07-23 12:55:12 +0100536 unsigned int count = 0;
537 std::for_each(outputArg.dimensions.begin(), outputArg.dimensions.end(), [&](auto dim)
538 {
539 if (dim != 0)
540 {
541 outputTensorInfo.GetShape()[count] = dim;
542 }
543 else
544 {
545 outputTensorInfo.GetShape()[count] = outputArg.dimensions.size();
546 }
547
548 count++;
549 });
550
Finn Williamsa4983ce2020-07-23 12:55:12 +0100551 outputs.emplace_back(i, outputTensor);
552 outputShapes[i] = ComputeShape(outputTensorInfo);
553
554 if (outputArg.location.length < outputSize)
555 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100556 ALOGW("ArmnnPreparedModel_1_3::Execute failed outputArg.location.length (%s) < outputSize (%s)",
557 std::to_string(outputArg.location.length).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100558 outputShapes[i].isSufficient = false;
559 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
560 }
561
Sadik Armagan188675f2021-02-12 17:16:42 +0000562 size_t bufferSize = 0;
563#if !defined(ARMNN_ANDROID_S)
564 bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
Sadik Armagan188675f2021-02-12 17:16:42 +0000565#else
Kevin Maydc873f62021-06-14 11:21:11 +0100566 bufferSize = memPools.at(outputArg.location.poolIndex).getSize();
Sadik Armagan188675f2021-02-12 17:16:42 +0000567#endif
Kevin May42477c12020-03-26 13:34:14 +0000568 if (bufferSize < outputSize)
569 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100570 ALOGW("ArmnnPreparedModel_1_3::Execute failed bufferSize (%s) < outputSize (%s)",
571 std::to_string(bufferSize).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100572 outputShapes[i].isSufficient = false;
Kevin May42477c12020-03-26 13:34:14 +0000573 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
574 }
Kevin May42477c12020-03-26 13:34:14 +0000575 }
576
577 return V1_3::ErrorStatus::NONE;
578}
579
580template<typename HalVersion>
Sadik Armagan188675f2021-02-12 17:16:42 +0000581std::tuple<V1_3::ErrorStatus, hidl_vec<V1_2::OutputShape>, V1_2::Timing, std::string>
Kevin May42477c12020-03-26 13:34:14 +0000582 ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForIO(armnn::InputTensors& inputs,
583 armnn::OutputTensors& outputs,
584 std::vector<android::nn::RunTimePoolInfo>& memPools,
585 const V1_3::Request& request)
586{
Sadik Armagan188675f2021-02-12 17:16:42 +0000587#if !defined(ARMNN_ANDROID_S)
Kevin May42477c12020-03-26 13:34:14 +0000588 if (!setRunTimePoolInfosFromMemoryPools(&memPools, request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000589#else
590 if (!setRunTimePoolInfosFromMemoryPools(&memPools, uncheckedConvert(request.pools)))
591#endif
Kevin May42477c12020-03-26 13:34:14 +0000592 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000593 return {V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000594 }
595
596 // add the inputs and outputs with their data
597 try
598 {
599 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_3::ErrorStatus::NONE)
600 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000601 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000602 }
603
Sadik Armagan188675f2021-02-12 17:16:42 +0000604 std::vector<V1_2::OutputShape> outputShapes(request.outputs.size());
Kevin May42477c12020-03-26 13:34:14 +0000605
606 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
607 if (errorStatus != V1_3::ErrorStatus::NONE)
608 {
609 return {errorStatus, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
610 }
611 }
612 catch (armnn::Exception& e)
613 {
614 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000615 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000616 }
617 catch (std::exception& e)
618 {
619 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000620 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000621 }
622
623 return {V1_3::ErrorStatus::NONE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
624}
625
626template<typename HalVersion>
627template<typename CallbackContext>
628Return<void> ArmnnPreparedModel_1_3<HalVersion>::ExecuteSynchronously(const V1_3::Request& request,
629 CallbackContext cbCtx)
630{
Sadik Armagan188675f2021-02-12 17:16:42 +0000631 if (cbCtx.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000632 {
633 cbCtx.ctx.driverStart = Now();
634 }
635
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100636 if (!m_PreparedFromCache && !android::nn::validateRequest(convertToV1_3(request), m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000637 {
638 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
639 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
640 {},
641 g_NoTiming,
642 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
643 return Void();
644 }
645
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100646 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000647 {
648 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
649 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
650 {},
651 g_NoTiming,
652 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
Sadik Armaganef8a3932020-04-09 17:21:50 +0100653 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000654 }
655
656
657 // map the memory pool into shared pointers
658 // use a shared memory pools vector on the heap, as it is passed to the request thread
659 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
660
661 // allocate the tensors on the heap, as they are passed to the request thread
662 auto inputs = std::make_shared<armnn::InputTensors>();
663 auto outputs = std::make_shared<armnn::OutputTensors>();
664
665 auto [status, outputShapes, timing, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
666 if (status != V1_3::ErrorStatus::NONE)
667 {
668 cbCtx.callback(status, outputShapes, timing, message);
Sadik Armaganef8a3932020-04-09 17:21:50 +0100669 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000670 }
671
672 ALOGV("ArmnnPreparedModel_1_3::ExecuteSynchronously() before Execution");
673
674 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
675 return Void();
676}
677
678template<typename HalVersion>
679Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000680 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000681 executeSynchronously_cb cb)
682{
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100683 if (!m_PreparedFromCache)
684 {
685 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
686 }
Kevin May42477c12020-03-26 13:34:14 +0000687 m_RequestCount++;
688
689 if (cb == nullptr)
690 {
691 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously invalid callback passed");
692 return Void();
693 }
694
695 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000696 std::vector<V1_2::OutputShape> outputShapes,
697 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000698 std::string)
699 {
700 cb(convertToV1_0(errorStatus), outputShapes, timing);
701 };
702
703 CallbackContext_1_3 cbCtx;
704 cbCtx.callback = cbWrapper;
705 cbCtx.ctx.measureTimings = measureTiming;
706
707 ExecuteSynchronously(convertToV1_3(request), cbCtx);
708 return Void();
709}
710
711template<typename HalVersion>
Kevin May352d8382020-03-31 15:03:42 +0100712Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously_1_3(
713 const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000714 V1_2::MeasureTiming measureTiming,
Kevin May352d8382020-03-31 15:03:42 +0100715 const V1_3::OptionalTimePoint& deadline,
716 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
717 executeSynchronously_1_3_cb cb)
Kevin May42477c12020-03-26 13:34:14 +0000718{
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100719 if (!m_PreparedFromCache)
720 {
721 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously_1_3(): %s", GetModelSummary(m_Model).c_str());
722 }
Kevin May42477c12020-03-26 13:34:14 +0000723 m_RequestCount++;
724
725 if (cb == nullptr)
726 {
727 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid callback passed");
728 return Void();
729 }
730
Sadik Armagan188675f2021-02-12 17:16:42 +0000731 if (deadline.getDiscriminator() != V1_3::OptionalTimePoint::hidl_discriminator::none)
Kevin May42477c12020-03-26 13:34:14 +0000732 {
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100733 ALOGW("ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter deadline is set but not supported.");
Kevin May42477c12020-03-26 13:34:14 +0000734 }
735
Sadik Armagan188675f2021-02-12 17:16:42 +0000736 if (loopTimeoutDuration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100737 {
738 ALOGW(
739 "ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter loopTimeoutDuration is set but not supported.");
Kevin May352d8382020-03-31 15:03:42 +0100740 }
741
Kevin May42477c12020-03-26 13:34:14 +0000742 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000743 std::vector<V1_2::OutputShape> outputShapes,
744 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000745 std::string)
746 {
747 cb(errorStatus, outputShapes, timing);
748 };
749
750 CallbackContext_1_3 cbCtx;
751 cbCtx.callback = cbWrapper;
752 cbCtx.ctx.measureTimings = measureTiming;
753
754 ExecuteSynchronously(request, cbCtx);
755 return Void();
756}
757
758template<typename HalVersion>
759Return<void> ArmnnPreparedModel_1_3<HalVersion>::configureExecutionBurst(
760 const sp<V1_2::IBurstCallback>& callback,
761 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
762 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
763 V1_3::IPreparedModel::configureExecutionBurst_cb cb)
764{
765 ALOGV("ArmnnPreparedModel_1_3::configureExecutionBurst");
766 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
767 requestChannel,
768 resultChannel,
769 this);
770
771 if (burst == nullptr)
772 {
773 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
774 }
775 else
776 {
777 cb(V1_0::ErrorStatus::NONE, burst);
778 }
779 return Void();
780}
781
782template<typename HalVersion>
783template<typename CallbackContext>
Sadik Armagand7be72e2020-04-23 12:56:05 +0100784Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::ExecuteGraph(
Kevin May42477c12020-03-26 13:34:14 +0000785 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
786 armnn::InputTensors& inputTensors,
787 armnn::OutputTensors& outputTensors,
788 CallbackContext cb)
789{
790 ALOGV("ArmnnPreparedModel_1_3::ExecuteGraph(...)");
791
Kevin May42477c12020-03-26 13:34:14 +0000792 DumpTensorsIfRequired("Input", inputTensors);
793
Sadik Armagan188675f2021-02-12 17:16:42 +0000794 std::vector<V1_2::OutputShape> outputShapes(outputTensors.size());
Kevin May42477c12020-03-26 13:34:14 +0000795 for (unsigned int i = 0; i < outputTensors.size(); i++)
796 {
797 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
798 const armnn::Tensor outputTensor = outputTensorPair.second;
799 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
800
801 outputShapes[i] = ComputeShape(outputTensorInfo);
802 }
803
804 // run it
805 try
806 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000807 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000808 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100809 cb.ctx.deviceStart = Now();
Kevin May42477c12020-03-26 13:34:14 +0000810 }
Finn Williamsd8fb5402021-05-19 20:52:00 +0100811 armnn::Status status;
812 if (m_AsyncModelExecutionEnabled)
813 {
814 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled true");
815 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
816 }
817 else
818 {
819 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled false");
820 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
821 }
Kevin May42477c12020-03-26 13:34:14 +0000822
Sadik Armagan188675f2021-02-12 17:16:42 +0000823 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000824 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100825 cb.ctx.deviceEnd = Now();
Kevin May42477c12020-03-26 13:34:14 +0000826 }
827 if (status != armnn::Status::Success)
828 {
Finn Williamsd8fb5402021-05-19 20:52:00 +0100829 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph EnqueueWorkload failed");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100830 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
831 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000832 }
833 }
834 catch (armnn::Exception& e)
835 {
836 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
837 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100838 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000839 }
840 catch (std::exception& e)
841 {
842 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
843 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100844 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000845 }
846
847 CommitPools(*pMemPools);
848
849 DumpTensorsIfRequired("Output", outputTensors);
850
Sadik Armagan188675f2021-02-12 17:16:42 +0000851 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000852 {
Kevin May949a69e2020-04-24 10:21:40 +0100853 cb.ctx.driverEnd = Now();
Sadik Armagan188675f2021-02-12 17:16:42 +0000854 V1_2::Timing timing;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100855 timing.timeOnDevice = MicrosecondsDuration(cb.ctx.deviceEnd, cb.ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100856 timing.timeInDriver = MicrosecondsDuration(cb.ctx.driverEnd, cb.ctx.driverStart);
857 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
Kevin May42477c12020-03-26 13:34:14 +0000858 timing.timeInDriver);
859 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100860 } else
861 {
Kevin May42477c12020-03-26 13:34:14 +0000862 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
863 }
Sadik Armagand7be72e2020-04-23 12:56:05 +0100864 return V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000865}
866
Finn Williamsd8fb5402021-05-19 20:52:00 +0100867/// Schedule the graph prepared from the request for execution
868template<typename HalVersion>
869template<typename CallbackContext>
870void ArmnnPreparedModel_1_3<HalVersion>::ScheduleGraphForExecution(
871 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
872 std::shared_ptr<armnn::InputTensors>& inputTensors,
873 std::shared_ptr<armnn::OutputTensors>& outputTensors,
874 CallbackContext callbackContext,
875 armnn::QosExecPriority priority)
876{
877 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution(...)");
878
879 DumpTensorsIfRequired("Input", *inputTensors);
880
881 unsigned int outputTensorSize = outputTensors.get()->size();
882 std::vector<V1_2::OutputShape> outputShapes(outputTensorSize);
883 for (unsigned int i = 0; i < outputTensorSize; i++)
884 {
885 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors.get()->at(i);
886 const armnn::Tensor outputTensor = outputTensorPair.second;
887 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
888
889 outputShapes[i] = ComputeShape(outputTensorInfo);
890 }
891
892 auto tpCb = std::make_shared<
893 ArmnnThreadPoolCallback_1_3<CallbackContext_1_3>>(this,
894 pMemPools,
895 outputShapes,
896 inputTensors,
897 outputTensors,
898 callbackContext);
899
Finn Williamsca3a3e02021-06-11 15:04:02 +0100900 m_Threadpool->Schedule(m_NetworkId,
901 *tpCb->m_InputTensors,
902 *tpCb->m_OutputTensors,
903 priority,
904 tpCb);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100905 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution end");
906}
907
Kevin May42477c12020-03-26 13:34:14 +0000908template<typename HalVersion>
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100909bool ArmnnPreparedModel_1_3<HalVersion>::ExecuteWithDummyInputs(unsigned int numInputs, unsigned int numOutputs)
Kevin May42477c12020-03-26 13:34:14 +0000910{
911 std::vector<std::vector<char>> storage;
912 armnn::InputTensors inputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100913 for (unsigned int i = 0; i < numInputs; i++)
Kevin May42477c12020-03-26 13:34:14 +0000914 {
915 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
916 storage.emplace_back(inputTensorInfo.GetNumBytes());
917 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
918
919 inputTensors.emplace_back(i, inputTensor);
920 }
921
922 armnn::OutputTensors outputTensors;
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100923 for (unsigned int i = 0; i < numOutputs; i++)
Kevin May42477c12020-03-26 13:34:14 +0000924 {
925 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
926 storage.emplace_back(outputTensorInfo.GetNumBytes());
927 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
928
929 outputTensors.emplace_back(i, outputTensor);
930 }
931
Sadik Armagan188675f2021-02-12 17:16:42 +0000932 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Kevin May42477c12020-03-26 13:34:14 +0000933 CallbackContext_1_3 callbackContext;
934 callbackContext.callback = nullCallback;
Sadik Armagan188675f2021-02-12 17:16:42 +0000935 callbackContext.ctx.measureTimings = V1_2::MeasureTiming::NO;
Kevin May42477c12020-03-26 13:34:14 +0000936 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
Sadik Armagand7be72e2020-04-23 12:56:05 +0100937
938 auto errorStatus = ExecuteGraph(memPools,
939 inputTensors,
940 outputTensors,
941 callbackContext);
942 return errorStatus == V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000943}
944
945template<typename HalVersion>
946Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::Execute(const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000947 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000948 CallbackAsync_1_3 callback)
949{
950 ExecutionContext_1_3 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000951 if (measureTiming == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000952 {
953 ctx.measureTimings = measureTiming;
954 ctx.driverStart = Now();
955 }
956
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100957 if (!m_PreparedFromCache)
958 {
959 ALOGV("ArmnnPreparedModel_1_3::execute(): %s", GetModelSummary(m_Model).c_str());
960 }
Kevin May42477c12020-03-26 13:34:14 +0000961 m_RequestCount++;
962
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100963 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000964 {
965 callback(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute");
966 return V1_3::ErrorStatus::INVALID_ARGUMENT;
967 }
968
969 if (!m_RequestInputsAndOutputsDumpDir.empty())
970 {
971 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
972 }
973
974 // map the memory pool into shared pointers
975 // use a shared memory pools vector on the heap, as it is passed to the request thread
976 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
977
978 // allocate the tensors on the heap, as they are passed to the request thread
979 auto inputTensors = std::make_shared<armnn::InputTensors>();
980 auto outputTensors = std::make_shared<armnn::OutputTensors>();
981
982 auto [status, outShapes, timing, message] = PrepareMemoryForIO(*inputTensors, *outputTensors,
983 *memPools, request);
984 if (status != V1_3::ErrorStatus::NONE)
985 {
986 callback(status, outShapes, timing, message);
987 }
988
989 switch(status)
990 {
991 case V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
992 return V1_3::ErrorStatus::NONE;
993 case V1_3::ErrorStatus::GENERAL_FAILURE:
994 return V1_3::ErrorStatus::GENERAL_FAILURE;
Sadik Armagana07d2752021-05-12 20:33:58 +0100995 case V1_3::ErrorStatus::INVALID_ARGUMENT:
996 return V1_3::ErrorStatus::INVALID_ARGUMENT;
Kevin May42477c12020-03-26 13:34:14 +0000997 default:
998 {}
999 }
Kevin May42477c12020-03-26 13:34:14 +00001000 CallbackContext_1_3 cb;
1001 cb.callback = callback;
1002 cb.ctx = ctx;
Finn Williamsd8fb5402021-05-19 20:52:00 +01001003
1004
1005 enum class QosExecPriority
1006 {
1007 Low = 0,
1008 Medium = 1,
1009 High = 2
1010 };
1011
1012
1013 if (m_AsyncModelExecutionEnabled)
1014 {
1015 armnn::QosExecPriority priority;
1016
1017 switch (GetModelPriority()) {
1018 case V1_3::Priority::LOW:
1019 priority = armnn::QosExecPriority::Low;
1020 break;
1021 case V1_3::Priority::MEDIUM:
1022 priority = armnn::QosExecPriority::Medium;
1023 break;
1024 case V1_3::Priority::HIGH:
1025 priority = armnn::QosExecPriority::High;
1026 break;
1027 default:
1028 priority = armnn::QosExecPriority::Medium;
1029
1030 }
1031
1032 ALOGV("ArmnnPreparedModel_1_3::execute(...) before ScheduleGraphForExecution");
1033 ScheduleGraphForExecution(memPools, inputTensors, outputTensors, cb, priority);
1034 ALOGV("ArmnnPreparedModel_1_3::execute(...) after ScheduleGraphForExecution");
1035 return V1_3::ErrorStatus::NONE;
1036 }
1037
1038 ALOGV("ArmnnPreparedModel_1_3::execute(...) before PostMsg");
1039 // post the request for asynchronous execution
Kevin May42477c12020-03-26 13:34:14 +00001040 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
1041 ALOGV("ArmnnPreparedModel_1_3::execute(...) after PostMsg");
1042 return V1_3::ErrorStatus::NONE;
1043}
1044
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +01001045template<typename HalVersion>
1046V1_3::Priority ArmnnPreparedModel_1_3<HalVersion>::GetModelPriority()
1047{
1048 return m_ModelPriority;
1049}
1050
Finn Williamsd8fb5402021-05-19 20:52:00 +01001051template<typename HalVersion>
1052template <typename CallbackContext>
1053void ArmnnPreparedModel_1_3<HalVersion>::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify(
1054 armnn::Status status, armnn::InferenceTimingPair timeTaken)
1055{
1056 ALOGV("ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify");
1057 CommitPools(*m_MemPools);
1058
1059 m_Model->DumpTensorsIfRequired("Output", *m_OutputTensors);
1060
1061 if (status != armnn::Status::Success)
1062 {
1063 ALOGW("ArmnnThreadPoolCallback_1_3::Notify EnqueueWorkload failed");
1064 m_CallbackContext.callback(V1_3::ErrorStatus::GENERAL_FAILURE,
1065 {},
1066 g_NoTiming,
1067 "ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3");
1068 return;
1069 }
1070
1071 if (m_CallbackContext.ctx.measureTimings == V1_2::MeasureTiming::YES)
1072 {
1073 m_CallbackContext.ctx.deviceStart = timeTaken.first;
1074 m_CallbackContext.ctx.deviceEnd = timeTaken.second;
1075 m_CallbackContext.ctx.driverEnd = std::chrono::steady_clock::now();
1076 V1_2::Timing timing;
1077 timing.timeOnDevice = MicrosecondsDuration(m_CallbackContext.ctx.deviceEnd, m_CallbackContext.ctx.deviceStart);
1078 timing.timeInDriver = MicrosecondsDuration(m_CallbackContext.ctx.driverEnd, m_CallbackContext.ctx.driverStart);
1079 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
1080 timing.timeInDriver);
1081 m_CallbackContext.callback(
1082 V1_3::ErrorStatus::NONE, m_OutputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
1083 } else
1084 {
1085 m_CallbackContext.callback(
1086 V1_3::ErrorStatus::NONE, m_OutputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
1087 }
1088 return;
1089}
1090
Kevin May42477c12020-03-26 13:34:14 +00001091#ifdef ARMNN_ANDROID_NN_V1_3
1092template class ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>;
Sadik Armagand7be72e2020-04-23 12:56:05 +01001093template Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ExecuteGraph<CallbackContext_1_3>(
Kevin May42477c12020-03-26 13:34:14 +00001094 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1095 armnn::InputTensors& pInputTensors,
1096 armnn::OutputTensors& pOutputTensors,
1097 CallbackContext_1_3 cb);
Finn Williamsd8fb5402021-05-19 20:52:00 +01001098
1099template void ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ScheduleGraphForExecution<CallbackContext_1_3>(
1100 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1101 std::shared_ptr<armnn::InputTensors>& inputTensors,
1102 std::shared_ptr<armnn::OutputTensors>& outputTensors,
1103 CallbackContext_1_3 callbackContext,
1104 armnn::QosExecPriority priority);
Kevin May42477c12020-03-26 13:34:14 +00001105#endif
1106
1107} // namespace armnn_driver