blob: f5c73cf26a14561d59f522e4c52771e136327831 [file] [log] [blame]
Mike Kellyb5fdf382019-06-11 16:35:25 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#define LOG_TAG "ArmnnDriver"
7
8#include "ArmnnPreparedModel_1_2.hpp"
9#include "Utils.hpp"
10
Mike Kellyb5fdf382019-06-11 16:35:25 +010011#include <log/log.h>
12#include <OperationsUtils.h>
13#include <ExecutionBurstServer.h>
14#include <ValidateHal.h>
15
16#include <cassert>
17#include <cinttypes>
18
19using namespace android;
20using namespace android::hardware;
21
Mike Kellyb5fdf382019-06-11 16:35:25 +010022namespace {
23
Kevin DuBois30c34ae2020-08-26 13:53:41 -070024static const V1_2::Timing g_NoTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX};
Mike Kellyb5fdf382019-06-11 16:35:25 +010025using namespace armnn_driver;
Mike Kelly44381512019-07-08 17:37:35 +010026using TimePoint = std::chrono::steady_clock::time_point;
27
28TimePoint Now()
29{
30 return std::chrono::steady_clock::now();
31}
32
33unsigned long MicrosecondsDuration(TimePoint endPoint, TimePoint startPoint)
34{
35 return static_cast<unsigned long>(std::chrono::duration_cast<std::chrono::microseconds>(
36 endPoint - startPoint).count());
37}
Mike Kellyb5fdf382019-06-11 16:35:25 +010038
Mike Kelly65c42dc2019-07-22 14:06:00 +010039void NotifyCallbackAndCheck(const ::android::sp<V1_0::IExecutionCallback>& callback,
Kevin DuBois30c34ae2020-08-26 13:53:41 -070040 V1_0::ErrorStatus errorStatus,
Kevin DuBois23e678a2020-11-20 14:54:05 -080041 std::vector<V1_2::OutputShape>,
42 const V1_2::Timing,
Mike Kellyb5fdf382019-06-11 16:35:25 +010043 std::string callingFunction)
44{
45 Return<void> returned = callback->notify(errorStatus);
46 // This check is required, if the callback fails and it isn't checked it will bring down the service
47 if (!returned.isOk())
48 {
49 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
50 callingFunction.c_str(), returned.description().c_str());
51 }
52}
53
Mike Kelly65c42dc2019-07-22 14:06:00 +010054void NotifyCallbackAndCheck(const ::android::sp<V1_2::IExecutionCallback>& callback,
Kevin DuBois30c34ae2020-08-26 13:53:41 -070055 V1_0::ErrorStatus errorStatus,
Kevin DuBois23e678a2020-11-20 14:54:05 -080056 std::vector<V1_2::OutputShape> outputShapes,
57 const V1_2::Timing timing,
Mike Kellyb5fdf382019-06-11 16:35:25 +010058 std::string callingFunction)
59{
Mike Kelly65c42dc2019-07-22 14:06:00 +010060 Return<void> returned = callback->notify_1_2(errorStatus, outputShapes, timing);
Mike Kellyb5fdf382019-06-11 16:35:25 +010061 // This check is required, if the callback fails and it isn't checked it will bring down the service
62 if (!returned.isOk())
63 {
64 ALOGE("ArmnnDriver::%s: hidl callback failed to return properly: %s",
65 callingFunction.c_str(), returned.description().c_str());
66 }
67}
68
Kevin DuBois30c34ae2020-08-26 13:53:41 -070069bool ValidateRequestArgument(const V1_0::RequestArgument& requestArg, const armnn::TensorInfo& tensorInfo)
Mike Kellyb5fdf382019-06-11 16:35:25 +010070{
71 if (requestArg.dimensions.size() != 0)
72 {
73 if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
74 {
75 ALOGE("Mismatched dimensions (request argument: %zu, expected: %u)",
76 requestArg.dimensions.size(), tensorInfo.GetNumDimensions());
77 return false;
78 }
79
80 for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
81 {
Finn Williamsa4983ce2020-07-23 12:55:12 +010082 if (requestArg.dimensions[d] != 0 && requestArg.dimensions[d] != tensorInfo.GetShape()[d])
Mike Kellyb5fdf382019-06-11 16:35:25 +010083 {
84 ALOGE("Mismatched size for dimension %d (request argument: %u, expected %u)",
85 d, requestArg.dimensions[d], tensorInfo.GetShape()[d]);
86 return false;
87 }
88 }
89 }
90
91 return true;
92}
93
Kevin DuBois30c34ae2020-08-26 13:53:41 -070094armnn::Tensor GetTensorForRequestArgument(const V1_0::RequestArgument& requestArg,
Mike Kellyb5fdf382019-06-11 16:35:25 +010095 const armnn::TensorInfo& tensorInfo,
96 const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
97{
98 if (!ValidateRequestArgument(requestArg, tensorInfo))
99 {
100 return armnn::Tensor();
101 }
102
103 return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
104}
105
106inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
107{
108 return tensorNamePrefix + std::to_string(index);
109}
110
111} // anonymous namespace
112
113using namespace android::hardware;
114
115namespace armnn_driver
116{
117
118template<typename HalVersion>
Derek Lamberti4de83c52020-03-17 13:40:18 +0000119RequestThread<ArmnnPreparedModel_1_2, HalVersion, CallbackContext_1_2>
Mike Kelly65c42dc2019-07-22 14:06:00 +0100120 ArmnnPreparedModel_1_2<HalVersion>::m_RequestThread;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100121
122template<typename HalVersion>
123template<typename TensorBindingCollection>
124void ArmnnPreparedModel_1_2<HalVersion>::DumpTensorsIfRequired(char const* tensorNamePrefix,
125 const TensorBindingCollection& tensorBindings)
126{
127 if (!m_RequestInputsAndOutputsDumpDir.empty())
128 {
Colm Donelan08d9a1c2020-09-09 17:56:55 +0100129 const std::string requestName = std::to_string(m_NetworkId) + "_" + std::to_string(m_RequestCount) + ".dump";
Mike Kellyb5fdf382019-06-11 16:35:25 +0100130 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
131 {
132 DumpTensor(m_RequestInputsAndOutputsDumpDir,
133 requestName,
134 BuildTensorName(tensorNamePrefix, i),
135 tensorBindings[i].second);
136 }
137 }
138}
139
140template<typename HalVersion>
141ArmnnPreparedModel_1_2<HalVersion>::ArmnnPreparedModel_1_2(armnn::NetworkId networkId,
142 armnn::IRuntime* runtime,
143 const V1_2::Model& model,
144 const std::string& requestInputsAndOutputsDumpDir,
145 const bool gpuProfilingEnabled)
146 : m_NetworkId(networkId)
147 , m_Runtime(runtime)
148 , m_Model(model)
149 , m_RequestCount(0)
150 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
151 , m_GpuProfilingEnabled(gpuProfilingEnabled)
152{
153 // Enable profiling if required.
154 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
155}
156
157template<typename HalVersion>
158ArmnnPreparedModel_1_2<HalVersion>::~ArmnnPreparedModel_1_2()
159{
160 // Get a hold of the profiler used by this model.
161 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
162
163 // Unload the network associated with this model.
164 m_Runtime->UnloadNetwork(m_NetworkId);
165
166 // Dump the profiling info to a file if required.
167 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled, m_RequestInputsAndOutputsDumpDir, m_NetworkId, profiler.get());
168}
169
170template<typename HalVersion>
Kevin DuBois30c34ae2020-08-26 13:53:41 -0700171Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::execute(const V1_0::Request& request,
Mike Kellyb5fdf382019-06-11 16:35:25 +0100172 const ::android::sp<V1_0::IExecutionCallback>& callback)
173{
Mike Kelly65c42dc2019-07-22 14:06:00 +0100174 if (callback.get() == nullptr)
175 {
176 ALOGE("ArmnnPreparedModel_1_2::execute invalid callback passed");
Kevin DuBois30c34ae2020-08-26 13:53:41 -0700177 return V1_0::ErrorStatus::INVALID_ARGUMENT;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100178 }
179
Kevin DuBois30c34ae2020-08-26 13:53:41 -0700180 auto cb = [callback](V1_0::ErrorStatus errorStatus,
Kevin DuBois23e678a2020-11-20 14:54:05 -0800181 std::vector<V1_2::OutputShape> outputShapes,
182 const V1_2::Timing& timing,
Mike Kelly65c42dc2019-07-22 14:06:00 +0100183 std::string callingFunction)
184 {
185 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
186 };
187
Kevin DuBois30c34ae2020-08-26 13:53:41 -0700188 return Execute(request, V1_2::MeasureTiming::NO, cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100189}
190
191template<typename HalVersion>
Kevin Mayec1e5b82020-02-26 17:00:39 +0000192Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::execute_1_2(
193 const V1_0::Request& request,
Kevin DuBois23e678a2020-11-20 14:54:05 -0800194 V1_2::MeasureTiming measureTiming,
Kevin Mayec1e5b82020-02-26 17:00:39 +0000195 const sp<V1_2::IExecutionCallback>& callback)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100196{
Mike Kelly65c42dc2019-07-22 14:06:00 +0100197 if (callback.get() == nullptr)
198 {
199 ALOGE("ArmnnPreparedModel_1_2::execute_1_2 invalid callback passed");
Kevin DuBois30c34ae2020-08-26 13:53:41 -0700200 return V1_0::ErrorStatus::INVALID_ARGUMENT;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100201 }
202
Kevin DuBois30c34ae2020-08-26 13:53:41 -0700203 auto cb = [callback](V1_0::ErrorStatus errorStatus,
Kevin DuBois23e678a2020-11-20 14:54:05 -0800204 std::vector<V1_2::OutputShape> outputShapes,
205 const V1_2::Timing& timing,
Mike Kelly65c42dc2019-07-22 14:06:00 +0100206 std::string callingFunction)
207 {
208 NotifyCallbackAndCheck(callback, errorStatus, outputShapes, timing, callingFunction);
209 };
210
211 return Execute(request, measureTiming, cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100212}
213
214template<typename HalVersion>
Derek Lamberti4de83c52020-03-17 13:40:18 +0000215Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForInputs(
216 armnn::InputTensors& inputs,
217 const V1_0::Request& request,
218 const std::vector<android::nn::RunTimePoolInfo>& memPools)
219{
220 inputs.reserve(request.inputs.size());
221 for (unsigned int i = 0; i < request.inputs.size(); i++)
222 {
223 const auto& inputArg = request.inputs[i];
224
225 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
226 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
227
Renato Grottesic8713e02022-12-14 17:04:16 +0000228 uint32_t poolIndex = inputArg.location.poolIndex;
229 if (poolIndex >= memPools.size())
230 {
231 ALOGE("Cannot execute request. Error converting request input %u to tensor: wrong poolIndex", i);
232 return V1_0::ErrorStatus::GENERAL_FAILURE;
233 }
234
235 uint8_t* inputTensorBegin = static_cast<uint8_t*>(inputTensor.GetMemoryArea());
236 if (inputTensorBegin == nullptr)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000237 {
238 ALOGE("Cannot execute request. Error converting request input %u to tensor", i);
239 return V1_0::ErrorStatus::GENERAL_FAILURE;
240 }
241
Renato Grottesic8713e02022-12-14 17:04:16 +0000242 const size_t inputTensorSize = inputTensorInfo.GetNumBytes();
243 uint8_t* memoryPoolBegin = memPools[poolIndex].getBuffer();
244 uint32_t memoryPoolSize = memPools[poolIndex].getSize();
245 bool inputTensorIsOutOfMemoryRage = (inputTensorBegin + inputTensorSize) > (memoryPoolBegin + memoryPoolSize);
246
247 if (inputTensorIsOutOfMemoryRage)
248 {
249 ALOGE("Cannot execute request. Error converting request input %u to tensor: out of Memory Pool", i);
250 return V1_0::ErrorStatus::GENERAL_FAILURE;
251 }
252
Derek Lamberti4de83c52020-03-17 13:40:18 +0000253 inputs.emplace_back(i, inputTensor);
254 }
255
256 return V1_0::ErrorStatus::NONE;
257}
258
259template<typename HalVersion>
260Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForOutputs(
261 armnn::OutputTensors& outputs,
Kevin DuBois23e678a2020-11-20 14:54:05 -0800262 std::vector<V1_2::OutputShape> &outputShapes,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000263 const V1_0::Request& request,
264 const std::vector<android::nn::RunTimePoolInfo>& memPools)
265{
266 outputs.reserve(request.outputs.size());
267 for (unsigned int i = 0; i < request.outputs.size(); i++)
268 {
269 const auto& outputArg = request.outputs[i];
270
271 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
272 const armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
Renato Grottesic8713e02022-12-14 17:04:16 +0000273 uint8_t* outputTensorBegin = static_cast<uint8_t*>(outputTensor.GetMemoryArea());
274 if (outputTensorBegin == nullptr)
Derek Lamberti4de83c52020-03-17 13:40:18 +0000275 {
276 ALOGE("Cannot execute request. Error converting request output %u to tensor", i);
277 return V1_0::ErrorStatus::GENERAL_FAILURE;
278 }
279
280 const size_t outputSize = outputTensorInfo.GetNumBytes();
Finn Williamsa4983ce2020-07-23 12:55:12 +0100281
282 if (outputArg.location.length < outputSize)
283 {
284 ALOGW("ArmnnPreparedModel_1_2::Execute failed: outputArg.location.length < outputSize");
285 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
286 }
287
Kevin DuBoisbbcff192020-11-20 14:36:59 -0800288 const size_t bufferSize = memPools.at(outputArg.location.poolIndex).getSize();
Derek Lamberti4de83c52020-03-17 13:40:18 +0000289 if (bufferSize < outputSize)
290 {
Finn Williamsa4983ce2020-07-23 12:55:12 +0100291 ALOGW("ArmnnPreparedModel_1_2::Execute failed: bufferSize < outputSize");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000292 return V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
293 }
294
Renato Grottesic8713e02022-12-14 17:04:16 +0000295 uint32_t poolIndex = outputArg.location.poolIndex;
296 if (poolIndex >= memPools.size())
297 {
298 ALOGE("Cannot execute request. Error converting request output %u to tensor: wrong poolIndex", i);
299 return V1_0::ErrorStatus::GENERAL_FAILURE;
300 }
301
302 uint8_t* memoryPoolBegin = memPools[poolIndex].getBuffer();
303 uint32_t memoryPoolSize = memPools[poolIndex].getSize();
304 bool outputTensorIsOutOfMemoryRage = (outputTensorBegin + outputSize) > (memoryPoolBegin + memoryPoolSize);
305 if (outputTensorIsOutOfMemoryRage)
306 {
307 ALOGE("Cannot execute request. Error converting request output %u to tensor: out of Memory Pool", i);
308 return V1_0::ErrorStatus::GENERAL_FAILURE;
309 }
310
Derek Lamberti4de83c52020-03-17 13:40:18 +0000311 outputs.emplace_back(i, outputTensor);
312 outputShapes[i] = ComputeShape(outputTensorInfo);
313 }
314
315 return V1_0::ErrorStatus::NONE;
316}
317
318template<typename HalVersion>
319Return<V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::PrepareMemoryForIO(
320 armnn::InputTensors& inputs,
321 armnn::OutputTensors& outputs,
322 std::vector<android::nn::RunTimePoolInfo>& memPools,
323 const V1_0::Request& request,
324 CallbackAsync_1_2 callback)
325{
326 if (!setRunTimePoolInfosFromHidlMemories(&memPools, request.pools))
327 {
328 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
329 return V1_0::ErrorStatus::GENERAL_FAILURE;
330 }
331
332 // add the inputs and outputs with their data
333 try
334 {
335 if (PrepareMemoryForInputs(inputs, request, memPools) != V1_0::ErrorStatus::NONE)
336 {
337 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
338 return V1_0::ErrorStatus::GENERAL_FAILURE;
339 }
340
Kevin DuBois23e678a2020-11-20 14:54:05 -0800341 std::vector<V1_2::OutputShape> outputShapes(request.outputs.size());
Derek Lamberti4de83c52020-03-17 13:40:18 +0000342
343 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
344 if (errorStatus != V1_0::ErrorStatus::NONE)
345 {
346 callback(errorStatus,
347 outputShapes,
348 g_NoTiming,
349 "ArmnnPreparedModel_1_2::Execute");
350 return errorStatus;
351 }
352 }
353 catch (armnn::Exception& e)
354 {
355 ALOGW("armnn::Exception caught while preparing for EnqueueWorkload: %s", e.what());
356 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
357 return V1_0::ErrorStatus::GENERAL_FAILURE;
358 }
359 catch (std::exception& e)
360 {
361 ALOGE("std::exception caught while preparing for EnqueueWorkload: %s", e.what());
362 callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
363 return V1_0::ErrorStatus::GENERAL_FAILURE;
364 }
365
366 return V1_0::ErrorStatus::NONE;
367}
368
Mike Kellyb5fdf382019-06-11 16:35:25 +0100369template<typename HalVersion>
Kevin DuBois30c34ae2020-08-26 13:53:41 -0700370Return<void> ArmnnPreparedModel_1_2<HalVersion>::executeSynchronously(const V1_0::Request& request,
Kevin DuBois23e678a2020-11-20 14:54:05 -0800371 V1_2::MeasureTiming measureTiming,
372 V1_2::IPreparedModel::executeSynchronously_cb cb)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100373{
374 ALOGV("ArmnnPreparedModel_1_2::executeSynchronously(): %s", GetModelSummary(m_Model).c_str());
375 m_RequestCount++;
376
377 if (cb == nullptr)
378 {
379 ALOGE("ArmnnPreparedModel_1_2::executeSynchronously invalid callback passed");
380 return Void();
381 }
382
Derek Lamberti4de83c52020-03-17 13:40:18 +0000383 TimePoint driverStart;
Mike Kelly44381512019-07-08 17:37:35 +0100384
Kevin DuBois23e678a2020-11-20 14:54:05 -0800385 if (measureTiming == V1_2::MeasureTiming::YES)
Mike Kelly44381512019-07-08 17:37:35 +0100386 {
387 driverStart = Now();
388 }
389
Mike Kellyb5fdf382019-06-11 16:35:25 +0100390 if (!android::nn::validateRequest(request, m_Model))
391 {
Mike Kelly44381512019-07-08 17:37:35 +0100392 ALOGE("ArmnnPreparedModel_1_2::executeSynchronously invalid request model");
Kevin DuBois30c34ae2020-08-26 13:53:41 -0700393 cb(V1_0::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100394 return Void();
395 }
396
Derek Lamberti4de83c52020-03-17 13:40:18 +0000397 auto cbWrapper = [cb](V1_0::ErrorStatus errorStatus,
Kevin DuBois23e678a2020-11-20 14:54:05 -0800398 std::vector<V1_2::OutputShape> outputShapes,
399 const V1_2::Timing& timing,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000400 std::string)
401 {
402 cb(errorStatus, outputShapes, timing);
403 };
Mike Kellyb5fdf382019-06-11 16:35:25 +0100404
405 // map the memory pool into shared pointers
406 // use a shared memory pools vector on the heap, as it is passed to the request thread
Derek Lamberti4de83c52020-03-17 13:40:18 +0000407 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
Mike Kellyb5fdf382019-06-11 16:35:25 +0100408
Derek Lamberti4de83c52020-03-17 13:40:18 +0000409 // allocate the tensors on the heap, as they are passed to the request thread
410 auto inputs = std::make_shared<armnn::InputTensors>();
411 auto outputs = std::make_shared<armnn::OutputTensors>();
412
413 auto prepareStatus = PrepareMemoryForIO(*inputs, *outputs, *memPools, request, cbWrapper);
414 if (prepareStatus != V1_0::ErrorStatus::NONE)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100415 {
Kevin May7bdaac52020-02-10 12:10:07 +0000416 return Void();
417 }
418
Mike Kellyb5fdf382019-06-11 16:35:25 +0100419 ALOGV("ArmnnPreparedModel_1_2::executeSynchronously() before Execution");
420
Derek Lamberti4de83c52020-03-17 13:40:18 +0000421 CallbackContext_1_2 cbCtx;
422 cbCtx.callback = cbWrapper;
423 cbCtx.ctx.measureTimings = measureTiming;
424 cbCtx.ctx.driverStart = driverStart;
425 ExecuteGraph(memPools, *inputs, *outputs, cbCtx);
Mike Kelly44381512019-07-08 17:37:35 +0100426
Mike Kellyb5fdf382019-06-11 16:35:25 +0100427 return Void();
428}
429
430template<typename HalVersion>
Derek Lamberti4de83c52020-03-17 13:40:18 +0000431template<typename CallbackContext>
432bool ArmnnPreparedModel_1_2<HalVersion>::ExecuteGraph(
Mike Kellyb5fdf382019-06-11 16:35:25 +0100433 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000434 armnn::InputTensors& inputTensors,
435 armnn::OutputTensors& outputTensors,
436 CallbackContext cb)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100437{
438 ALOGV("ArmnnPreparedModel_1_2::ExecuteGraph(...)");
439
Mike Kelly65c42dc2019-07-22 14:06:00 +0100440 TimePoint driverEnd, deviceStart, deviceEnd;
441
Derek Lamberti4de83c52020-03-17 13:40:18 +0000442 DumpTensorsIfRequired("Input", inputTensors);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100443
Kevin DuBois23e678a2020-11-20 14:54:05 -0800444 std::vector<V1_2::OutputShape> outputShapes(outputTensors.size());
Mike Kelly65c42dc2019-07-22 14:06:00 +0100445 for (unsigned int i = 0; i < outputTensors.size(); i++)
446 {
447 std::pair<int, armnn::Tensor> outputTensorPair = outputTensors[i];
448 const armnn::Tensor outputTensor = outputTensorPair.second;
449 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
450
Derek Lamberti4de83c52020-03-17 13:40:18 +0000451 outputShapes[i] = ComputeShape(outputTensorInfo);
Mike Kelly65c42dc2019-07-22 14:06:00 +0100452 }
453
Mike Kellyb5fdf382019-06-11 16:35:25 +0100454 // run it
455 try
456 {
Kevin DuBois23e678a2020-11-20 14:54:05 -0800457 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly65c42dc2019-07-22 14:06:00 +0100458 {
459 deviceStart = Now();
460 }
461
Derek Lamberti4de83c52020-03-17 13:40:18 +0000462 armnn::Status status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
Mike Kelly65c42dc2019-07-22 14:06:00 +0100463
Kevin DuBois23e678a2020-11-20 14:54:05 -0800464 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly65c42dc2019-07-22 14:06:00 +0100465 {
466 deviceEnd = Now();
467 }
Mike Kellyb5fdf382019-06-11 16:35:25 +0100468 if (status != armnn::Status::Success)
469 {
470 ALOGW("EnqueueWorkload failed");
Kevin DuBois30c34ae2020-08-26 13:53:41 -0700471 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming,
Mike Kelly65c42dc2019-07-22 14:06:00 +0100472 "ArmnnPreparedModel_1_2::ExecuteGraph");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000473 return false;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100474 }
475 }
Kevin May7bdaac52020-02-10 12:10:07 +0000476 catch (armnn::Exception& e)
477 {
478 ALOGW("armnn:Exception caught from EnqueueWorkload: %s", e.what());
Kevin DuBois30c34ae2020-08-26 13:53:41 -0700479 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000480 return false;
Kevin May7bdaac52020-02-10 12:10:07 +0000481 }
Derek Lambertib9cb8442019-11-28 13:34:48 +0000482 catch (std::exception& e)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100483 {
Kevin May7bdaac52020-02-10 12:10:07 +0000484 ALOGE("std::exception caught from EnqueueWorkload: %s", e.what());
Kevin DuBois30c34ae2020-08-26 13:53:41 -0700485 cb.callback(V1_0::ErrorStatus::GENERAL_FAILURE, {}, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000486 return false;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100487 }
488
Derek Lamberti4de83c52020-03-17 13:40:18 +0000489 CommitPools(*pMemPools);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100490
Derek Lamberti4de83c52020-03-17 13:40:18 +0000491 DumpTensorsIfRequired("Output", outputTensors);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100492
Kevin DuBois17c424b2020-11-20 14:18:03 -0800493 if (cb.ctx.measureTimings == V1_2::MeasureTiming::YES)
Mike Kelly65c42dc2019-07-22 14:06:00 +0100494 {
495 driverEnd = Now();
Kevin DuBois30c34ae2020-08-26 13:53:41 -0700496 V1_2::Timing timing;
Mike Kelly65c42dc2019-07-22 14:06:00 +0100497 timing.timeOnDevice = MicrosecondsDuration(deviceEnd, deviceStart);
Derek Lamberti4de83c52020-03-17 13:40:18 +0000498 timing.timeInDriver = MicrosecondsDuration(driverEnd, cb.ctx.driverStart);
Kevin DuBois17c424b2020-11-20 14:18:03 -0800499 ALOGV("ArmnnPreparedModel_1_2::execute timing - Device = %" PRIu64 " Driver = %" PRIu64, timing.timeOnDevice,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000500 timing.timeInDriver);
501 cb.callback(V1_0::ErrorStatus::NONE, outputShapes, timing, "ArmnnPreparedModel_1_2::ExecuteGraph");
Mike Kelly65c42dc2019-07-22 14:06:00 +0100502 } else {
Derek Lamberti4de83c52020-03-17 13:40:18 +0000503 cb.callback(V1_0::ErrorStatus::NONE, outputShapes, g_NoTiming, "ArmnnPreparedModel_1_2::ExecuteGraph");
Mike Kelly65c42dc2019-07-22 14:06:00 +0100504 }
Derek Lamberti4de83c52020-03-17 13:40:18 +0000505
506 return true;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100507}
508
509template<typename HalVersion>
510bool ArmnnPreparedModel_1_2<HalVersion>::ExecuteWithDummyInputs()
511{
512 std::vector<std::vector<char>> storage;
513 armnn::InputTensors inputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000514 for (unsigned int i = 0; i < getMainModel(m_Model).inputIndexes.size(); i++)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100515 {
516 const armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
517 storage.emplace_back(inputTensorInfo.GetNumBytes());
518 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
519
520 inputTensors.emplace_back(i, inputTensor);
521 }
522
523 armnn::OutputTensors outputTensors;
Kevin May42477c12020-03-26 13:34:14 +0000524 for (unsigned int i = 0; i < getMainModel(m_Model).outputIndexes.size(); i++)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100525 {
526 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
527 storage.emplace_back(outputTensorInfo.GetNumBytes());
528 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
529
530 outputTensors.emplace_back(i, outputTensor);
531 }
532
Kevin DuBois23e678a2020-11-20 14:54:05 -0800533 auto nullCallback = [](V1_0::ErrorStatus, std::vector<V1_2::OutputShape>, const V1_2::Timing&, std::string) {};
Derek Lamberti4de83c52020-03-17 13:40:18 +0000534 CallbackContext_1_2 callbackContext;
535 callbackContext.callback = nullCallback;
Kevin DuBois23e678a2020-11-20 14:54:05 -0800536 callbackContext.ctx.measureTimings = V1_2::MeasureTiming::NO;
Derek Lamberti4de83c52020-03-17 13:40:18 +0000537 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
538 return ExecuteGraph(memPools,
539 inputTensors,
540 outputTensors,
541 callbackContext);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100542}
543
544template<typename HalVersion>
Kevin DuBois30c34ae2020-08-26 13:53:41 -0700545Return <V1_0::ErrorStatus> ArmnnPreparedModel_1_2<HalVersion>::Execute(const V1_0::Request& request,
Kevin DuBois23e678a2020-11-20 14:54:05 -0800546 V1_2::MeasureTiming measureTiming,
Derek Lamberti4de83c52020-03-17 13:40:18 +0000547 CallbackAsync_1_2 callback)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100548{
Derek Lamberti4de83c52020-03-17 13:40:18 +0000549 ExecutionContext_1_2 ctx;
Kevin DuBois23e678a2020-11-20 14:54:05 -0800550 if (measureTiming == V1_2::MeasureTiming::YES)
Mike Kelly65c42dc2019-07-22 14:06:00 +0100551 {
Derek Lamberti4de83c52020-03-17 13:40:18 +0000552 ctx.measureTimings = measureTiming;
553 ctx.driverStart = Now();
Mike Kelly65c42dc2019-07-22 14:06:00 +0100554 }
555
Mike Kellyb5fdf382019-06-11 16:35:25 +0100556 ALOGV("ArmnnPreparedModel_1_2::execute(): %s", GetModelSummary(m_Model).c_str());
557 m_RequestCount++;
558
Mike Kellyb5fdf382019-06-11 16:35:25 +0100559 if (!android::nn::validateRequest(request, m_Model))
560 {
Kevin DuBois30c34ae2020-08-26 13:53:41 -0700561 callback(V1_0::ErrorStatus::INVALID_ARGUMENT, {}, g_NoTiming, "ArmnnPreparedModel_1_2::execute");
562 return V1_0::ErrorStatus::INVALID_ARGUMENT;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100563 }
564
565 if (!m_RequestInputsAndOutputsDumpDir.empty())
566 {
Mike Kelly65c42dc2019-07-22 14:06:00 +0100567 ALOGD("Dumping inputs and outputs for request %" PRIuPTR, reinterpret_cast<std::uintptr_t>(&callback));
Mike Kellyb5fdf382019-06-11 16:35:25 +0100568 }
569
Mike Kellyb5fdf382019-06-11 16:35:25 +0100570 // map the memory pool into shared pointers
571 // use a shared memory pools vector on the heap, as it is passed to the request thread
Derek Lamberti4de83c52020-03-17 13:40:18 +0000572 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
Mike Kellyb5fdf382019-06-11 16:35:25 +0100573
Derek Lamberti4de83c52020-03-17 13:40:18 +0000574 // allocate the tensors on the heap, as they are passed to the request thread
575 auto inputTensors = std::make_shared<armnn::InputTensors>();
576 auto outputTensors = std::make_shared<armnn::OutputTensors>();
577
578 auto prepareStatus = PrepareMemoryForIO(*inputTensors, *outputTensors, *memPools, request, callback);
579 switch(prepareStatus)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100580 {
Derek Lamberti4de83c52020-03-17 13:40:18 +0000581 case V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
582 return V1_0::ErrorStatus::NONE;
583 case V1_0::ErrorStatus::GENERAL_FAILURE:
584 return V1_0::ErrorStatus::GENERAL_FAILURE;
585 default:
586 {}
Mike Kellyb5fdf382019-06-11 16:35:25 +0100587 }
588
589 ALOGV("ArmnnPreparedModel_1_2::execute(...) before PostMsg");
Derek Lamberti4de83c52020-03-17 13:40:18 +0000590
Mike Kellyb5fdf382019-06-11 16:35:25 +0100591 // post the request for asynchronous execution
Derek Lamberti4de83c52020-03-17 13:40:18 +0000592 CallbackContext_1_2 cb;
593 cb.callback = callback;
594 cb.ctx = ctx;
595 m_RequestThread.PostMsg(this, memPools, inputTensors, outputTensors, cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100596 ALOGV("ArmnnPreparedModel_1_2::execute(...) after PostMsg");
Kevin DuBois30c34ae2020-08-26 13:53:41 -0700597 return V1_0::ErrorStatus::NONE;
Mike Kellyb5fdf382019-06-11 16:35:25 +0100598}
599
Mike Kellyb5fdf382019-06-11 16:35:25 +0100600template<typename HalVersion>
601Return<void> ArmnnPreparedModel_1_2<HalVersion>::configureExecutionBurst(
Derek Lamberti4de83c52020-03-17 13:40:18 +0000602 const sp<V1_2::IBurstCallback>& callback,
603 const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
604 const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
605 V1_2::IPreparedModel::configureExecutionBurst_cb cb)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100606{
607 ALOGV("ArmnnPreparedModel_1_2::configureExecutionBurst");
Mike Kellyb5fdf382019-06-11 16:35:25 +0100608 const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(callback,
609 requestChannel,
610 resultChannel,
Kevin May42477c12020-03-26 13:34:14 +0000611 this);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100612
613 if (burst == nullptr)
614 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000615 cb(V1_0::ErrorStatus::GENERAL_FAILURE, {});
Mike Kellyb5fdf382019-06-11 16:35:25 +0100616 }
617 else
618 {
Kevin Mayec1e5b82020-02-26 17:00:39 +0000619 cb(V1_0::ErrorStatus::NONE, burst);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100620 }
621 return Void();
622}
623
Kevin May42477c12020-03-26 13:34:14 +0000624#if defined(ARMNN_ANDROID_NN_V1_2) || defined(ARMNN_ANDROID_NN_V1_3)
Mike Kellyb5fdf382019-06-11 16:35:25 +0100625template class ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>;
Derek Lamberti4de83c52020-03-17 13:40:18 +0000626template bool ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>::ExecuteGraph<CallbackContext_1_2>(
627 std::shared_ptr<std::vector<::android::nn::RunTimePoolInfo>>& pMemPools,
628 armnn::InputTensors& pInputTensors,
629 armnn::OutputTensors& pOutputTensors,
630 CallbackContext_1_2 cb);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100631#endif
632
633} // namespace armnn_driver