blob: 7dc692fb7830b75aa2be78ae2df48d9261f7eaac [file] [log] [blame]
Kevin May42477c12020-03-26 13:34:14 +00001//
Renato Grottesi77a0fb02023-05-08 12:55:03 +00002// Copyright © 2020-2023 Arm Ltd and Contributors. All rights reserved.
Kevin May42477c12020-03-26 13:34:14 +00003// SPDX-License-Identifier: MIT
4//
Sadik Armagand7be72e2020-04-23 12:56:05 +01005// Note: the ArmnnFencedExecutionCallback and code snippet in the executeFenced() function
6// in this file is based on Android code
7// under the Apache 2.0 license. See comments below for details.
8//
Kevin May42477c12020-03-26 13:34:14 +00009
10#define LOG_TAG "ArmnnDriver"
11
12#include "ArmnnPreparedModel_1_3.hpp"
13#include "Utils.hpp"
14
Renato Grottesi77a0fb02023-05-08 12:55:03 +000015#include <armnn/Types.hpp>
16
Kevin May42477c12020-03-26 13:34:14 +000017#include <Utils.h>
Sadik Armagand7be72e2020-04-23 12:56:05 +010018#include <android/sync.h>
Kevin May42477c12020-03-26 13:34:14 +000019#include <log/log.h>
20#include <OperationsUtils.h>
21#include <ExecutionBurstServer.h>
22#include <ValidateHal.h>
23
Renato Grottesi77a0fb02023-05-08 12:55:03 +000024#include <chrono>
Kevin May42477c12020-03-26 13:34:14 +000025#include <cinttypes>
26
Renato Grottesi77a0fb02023-05-08 12:55:03 +000027#ifdef ARMNN_ANDROID_S
28#include <LegacyUtils.h>
29#endif
30
Kevin May42477c12020-03-26 13:34:14 +000031using namespace android;
32using namespace android::hardware;
33
34namespace {
35
Sadik Armagan188675f2021-02-12 17:16:42 +000036static const V1_2::Timing g_NoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX};
Kevin May42477c12020-03-26 13:34:14 +000037using namespace armnn_driver;
38using TimePoint = std::chrono::steady_clock::time_point;
39
40TimePoint Now()
41{
42 return std::chrono::steady_clock::now();
43}
44
45unsigned long MicrosecondsDuration(TimePoint endPoint, TimePoint startPoint)
46{
47 return static_cast<unsigned long>(std::chrono::duration_cast<std::chrono::microseconds>(
48 endPoint - startPoint).count());
49}
50
51void NotifyCallbackAndCheck(const ::android::sp<V1_0::IExecutionCallback>& callback,
52 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000053 std::vector<V1_2::OutputShape>,
54 const V1_2::Timing,
Kevin May42477c12020-03-26 13:34:14 +000055 std::string callingFunction)
56{
57 Return<void> returned = callback->notify(convertToV1_0(errorStatus));
58 // This check is required, if the callback fails and it isn't checked it will bring down the service
59 if (!returned.isOk())
60 {
61 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
62 callingFunction.c_str(), returned.description().c_str());
63 }
64}
65
66void NotifyCallbackAndCheck(const ::android::sp<V1_2::IExecutionCallback>& callback,
67 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000068 std::vector<V1_2::OutputShape> outputShapes,
69 const V1_2::Timing timing,
Kevin May42477c12020-03-26 13:34:14 +000070 std::string callingFunction)
71{
72 Return<void> returned = callback->notify_1_2(convertToV1_0(errorStatus), outputShapes, timing);
73 // This check is required, if the callback fails and it isn't checked it will bring down the service
74 if (!returned.isOk())
75 {
76 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
77 callingFunction.c_str(), returned.description().c_str());
78 }
79}
80
81void NotifyCallbackAndCheck(const ::android::sp<V1_3::IExecutionCallback>& callback,
82 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000083 std::vector<V1_2::OutputShape> outputShapes,
84 const V1_2::Timing timing,
Kevin May42477c12020-03-26 13:34:14 +000085 std::string callingFunction)
86{
87 Return<void> returned = callback->notify_1_3(errorStatus, outputShapes, timing);
88 // This check is required, if the callback fails and it isn't checked it will bring down the service
89 if (!returned.isOk())
90 {
91 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
92 callingFunction.c_str(), returned.description().c_str());
93 }
94}
95
Sadik Armagan188675f2021-02-12 17:16:42 +000096bool ValidateRequestArgument(const V1_0::RequestArgument& requestArg, const armnn::TensorInfo& tensorInfo)
Kevin May42477c12020-03-26 13:34:14 +000097{
98 if (requestArg.dimensions.size() != 0)
99 {
100 if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
101 {
102 ALOGE("Mismatched dimensions (request argument: %zu, expected: %u)",
103 requestArg.dimensions.size(), tensorInfo.GetNumDimensions());
104 return false;
105 }
106
107 for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
108 {
Finn Williamsa4983ce2020-07-23 12:55:12 +0100109 if (requestArg.dimensions[d] != 0 && requestArg.dimensions[d] != tensorInfo.GetShape()[d])
Kevin May42477c12020-03-26 13:34:14 +0000110 {
111 ALOGE("Mismatched size for dimension %d (request argument: %u, expected %u)",
112 d, requestArg.dimensions[d], tensorInfo.GetShape()[d]);
113 return false;
114 }
115 }
116 }
117
118 return true;
119}
120
Sadik Armagan188675f2021-02-12 17:16:42 +0000121armnn::Tensor GetTensorForRequestArgument(const V1_0::RequestArgument& requestArg,
Kevin May42477c12020-03-26 13:34:14 +0000122 const armnn::TensorInfo& tensorInfo,
123 const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
124{
125 if (!ValidateRequestArgument(requestArg, tensorInfo))
126 {
127 return armnn::Tensor();
128 }
129
130 return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
131}
132
133inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
134{
135 return tensorNamePrefix + std::to_string(index);
136}
137
138} // anonymous namespace
139
140using namespace android::hardware;
141
142namespace armnn_driver
143{
144
145template<typename HalVersion>
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100146RequestThread_1_3<ArmnnPreparedModel_1_3, HalVersion, CallbackContext_1_3>
Kevin May42477c12020-03-26 13:34:14 +0000147 ArmnnPreparedModel_1_3<HalVersion>::m_RequestThread;
148
149template<typename HalVersion>
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000150std::unique_ptr<armnn::Threadpool> ArmnnPreparedModel_1_3<HalVersion>::m_Threadpool(nullptr);
151
152template<typename HalVersion>
Kevin May42477c12020-03-26 13:34:14 +0000153template<typename TensorBindingCollection>
154void ArmnnPreparedModel_1_3<HalVersion>::DumpTensorsIfRequired(char const* tensorNamePrefix,
155 const TensorBindingCollection& tensorBindings)
156{
157 if (!m_RequestInputsAndOutputsDumpDir.empty())
158 {
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100159 const std::string requestName = std::to_string(m_NetworkId) + "_" + std::to_string(m_RequestCount) + ".dump";
Kevin May42477c12020-03-26 13:34:14 +0000160 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
161 {
162 DumpTensor(m_RequestInputsAndOutputsDumpDir,
163 requestName,
164 BuildTensorName(tensorNamePrefix, i),
165 tensorBindings[i].second);
166 }
167 }
168}
169
170template<typename HalVersion>
171ArmnnPreparedModel_1_3<HalVersion>::ArmnnPreparedModel_1_3(armnn::NetworkId networkId,
172 armnn::IRuntime* runtime,
173 const V1_3::Model& model,
174 const std::string& requestInputsAndOutputsDumpDir,
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100175 const bool gpuProfilingEnabled,
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000176 V1_3::Priority priority,
177 const bool asyncModelExecutionEnabled,
178 const unsigned int numberOfThreads,
179 const bool importEnabled,
180 const bool exportEnabled)
Kevin May42477c12020-03-26 13:34:14 +0000181 : m_NetworkId(networkId)
182 , m_Runtime(runtime)
183 , m_Model(model)
184 , m_RequestCount(0)
185 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
186 , m_GpuProfilingEnabled(gpuProfilingEnabled)
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100187 , m_ModelPriority(priority)
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000188 , m_AsyncModelExecutionEnabled(asyncModelExecutionEnabled)
189 , m_EnableImport(importEnabled)
190 , m_EnableExport(exportEnabled)
191 , m_PreparedFromCache(false)
Sadik Armagan0a2dfab2021-10-06 16:41:44 +0100192{
193 // Enable profiling if required.
194 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000195
196 if (m_AsyncModelExecutionEnabled)
197 {
198 std::vector<std::shared_ptr<armnn::IWorkingMemHandle>> memHandles;
199 for (unsigned int i=0; i < numberOfThreads; ++i)
200 {
201 memHandles.emplace_back(m_Runtime->CreateWorkingMemHandle(networkId));
202 }
203
204 if (!m_Threadpool)
205 {
206 m_Threadpool = std::make_unique<armnn::Threadpool>(numberOfThreads, runtime, memHandles);
207 }
208 else
209 {
210 m_Threadpool->LoadMemHandles(memHandles);
211 }
212
213 m_WorkingMemHandle = memHandles.back();
214 }
215}
216
217template<typename HalVersion>
218ArmnnPreparedModel_1_3<HalVersion>::ArmnnPreparedModel_1_3(armnn::NetworkId networkId,
219 armnn::IRuntime* runtime,
220 const std::string& requestInputsAndOutputsDumpDir,
221 const bool gpuProfilingEnabled,
222 V1_3::Priority priority,
223 const bool asyncModelExecutionEnabled,
224 const unsigned int numberOfThreads,
225 const bool importEnabled,
226 const bool exportEnabled,
227 const bool preparedFromCache)
228 : m_NetworkId(networkId)
229 , m_Runtime(runtime)
230 , m_RequestCount(0)
231 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
232 , m_GpuProfilingEnabled(gpuProfilingEnabled)
233 , m_ModelPriority(priority)
234 , m_AsyncModelExecutionEnabled(asyncModelExecutionEnabled)
235 , m_EnableImport(importEnabled)
236 , m_EnableExport(exportEnabled)
237 , m_PreparedFromCache(preparedFromCache)
238{
239 // Enable profiling if required.
240 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
241
242 if (m_AsyncModelExecutionEnabled)
243 {
244 std::vector<std::shared_ptr<armnn::IWorkingMemHandle>> memHandles;
245 for (unsigned int i=0; i < numberOfThreads; ++i)
246 {
247 memHandles.emplace_back(m_Runtime->CreateWorkingMemHandle(networkId));
248 }
249
250 if (!m_Threadpool)
251 {
252 m_Threadpool = std::make_unique<armnn::Threadpool>(numberOfThreads, runtime, memHandles);
253 }
254 else
255 {
256 m_Threadpool->LoadMemHandles(memHandles);
257 }
258
259 m_WorkingMemHandle = memHandles.back();
260 }
Kevin May42477c12020-03-26 13:34:14 +0000261}
262
263template<typename HalVersion>
264ArmnnPreparedModel_1_3<HalVersion>::~ArmnnPreparedModel_1_3()
265{
266 // Get a hold of the profiler used by this model.
267 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000268 if (profiler && m_GpuProfilingEnabled)
269 {
270 // Dump the profiling info to a file if required.
271 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId,
272 profiler.get());
273 }
Kevin May42477c12020-03-26 13:34:14 +0000274
275 // Unload the network associated with this model.
276 m_Runtime->UnloadNetwork(m_NetworkId);
277
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000278 // Unload the network memhandles from the threadpool
279 if (m_AsyncModelExecutionEnabled)
280 {
281 m_Threadpool->UnloadMemHandles(m_NetworkId);
282 }
Kevin May42477c12020-03-26 13:34:14 +0000283}
284
285template<typename HalVersion>
286Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute(const V1_0::Request& request,
287 const ::android::sp<V1_0::IExecutionCallback>& callback)
288{
289 if (callback.get() == nullptr)
290 {
291 ALOGE("ArmnnPreparedModel_1_3::execute invalid callback passed");
292 return V1_0::ErrorStatus::INVALID_ARGUMENT;
293 }
294
295 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000296 std::vector<V1_2::OutputShape> outputShapes,
297 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000298 std::string callingFunction)
299 {
300 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
301 };
302
303
Sadik Armagan188675f2021-02-12 17:16:42 +0000304 return convertToV1_0(Execute(convertToV1_3(request), V1_2::MeasureTiming::NO, cb));
Kevin May42477c12020-03-26 13:34:14 +0000305}
306
307template<typename HalVersion>
308Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute_1_2(
309 const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000310 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000311 const sp<V1_2::IExecutionCallback>& callback)
312{
313 if (callback.get() == nullptr)
314 {
315 ALOGE("ArmnnPreparedModel_1_3::execute_1_2 invalid callback passed");
316 return V1_0::ErrorStatus::INVALID_ARGUMENT;
317 }
318
319 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000320 std::vector<V1_2::OutputShape> outputShapes,
321 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000322 std::string callingFunction)
323 {
324 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
325 };
326
327 return convertToV1_0(Execute(convertToV1_3(request), measureTiming, cb));
328}
329
330template<typename HalVersion>
331Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute_1_3(
332 const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000333 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000334 const V1_3::OptionalTimePoint&,
Kevin May352d8382020-03-31 15:03:42 +0100335 const V1_3::OptionalTimeoutDuration&,
Kevin May42477c12020-03-26 13:34:14 +0000336 const sp<V1_3::IExecutionCallback>& callback)
337{
338 if (callback.get() == nullptr)
339 {
340 ALOGE("ArmnnPreparedModel_1_3::execute_1_3 invalid callback passed");
341 return V1_3::ErrorStatus::INVALID_ARGUMENT;
342 }
343
344 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000345 std::vector<V1_2::OutputShape> outputShapes,
346 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000347 std::string callingFunction)
348 {
349 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
350 };
351
352 return Execute(request, measureTiming, cb);
353}
354
Sadik Armagand7be72e2020-04-23 12:56:05 +0100355/// This class is inspired by the sample implementation in Android named SampleFencedExecutionCallback.
356/// The original code is licensed under Apache-2.0 and can be found at the following link:
357/// https://android.googlesource.com/platform/frameworks/ml/+/master/nn/driver/sample/SampleDriver.h
358class ArmnnFencedExecutionCallback : public V1_3::IFencedExecutionCallback
359{
360public:
Sadik Armagan188675f2021-02-12 17:16:42 +0000361 ArmnnFencedExecutionCallback(V1_3::ErrorStatus errorStatus, V1_2::Timing timing, V1_2::Timing fenceTiming)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100362 : m_ErrorStatus(errorStatus), m_Timing(timing), m_FenceTiming(fenceTiming) {}
363 ~ArmnnFencedExecutionCallback() {}
364
365 Return<void> getExecutionInfo(getExecutionInfo_cb callback) override
366 {
367 callback(m_ErrorStatus, m_Timing, m_FenceTiming);
368 return Void();
369 }
370private:
371 V1_3::ErrorStatus m_ErrorStatus;
Sadik Armagan188675f2021-02-12 17:16:42 +0000372 V1_2::Timing m_Timing;
373 V1_2::Timing m_FenceTiming;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100374};
375
Kevin May42477c12020-03-26 13:34:14 +0000376template<typename HalVersion>
Sadik Armagand7be72e2020-04-23 12:56:05 +0100377Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeFenced(const V1_3::Request& request,
378 const hidl_vec<hidl_handle>& fenceWaitFor,
Sadik Armagan188675f2021-02-12 17:16:42 +0000379 V1_2::MeasureTiming measureTiming,
380 const V1_3::OptionalTimePoint& deadline,
381 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
382 const V1_3::OptionalTimeoutDuration&,
Kevin May42477c12020-03-26 13:34:14 +0000383 executeFenced_cb cb)
384{
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100385 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...)");
386 if (cb == nullptr)
387 {
388 ALOGE("ArmnnPreparedModel_1_3::executeFenced invalid callback passed");
Sadik Armagan188675f2021-02-12 17:16:42 +0000389 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100390 return Void();
391 }
392
Sadik Armagan188675f2021-02-12 17:16:42 +0000393 if (deadline.getDiscriminator() != V1_3::OptionalTimePoint::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100394 {
395 ALOGW("ArmnnPreparedModel_1_3::executeFenced parameter deadline is set but not supported.");
396 }
397
Sadik Armagan188675f2021-02-12 17:16:42 +0000398 if (loopTimeoutDuration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100399 {
400 ALOGW("ArmnnPreparedModel_1_3::executeFenced parameter loopTimeoutDuration is set but not supported.");
401 }
402
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000403 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model, /*allowUnspecifiedOutput=*/false))
Finn Williamsa4983ce2020-07-23 12:55:12 +0100404 {
405 ALOGV("ArmnnPreparedModel_1_3::executeFenced outputs must be specified for fenced execution ");
Sadik Armagan188675f2021-02-12 17:16:42 +0000406 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Finn Williamsa4983ce2020-07-23 12:55:12 +0100407 return Void();
408 }
409
Sadik Armagand7be72e2020-04-23 12:56:05 +0100410 ExecutionContext_1_3 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000411 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100412 {
413 ctx.measureTimings = measureTiming;
414 ctx.driverStart = Now();
415 }
416
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000417 if (!m_PreparedFromCache)
418 {
419 ALOGV("ArmnnPreparedModel_1_3::executeFenced(): %s", GetModelSummary(m_Model).c_str());
420 }
Sadik Armagand7be72e2020-04-23 12:56:05 +0100421 m_RequestCount++;
422
Sadik Armagand7be72e2020-04-23 12:56:05 +0100423 if (!m_RequestInputsAndOutputsDumpDir.empty())
424 {
425 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&cb));
426 }
427
428 // This code snippet is inspired by the sample implementation in Android named SampleDriver::executeFenced()
429 // function. The original code is licensed under Apache-2.0 and can be found at the following link:
430 // https://android.googlesource.com/platform/frameworks/ml/+/master/nn/driver/sample/SampleDriver.cpp
431 const auto fenceSize = fenceWaitFor.size();
432 for (unsigned int index = 0; index < fenceSize; ++index)
433 {
434 auto fenceNativeHandle = fenceWaitFor[index].getNativeHandle();
435 if (!fenceNativeHandle)
436 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000437 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100438 return Void();
439 }
440
Guus Sliepen671afb12023-05-23 20:34:42 +0000441 if (fenceNativeHandle->numFds != 1)
442 {
443 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
444 return Void();
445 }
446
Sadik Armagand7be72e2020-04-23 12:56:05 +0100447 if (sync_wait(fenceNativeHandle->data[0], -1) < 0)
448 {
449 ALOGE("ArmnnPreparedModel_1_3::executeFenced sync fence failed.");
Sadik Armagan188675f2021-02-12 17:16:42 +0000450 cb(V1_3::ErrorStatus::GENERAL_FAILURE, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100451 return Void();
452 }
453 }
454
455 TimePoint fenceExecutionStart;
Sadik Armagan188675f2021-02-12 17:16:42 +0000456 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100457 {
458 fenceExecutionStart = Now();
459 }
460
461 // map the memory pool into shared pointers
462 // use a shared memory pools vector on the heap, as it is passed to the request thread
463 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
464
465 // allocate the tensors on the heap, as they are passed to the request thread
466 auto inputs = std::make_shared<armnn::InputTensors>();
467 auto outputs = std::make_shared<armnn::OutputTensors>();
468
469 auto [status, outShapes, timings, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
470 if (status != V1_3::ErrorStatus::NONE)
471 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000472 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100473 return Void();
474 }
475
476 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...) before ExecuteGraph");
477
478 // call it with nullCallback for now as we will report the error status from here..
Sadik Armagan188675f2021-02-12 17:16:42 +0000479 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Sadik Armagand7be72e2020-04-23 12:56:05 +0100480 CallbackContext_1_3 cbCtx;
481 cbCtx.callback = nullCallback;
482 cbCtx.ctx = ctx;
483
484 auto errorStatus = ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
485 if (errorStatus != V1_3::ErrorStatus::NONE)
486 {
487 cb(errorStatus, hidl_handle(nullptr), nullptr);
488 return Void();
489 }
490 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...) after ExecuteGraph");
491
Sadik Armagan188675f2021-02-12 17:16:42 +0000492 V1_2::Timing timing = g_NoTiming;
493 V1_2::Timing fenceTiming = g_NoTiming;
494 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100495 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100496 fenceTiming.timeOnDevice = MicrosecondsDuration(ctx.deviceEnd, ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100497 fenceTiming.timeInDriver = MicrosecondsDuration(ctx.driverEnd, fenceExecutionStart);
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000498 ALOGV("ArmnnPreparedModel_1_3::fenceFinishExecutionTiming - Device = %lu Driver = %lu",
499 static_cast<unsigned long>(fenceTiming.timeOnDevice),
500 static_cast<unsigned long>(fenceTiming.timeInDriver));
Sadik Armagand7be72e2020-04-23 12:56:05 +0100501 }
502
503 sp<ArmnnFencedExecutionCallback> armnnFencedExecutionCallback =
Sadik Armagan188675f2021-02-12 17:16:42 +0000504 new ArmnnFencedExecutionCallback(V1_3::ErrorStatus::NONE, timing, fenceTiming);
505 cb(V1_3::ErrorStatus::NONE, hidl_handle(nullptr), armnnFencedExecutionCallback);
Kevin May42477c12020-03-26 13:34:14 +0000506 return Void();
507}
508
509template<typename HalVersion>
510Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForInputs(
511 armnn::InputTensors& inputs,
512 const V1_3::Request& request,
513 const std::vector<android::nn::RunTimePoolInfo>& memPools)
514{
515 inputs.reserve(request.inputs.size());
516 for (unsigned int i = 0; i < request.inputs.size(); i++)
517 {
518 const auto& inputArg = request.inputs[i];
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000519 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
520 // inputs (of type InputTensors) is composed of a vector of ConstTensors.
521 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
522 inputTensorInfo.SetConstant();
523 auto result = ValidateRequestArgument<V1_3::ErrorStatus, V1_3::Request>(request,
524 inputTensorInfo,
525 inputArg,
526 "input");
Mike Kellyde547162023-03-08 10:08:20 +0000527
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000528 if (result != V1_3::ErrorStatus::NONE)
529 {
530 return result;
531 }
532
Kevin May42477c12020-03-26 13:34:14 +0000533 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
534
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000535 if (inputTensor.GetMemoryArea() == nullptr)
Kevin May42477c12020-03-26 13:34:14 +0000536 {
537 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
538 return V1_3::ErrorStatus::GENERAL_FAILURE;
539 }
540
541 inputs.emplace_back(i, inputTensor);
542 }
543
544 return V1_3::ErrorStatus::NONE;
545}
546
547template<typename HalVersion>
548Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForOutputs(
549 armnn::OutputTensors& outputs,
Sadik Armagan188675f2021-02-12 17:16:42 +0000550 std::vector<V1_2::OutputShape> &outputShapes,
Kevin May42477c12020-03-26 13:34:14 +0000551 const V1_3::Request& request,
552 const std::vector<android::nn::RunTimePoolInfo>& memPools)
553{
554 outputs.reserve(request.outputs.size());
555 for (unsigned int i = 0; i < request.outputs.size(); i++)
556 {
557 const auto& outputArg = request.outputs[i];
Finn Williamsa4983ce2020-07-23 12:55:12 +0100558 armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000559 auto result = ValidateRequestArgument<V1_3::ErrorStatus, V1_3::Request>(request,
560 outputTensorInfo,
561 outputArg,
562 "output");
563
564 if (result != V1_3::ErrorStatus::NONE)
565 {
566 return result;
567 }
568
Kevin May42477c12020-03-26 13:34:14 +0000569 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000570
571 if (outputTensor.GetMemoryArea() == nullptr)
Kevin May42477c12020-03-26 13:34:14 +0000572 {
573 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
574 return V1_3::ErrorStatus::GENERAL_FAILURE;
575 }
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100576 const size_t outputSize = outputTensorInfo.GetNumBytes();
577
Finn Williamsa4983ce2020-07-23 12:55:12 +0100578 unsigned int count = 0;
579 std::for_each(outputArg.dimensions.begin(), outputArg.dimensions.end(), [&](auto dim)
580 {
581 if (dim != 0)
582 {
583 outputTensorInfo.GetShape()[count] = dim;
584 }
585 else
586 {
587 outputTensorInfo.GetShape()[count] = outputArg.dimensions.size();
588 }
589
590 count++;
591 });
592
Finn Williamsa4983ce2020-07-23 12:55:12 +0100593 outputs.emplace_back(i, outputTensor);
594 outputShapes[i] = ComputeShape(outputTensorInfo);
595
596 if (outputArg.location.length < outputSize)
597 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100598 ALOGW("ArmnnPreparedModel_1_3::Execute failed outputArg.location.length (%s) < outputSize (%s)",
599 std::to_string(outputArg.location.length).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100600 outputShapes[i].isSufficient = false;
601 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
602 }
603
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000604 size_t bufferSize = 0;
605#if !defined(ARMNN_ANDROID_S)
606 bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
607#else
608 bufferSize = memPools.at(outputArg.location.poolIndex).getSize();
609#endif
Kevin May42477c12020-03-26 13:34:14 +0000610 if (bufferSize < outputSize)
611 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100612 ALOGW("ArmnnPreparedModel_1_3::Execute failed bufferSize (%s) < outputSize (%s)",
613 std::to_string(bufferSize).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100614 outputShapes[i].isSufficient = false;
Kevin May42477c12020-03-26 13:34:14 +0000615 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
616 }
Kevin May42477c12020-03-26 13:34:14 +0000617 }
618
619 return V1_3::ErrorStatus::NONE;
620}
621
622template<typename HalVersion>
Sadik Armagan188675f2021-02-12 17:16:42 +0000623std::tuple<V1_3::ErrorStatus, hidl_vec<V1_2::OutputShape>, V1_2::Timing, std::string>
Kevin May42477c12020-03-26 13:34:14 +0000624 ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForIO(armnn::InputTensors& inputs,
625 armnn::OutputTensors& outputs,
626 std::vector<android::nn::RunTimePoolInfo>& memPools,
627 const V1_3::Request& request)
628{
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000629#if !defined(ARMNN_ANDROID_S)
630 if (!setRunTimePoolInfosFromMemoryPools(&memPools, request.pools))
631#else
Sadik Armagan188675f2021-02-12 17:16:42 +0000632 if (!setRunTimePoolInfosFromMemoryPools(&memPools, uncheckedConvert(request.pools)))
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000633#endif
Kevin May42477c12020-03-26 13:34:14 +0000634 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000635 return {V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000636 }
637
638 // add the inputs and outputs with their data
639 try
640 {
641 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_3::ErrorStatus::NONE)
642 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000643 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000644 }
645
Sadik Armagan188675f2021-02-12 17:16:42 +0000646 std::vector<V1_2::OutputShape> outputShapes(request.outputs.size());
Kevin May42477c12020-03-26 13:34:14 +0000647
648 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
649 if (errorStatus != V1_3::ErrorStatus::NONE)
650 {
651 return {errorStatus, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
652 }
653 }
654 catch (armnn::Exception& e)
655 {
656 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000657 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000658 }
659 catch (std::exception& e)
660 {
661 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000662 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000663 }
664
665 return {V1_3::ErrorStatus::NONE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
666}
667
668template<typename HalVersion>
669template<typename CallbackContext>
670Return<void> ArmnnPreparedModel_1_3<HalVersion>::ExecuteSynchronously(const V1_3::Request& request,
671 CallbackContext cbCtx)
672{
Sadik Armagan188675f2021-02-12 17:16:42 +0000673 if (cbCtx.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000674 {
675 cbCtx.ctx.driverStart = Now();
676 }
677
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000678 if (!m_PreparedFromCache && !android::nn::validateRequest(convertToV1_3(request), m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000679 {
680 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
681 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
682 {},
683 g_NoTiming,
684 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
685 return Void();
686 }
687
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000688 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Kevin May42477c12020-03-26 13:34:14 +0000689 {
690 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
691 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
692 {},
693 g_NoTiming,
694 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
Sadik Armaganef8a3932020-04-09 17:21:50 +0100695 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000696 }
697
698
699 // map the memory pool into shared pointers
700 // use a shared memory pools vector on the heap, as it is passed to the request thread
701 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
702
703 // allocate the tensors on the heap, as they are passed to the request thread
704 auto inputs = std::make_shared<armnn::InputTensors>();
705 auto outputs = std::make_shared<armnn::OutputTensors>();
706
707 auto [status, outputShapes, timing, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
708 if (status != V1_3::ErrorStatus::NONE)
709 {
710 cbCtx.callback(status, outputShapes, timing, message);
Sadik Armaganef8a3932020-04-09 17:21:50 +0100711 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000712 }
713
714 ALOGV("ArmnnPreparedModel_1_3::ExecuteSynchronously() before Execution");
715
716 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
717 return Void();
718}
719
720template<typename HalVersion>
721Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000722 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000723 executeSynchronously_cb cb)
724{
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000725 if (!m_PreparedFromCache)
726 {
727 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
728 }
Kevin May42477c12020-03-26 13:34:14 +0000729 m_RequestCount++;
730
731 if (cb == nullptr)
732 {
733 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously invalid callback passed");
734 return Void();
735 }
736
737 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000738 std::vector<V1_2::OutputShape> outputShapes,
739 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000740 std::string)
741 {
742 cb(convertToV1_0(errorStatus), outputShapes, timing);
743 };
744
745 CallbackContext_1_3 cbCtx;
746 cbCtx.callback = cbWrapper;
747 cbCtx.ctx.measureTimings = measureTiming;
748
749 ExecuteSynchronously(convertToV1_3(request), cbCtx);
750 return Void();
751}
752
753template<typename HalVersion>
Kevin May352d8382020-03-31 15:03:42 +0100754Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously_1_3(
755 const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000756 V1_2::MeasureTiming measureTiming,
Kevin May352d8382020-03-31 15:03:42 +0100757 const V1_3::OptionalTimePoint& deadline,
758 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
759 executeSynchronously_1_3_cb cb)
Kevin May42477c12020-03-26 13:34:14 +0000760{
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000761 if (!m_PreparedFromCache)
762 {
763 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously_1_3(): %s", GetModelSummary(m_Model).c_str());
764 }
Kevin May42477c12020-03-26 13:34:14 +0000765 m_RequestCount++;
766
767 if (cb == nullptr)
768 {
769 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid callback passed");
770 return Void();
771 }
772
Sadik Armagan188675f2021-02-12 17:16:42 +0000773 if (deadline.getDiscriminator() != V1_3::OptionalTimePoint::hidl_discriminator::none)
Kevin May42477c12020-03-26 13:34:14 +0000774 {
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100775 ALOGW("ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter deadline is set but not supported.");
Kevin May42477c12020-03-26 13:34:14 +0000776 }
777
Sadik Armagan188675f2021-02-12 17:16:42 +0000778 if (loopTimeoutDuration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100779 {
780 ALOGW(
781 "ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter loopTimeoutDuration is set but not supported.");
Kevin May352d8382020-03-31 15:03:42 +0100782 }
783
Kevin May42477c12020-03-26 13:34:14 +0000784 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000785 std::vector<V1_2::OutputShape> outputShapes,
786 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000787 std::string)
788 {
789 cb(errorStatus, outputShapes, timing);
790 };
791
792 CallbackContext_1_3 cbCtx;
793 cbCtx.callback = cbWrapper;
794 cbCtx.ctx.measureTimings = measureTiming;
795
796 ExecuteSynchronously(request, cbCtx);
797 return Void();
798}
799
800template<typename HalVersion>
801Return<void> ArmnnPreparedModel_1_3<HalVersion>::configureExecutionBurst(
802 const sp<V1_2::IBurstCallback>& callback,
803 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
804 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
805 V1_3::IPreparedModel::configureExecutionBurst_cb cb)
806{
807 ALOGV("ArmnnPreparedModel_1_3::configureExecutionBurst");
808 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
809 requestChannel,
810 resultChannel,
811 this);
812
813 if (burst == nullptr)
814 {
815 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
816 }
817 else
818 {
819 cb(V1_0::ErrorStatus::NONE, burst);
820 }
821 return Void();
822}
823
824template<typename HalVersion>
825template<typename CallbackContext>
Sadik Armagand7be72e2020-04-23 12:56:05 +0100826Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::ExecuteGraph(
Kevin May42477c12020-03-26 13:34:14 +0000827 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
828 armnn::InputTensors& inputTensors,
829 armnn::OutputTensors& outputTensors,
830 CallbackContext cb)
831{
832 ALOGV("ArmnnPreparedModel_1_3::ExecuteGraph(...)");
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000833 // Capture the graph execution start time.
834 std::chrono::time_point<std::chrono::system_clock> graphExecutionStart = std::chrono::system_clock::now();
Kevin May42477c12020-03-26 13:34:14 +0000835
Kevin May42477c12020-03-26 13:34:14 +0000836 DumpTensorsIfRequired("Input", inputTensors);
837
Sadik Armagan188675f2021-02-12 17:16:42 +0000838 std::vector<V1_2::OutputShape> outputShapes(outputTensors.size());
Kevin May42477c12020-03-26 13:34:14 +0000839 for (unsigned int i = 0; i < outputTensors.size(); i++)
840 {
841 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
842 const armnn::Tensor outputTensor = outputTensorPair.second;
843 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
844
845 outputShapes[i] = ComputeShape(outputTensorInfo);
846 }
847
848 // run it
849 try
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 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100853 cb.ctx.deviceStart = Now();
Kevin May42477c12020-03-26 13:34:14 +0000854 }
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000855 armnn::Status status;
856 if (m_AsyncModelExecutionEnabled)
857 {
858 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled true");
859 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
860 }
861 else
862 {
863 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled false");
864 // Create a vector of Input and Output Ids which can be imported. An empty vector means all will be copied.
865 std::vector<armnn::ImportedInputId> importedInputIds;
866 if (m_EnableImport)
867 {
868 importedInputIds = m_Runtime->ImportInputs(m_NetworkId, inputTensors, armnn::MemorySource::Malloc);
869 }
870 std::vector<armnn::ImportedOutputId> importedOutputIds;
871 if (m_EnableExport)
872 {
873 importedOutputIds = m_Runtime->ImportOutputs(m_NetworkId, outputTensors, armnn::MemorySource::Malloc);
874 }
875 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors,
876 importedInputIds, importedOutputIds);
877 }
Kevin May42477c12020-03-26 13:34:14 +0000878
Sadik Armagan188675f2021-02-12 17:16:42 +0000879 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000880 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100881 cb.ctx.deviceEnd = Now();
Kevin May42477c12020-03-26 13:34:14 +0000882 }
883 if (status != armnn::Status::Success)
884 {
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000885 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph EnqueueWorkload failed");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100886 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
887 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000888 }
889 }
890 catch (armnn::Exception& e)
891 {
892 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
893 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100894 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000895 }
896 catch (std::exception& e)
897 {
898 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
899 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100900 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000901 }
902
903 CommitPools(*pMemPools);
904
905 DumpTensorsIfRequired("Output", outputTensors);
906
Sadik Armagan188675f2021-02-12 17:16:42 +0000907 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000908 {
Kevin May949a69e2020-04-24 10:21:40 +0100909 cb.ctx.driverEnd = Now();
Sadik Armagan188675f2021-02-12 17:16:42 +0000910 V1_2::Timing timing;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100911 timing.timeOnDevice = MicrosecondsDuration(cb.ctx.deviceEnd, cb.ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100912 timing.timeInDriver = MicrosecondsDuration(cb.ctx.driverEnd, cb.ctx.driverStart);
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000913 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu",
914 static_cast<unsigned long>(timing.timeOnDevice), static_cast<unsigned long>(timing.timeInDriver));
Kevin May42477c12020-03-26 13:34:14 +0000915 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100916 } else
917 {
Kevin May42477c12020-03-26 13:34:14 +0000918 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
919 }
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000920 // Log the total time in this call. This is a good number to compare to that printed out by
921 // RuntimeImpl::EnqueueWorkload. The difference should be the execution overhead of the driver.
922 ALOGI("ArmnnPreparedModel_1_3::ExecuteGraph Execution time = %lld µs",
923 std::chrono::duration_cast<std::chrono::microseconds>
924 (std::chrono::system_clock::now() - graphExecutionStart).count());
Sadik Armagand7be72e2020-04-23 12:56:05 +0100925 return V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000926}
927
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000928/// Schedule the graph prepared from the request for execution
Finn Williamsd8fb5402021-05-19 20:52:00 +0100929template<typename HalVersion>
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000930template<typename CallbackContext>
931void ArmnnPreparedModel_1_3<HalVersion>::ScheduleGraphForExecution(
932 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
933 std::shared_ptr<armnn::InputTensors>& inputTensors,
934 std::shared_ptr<armnn::OutputTensors>& outputTensors,
935 CallbackContext callbackContext,
936 armnn::QosExecPriority priority)
937{
938 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution(...)");
939
940 DumpTensorsIfRequired("Input", *inputTensors);
941
942 unsigned int outputTensorSize = outputTensors.get()->size();
943 std::vector<V1_2::OutputShape> outputShapes(outputTensorSize);
944 for (unsigned int i = 0; i < outputTensorSize; i++)
945 {
946 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors.get()->at(i);
947 const armnn::Tensor outputTensor = outputTensorPair.second;
948 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
949
950 outputShapes[i] = ComputeShape(outputTensorInfo);
951 }
952
953 auto tpCb = std::make_shared<
954 ArmnnThreadPoolCallback_1_3<CallbackContext_1_3>>(this,
955 pMemPools,
956 outputShapes,
957 inputTensors,
958 outputTensors,
959 callbackContext);
960
961 m_Threadpool->Schedule(m_NetworkId,
962 *tpCb->m_InputTensors,
963 *tpCb->m_OutputTensors,
964 priority,
965 tpCb);
966 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution end");
967}
968
969template<typename HalVersion>
970bool ArmnnPreparedModel_1_3<HalVersion>::ExecuteWithDummyInputs(unsigned int numInputs, unsigned int numOutputs)
Kevin May42477c12020-03-26 13:34:14 +0000971{
972 std::vector<std::vector<char>> storage;
973 armnn::InputTensors inputTensors;
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000974 for (unsigned int i = 0; i < numInputs; i++)
Kevin May42477c12020-03-26 13:34:14 +0000975 {
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000976 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
977 // pInputTensors (of type InputTensors) is composed of a vector of ConstTensors.
978 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
979 inputTensorInfo.SetConstant();
980
Kevin May42477c12020-03-26 13:34:14 +0000981 storage.emplace_back(inputTensorInfo.GetNumBytes());
982 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
983
984 inputTensors.emplace_back(i, inputTensor);
985 }
986
987 armnn::OutputTensors outputTensors;
Renato Grottesi77a0fb02023-05-08 12:55:03 +0000988 for (unsigned int i = 0; i < numOutputs; i++)
Kevin May42477c12020-03-26 13:34:14 +0000989 {
990 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
991 storage.emplace_back(outputTensorInfo.GetNumBytes());
992 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
993
994 outputTensors.emplace_back(i, outputTensor);
995 }
996
Sadik Armagan188675f2021-02-12 17:16:42 +0000997 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Kevin May42477c12020-03-26 13:34:14 +0000998 CallbackContext_1_3 callbackContext;
999 callbackContext.callback = nullCallback;
Sadik Armagan188675f2021-02-12 17:16:42 +00001000 callbackContext.ctx.measureTimings = V1_2::MeasureTiming::NO;
Kevin May42477c12020-03-26 13:34:14 +00001001 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
Sadik Armagand7be72e2020-04-23 12:56:05 +01001002
1003 auto errorStatus = ExecuteGraph(memPools,
1004 inputTensors,
1005 outputTensors,
1006 callbackContext);
1007 return errorStatus == V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +00001008}
1009
1010template<typename HalVersion>
1011Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::Execute(const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +00001012 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +00001013 CallbackAsync_1_3 callback)
1014{
1015 ExecutionContext_1_3 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +00001016 if (measureTiming == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +00001017 {
1018 ctx.measureTimings = measureTiming;
1019 ctx.driverStart = Now();
1020 }
1021
Renato Grottesi77a0fb02023-05-08 12:55:03 +00001022 if (!m_PreparedFromCache)
1023 {
1024 ALOGV("ArmnnPreparedModel_1_3::execute(): %s", GetModelSummary(m_Model).c_str());
1025 }
Kevin May42477c12020-03-26 13:34:14 +00001026 m_RequestCount++;
1027
Renato Grottesi77a0fb02023-05-08 12:55:03 +00001028 if (!m_PreparedFromCache && !android::nn::validateRequest(request, m_Model))
Kevin May42477c12020-03-26 13:34:14 +00001029 {
1030 callback(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute");
1031 return V1_3::ErrorStatus::INVALID_ARGUMENT;
1032 }
1033
1034 if (!m_RequestInputsAndOutputsDumpDir.empty())
1035 {
1036 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
1037 }
1038
1039 // map the memory pool into shared pointers
1040 // use a shared memory pools vector on the heap, as it is passed to the request thread
1041 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
1042
1043 // allocate the tensors on the heap, as they are passed to the request thread
1044 auto inputTensors = std::make_shared<armnn::InputTensors>();
1045 auto outputTensors = std::make_shared<armnn::OutputTensors>();
1046
1047 auto [status, outShapes, timing, message] = PrepareMemoryForIO(*inputTensors, *outputTensors,
1048 *memPools, request);
1049 if (status != V1_3::ErrorStatus::NONE)
1050 {
1051 callback(status, outShapes, timing, message);
1052 }
1053
1054 switch(status)
1055 {
1056 case V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
1057 return V1_3::ErrorStatus::NONE;
1058 case V1_3::ErrorStatus::GENERAL_FAILURE:
1059 return V1_3::ErrorStatus::GENERAL_FAILURE;
Renato Grottesi77a0fb02023-05-08 12:55:03 +00001060 case V1_3::ErrorStatus::INVALID_ARGUMENT:
1061 return V1_3::ErrorStatus::INVALID_ARGUMENT;
Kevin May42477c12020-03-26 13:34:14 +00001062 default:
1063 {}
1064 }
Kevin May42477c12020-03-26 13:34:14 +00001065 CallbackContext_1_3 cb;
1066 cb.callback = callback;
1067 cb.ctx = ctx;
Renato Grottesi77a0fb02023-05-08 12:55:03 +00001068
1069
1070 enum class QosExecPriority
1071 {
1072 Low = 0,
1073 Medium = 1,
1074 High = 2
1075 };
1076
1077
1078 if (m_AsyncModelExecutionEnabled)
1079 {
1080 armnn::QosExecPriority priority;
1081
1082 switch (GetModelPriority()) {
1083 case V1_3::Priority::LOW:
1084 priority = armnn::QosExecPriority::Low;
1085 break;
1086 case V1_3::Priority::MEDIUM:
1087 priority = armnn::QosExecPriority::Medium;
1088 break;
1089 case V1_3::Priority::HIGH:
1090 priority = armnn::QosExecPriority::High;
1091 break;
1092 default:
1093 priority = armnn::QosExecPriority::Medium;
1094
1095 }
1096
1097 ALOGV("ArmnnPreparedModel_1_3::execute(...) before ScheduleGraphForExecution");
1098 ScheduleGraphForExecution(memPools, inputTensors, outputTensors, cb, priority);
1099 ALOGV("ArmnnPreparedModel_1_3::execute(...) after ScheduleGraphForExecution");
1100 return V1_3::ErrorStatus::NONE;
1101 }
1102
1103 ALOGV("ArmnnPreparedModel_1_3::execute(...) before PostMsg");
1104 // post the request for asynchronous execution
Kevin May42477c12020-03-26 13:34:14 +00001105 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
1106 ALOGV("ArmnnPreparedModel_1_3::execute(...) after PostMsg");
1107 return V1_3::ErrorStatus::NONE;
1108}
1109
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +01001110template<typename HalVersion>
1111V1_3::Priority ArmnnPreparedModel_1_3<HalVersion>::GetModelPriority()
1112{
1113 return m_ModelPriority;
1114}
1115
Renato Grottesi77a0fb02023-05-08 12:55:03 +00001116template<typename HalVersion>
1117template <typename CallbackContext>
1118void ArmnnPreparedModel_1_3<HalVersion>::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify(
1119 armnn::Status status, armnn::InferenceTimingPair timeTaken)
1120{
1121 ALOGV("ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify");
1122 CommitPools(*m_MemPools);
1123
1124 m_Model->DumpTensorsIfRequired("Output", *m_OutputTensors);
1125
1126 if (status != armnn::Status::Success)
1127 {
1128 ALOGW("ArmnnThreadPoolCallback_1_3::Notify EnqueueWorkload failed");
1129 m_CallbackContext.callback(V1_3::ErrorStatus::GENERAL_FAILURE,
1130 {},
1131 g_NoTiming,
1132 "ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3");
1133 return;
1134 }
1135
1136 if (m_CallbackContext.ctx.measureTimings == V1_2::MeasureTiming::YES)
1137 {
1138 m_CallbackContext.ctx.deviceStart = timeTaken.first;
1139 m_CallbackContext.ctx.deviceEnd = timeTaken.second;
1140 m_CallbackContext.ctx.driverEnd = std::chrono::steady_clock::now();
1141 V1_2::Timing timing;
1142 timing.timeOnDevice = MicrosecondsDuration(m_CallbackContext.ctx.deviceEnd, m_CallbackContext.ctx.deviceStart);
1143 timing.timeInDriver = MicrosecondsDuration(m_CallbackContext.ctx.driverEnd, m_CallbackContext.ctx.driverStart);
1144 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu",
1145 static_cast<unsigned long>(timing.timeOnDevice), static_cast<unsigned long>(timing.timeInDriver));
1146 m_CallbackContext.callback(
1147 V1_3::ErrorStatus::NONE, m_OutputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
1148 } else
1149 {
1150 m_CallbackContext.callback(
1151 V1_3::ErrorStatus::NONE, m_OutputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
1152 }
1153 return;
1154}
1155
Kevin May42477c12020-03-26 13:34:14 +00001156#ifdef ARMNN_ANDROID_NN_V1_3
1157template class ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>;
Sadik Armagand7be72e2020-04-23 12:56:05 +01001158template Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ExecuteGraph<CallbackContext_1_3>(
Kevin May42477c12020-03-26 13:34:14 +00001159 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1160 armnn::InputTensors& pInputTensors,
1161 armnn::OutputTensors& pOutputTensors,
1162 CallbackContext_1_3 cb);
Renato Grottesi77a0fb02023-05-08 12:55:03 +00001163
1164template void ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ScheduleGraphForExecution<CallbackContext_1_3>(
1165 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1166 std::shared_ptr<armnn::InputTensors>& inputTensors,
1167 std::shared_ptr<armnn::OutputTensors>& outputTensors,
1168 CallbackContext_1_3 callbackContext,
1169 armnn::QosExecPriority priority);
Kevin May42477c12020-03-26 13:34:14 +00001170#endif
1171
1172} // namespace armnn_driver