blob: 5a370321ca2a7e7d5bb91b1e3521d88d1790b020 [file] [log] [blame]
Kevin May42477c12020-03-26 13:34:14 +00001//
2// Copyright © 2020 Arm Ltd. All rights reserved.
3// 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
22#include <cassert>
23#include <cinttypes>
24
Sadik Armagan188675f2021-02-12 17:16:42 +000025#ifdef ARMNN_ANDROID_S
26#include <LegacyUtils.h>
27#endif
28
Kevin May42477c12020-03-26 13:34:14 +000029using namespace android;
30using namespace android::hardware;
31
32namespace {
33
Sadik Armagan188675f2021-02-12 17:16:42 +000034static const V1_2::Timing g_NoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX};
Kevin May42477c12020-03-26 13:34:14 +000035using namespace armnn_driver;
36using TimePoint = std::chrono::steady_clock::time_point;
37
38TimePoint Now()
39{
40 return std::chrono::steady_clock::now();
41}
42
43unsigned long MicrosecondsDuration(TimePoint endPoint, TimePoint startPoint)
44{
45 return static_cast<unsigned long>(std::chrono::duration_cast<std::chrono::microseconds>(
46 endPoint - startPoint).count());
47}
48
49void NotifyCallbackAndCheck(const ::android::sp<V1_0::IExecutionCallback>& callback,
50 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000051 std::vector<V1_2::OutputShape>,
52 const V1_2::Timing,
Kevin May42477c12020-03-26 13:34:14 +000053 std::string callingFunction)
54{
55 Return<void> returned = callback->notify(convertToV1_0(errorStatus));
56 // This check is required, if the callback fails and it isn't checked it will bring down the service
57 if (!returned.isOk())
58 {
59 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
60 callingFunction.c_str(), returned.description().c_str());
61 }
62}
63
64void NotifyCallbackAndCheck(const ::android::sp<V1_2::IExecutionCallback>& callback,
65 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000066 std::vector<V1_2::OutputShape> outputShapes,
67 const V1_2::Timing timing,
Kevin May42477c12020-03-26 13:34:14 +000068 std::string callingFunction)
69{
70 Return<void> returned = callback->notify_1_2(convertToV1_0(errorStatus), outputShapes, timing);
71 // This check is required, if the callback fails and it isn't checked it will bring down the service
72 if (!returned.isOk())
73 {
74 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
75 callingFunction.c_str(), returned.description().c_str());
76 }
77}
78
79void NotifyCallbackAndCheck(const ::android::sp<V1_3::IExecutionCallback>& callback,
80 V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +000081 std::vector<V1_2::OutputShape> outputShapes,
82 const V1_2::Timing timing,
Kevin May42477c12020-03-26 13:34:14 +000083 std::string callingFunction)
84{
85 Return<void> returned = callback->notify_1_3(errorStatus, outputShapes, timing);
86 // This check is required, if the callback fails and it isn't checked it will bring down the service
87 if (!returned.isOk())
88 {
89 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
90 callingFunction.c_str(), returned.description().c_str());
91 }
92}
93
Sadik Armagan188675f2021-02-12 17:16:42 +000094bool ValidateRequestArgument(const V1_0::RequestArgument& requestArg, const armnn::TensorInfo& tensorInfo)
Kevin May42477c12020-03-26 13:34:14 +000095{
96 if (requestArg.dimensions.size() != 0)
97 {
98 if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
99 {
100 ALOGE("Mismatched dimensions (request argument: %zu, expected: %u)",
101 requestArg.dimensions.size(), tensorInfo.GetNumDimensions());
102 return false;
103 }
104
105 for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
106 {
Finn Williamsa4983ce2020-07-23 12:55:12 +0100107 if (requestArg.dimensions[d] != 0 && requestArg.dimensions[d] != tensorInfo.GetShape()[d])
Kevin May42477c12020-03-26 13:34:14 +0000108 {
109 ALOGE("Mismatched size for dimension %d (request argument: %u, expected %u)",
110 d, requestArg.dimensions[d], tensorInfo.GetShape()[d]);
111 return false;
112 }
113 }
114 }
115
116 return true;
117}
118
Sadik Armagan188675f2021-02-12 17:16:42 +0000119armnn::Tensor GetTensorForRequestArgument(const V1_0::RequestArgument& requestArg,
Kevin May42477c12020-03-26 13:34:14 +0000120 const armnn::TensorInfo& tensorInfo,
121 const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
122{
123 if (!ValidateRequestArgument(requestArg, tensorInfo))
124 {
125 return armnn::Tensor();
126 }
127
128 return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
129}
130
131inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
132{
133 return tensorNamePrefix + std::to_string(index);
134}
135
136} // anonymous namespace
137
138using namespace android::hardware;
139
140namespace armnn_driver
141{
142
143template<typename HalVersion>
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100144RequestThread_1_3<ArmnnPreparedModel_1_3, HalVersion, CallbackContext_1_3>
Kevin May42477c12020-03-26 13:34:14 +0000145 ArmnnPreparedModel_1_3<HalVersion>::m_RequestThread;
146
147template<typename HalVersion>
148template<typename TensorBindingCollection>
149void ArmnnPreparedModel_1_3<HalVersion>::DumpTensorsIfRequired(char const* tensorNamePrefix,
150 const TensorBindingCollection& tensorBindings)
151{
152 if (!m_RequestInputsAndOutputsDumpDir.empty())
153 {
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100154 const std::string requestName = std::to_string(m_NetworkId) + "_" + std::to_string(m_RequestCount) + ".dump";
Kevin May42477c12020-03-26 13:34:14 +0000155 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
156 {
157 DumpTensor(m_RequestInputsAndOutputsDumpDir,
158 requestName,
159 BuildTensorName(tensorNamePrefix, i),
160 tensorBindings[i].second);
161 }
162 }
163}
164
165template<typename HalVersion>
166ArmnnPreparedModel_1_3<HalVersion>::ArmnnPreparedModel_1_3(armnn::NetworkId networkId,
167 armnn::IRuntime* runtime,
168 const V1_3::Model& model,
169 const std::string& requestInputsAndOutputsDumpDir,
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100170 const bool gpuProfilingEnabled,
Finn Williamsd8fb5402021-05-19 20:52:00 +0100171 V1_3::Priority priority,
172 const bool asyncModelExecutionEnabled)
Kevin May42477c12020-03-26 13:34:14 +0000173 : m_NetworkId(networkId)
174 , m_Runtime(runtime)
175 , m_Model(model)
176 , m_RequestCount(0)
177 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
178 , m_GpuProfilingEnabled(gpuProfilingEnabled)
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100179 , m_ModelPriority(priority)
Finn Williamsd8fb5402021-05-19 20:52:00 +0100180 , m_AsyncModelExecutionEnabled(asyncModelExecutionEnabled)
Kevin May42477c12020-03-26 13:34:14 +0000181{
182 // Enable profiling if required.
183 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
Finn Williamsd8fb5402021-05-19 20:52:00 +0100184
185 if (asyncModelExecutionEnabled)
186 {
187 m_WorkingMemHandle = m_Runtime->CreateWorkingMemHandle(networkId);
188 }
Kevin May42477c12020-03-26 13:34:14 +0000189}
190
191template<typename HalVersion>
192ArmnnPreparedModel_1_3<HalVersion>::~ArmnnPreparedModel_1_3()
193{
194 // Get a hold of the profiler used by this model.
195 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
196
197 // Unload the network associated with this model.
198 m_Runtime->UnloadNetwork(m_NetworkId);
199
200 // Dump the profiling info to a file if required.
201 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId, profiler.get());
202}
203
204template<typename HalVersion>
205Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute(const V1_0::Request& request,
206 const ::android::sp<V1_0::IExecutionCallback>& callback)
207{
208 if (callback.get() == nullptr)
209 {
210 ALOGE("ArmnnPreparedModel_1_3::execute invalid callback passed");
211 return V1_0::ErrorStatus::INVALID_ARGUMENT;
212 }
213
214 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000215 std::vector<V1_2::OutputShape> outputShapes,
216 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000217 std::string callingFunction)
218 {
219 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
220 };
221
222
Sadik Armagan188675f2021-02-12 17:16:42 +0000223 return convertToV1_0(Execute(convertToV1_3(request), V1_2::MeasureTiming::NO, cb));
Kevin May42477c12020-03-26 13:34:14 +0000224}
225
226template<typename HalVersion>
227Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute_1_2(
228 const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000229 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000230 const sp<V1_2::IExecutionCallback>& callback)
231{
232 if (callback.get() == nullptr)
233 {
234 ALOGE("ArmnnPreparedModel_1_3::execute_1_2 invalid callback passed");
235 return V1_0::ErrorStatus::INVALID_ARGUMENT;
236 }
237
238 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000239 std::vector<V1_2::OutputShape> outputShapes,
240 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000241 std::string callingFunction)
242 {
243 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
244 };
245
246 return convertToV1_0(Execute(convertToV1_3(request), measureTiming, cb));
247}
248
249template<typename HalVersion>
250Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute_1_3(
251 const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000252 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000253 const V1_3::OptionalTimePoint&,
Kevin May352d8382020-03-31 15:03:42 +0100254 const V1_3::OptionalTimeoutDuration&,
Kevin May42477c12020-03-26 13:34:14 +0000255 const sp<V1_3::IExecutionCallback>& callback)
256{
257 if (callback.get() == nullptr)
258 {
259 ALOGE("ArmnnPreparedModel_1_3::execute_1_3 invalid callback passed");
260 return V1_3::ErrorStatus::INVALID_ARGUMENT;
261 }
262
263 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000264 std::vector<V1_2::OutputShape> outputShapes,
265 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000266 std::string callingFunction)
267 {
268 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
269 };
270
271 return Execute(request, measureTiming, cb);
272}
273
Sadik Armagand7be72e2020-04-23 12:56:05 +0100274/// This class is inspired by the sample implementation in Android named SampleFencedExecutionCallback.
275/// The original code is licensed under Apache-2.0 and can be found at the following link:
276/// https://android.googlesource.com/platform/frameworks/ml/+/master/nn/driver/sample/SampleDriver.h
277class ArmnnFencedExecutionCallback : public V1_3::IFencedExecutionCallback
278{
279public:
Sadik Armagan188675f2021-02-12 17:16:42 +0000280 ArmnnFencedExecutionCallback(V1_3::ErrorStatus errorStatus, V1_2::Timing timing, V1_2::Timing fenceTiming)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100281 : m_ErrorStatus(errorStatus), m_Timing(timing), m_FenceTiming(fenceTiming) {}
282 ~ArmnnFencedExecutionCallback() {}
283
284 Return<void> getExecutionInfo(getExecutionInfo_cb callback) override
285 {
286 callback(m_ErrorStatus, m_Timing, m_FenceTiming);
287 return Void();
288 }
289private:
290 V1_3::ErrorStatus m_ErrorStatus;
Sadik Armagan188675f2021-02-12 17:16:42 +0000291 V1_2::Timing m_Timing;
292 V1_2::Timing m_FenceTiming;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100293};
294
Kevin May42477c12020-03-26 13:34:14 +0000295template<typename HalVersion>
Sadik Armagand7be72e2020-04-23 12:56:05 +0100296Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeFenced(const V1_3::Request& request,
297 const hidl_vec<hidl_handle>& fenceWaitFor,
Sadik Armagan188675f2021-02-12 17:16:42 +0000298 V1_2::MeasureTiming measureTiming,
299 const V1_3::OptionalTimePoint& deadline,
300 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
301 const V1_3::OptionalTimeoutDuration&,
Kevin May42477c12020-03-26 13:34:14 +0000302 executeFenced_cb cb)
303{
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100304 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...)");
305 if (cb == nullptr)
306 {
307 ALOGE("ArmnnPreparedModel_1_3::executeFenced invalid callback passed");
Sadik Armagan188675f2021-02-12 17:16:42 +0000308 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100309 return Void();
310 }
311
Sadik Armagan188675f2021-02-12 17:16:42 +0000312 if (deadline.getDiscriminator() != V1_3::OptionalTimePoint::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100313 {
314 ALOGW("ArmnnPreparedModel_1_3::executeFenced parameter deadline is set but not supported.");
315 }
316
Sadik Armagan188675f2021-02-12 17:16:42 +0000317 if (loopTimeoutDuration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100318 {
319 ALOGW("ArmnnPreparedModel_1_3::executeFenced parameter loopTimeoutDuration is set but not supported.");
320 }
321
Finn Williamsa4983ce2020-07-23 12:55:12 +0100322 if (!android::nn::validateRequest(request, m_Model, /*allowUnspecifiedOutput=*/false))
323 {
324 ALOGV("ArmnnPreparedModel_1_3::executeFenced outputs must be specified for fenced execution ");
Sadik Armagan188675f2021-02-12 17:16:42 +0000325 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Finn Williamsa4983ce2020-07-23 12:55:12 +0100326 return Void();
327 }
328
Sadik Armagand7be72e2020-04-23 12:56:05 +0100329 ExecutionContext_1_3 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000330 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100331 {
332 ctx.measureTimings = measureTiming;
333 ctx.driverStart = Now();
334 }
335
336 ALOGV("ArmnnPreparedModel_1_3::executeFenced(): %s", GetModelSummary(m_Model).c_str());
337 m_RequestCount++;
338
Sadik Armagand7be72e2020-04-23 12:56:05 +0100339 if (!m_RequestInputsAndOutputsDumpDir.empty())
340 {
341 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&cb));
342 }
343
344 // This code snippet is inspired by the sample implementation in Android named SampleDriver::executeFenced()
345 // function. The original code is licensed under Apache-2.0 and can be found at the following link:
346 // https://android.googlesource.com/platform/frameworks/ml/+/master/nn/driver/sample/SampleDriver.cpp
347 const auto fenceSize = fenceWaitFor.size();
348 for (unsigned int index = 0; index < fenceSize; ++index)
349 {
350 auto fenceNativeHandle = fenceWaitFor[index].getNativeHandle();
351 if (!fenceNativeHandle)
352 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000353 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100354 return Void();
355 }
356
357 if (sync_wait(fenceNativeHandle->data[0], -1) < 0)
358 {
359 ALOGE("ArmnnPreparedModel_1_3::executeFenced sync fence failed.");
Sadik Armagan188675f2021-02-12 17:16:42 +0000360 cb(V1_3::ErrorStatus::GENERAL_FAILURE, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100361 return Void();
362 }
363 }
364
365 TimePoint fenceExecutionStart;
Sadik Armagan188675f2021-02-12 17:16:42 +0000366 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100367 {
368 fenceExecutionStart = Now();
369 }
370
371 // map the memory pool into shared pointers
372 // use a shared memory pools vector on the heap, as it is passed to the request thread
373 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
374
375 // allocate the tensors on the heap, as they are passed to the request thread
376 auto inputs = std::make_shared<armnn::InputTensors>();
377 auto outputs = std::make_shared<armnn::OutputTensors>();
378
379 auto [status, outShapes, timings, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
380 if (status != V1_3::ErrorStatus::NONE)
381 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000382 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100383 return Void();
384 }
385
386 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...) before ExecuteGraph");
387
388 // call it with nullCallback for now as we will report the error status from here..
Sadik Armagan188675f2021-02-12 17:16:42 +0000389 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Sadik Armagand7be72e2020-04-23 12:56:05 +0100390 CallbackContext_1_3 cbCtx;
391 cbCtx.callback = nullCallback;
392 cbCtx.ctx = ctx;
393
394 auto errorStatus = ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
395 if (errorStatus != V1_3::ErrorStatus::NONE)
396 {
397 cb(errorStatus, hidl_handle(nullptr), nullptr);
398 return Void();
399 }
400 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...) after ExecuteGraph");
401
Sadik Armagan188675f2021-02-12 17:16:42 +0000402 V1_2::Timing timing = g_NoTiming;
403 V1_2::Timing fenceTiming = g_NoTiming;
404 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100405 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100406 fenceTiming.timeOnDevice = MicrosecondsDuration(ctx.deviceEnd, ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100407 fenceTiming.timeInDriver = MicrosecondsDuration(ctx.driverEnd, fenceExecutionStart);
408 ALOGV("ArmnnPreparedModel_1_3::fenceFinishExecutionTiming - Device = %lu Driver = %lu",
Sadik Armagand7be72e2020-04-23 12:56:05 +0100409 fenceTiming.timeOnDevice, fenceTiming.timeInDriver);
410 }
411
412 sp<ArmnnFencedExecutionCallback> armnnFencedExecutionCallback =
Sadik Armagan188675f2021-02-12 17:16:42 +0000413 new ArmnnFencedExecutionCallback(V1_3::ErrorStatus::NONE, timing, fenceTiming);
414 cb(V1_3::ErrorStatus::NONE, hidl_handle(nullptr), armnnFencedExecutionCallback);
Kevin May42477c12020-03-26 13:34:14 +0000415 return Void();
416}
417
418template<typename HalVersion>
419Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForInputs(
420 armnn::InputTensors& inputs,
421 const V1_3::Request& request,
422 const std::vector<android::nn::RunTimePoolInfo>& memPools)
423{
424 inputs.reserve(request.inputs.size());
425 for (unsigned int i = 0; i < request.inputs.size(); i++)
426 {
427 const auto& inputArg = request.inputs[i];
428
429 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
430 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
431
432 if (inputTensor.GetMemoryArea() == nullptr)
433 {
434 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
435 return V1_3::ErrorStatus::GENERAL_FAILURE;
436 }
437
438 inputs.emplace_back(i, inputTensor);
439 }
440
441 return V1_3::ErrorStatus::NONE;
442}
443
444template<typename HalVersion>
445Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForOutputs(
446 armnn::OutputTensors& outputs,
Sadik Armagan188675f2021-02-12 17:16:42 +0000447 std::vector<V1_2::OutputShape> &outputShapes,
Kevin May42477c12020-03-26 13:34:14 +0000448 const V1_3::Request& request,
449 const std::vector<android::nn::RunTimePoolInfo>& memPools)
450{
451 outputs.reserve(request.outputs.size());
452 for (unsigned int i = 0; i < request.outputs.size(); i++)
453 {
454 const auto& outputArg = request.outputs[i];
455
Finn Williamsa4983ce2020-07-23 12:55:12 +0100456 armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
Kevin May42477c12020-03-26 13:34:14 +0000457 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
458 if (outputTensor.GetMemoryArea() == nullptr)
459 {
460 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
461 return V1_3::ErrorStatus::GENERAL_FAILURE;
462 }
463
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100464 const size_t outputSize = outputTensorInfo.GetNumBytes();
465
Finn Williamsa4983ce2020-07-23 12:55:12 +0100466 unsigned int count = 0;
467 std::for_each(outputArg.dimensions.begin(), outputArg.dimensions.end(), [&](auto dim)
468 {
469 if (dim != 0)
470 {
471 outputTensorInfo.GetShape()[count] = dim;
472 }
473 else
474 {
475 outputTensorInfo.GetShape()[count] = outputArg.dimensions.size();
476 }
477
478 count++;
479 });
480
Finn Williamsa4983ce2020-07-23 12:55:12 +0100481 outputs.emplace_back(i, outputTensor);
482 outputShapes[i] = ComputeShape(outputTensorInfo);
483
484 if (outputArg.location.length < outputSize)
485 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100486 ALOGW("ArmnnPreparedModel_1_3::Execute failed outputArg.location.length (%s) < outputSize (%s)",
487 std::to_string(outputArg.location.length).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100488 outputShapes[i].isSufficient = false;
489 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
490 }
491
Sadik Armagan188675f2021-02-12 17:16:42 +0000492 size_t bufferSize = 0;
493#if !defined(ARMNN_ANDROID_S)
494 bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
495 if (bufferSize < outputSize)
496#else
497 bufferSize = memPools.at(outputArg.location.poolIndex).getMemory().size;
498#endif
Kevin May42477c12020-03-26 13:34:14 +0000499 if (bufferSize < outputSize)
500 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100501 ALOGW("ArmnnPreparedModel_1_3::Execute failed bufferSize (%s) < outputSize (%s)",
502 std::to_string(bufferSize).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100503 outputShapes[i].isSufficient = false;
Kevin May42477c12020-03-26 13:34:14 +0000504 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
505 }
Kevin May42477c12020-03-26 13:34:14 +0000506 }
507
508 return V1_3::ErrorStatus::NONE;
509}
510
511template<typename HalVersion>
Sadik Armagan188675f2021-02-12 17:16:42 +0000512std::tuple<V1_3::ErrorStatus, hidl_vec<V1_2::OutputShape>, V1_2::Timing, std::string>
Kevin May42477c12020-03-26 13:34:14 +0000513 ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForIO(armnn::InputTensors& inputs,
514 armnn::OutputTensors& outputs,
515 std::vector<android::nn::RunTimePoolInfo>& memPools,
516 const V1_3::Request& request)
517{
Sadik Armagan188675f2021-02-12 17:16:42 +0000518#if !defined(ARMNN_ANDROID_S)
Kevin May42477c12020-03-26 13:34:14 +0000519 if (!setRunTimePoolInfosFromMemoryPools(&memPools, request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000520#else
521 if (!setRunTimePoolInfosFromMemoryPools(&memPools, uncheckedConvert(request.pools)))
522#endif
Kevin May42477c12020-03-26 13:34:14 +0000523 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000524 return {V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000525 }
526
527 // add the inputs and outputs with their data
528 try
529 {
530 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_3::ErrorStatus::NONE)
531 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000532 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000533 }
534
Sadik Armagan188675f2021-02-12 17:16:42 +0000535 std::vector<V1_2::OutputShape> outputShapes(request.outputs.size());
Kevin May42477c12020-03-26 13:34:14 +0000536
537 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
538 if (errorStatus != V1_3::ErrorStatus::NONE)
539 {
540 return {errorStatus, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
541 }
542 }
543 catch (armnn::Exception& e)
544 {
545 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000546 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000547 }
548 catch (std::exception& e)
549 {
550 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000551 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000552 }
553
554 return {V1_3::ErrorStatus::NONE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
555}
556
557template<typename HalVersion>
558template<typename CallbackContext>
559Return<void> ArmnnPreparedModel_1_3<HalVersion>::ExecuteSynchronously(const V1_3::Request& request,
560 CallbackContext cbCtx)
561{
Sadik Armagan188675f2021-02-12 17:16:42 +0000562 if (cbCtx.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000563 {
564 cbCtx.ctx.driverStart = Now();
565 }
566
567 if (!android::nn::validateRequest(convertToV1_3(request), m_Model))
568 {
569 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
570 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
571 {},
572 g_NoTiming,
573 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
574 return Void();
575 }
576
577 if (!android::nn::validateRequest(request, m_Model))
578 {
579 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
580 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
581 {},
582 g_NoTiming,
583 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
Sadik Armaganef8a3932020-04-09 17:21:50 +0100584 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000585 }
586
587
588 // map the memory pool into shared pointers
589 // use a shared memory pools vector on the heap, as it is passed to the request thread
590 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
591
592 // allocate the tensors on the heap, as they are passed to the request thread
593 auto inputs = std::make_shared<armnn::InputTensors>();
594 auto outputs = std::make_shared<armnn::OutputTensors>();
595
596 auto [status, outputShapes, timing, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
597 if (status != V1_3::ErrorStatus::NONE)
598 {
599 cbCtx.callback(status, outputShapes, timing, message);
Sadik Armaganef8a3932020-04-09 17:21:50 +0100600 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000601 }
602
603 ALOGV("ArmnnPreparedModel_1_3::ExecuteSynchronously() before Execution");
604
605 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
606 return Void();
607}
608
609template<typename HalVersion>
610Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000611 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000612 executeSynchronously_cb cb)
613{
614 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
615 m_RequestCount++;
616
617 if (cb == nullptr)
618 {
619 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously invalid callback passed");
620 return Void();
621 }
622
623 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000624 std::vector<V1_2::OutputShape> outputShapes,
625 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000626 std::string)
627 {
628 cb(convertToV1_0(errorStatus), outputShapes, timing);
629 };
630
631 CallbackContext_1_3 cbCtx;
632 cbCtx.callback = cbWrapper;
633 cbCtx.ctx.measureTimings = measureTiming;
634
635 ExecuteSynchronously(convertToV1_3(request), cbCtx);
636 return Void();
637}
638
639template<typename HalVersion>
Kevin May352d8382020-03-31 15:03:42 +0100640Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously_1_3(
641 const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000642 V1_2::MeasureTiming measureTiming,
Kevin May352d8382020-03-31 15:03:42 +0100643 const V1_3::OptionalTimePoint& deadline,
644 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
645 executeSynchronously_1_3_cb cb)
Kevin May42477c12020-03-26 13:34:14 +0000646{
647 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously_1_3(): %s", GetModelSummary(m_Model).c_str());
648 m_RequestCount++;
649
650 if (cb == nullptr)
651 {
652 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid callback passed");
653 return Void();
654 }
655
Sadik Armagan188675f2021-02-12 17:16:42 +0000656 if (deadline.getDiscriminator() != V1_3::OptionalTimePoint::hidl_discriminator::none)
Kevin May42477c12020-03-26 13:34:14 +0000657 {
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100658 ALOGW("ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter deadline is set but not supported.");
Kevin May42477c12020-03-26 13:34:14 +0000659 }
660
Sadik Armagan188675f2021-02-12 17:16:42 +0000661 if (loopTimeoutDuration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100662 {
663 ALOGW(
664 "ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter loopTimeoutDuration is set but not supported.");
Kevin May352d8382020-03-31 15:03:42 +0100665 }
666
Kevin May42477c12020-03-26 13:34:14 +0000667 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000668 std::vector<V1_2::OutputShape> outputShapes,
669 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000670 std::string)
671 {
672 cb(errorStatus, outputShapes, timing);
673 };
674
675 CallbackContext_1_3 cbCtx;
676 cbCtx.callback = cbWrapper;
677 cbCtx.ctx.measureTimings = measureTiming;
678
679 ExecuteSynchronously(request, cbCtx);
680 return Void();
681}
682
683template<typename HalVersion>
684Return<void> ArmnnPreparedModel_1_3<HalVersion>::configureExecutionBurst(
685 const sp<V1_2::IBurstCallback>& callback,
686 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
687 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
688 V1_3::IPreparedModel::configureExecutionBurst_cb cb)
689{
690 ALOGV("ArmnnPreparedModel_1_3::configureExecutionBurst");
691 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
692 requestChannel,
693 resultChannel,
694 this);
695
696 if (burst == nullptr)
697 {
698 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
699 }
700 else
701 {
702 cb(V1_0::ErrorStatus::NONE, burst);
703 }
704 return Void();
705}
706
707template<typename HalVersion>
708template<typename CallbackContext>
Sadik Armagand7be72e2020-04-23 12:56:05 +0100709Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::ExecuteGraph(
Kevin May42477c12020-03-26 13:34:14 +0000710 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
711 armnn::InputTensors& inputTensors,
712 armnn::OutputTensors& outputTensors,
713 CallbackContext cb)
714{
715 ALOGV("ArmnnPreparedModel_1_3::ExecuteGraph(...)");
716
Kevin May42477c12020-03-26 13:34:14 +0000717 DumpTensorsIfRequired("Input", inputTensors);
718
Sadik Armagan188675f2021-02-12 17:16:42 +0000719 std::vector<V1_2::OutputShape> outputShapes(outputTensors.size());
Kevin May42477c12020-03-26 13:34:14 +0000720 for (unsigned int i = 0; i < outputTensors.size(); i++)
721 {
722 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
723 const armnn::Tensor outputTensor = outputTensorPair.second;
724 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
725
726 outputShapes[i] = ComputeShape(outputTensorInfo);
727 }
728
729 // run it
730 try
731 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000732 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000733 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100734 cb.ctx.deviceStart = Now();
Kevin May42477c12020-03-26 13:34:14 +0000735 }
Finn Williamsd8fb5402021-05-19 20:52:00 +0100736 armnn::Status status;
737 if (m_AsyncModelExecutionEnabled)
738 {
739 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled true");
740 status = m_Runtime->Execute(*m_WorkingMemHandle, inputTensors, outputTensors);
741 }
742 else
743 {
744 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph m_AsyncModelExecutionEnabled false");
745 status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
746 }
Kevin May42477c12020-03-26 13:34:14 +0000747
Sadik Armagan188675f2021-02-12 17:16:42 +0000748 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000749 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100750 cb.ctx.deviceEnd = Now();
Kevin May42477c12020-03-26 13:34:14 +0000751 }
752 if (status != armnn::Status::Success)
753 {
Finn Williamsd8fb5402021-05-19 20:52:00 +0100754 ALOGW("ArmnnPreparedModel_1_3::ExecuteGraph EnqueueWorkload failed");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100755 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
756 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000757 }
758 }
759 catch (armnn::Exception& e)
760 {
761 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
762 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100763 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000764 }
765 catch (std::exception& e)
766 {
767 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
768 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100769 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000770 }
771
772 CommitPools(*pMemPools);
773
774 DumpTensorsIfRequired("Output", outputTensors);
775
Sadik Armagan188675f2021-02-12 17:16:42 +0000776 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000777 {
Kevin May949a69e2020-04-24 10:21:40 +0100778 cb.ctx.driverEnd = Now();
Sadik Armagan188675f2021-02-12 17:16:42 +0000779 V1_2::Timing timing;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100780 timing.timeOnDevice = MicrosecondsDuration(cb.ctx.deviceEnd, cb.ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100781 timing.timeInDriver = MicrosecondsDuration(cb.ctx.driverEnd, cb.ctx.driverStart);
782 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
Kevin May42477c12020-03-26 13:34:14 +0000783 timing.timeInDriver);
784 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100785 } else
786 {
Kevin May42477c12020-03-26 13:34:14 +0000787 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
788 }
Sadik Armagand7be72e2020-04-23 12:56:05 +0100789 return V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000790}
791
Finn Williamsd8fb5402021-05-19 20:52:00 +0100792/// Schedule the graph prepared from the request for execution
793template<typename HalVersion>
794template<typename CallbackContext>
795void ArmnnPreparedModel_1_3<HalVersion>::ScheduleGraphForExecution(
796 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
797 std::shared_ptr<armnn::InputTensors>& inputTensors,
798 std::shared_ptr<armnn::OutputTensors>& outputTensors,
799 CallbackContext callbackContext,
800 armnn::QosExecPriority priority)
801{
802 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution(...)");
803
804 DumpTensorsIfRequired("Input", *inputTensors);
805
806 unsigned int outputTensorSize = outputTensors.get()->size();
807 std::vector<V1_2::OutputShape> outputShapes(outputTensorSize);
808 for (unsigned int i = 0; i < outputTensorSize; i++)
809 {
810 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors.get()->at(i);
811 const armnn::Tensor outputTensor = outputTensorPair.second;
812 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
813
814 outputShapes[i] = ComputeShape(outputTensorInfo);
815 }
816
817 auto tpCb = std::make_shared<
818 ArmnnThreadPoolCallback_1_3<CallbackContext_1_3>>(this,
819 pMemPools,
820 outputShapes,
821 inputTensors,
822 outputTensors,
823 callbackContext);
824
825 m_Runtime->Schedule(m_NetworkId,
826 *tpCb->m_InputTensors,
827 *tpCb->m_OutputTensors,
828 priority,
829 tpCb);
830 ALOGV("ArmnnPreparedModel_1_3::ScheduleGraphForExecution end");
831}
832
Kevin May42477c12020-03-26 13:34:14 +0000833template<typename HalVersion>
834bool ArmnnPreparedModel_1_3<HalVersion>::ExecuteWithDummyInputs()
835{
836 std::vector<std::vector<char>> storage;
837 armnn::InputTensors inputTensors;
838 for (unsigned int i = 0; i < getMainModel(m_Model).inputIndexes.size(); i++)
839 {
840 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
841 storage.emplace_back(inputTensorInfo.GetNumBytes());
842 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
843
844 inputTensors.emplace_back(i, inputTensor);
845 }
846
847 armnn::OutputTensors outputTensors;
848 for (unsigned int i = 0; i < getMainModel(m_Model).outputIndexes.size(); i++)
849 {
850 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
851 storage.emplace_back(outputTensorInfo.GetNumBytes());
852 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
853
854 outputTensors.emplace_back(i, outputTensor);
855 }
856
Sadik Armagan188675f2021-02-12 17:16:42 +0000857 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Kevin May42477c12020-03-26 13:34:14 +0000858 CallbackContext_1_3 callbackContext;
859 callbackContext.callback = nullCallback;
Sadik Armagan188675f2021-02-12 17:16:42 +0000860 callbackContext.ctx.measureTimings = V1_2::MeasureTiming::NO;
Kevin May42477c12020-03-26 13:34:14 +0000861 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
Sadik Armagand7be72e2020-04-23 12:56:05 +0100862
863 auto errorStatus = ExecuteGraph(memPools,
864 inputTensors,
865 outputTensors,
866 callbackContext);
867 return errorStatus == V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000868}
869
870template<typename HalVersion>
871Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::Execute(const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000872 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000873 CallbackAsync_1_3 callback)
874{
875 ExecutionContext_1_3 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000876 if (measureTiming == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000877 {
878 ctx.measureTimings = measureTiming;
879 ctx.driverStart = Now();
880 }
881
882 ALOGV("ArmnnPreparedModel_1_3::execute(): %s", GetModelSummary(m_Model).c_str());
883 m_RequestCount++;
884
885 if (!android::nn::validateRequest(request, m_Model))
886 {
887 callback(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute");
888 return V1_3::ErrorStatus::INVALID_ARGUMENT;
889 }
890
891 if (!m_RequestInputsAndOutputsDumpDir.empty())
892 {
893 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
894 }
895
896 // map the memory pool into shared pointers
897 // use a shared memory pools vector on the heap, as it is passed to the request thread
898 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
899
900 // allocate the tensors on the heap, as they are passed to the request thread
901 auto inputTensors = std::make_shared<armnn::InputTensors>();
902 auto outputTensors = std::make_shared<armnn::OutputTensors>();
903
904 auto [status, outShapes, timing, message] = PrepareMemoryForIO(*inputTensors, *outputTensors,
905 *memPools, request);
906 if (status != V1_3::ErrorStatus::NONE)
907 {
908 callback(status, outShapes, timing, message);
909 }
910
911 switch(status)
912 {
913 case V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
914 return V1_3::ErrorStatus::NONE;
915 case V1_3::ErrorStatus::GENERAL_FAILURE:
916 return V1_3::ErrorStatus::GENERAL_FAILURE;
Sadik Armagana07d2752021-05-12 20:33:58 +0100917 case V1_3::ErrorStatus::INVALID_ARGUMENT:
918 return V1_3::ErrorStatus::INVALID_ARGUMENT;
Kevin May42477c12020-03-26 13:34:14 +0000919 default:
920 {}
921 }
Kevin May42477c12020-03-26 13:34:14 +0000922 CallbackContext_1_3 cb;
923 cb.callback = callback;
924 cb.ctx = ctx;
Finn Williamsd8fb5402021-05-19 20:52:00 +0100925
926
927 enum class QosExecPriority
928 {
929 Low = 0,
930 Medium = 1,
931 High = 2
932 };
933
934
935 if (m_AsyncModelExecutionEnabled)
936 {
937 armnn::QosExecPriority priority;
938
939 switch (GetModelPriority()) {
940 case V1_3::Priority::LOW:
941 priority = armnn::QosExecPriority::Low;
942 break;
943 case V1_3::Priority::MEDIUM:
944 priority = armnn::QosExecPriority::Medium;
945 break;
946 case V1_3::Priority::HIGH:
947 priority = armnn::QosExecPriority::High;
948 break;
949 default:
950 priority = armnn::QosExecPriority::Medium;
951
952 }
953
954 ALOGV("ArmnnPreparedModel_1_3::execute(...) before ScheduleGraphForExecution");
955 ScheduleGraphForExecution(memPools, inputTensors, outputTensors, cb, priority);
956 ALOGV("ArmnnPreparedModel_1_3::execute(...) after ScheduleGraphForExecution");
957 return V1_3::ErrorStatus::NONE;
958 }
959
960 ALOGV("ArmnnPreparedModel_1_3::execute(...) before PostMsg");
961 // post the request for asynchronous execution
Kevin May42477c12020-03-26 13:34:14 +0000962 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
963 ALOGV("ArmnnPreparedModel_1_3::execute(...) after PostMsg");
964 return V1_3::ErrorStatus::NONE;
965}
966
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100967template<typename HalVersion>
968V1_3::Priority ArmnnPreparedModel_1_3<HalVersion>::GetModelPriority()
969{
970 return m_ModelPriority;
971}
972
Finn Williamsd8fb5402021-05-19 20:52:00 +0100973template<typename HalVersion>
974template <typename CallbackContext>
975void ArmnnPreparedModel_1_3<HalVersion>::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify(
976 armnn::Status status, armnn::InferenceTimingPair timeTaken)
977{
978 ALOGV("ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3<CallbackContext>::Notify");
979 CommitPools(*m_MemPools);
980
981 m_Model->DumpTensorsIfRequired("Output", *m_OutputTensors);
982
983 if (status != armnn::Status::Success)
984 {
985 ALOGW("ArmnnThreadPoolCallback_1_3::Notify EnqueueWorkload failed");
986 m_CallbackContext.callback(V1_3::ErrorStatus::GENERAL_FAILURE,
987 {},
988 g_NoTiming,
989 "ArmnnPreparedModel_1_3::ArmnnThreadPoolCallback_1_3");
990 return;
991 }
992
993 if (m_CallbackContext.ctx.measureTimings == V1_2::MeasureTiming::YES)
994 {
995 m_CallbackContext.ctx.deviceStart = timeTaken.first;
996 m_CallbackContext.ctx.deviceEnd = timeTaken.second;
997 m_CallbackContext.ctx.driverEnd = std::chrono::steady_clock::now();
998 V1_2::Timing timing;
999 timing.timeOnDevice = MicrosecondsDuration(m_CallbackContext.ctx.deviceEnd, m_CallbackContext.ctx.deviceStart);
1000 timing.timeInDriver = MicrosecondsDuration(m_CallbackContext.ctx.driverEnd, m_CallbackContext.ctx.driverStart);
1001 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
1002 timing.timeInDriver);
1003 m_CallbackContext.callback(
1004 V1_3::ErrorStatus::NONE, m_OutputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
1005 } else
1006 {
1007 m_CallbackContext.callback(
1008 V1_3::ErrorStatus::NONE, m_OutputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
1009 }
1010 return;
1011}
1012
Kevin May42477c12020-03-26 13:34:14 +00001013#ifdef ARMNN_ANDROID_NN_V1_3
1014template class ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>;
Sadik Armagand7be72e2020-04-23 12:56:05 +01001015template Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ExecuteGraph<CallbackContext_1_3>(
Kevin May42477c12020-03-26 13:34:14 +00001016 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1017 armnn::InputTensors& pInputTensors,
1018 armnn::OutputTensors& pOutputTensors,
1019 CallbackContext_1_3 cb);
Finn Williamsd8fb5402021-05-19 20:52:00 +01001020
1021template void ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ScheduleGraphForExecution<CallbackContext_1_3>(
1022 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
1023 std::shared_ptr<armnn::InputTensors>& inputTensors,
1024 std::shared_ptr<armnn::OutputTensors>& outputTensors,
1025 CallbackContext_1_3 callbackContext,
1026 armnn::QosExecPriority priority);
Kevin May42477c12020-03-26 13:34:14 +00001027#endif
1028
1029} // namespace armnn_driver