blob: 2970e8ff0a1df5a664a60ef8532b261319d9b476 [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,
171 V1_3::Priority priority)
Kevin May42477c12020-03-26 13:34:14 +0000172 : m_NetworkId(networkId)
173 , m_Runtime(runtime)
174 , m_Model(model)
175 , m_RequestCount(0)
176 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
177 , m_GpuProfilingEnabled(gpuProfilingEnabled)
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100178 , m_ModelPriority(priority)
Kevin May42477c12020-03-26 13:34:14 +0000179{
180 // Enable profiling if required.
181 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
182}
183
184template<typename HalVersion>
185ArmnnPreparedModel_1_3<HalVersion>::~ArmnnPreparedModel_1_3()
186{
187 // Get a hold of the profiler used by this model.
188 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
189
190 // Unload the network associated with this model.
191 m_Runtime->UnloadNetwork(m_NetworkId);
192
193 // Dump the profiling info to a file if required.
194 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId, profiler.get());
195}
196
197template<typename HalVersion>
198Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute(const V1_0::Request& request,
199 const ::android::sp<V1_0::IExecutionCallback>& callback)
200{
201 if (callback.get() == nullptr)
202 {
203 ALOGE("ArmnnPreparedModel_1_3::execute invalid callback passed");
204 return V1_0::ErrorStatus::INVALID_ARGUMENT;
205 }
206
207 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000208 std::vector<V1_2::OutputShape> outputShapes,
209 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000210 std::string callingFunction)
211 {
212 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
213 };
214
215
Sadik Armagan188675f2021-02-12 17:16:42 +0000216 return convertToV1_0(Execute(convertToV1_3(request), V1_2::MeasureTiming::NO, cb));
Kevin May42477c12020-03-26 13:34:14 +0000217}
218
219template<typename HalVersion>
220Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute_1_2(
221 const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000222 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000223 const sp<V1_2::IExecutionCallback>& callback)
224{
225 if (callback.get() == nullptr)
226 {
227 ALOGE("ArmnnPreparedModel_1_3::execute_1_2 invalid callback passed");
228 return V1_0::ErrorStatus::INVALID_ARGUMENT;
229 }
230
231 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000232 std::vector<V1_2::OutputShape> outputShapes,
233 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000234 std::string callingFunction)
235 {
236 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
237 };
238
239 return convertToV1_0(Execute(convertToV1_3(request), measureTiming, cb));
240}
241
242template<typename HalVersion>
243Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::execute_1_3(
244 const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000245 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000246 const V1_3::OptionalTimePoint&,
Kevin May352d8382020-03-31 15:03:42 +0100247 const V1_3::OptionalTimeoutDuration&,
Kevin May42477c12020-03-26 13:34:14 +0000248 const sp<V1_3::IExecutionCallback>& callback)
249{
250 if (callback.get() == nullptr)
251 {
252 ALOGE("ArmnnPreparedModel_1_3::execute_1_3 invalid callback passed");
253 return V1_3::ErrorStatus::INVALID_ARGUMENT;
254 }
255
256 auto cb = [callback](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000257 std::vector<V1_2::OutputShape> outputShapes,
258 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000259 std::string callingFunction)
260 {
261 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
262 };
263
264 return Execute(request, measureTiming, cb);
265}
266
Sadik Armagand7be72e2020-04-23 12:56:05 +0100267/// This class is inspired by the sample implementation in Android named SampleFencedExecutionCallback.
268/// The original code is licensed under Apache-2.0 and can be found at the following link:
269/// https://android.googlesource.com/platform/frameworks/ml/+/master/nn/driver/sample/SampleDriver.h
270class ArmnnFencedExecutionCallback : public V1_3::IFencedExecutionCallback
271{
272public:
Sadik Armagan188675f2021-02-12 17:16:42 +0000273 ArmnnFencedExecutionCallback(V1_3::ErrorStatus errorStatus, V1_2::Timing timing, V1_2::Timing fenceTiming)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100274 : m_ErrorStatus(errorStatus), m_Timing(timing), m_FenceTiming(fenceTiming) {}
275 ~ArmnnFencedExecutionCallback() {}
276
277 Return<void> getExecutionInfo(getExecutionInfo_cb callback) override
278 {
279 callback(m_ErrorStatus, m_Timing, m_FenceTiming);
280 return Void();
281 }
282private:
283 V1_3::ErrorStatus m_ErrorStatus;
Sadik Armagan188675f2021-02-12 17:16:42 +0000284 V1_2::Timing m_Timing;
285 V1_2::Timing m_FenceTiming;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100286};
287
Kevin May42477c12020-03-26 13:34:14 +0000288template<typename HalVersion>
Sadik Armagand7be72e2020-04-23 12:56:05 +0100289Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeFenced(const V1_3::Request& request,
290 const hidl_vec<hidl_handle>& fenceWaitFor,
Sadik Armagan188675f2021-02-12 17:16:42 +0000291 V1_2::MeasureTiming measureTiming,
292 const V1_3::OptionalTimePoint& deadline,
293 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
294 const V1_3::OptionalTimeoutDuration&,
Kevin May42477c12020-03-26 13:34:14 +0000295 executeFenced_cb cb)
296{
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100297 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...)");
298 if (cb == nullptr)
299 {
300 ALOGE("ArmnnPreparedModel_1_3::executeFenced invalid callback passed");
Sadik Armagan188675f2021-02-12 17:16:42 +0000301 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100302 return Void();
303 }
304
Sadik Armagan188675f2021-02-12 17:16:42 +0000305 if (deadline.getDiscriminator() != V1_3::OptionalTimePoint::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100306 {
307 ALOGW("ArmnnPreparedModel_1_3::executeFenced parameter deadline is set but not supported.");
308 }
309
Sadik Armagan188675f2021-02-12 17:16:42 +0000310 if (loopTimeoutDuration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100311 {
312 ALOGW("ArmnnPreparedModel_1_3::executeFenced parameter loopTimeoutDuration is set but not supported.");
313 }
314
Finn Williamsa4983ce2020-07-23 12:55:12 +0100315 if (!android::nn::validateRequest(request, m_Model, /*allowUnspecifiedOutput=*/false))
316 {
317 ALOGV("ArmnnPreparedModel_1_3::executeFenced outputs must be specified for fenced execution ");
Sadik Armagan188675f2021-02-12 17:16:42 +0000318 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Finn Williamsa4983ce2020-07-23 12:55:12 +0100319 return Void();
320 }
321
Sadik Armagand7be72e2020-04-23 12:56:05 +0100322 ExecutionContext_1_3 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000323 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100324 {
325 ctx.measureTimings = measureTiming;
326 ctx.driverStart = Now();
327 }
328
329 ALOGV("ArmnnPreparedModel_1_3::executeFenced(): %s", GetModelSummary(m_Model).c_str());
330 m_RequestCount++;
331
Sadik Armagand7be72e2020-04-23 12:56:05 +0100332 if (!m_RequestInputsAndOutputsDumpDir.empty())
333 {
334 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&cb));
335 }
336
337 // This code snippet is inspired by the sample implementation in Android named SampleDriver::executeFenced()
338 // function. The original code is licensed under Apache-2.0 and can be found at the following link:
339 // https://android.googlesource.com/platform/frameworks/ml/+/master/nn/driver/sample/SampleDriver.cpp
340 const auto fenceSize = fenceWaitFor.size();
341 for (unsigned int index = 0; index < fenceSize; ++index)
342 {
343 auto fenceNativeHandle = fenceWaitFor[index].getNativeHandle();
344 if (!fenceNativeHandle)
345 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000346 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100347 return Void();
348 }
349
350 if (sync_wait(fenceNativeHandle->data[0], -1) < 0)
351 {
352 ALOGE("ArmnnPreparedModel_1_3::executeFenced sync fence failed.");
Sadik Armagan188675f2021-02-12 17:16:42 +0000353 cb(V1_3::ErrorStatus::GENERAL_FAILURE, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100354 return Void();
355 }
356 }
357
358 TimePoint fenceExecutionStart;
Sadik Armagan188675f2021-02-12 17:16:42 +0000359 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100360 {
361 fenceExecutionStart = Now();
362 }
363
364 // map the memory pool into shared pointers
365 // use a shared memory pools vector on the heap, as it is passed to the request thread
366 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
367
368 // allocate the tensors on the heap, as they are passed to the request thread
369 auto inputs = std::make_shared<armnn::InputTensors>();
370 auto outputs = std::make_shared<armnn::OutputTensors>();
371
372 auto [status, outShapes, timings, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
373 if (status != V1_3::ErrorStatus::NONE)
374 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000375 cb(V1_3::ErrorStatus::INVALID_ARGUMENT, hidl_handle(nullptr), nullptr);
Sadik Armagand7be72e2020-04-23 12:56:05 +0100376 return Void();
377 }
378
379 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...) before ExecuteGraph");
380
381 // call it with nullCallback for now as we will report the error status from here..
Sadik Armagan188675f2021-02-12 17:16:42 +0000382 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Sadik Armagand7be72e2020-04-23 12:56:05 +0100383 CallbackContext_1_3 cbCtx;
384 cbCtx.callback = nullCallback;
385 cbCtx.ctx = ctx;
386
387 auto errorStatus = ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
388 if (errorStatus != V1_3::ErrorStatus::NONE)
389 {
390 cb(errorStatus, hidl_handle(nullptr), nullptr);
391 return Void();
392 }
393 ALOGV("ArmnnPreparedModel_1_3::executeFenced(...) after ExecuteGraph");
394
Sadik Armagan188675f2021-02-12 17:16:42 +0000395 V1_2::Timing timing = g_NoTiming;
396 V1_2::Timing fenceTiming = g_NoTiming;
397 if (measureTiming == V1_2::MeasureTiming::YES)
Sadik Armagand7be72e2020-04-23 12:56:05 +0100398 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100399 fenceTiming.timeOnDevice = MicrosecondsDuration(ctx.deviceEnd, ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100400 fenceTiming.timeInDriver = MicrosecondsDuration(ctx.driverEnd, fenceExecutionStart);
401 ALOGV("ArmnnPreparedModel_1_3::fenceFinishExecutionTiming - Device = %lu Driver = %lu",
Sadik Armagand7be72e2020-04-23 12:56:05 +0100402 fenceTiming.timeOnDevice, fenceTiming.timeInDriver);
403 }
404
405 sp<ArmnnFencedExecutionCallback> armnnFencedExecutionCallback =
Sadik Armagan188675f2021-02-12 17:16:42 +0000406 new ArmnnFencedExecutionCallback(V1_3::ErrorStatus::NONE, timing, fenceTiming);
407 cb(V1_3::ErrorStatus::NONE, hidl_handle(nullptr), armnnFencedExecutionCallback);
Kevin May42477c12020-03-26 13:34:14 +0000408 return Void();
409}
410
411template<typename HalVersion>
412Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForInputs(
413 armnn::InputTensors& inputs,
414 const V1_3::Request& request,
415 const std::vector<android::nn::RunTimePoolInfo>& memPools)
416{
417 inputs.reserve(request.inputs.size());
418 for (unsigned int i = 0; i < request.inputs.size(); i++)
419 {
420 const auto& inputArg = request.inputs[i];
421
422 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
423 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
424
425 if (inputTensor.GetMemoryArea() == nullptr)
426 {
427 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
428 return V1_3::ErrorStatus::GENERAL_FAILURE;
429 }
430
431 inputs.emplace_back(i, inputTensor);
432 }
433
434 return V1_3::ErrorStatus::NONE;
435}
436
437template<typename HalVersion>
438Return<V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForOutputs(
439 armnn::OutputTensors& outputs,
Sadik Armagan188675f2021-02-12 17:16:42 +0000440 std::vector<V1_2::OutputShape> &outputShapes,
Kevin May42477c12020-03-26 13:34:14 +0000441 const V1_3::Request& request,
442 const std::vector<android::nn::RunTimePoolInfo>& memPools)
443{
444 outputs.reserve(request.outputs.size());
445 for (unsigned int i = 0; i < request.outputs.size(); i++)
446 {
447 const auto& outputArg = request.outputs[i];
448
Finn Williamsa4983ce2020-07-23 12:55:12 +0100449 armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
Kevin May42477c12020-03-26 13:34:14 +0000450 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
451 if (outputTensor.GetMemoryArea() == nullptr)
452 {
453 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
454 return V1_3::ErrorStatus::GENERAL_FAILURE;
455 }
456
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100457 const size_t outputSize = outputTensorInfo.GetNumBytes();
458
Finn Williamsa4983ce2020-07-23 12:55:12 +0100459 unsigned int count = 0;
460 std::for_each(outputArg.dimensions.begin(), outputArg.dimensions.end(), [&](auto dim)
461 {
462 if (dim != 0)
463 {
464 outputTensorInfo.GetShape()[count] = dim;
465 }
466 else
467 {
468 outputTensorInfo.GetShape()[count] = outputArg.dimensions.size();
469 }
470
471 count++;
472 });
473
Finn Williamsa4983ce2020-07-23 12:55:12 +0100474 outputs.emplace_back(i, outputTensor);
475 outputShapes[i] = ComputeShape(outputTensorInfo);
476
477 if (outputArg.location.length < outputSize)
478 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100479 ALOGW("ArmnnPreparedModel_1_3::Execute failed outputArg.location.length (%s) < outputSize (%s)",
480 std::to_string(outputArg.location.length).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100481 outputShapes[i].isSufficient = false;
482 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
483 }
484
Sadik Armagan188675f2021-02-12 17:16:42 +0000485 size_t bufferSize = 0;
486#if !defined(ARMNN_ANDROID_S)
487 bufferSize = memPools.at(outputArg.location.poolIndex).getHidlMemory().size();
488 if (bufferSize < outputSize)
489#else
490 bufferSize = memPools.at(outputArg.location.poolIndex).getMemory().size;
491#endif
Kevin May42477c12020-03-26 13:34:14 +0000492 if (bufferSize < outputSize)
493 {
Teresa Charlin4bd9a742020-08-12 12:58:50 +0100494 ALOGW("ArmnnPreparedModel_1_3::Execute failed bufferSize (%s) < outputSize (%s)",
495 std::to_string(bufferSize).c_str(), std::to_string(outputSize).c_str());
Finn Williamsa4983ce2020-07-23 12:55:12 +0100496 outputShapes[i].isSufficient = false;
Kevin May42477c12020-03-26 13:34:14 +0000497 return V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
498 }
Kevin May42477c12020-03-26 13:34:14 +0000499 }
500
501 return V1_3::ErrorStatus::NONE;
502}
503
504template<typename HalVersion>
Sadik Armagan188675f2021-02-12 17:16:42 +0000505std::tuple<V1_3::ErrorStatus, hidl_vec<V1_2::OutputShape>, V1_2::Timing, std::string>
Kevin May42477c12020-03-26 13:34:14 +0000506 ArmnnPreparedModel_1_3<HalVersion>::PrepareMemoryForIO(armnn::InputTensors& inputs,
507 armnn::OutputTensors& outputs,
508 std::vector<android::nn::RunTimePoolInfo>& memPools,
509 const V1_3::Request& request)
510{
Sadik Armagan188675f2021-02-12 17:16:42 +0000511#if !defined(ARMNN_ANDROID_S)
Kevin May42477c12020-03-26 13:34:14 +0000512 if (!setRunTimePoolInfosFromMemoryPools(&memPools, request.pools))
Sadik Armagan188675f2021-02-12 17:16:42 +0000513#else
514 if (!setRunTimePoolInfosFromMemoryPools(&memPools, uncheckedConvert(request.pools)))
515#endif
Kevin May42477c12020-03-26 13:34:14 +0000516 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000517 return {V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000518 }
519
520 // add the inputs and outputs with their data
521 try
522 {
523 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_3::ErrorStatus::NONE)
524 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000525 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000526 }
527
Sadik Armagan188675f2021-02-12 17:16:42 +0000528 std::vector<V1_2::OutputShape> outputShapes(request.outputs.size());
Kevin May42477c12020-03-26 13:34:14 +0000529
530 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
531 if (errorStatus != V1_3::ErrorStatus::NONE)
532 {
533 return {errorStatus, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
534 }
535 }
536 catch (armnn::Exception& e)
537 {
538 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000539 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000540 }
541 catch (std::exception& e)
542 {
543 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
Sadik Armagan188675f2021-02-12 17:16:42 +0000544 return {V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
Kevin May42477c12020-03-26 13:34:14 +0000545 }
546
547 return {V1_3::ErrorStatus::NONE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute"};
548}
549
550template<typename HalVersion>
551template<typename CallbackContext>
552Return<void> ArmnnPreparedModel_1_3<HalVersion>::ExecuteSynchronously(const V1_3::Request& request,
553 CallbackContext cbCtx)
554{
Sadik Armagan188675f2021-02-12 17:16:42 +0000555 if (cbCtx.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000556 {
557 cbCtx.ctx.driverStart = Now();
558 }
559
560 if (!android::nn::validateRequest(convertToV1_3(request), m_Model))
561 {
562 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
563 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
564 {},
565 g_NoTiming,
566 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
567 return Void();
568 }
569
570 if (!android::nn::validateRequest(request, m_Model))
571 {
572 ALOGE("ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
573 cbCtx.callback(V1_3::ErrorStatus::INVALID_ARGUMENT,
574 {},
575 g_NoTiming,
576 "ArmnnPreparedModel_1_3::ExecuteSynchronously invalid request model");
Sadik Armaganef8a3932020-04-09 17:21:50 +0100577 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000578 }
579
580
581 // map the memory pool into shared pointers
582 // use a shared memory pools vector on the heap, as it is passed to the request thread
583 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
584
585 // allocate the tensors on the heap, as they are passed to the request thread
586 auto inputs = std::make_shared<armnn::InputTensors>();
587 auto outputs = std::make_shared<armnn::OutputTensors>();
588
589 auto [status, outputShapes, timing, message] = PrepareMemoryForIO(*inputs, *outputs, *memPools, request);
590 if (status != V1_3::ErrorStatus::NONE)
591 {
592 cbCtx.callback(status, outputShapes, timing, message);
Sadik Armaganef8a3932020-04-09 17:21:50 +0100593 return Void();
Kevin May42477c12020-03-26 13:34:14 +0000594 }
595
596 ALOGV("ArmnnPreparedModel_1_3::ExecuteSynchronously() before Execution");
597
598 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
599 return Void();
600}
601
602template<typename HalVersion>
603Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously(const V1_0::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000604 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000605 executeSynchronously_cb cb)
606{
607 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
608 m_RequestCount++;
609
610 if (cb == nullptr)
611 {
612 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously invalid callback passed");
613 return Void();
614 }
615
616 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000617 std::vector<V1_2::OutputShape> outputShapes,
618 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000619 std::string)
620 {
621 cb(convertToV1_0(errorStatus), outputShapes, timing);
622 };
623
624 CallbackContext_1_3 cbCtx;
625 cbCtx.callback = cbWrapper;
626 cbCtx.ctx.measureTimings = measureTiming;
627
628 ExecuteSynchronously(convertToV1_3(request), cbCtx);
629 return Void();
630}
631
632template<typename HalVersion>
Kevin May352d8382020-03-31 15:03:42 +0100633Return<void> ArmnnPreparedModel_1_3<HalVersion>::executeSynchronously_1_3(
634 const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000635 V1_2::MeasureTiming measureTiming,
Kevin May352d8382020-03-31 15:03:42 +0100636 const V1_3::OptionalTimePoint& deadline,
637 const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
638 executeSynchronously_1_3_cb cb)
Kevin May42477c12020-03-26 13:34:14 +0000639{
640 ALOGV("ArmnnPreparedModel_1_3::executeSynchronously_1_3(): %s", GetModelSummary(m_Model).c_str());
641 m_RequestCount++;
642
643 if (cb == nullptr)
644 {
645 ALOGE("ArmnnPreparedModel_1_3::executeSynchronously_1_3 invalid callback passed");
646 return Void();
647 }
648
Sadik Armagan188675f2021-02-12 17:16:42 +0000649 if (deadline.getDiscriminator() != V1_3::OptionalTimePoint::hidl_discriminator::none)
Kevin May42477c12020-03-26 13:34:14 +0000650 {
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100651 ALOGW("ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter deadline is set but not supported.");
Kevin May42477c12020-03-26 13:34:14 +0000652 }
653
Sadik Armagan188675f2021-02-12 17:16:42 +0000654 if (loopTimeoutDuration.getDiscriminator() != V1_3::OptionalTimeoutDuration::hidl_discriminator::none)
Sadik Armagan7b9ce8d2020-04-21 10:39:28 +0100655 {
656 ALOGW(
657 "ArmnnPreparedModel_1_3::executeSynchronously_1_3 parameter loopTimeoutDuration is set but not supported.");
Kevin May352d8382020-03-31 15:03:42 +0100658 }
659
Kevin May42477c12020-03-26 13:34:14 +0000660 auto cbWrapper = [cb](V1_3::ErrorStatus errorStatus,
Sadik Armagan188675f2021-02-12 17:16:42 +0000661 std::vector<V1_2::OutputShape> outputShapes,
662 const V1_2::Timing& timing,
Kevin May42477c12020-03-26 13:34:14 +0000663 std::string)
664 {
665 cb(errorStatus, outputShapes, timing);
666 };
667
668 CallbackContext_1_3 cbCtx;
669 cbCtx.callback = cbWrapper;
670 cbCtx.ctx.measureTimings = measureTiming;
671
672 ExecuteSynchronously(request, cbCtx);
673 return Void();
674}
675
676template<typename HalVersion>
677Return<void> ArmnnPreparedModel_1_3<HalVersion>::configureExecutionBurst(
678 const sp<V1_2::IBurstCallback>& callback,
679 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
680 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
681 V1_3::IPreparedModel::configureExecutionBurst_cb cb)
682{
683 ALOGV("ArmnnPreparedModel_1_3::configureExecutionBurst");
684 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
685 requestChannel,
686 resultChannel,
687 this);
688
689 if (burst == nullptr)
690 {
691 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
692 }
693 else
694 {
695 cb(V1_0::ErrorStatus::NONE, burst);
696 }
697 return Void();
698}
699
700template<typename HalVersion>
701template<typename CallbackContext>
Sadik Armagand7be72e2020-04-23 12:56:05 +0100702Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::ExecuteGraph(
Kevin May42477c12020-03-26 13:34:14 +0000703 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
704 armnn::InputTensors& inputTensors,
705 armnn::OutputTensors& outputTensors,
706 CallbackContext cb)
707{
708 ALOGV("ArmnnPreparedModel_1_3::ExecuteGraph(...)");
709
Kevin May42477c12020-03-26 13:34:14 +0000710 DumpTensorsIfRequired("Input", inputTensors);
711
Sadik Armagan188675f2021-02-12 17:16:42 +0000712 std::vector<V1_2::OutputShape> outputShapes(outputTensors.size());
Kevin May42477c12020-03-26 13:34:14 +0000713 for (unsigned int i = 0; i < outputTensors.size(); i++)
714 {
715 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
716 const armnn::Tensor outputTensor = outputTensorPair.second;
717 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
718
719 outputShapes[i] = ComputeShape(outputTensorInfo);
720 }
721
722 // run it
723 try
724 {
Sadik Armagan188675f2021-02-12 17:16:42 +0000725 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000726 {
Sadik Armagand7be72e2020-04-23 12:56:05 +0100727 cb.ctx.deviceStart = Now();
Kevin May42477c12020-03-26 13:34:14 +0000728 }
729
730 armnn::Status status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
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.deviceEnd = Now();
Kevin May42477c12020-03-26 13:34:14 +0000735 }
736 if (status != armnn::Status::Success)
737 {
738 ALOGW("EnqueueWorkload failed");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100739 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
740 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000741 }
742 }
743 catch (armnn::Exception& e)
744 {
745 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
746 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100747 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000748 }
749 catch (std::exception& e)
750 {
751 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
752 cb.callback(V1_3::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100753 return V1_3::ErrorStatus::GENERAL_FAILURE;
Kevin May42477c12020-03-26 13:34:14 +0000754 }
755
756 CommitPools(*pMemPools);
757
758 DumpTensorsIfRequired("Output", outputTensors);
759
Sadik Armagan188675f2021-02-12 17:16:42 +0000760 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000761 {
Kevin May949a69e2020-04-24 10:21:40 +0100762 cb.ctx.driverEnd = Now();
Sadik Armagan188675f2021-02-12 17:16:42 +0000763 V1_2::Timing timing;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100764 timing.timeOnDevice = MicrosecondsDuration(cb.ctx.deviceEnd, cb.ctx.deviceStart);
Kevin May949a69e2020-04-24 10:21:40 +0100765 timing.timeInDriver = MicrosecondsDuration(cb.ctx.driverEnd, cb.ctx.driverStart);
766 ALOGV("ArmnnPreparedModel_1_3::execute timing - Device = %lu Driver = %lu", timing.timeOnDevice,
Kevin May42477c12020-03-26 13:34:14 +0000767 timing.timeInDriver);
768 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_3::ExecuteGraph");
Sadik Armagand7be72e2020-04-23 12:56:05 +0100769 } else
770 {
Kevin May42477c12020-03-26 13:34:14 +0000771 cb.callback(V1_3::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_3::ExecuteGraph");
772 }
Sadik Armagand7be72e2020-04-23 12:56:05 +0100773 return V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000774}
775
776template<typename HalVersion>
777bool ArmnnPreparedModel_1_3<HalVersion>::ExecuteWithDummyInputs()
778{
779 std::vector<std::vector<char>> storage;
780 armnn::InputTensors inputTensors;
781 for (unsigned int i = 0; i < getMainModel(m_Model).inputIndexes.size(); i++)
782 {
783 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
784 storage.emplace_back(inputTensorInfo.GetNumBytes());
785 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
786
787 inputTensors.emplace_back(i, inputTensor);
788 }
789
790 armnn::OutputTensors outputTensors;
791 for (unsigned int i = 0; i < getMainModel(m_Model).outputIndexes.size(); i++)
792 {
793 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
794 storage.emplace_back(outputTensorInfo.GetNumBytes());
795 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
796
797 outputTensors.emplace_back(i, outputTensor);
798 }
799
Sadik Armagan188675f2021-02-12 17:16:42 +0000800 auto nullCallback = [](V1_3::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Kevin May42477c12020-03-26 13:34:14 +0000801 CallbackContext_1_3 callbackContext;
802 callbackContext.callback = nullCallback;
Sadik Armagan188675f2021-02-12 17:16:42 +0000803 callbackContext.ctx.measureTimings = V1_2::MeasureTiming::NO;
Kevin May42477c12020-03-26 13:34:14 +0000804 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
Sadik Armagand7be72e2020-04-23 12:56:05 +0100805
806 auto errorStatus = ExecuteGraph(memPools,
807 inputTensors,
808 outputTensors,
809 callbackContext);
810 return errorStatus == V1_3::ErrorStatus::NONE;
Kevin May42477c12020-03-26 13:34:14 +0000811}
812
813template<typename HalVersion>
814Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<HalVersion>::Execute(const V1_3::Request& request,
Sadik Armagan188675f2021-02-12 17:16:42 +0000815 V1_2::MeasureTiming measureTiming,
Kevin May42477c12020-03-26 13:34:14 +0000816 CallbackAsync_1_3 callback)
817{
818 ExecutionContext_1_3 ctx;
Sadik Armagan188675f2021-02-12 17:16:42 +0000819 if (measureTiming == V1_2::MeasureTiming::YES)
Kevin May42477c12020-03-26 13:34:14 +0000820 {
821 ctx.measureTimings = measureTiming;
822 ctx.driverStart = Now();
823 }
824
825 ALOGV("ArmnnPreparedModel_1_3::execute(): %s", GetModelSummary(m_Model).c_str());
826 m_RequestCount++;
827
828 if (!android::nn::validateRequest(request, m_Model))
829 {
830 callback(V1_3::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_3::execute");
831 return V1_3::ErrorStatus::INVALID_ARGUMENT;
832 }
833
834 if (!m_RequestInputsAndOutputsDumpDir.empty())
835 {
836 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
837 }
838
839 // map the memory pool into shared pointers
840 // use a shared memory pools vector on the heap, as it is passed to the request thread
841 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
842
843 // allocate the tensors on the heap, as they are passed to the request thread
844 auto inputTensors = std::make_shared<armnn::InputTensors>();
845 auto outputTensors = std::make_shared<armnn::OutputTensors>();
846
847 auto [status, outShapes, timing, message] = PrepareMemoryForIO(*inputTensors, *outputTensors,
848 *memPools, request);
849 if (status != V1_3::ErrorStatus::NONE)
850 {
851 callback(status, outShapes, timing, message);
852 }
853
854 switch(status)
855 {
856 case V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
857 return V1_3::ErrorStatus::NONE;
858 case V1_3::ErrorStatus::GENERAL_FAILURE:
859 return V1_3::ErrorStatus::GENERAL_FAILURE;
860 default:
861 {}
862 }
863
864 ALOGV("ArmnnPreparedModel_1_3::execute(...) before PostMsg");
865
866 // post the request for asynchronous execution
867 CallbackContext_1_3 cb;
868 cb.callback = callback;
869 cb.ctx = ctx;
870 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
871 ALOGV("ArmnnPreparedModel_1_3::execute(...) after PostMsg");
872 return V1_3::ErrorStatus::NONE;
873}
874
Narumol Prangnawaratcad4e912020-06-02 12:07:43 +0100875template<typename HalVersion>
876V1_3::Priority ArmnnPreparedModel_1_3<HalVersion>::GetModelPriority()
877{
878 return m_ModelPriority;
879}
880
Kevin May42477c12020-03-26 13:34:14 +0000881#ifdef ARMNN_ANDROID_NN_V1_3
882template class ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>;
Sadik Armagand7be72e2020-04-23 12:56:05 +0100883template Return <V1_3::ErrorStatus> ArmnnPreparedModel_1_3<hal_1_3::HalPolicy>::ExecuteGraph<CallbackContext_1_3>(
Kevin May42477c12020-03-26 13:34:14 +0000884 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
885 armnn::InputTensors& pInputTensors,
886 armnn::OutputTensors& pOutputTensors,
887 CallbackContext_1_3 cb);
888#endif
889
890} // namespace armnn_driver