blob: 91bd04ea485088d4c51d9f1597d8e624928be2d0 [file] [log] [blame]
Sadik Armagan8f397a12022-06-17 15:38:22 +01001//
2// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#define LOG_TAG "arm-armnn-sl"
7
8#include "ArmnnPreparedModel.hpp"
9#include "CanonicalUtils.hpp"
10
11#include <DefaultExecution.h>
12#include <LegacyUtils.h>
13#include <nnapi/IBurst.h>
14#include <nnapi/IPreparedModel.h>
15#include <nnapi/Result.h>
16#include <nnapi/SharedMemory.h>
17#include <nnapi/TypeUtils.h>
18#include <nnapi/Types.h>
19#include <nnapi/Validation.h>
20
21#include <memory>
22#include <tuple>
23#include <utility>
24#include <vector>
25
26using namespace android;
27using namespace android::nn;
28
29static const Timing g_NoTiming = {};
30
31namespace {
32
33using namespace armnn_driver;
34
35unsigned long MicrosecondsDuration(android::nn::TimePoint endPoint, android::nn::TimePoint startPoint)
36{
37 return static_cast<unsigned long>(std::chrono::duration_cast<std::chrono::microseconds>(
38 endPoint - startPoint).count());
39}
40
41bool ValidateRequestArgument(const Request::Argument& requestArg, const armnn::TensorInfo& tensorInfo)
42{
43 if (requestArg.dimensions.size() != 0)
44 {
45 if (requestArg.dimensions.size() != tensorInfo.GetNumDimensions())
46 {
47 VLOG(DRIVER) << "Mismatched dimensions (request argument: "
48 << requestArg.dimensions.size() << " expected: " << tensorInfo.GetNumDimensions();
49 return false;
50 }
51
52 for (unsigned int d = 0; d < tensorInfo.GetNumDimensions(); ++d)
53 {
54 if (requestArg.dimensions[d] != 0 && requestArg.dimensions[d] != tensorInfo.GetShape()[d])
55 {
56 VLOG(DRIVER) << "Mismatched dimensions " << d
57 << " (request argument: " << requestArg.dimensions[d]
58 << " expected: " << tensorInfo.GetShape()[d];
59 return false;
60 }
61 }
62 }
63
64 return true;
65}
66
67armnn::Tensor GetTensorForRequestArgument(const Request::Argument& requestArg,
68 const armnn::TensorInfo& tensorInfo,
69 const std::vector<::android::nn::RunTimePoolInfo>& requestPools)
70{
71 if (!ValidateRequestArgument(requestArg, tensorInfo))
72 {
73 return armnn::Tensor();
74 }
75
76 if (requestArg.lifetime == Request::Argument::LifeTime::POINTER)
77 {
78 return armnn::Tensor(tensorInfo, GetMemoryFromPointer(requestArg));
79 }
80 else if (requestArg.lifetime == Request::Argument::LifeTime::POOL)
81 {
82 return armnn::Tensor(tensorInfo, GetMemoryFromPool(requestArg.location, requestPools));
83 }
84 return armnn::Tensor();
85}
86
87inline std::string BuildTensorName(const char* tensorNamePrefix, std::size_t index)
88{
89 return tensorNamePrefix + std::to_string(index);
90}
91
92bool IsPointerTypeMemory(const Request& request)
93{
94 for (auto& input : request.inputs)
95 {
Sadik Armagana045ac02022-07-01 14:32:05 +010096 if (input.lifetime != Request::Argument::LifeTime::POINTER)
Sadik Armagan8f397a12022-06-17 15:38:22 +010097 {
Sadik Armagana045ac02022-07-01 14:32:05 +010098 return false;
Sadik Armagan8f397a12022-06-17 15:38:22 +010099 }
100 }
101
102 for (auto& output: request.outputs)
103 {
Sadik Armagana045ac02022-07-01 14:32:05 +0100104 if (output.lifetime != Request::Argument::LifeTime::POINTER)
Sadik Armagan8f397a12022-06-17 15:38:22 +0100105 {
Sadik Armagana045ac02022-07-01 14:32:05 +0100106 return false;
Sadik Armagan8f397a12022-06-17 15:38:22 +0100107 }
108 }
109
Sadik Armagana045ac02022-07-01 14:32:05 +0100110 return true;
Sadik Armagan8f397a12022-06-17 15:38:22 +0100111}
112
113} // anonymous namespace
114
115using namespace android::nn;
116
117namespace armnn_driver
118{
119
120void ArmnnPreparedModel::Init()
121{
122 // Enable profiling if required.
123 m_Runtime->GetProfiler(m_NetworkId)->EnableProfiling(m_GpuProfilingEnabled);
124}
125
126ArmnnPreparedModel::ArmnnPreparedModel(armnn::NetworkId networkId,
127 armnn::IRuntime* runtime,
128 const Model& model,
129 const std::string& requestInputsAndOutputsDumpDir,
130 const bool gpuProfilingEnabled,
131 Priority priority)
132 : m_NetworkId(networkId)
133 , m_Runtime(runtime)
134 , m_Model(model)
135 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
136 , m_GpuProfilingEnabled(gpuProfilingEnabled)
137 , m_ModelPriority(priority)
138 , m_PrepareFromCache(false)
139{
140 Init();
141}
142
143ArmnnPreparedModel::ArmnnPreparedModel(armnn::NetworkId networkId,
144 armnn::IRuntime* runtime,
145 const std::string& requestInputsAndOutputsDumpDir,
146 const bool gpuProfilingEnabled,
147 Priority priority,
148 const bool prepareModelFromCache)
149 : m_NetworkId(networkId)
150 , m_Runtime(runtime)
151 , m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
152 , m_GpuProfilingEnabled(gpuProfilingEnabled)
153 , m_ModelPriority(priority)
154 , m_PrepareFromCache(prepareModelFromCache)
155{
156 Init();
157}
158
159
160ErrorStatus ArmnnPreparedModel::PrepareMemoryForInputs(
161 armnn::InputTensors& inputs,
162 const Request& request,
163 const std::vector<android::nn::RunTimePoolInfo>& memPools) const
164{
165 inputs.reserve(request.inputs.size());
166 for (unsigned int i = 0; i < request.inputs.size(); i++)
167 {
168 const auto& inputArg = request.inputs[i];
169
170 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
171 // inputs (of type InputTensors) is composed of a vector of ConstTensors.
172 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
173 inputTensorInfo.SetConstant();
174 const armnn::Tensor inputTensor = GetTensorForRequestArgument(inputArg, inputTensorInfo, memPools);
175
176 if (inputTensor.GetMemoryArea() == nullptr)
177 {
178 VLOG(DRIVER) << "Cannot execute request. Error converting request input " << i << "to tensor.";
179 return ErrorStatus::GENERAL_FAILURE;
180 }
181 inputs.emplace_back(i, inputTensor);
182 }
183
184 return ErrorStatus::NONE;
185}
186
187ErrorStatus ArmnnPreparedModel::PrepareMemoryForOutputs(
188 armnn::OutputTensors& outputs,
189 std::vector<OutputShape> &outputShapes,
190 const Request& request,
191 const std::vector<android::nn::RunTimePoolInfo>& memPools) const
192{
193 outputs.reserve(request.outputs.size());
194 for (unsigned int i = 0; i < request.outputs.size(); i++)
195 {
196 auto& outputArg = request.outputs[i];
197
198 armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
199 armnn::Tensor outputTensor = GetTensorForRequestArgument(outputArg, outputTensorInfo, memPools);
200 if (outputTensor.GetMemoryArea() == nullptr)
201 {
202 VLOG(DRIVER) << "Cannot execute request. Error converting request output " << i << "to tensor.";
203 return ErrorStatus::GENERAL_FAILURE;
204 }
205
206 const size_t outputSize = outputTensorInfo.GetNumBytes();
207
208 unsigned int count = 0;
209 std::for_each(outputArg.dimensions.begin(), outputArg.dimensions.end(), [&](auto dim)
210 {
211 if (dim != 0)
212 {
213 outputTensorInfo.GetShape()[count] = dim;
214 }
215 else
216 {
217 outputTensorInfo.GetShape()[count] = outputArg.dimensions.size();
218 }
219
220 count++;
221 });
222
223 outputs.emplace_back(i, outputTensor);
224 outputShapes[i] = ComputeShape(outputTensorInfo);
225
226 if (outputArg.location.length < outputSize)
227 {
228 VLOG(DRIVER) << "ArmnnPreparedModel::Execute failed outputArg.location.length "
229 << std::to_string(outputArg.location.length).c_str()
230 << " < outputSize " << std::to_string(outputSize).c_str();
231 outputShapes[i].isSufficient = false;
232 return ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
233 }
234
Sadik Armagan8f397a12022-06-17 15:38:22 +0100235 if (outputArg.lifetime == Request::Argument::LifeTime::POOL)
236 {
237 size_t bufferSize = memPools.at(outputArg.location.poolIndex).getSize();
238 if (bufferSize < outputSize)
239 {
240 VLOG(DRIVER) << "ArmnnPreparedModel::Execute failed bufferSize "
241 << std::to_string(outputArg.location.length).c_str()
242 << " < outputSize " << std::to_string(outputSize).c_str();
243 outputShapes[i].isSufficient = false;
244 return ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
245 }
246 }
247 }
248 return ErrorStatus::NONE;
249}
250
251ErrorStatus ArmnnPreparedModel::PrepareMemoryForIO(armnn::InputTensors& inputs,
252 armnn::OutputTensors& outputs,
253 std::vector<android::nn::RunTimePoolInfo>& memPools,
Sadik Armagan30246502022-06-22 15:20:14 +0100254 const Request& request,
255 const bool pointerMemory) const
Sadik Armagan8f397a12022-06-17 15:38:22 +0100256{
257 //Check memory pools are not empty
258 // add the inputs and outputs with their data
259 try
260 {
Sadik Armagan30246502022-06-22 15:20:14 +0100261 if (!pointerMemory && !setRunTimePoolInfosFromMemoryPools(&memPools, request.pools))
Sadik Armagan8f397a12022-06-17 15:38:22 +0100262 {
263 return ErrorStatus::INVALID_ARGUMENT;
264 }
265
266 if (PrepareMemoryForInputs(inputs, request, memPools) != ErrorStatus::NONE)
267 {
268 VLOG(DRIVER) << "Failed when preparing memory for Inputs";
269 return ErrorStatus::GENERAL_FAILURE;
270 }
271
272 std::vector<OutputShape> outputShapes(request.outputs.size());
273
274 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
275 if (errorStatus != ErrorStatus::NONE)
276 {
277 return errorStatus;
278 }
279 }
280 catch (armnn::Exception& e)
281 {
282 VLOG(DRIVER) << "armnn::Exception caught while preparing for EnqueueWorkload: " << e.what();
283 return ErrorStatus::GENERAL_FAILURE;
284 }
285 catch (std::exception& e)
286 {
287 VLOG(DRIVER) << "std::exception caught while preparing for EnqueueWorkload: " << e.what();
288 return ErrorStatus::GENERAL_FAILURE;
289 }
290
291 return ErrorStatus::NONE;
292}
293
294ExecutionResult<std::pair<std::vector<OutputShape>, Timing>> ArmnnPreparedModel::execute(
295 const Request& request,
296 MeasureTiming measureTiming,
297 const OptionalTimePoint& deadline,
298 const OptionalDuration&,
299 const std::vector<android::nn::TokenValuePair>& hints,
300 const std::vector<android::nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const
301{
302 VLOG(DRIVER) << "CanonicalDriver::PreparedModel::execute()";
303
304 CanonicalExecutionContext ctx;
305 if (measureTiming == MeasureTiming::YES)
306 {
307 ctx.measureTimings = measureTiming;
308 ctx.driverStart = Clock::now();
309 }
310
311 if (!m_PrepareFromCache)
312 {
313 const auto modelRequest = validateRequestForModel(request, m_Model);
314 if (!modelRequest.ok())
315 {
316 return NN_ERROR(ErrorStatus::INVALID_ARGUMENT) << modelRequest.error();
317 }
318 VLOG(DRIVER) << "ArmnnPreparedModel::execute(): " << GetModelSummary(m_Model).c_str();
319 }
Sadik Armagana045ac02022-07-01 14:32:05 +0100320 if (hasDeadlinePassed(deadline))
321 {
Sadik Armagan8f397a12022-06-17 15:38:22 +0100322 return NN_ERROR(ErrorStatus::MISSED_DEADLINE_PERSISTENT);
323 }
324
325 // map the memory pool into shared pointers
326 // use a shared memory pools vector on the heap, as it is passed to the request thread
327 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
328
329 // allocate the tensors on the heap, as they are passed to the request thread
330 auto inputTensors = std::make_shared<armnn::InputTensors>();
331 auto outputTensors = std::make_shared<armnn::OutputTensors>();
332
Sadik Armagan8f397a12022-06-17 15:38:22 +0100333 auto isPointerTypeMemory = IsPointerTypeMemory(request);
Sadik Armagan30246502022-06-22 15:20:14 +0100334 ErrorStatus theErrorStatus = PrepareMemoryForIO(*inputTensors,
335 *outputTensors,
336 *memPools,
337 request,
338 isPointerTypeMemory);
Sadik Armagan8f397a12022-06-17 15:38:22 +0100339
340 switch(theErrorStatus)
341 {
342 case ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
343 return NN_ERROR(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE);
344 case ErrorStatus::GENERAL_FAILURE:
345 return NN_ERROR(ErrorStatus::GENERAL_FAILURE);
346 case ErrorStatus::INVALID_ARGUMENT:
347 return NN_ERROR(ErrorStatus::INVALID_ARGUMENT);
348 default:
349 {}
350 }
351
352 std::vector<OutputShape> outputShapes(outputTensors->size());
353 for (unsigned int i = 0; i < outputTensors->size(); i++)
354 {
355 std::pair<int, armnn::Tensor> outputTensorPair = (*outputTensors)[i];
356 const armnn::Tensor outputTensor = outputTensorPair.second;
357 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
358
359 outputShapes[i] = ComputeShape(outputTensorInfo);
360 }
361 Timing theTiming;
362
363 VLOG(DRIVER) << "ArmnnPreparedModel::execute(...) before ExecuteGraph";
Sadik Armagan30246502022-06-22 15:20:14 +0100364 auto errorStatus = ExecuteGraph(memPools, *inputTensors, *outputTensors, ctx, isPointerTypeMemory);
Sadik Armagan8f397a12022-06-17 15:38:22 +0100365 if (errorStatus != ErrorStatus::NONE)
366 {
367 return NN_ERROR(errorStatus) << "execute() failed";
368 }
369 VLOG(DRIVER) << "ArmnnPreparedModel::execute(...) after ExecuteGraph";
Sadik Armagan8f397a12022-06-17 15:38:22 +0100370
371 return std::make_pair(outputShapes, theTiming);
372}
373
374ErrorStatus ArmnnPreparedModel::ExecuteGraph(
375 std::shared_ptr<std::vector<android::nn::RunTimePoolInfo>>& pMemPools,
376 armnn::InputTensors& inputTensors,
377 armnn::OutputTensors& outputTensors,
Sadik Armagan30246502022-06-22 15:20:14 +0100378 CanonicalExecutionContext ctx,
379 const bool pointerMemory) const
Sadik Armagan8f397a12022-06-17 15:38:22 +0100380{
381 VLOG(DRIVER) << "ArmnnPreparedModel::ExecuteGraph(...)";
382
383 DumpTensorsIfRequired("Input", inputTensors);
Sadik Armagana045ac02022-07-01 14:32:05 +0100384 std::vector<armnn::ImportedInputId> importedInputIds;
385 std::vector<armnn::ImportedOutputId> importedOutputIds;
Sadik Armagan8f397a12022-06-17 15:38:22 +0100386 try
387 {
388 if (ctx.measureTimings == MeasureTiming::YES)
389 {
390 ctx.deviceStart = Clock::now();
391 }
392 armnn::Status status;
393 VLOG(DRIVER) << "ArmnnPreparedModel::ExecuteGraph m_AsyncModelExecutionEnabled false";
Sadik Armagana045ac02022-07-01 14:32:05 +0100394 importedInputIds = m_Runtime->ImportInputs(m_NetworkId, inputTensors, armnn::MemorySource::Malloc);
Sadik Armagan1e276f32022-07-19 12:37:20 +0100395 if (!importedInputIds.empty())
396 {
397 // Some or all of the input tensors been imported. We need to remove the ones that could from
398 // inputTensors.
399 for (armnn::ImportedInputId& importedId : importedInputIds)
400 {
401 inputTensors.erase(
402 std::remove_if(
403 inputTensors.begin(), inputTensors.end(),
404 [&importedId](std::pair<armnn::LayerBindingId, class armnn::ConstTensor>& element) {
405 return (element.first == static_cast<int>(importedId));
406 }),
407 inputTensors.end());
408 }
409 }
Sadik Armagana045ac02022-07-01 14:32:05 +0100410 importedOutputIds = m_Runtime->ImportOutputs(m_NetworkId, outputTensors, armnn::MemorySource::Malloc);
Sadik Armagan1e276f32022-07-19 12:37:20 +0100411 if (!importedOutputIds.empty())
412 {
413 // Some or all of the output tensors could not be imported. We need to remove the ones that could
414 // from outputTensors.
415 for (armnn::ImportedInputId& importedId : importedOutputIds)
416 {
417 outputTensors.erase(
418 std::remove_if(
419 outputTensors.begin(), outputTensors.end(),
420 [&importedId](std::pair<armnn::LayerBindingId, class armnn::Tensor>& element) {
421 return (element.first == static_cast<int>(importedId));
422 }),
423 outputTensors.end());
424 }
425 }
Sadik Armagana045ac02022-07-01 14:32:05 +0100426 status = m_Runtime->EnqueueWorkload(m_NetworkId,
427 inputTensors,
428 outputTensors,
429 importedInputIds,
430 importedOutputIds);
Sadik Armagan8f397a12022-06-17 15:38:22 +0100431
432 if (ctx.measureTimings == MeasureTiming::YES)
433 {
434 ctx.deviceEnd = Clock::now();
435 }
436 if (status != armnn::Status::Success)
437 {
438 VLOG(DRIVER) << "ArmnnPreparedModel:ExecuteGraph EnqueueWorkload failed";
439 return ErrorStatus::GENERAL_FAILURE;
440 }
441 }
442 catch (armnn::Exception& e)
443 {
444 VLOG(DRIVER) << "armnn:Exception caught from EnqueueWorkload: " << e.what();
445 return ErrorStatus::GENERAL_FAILURE;
446 }
447 catch (std::exception& e)
448 {
449 VLOG(DRIVER) << "std::exception caught from EnqueueWorkload: " << e.what();
450 return ErrorStatus::GENERAL_FAILURE;
451 }
452
Sadik Armagana045ac02022-07-01 14:32:05 +0100453 if (!pointerMemory && (!importedInputIds.empty() || !importedOutputIds.empty()))
Sadik Armagan30246502022-06-22 15:20:14 +0100454 {
455 CommitPools(*pMemPools);
456 }
Sadik Armagan8f397a12022-06-17 15:38:22 +0100457 DumpTensorsIfRequired("Output", outputTensors);
458
459 if (ctx.measureTimings == MeasureTiming::YES)
460 {
461 ctx.driverEnd = Clock::now();
462 Timing timing;
463 timing.timeOnDevice = ctx.deviceEnd - ctx.deviceStart;
464 timing.timeInDriver = ctx.driverEnd - ctx.driverStart;
465 VLOG(DRIVER) << "ArmnnPreparedModel::execute timing - Device = "
466 << timing.timeOnDevice << "Driver = " << timing.timeInDriver;
467 }
468 return ErrorStatus::NONE;
469}
470
471Priority ArmnnPreparedModel::GetModelPriority() const
472{
473 return m_ModelPriority;
474}
475
476
477GeneralResult<std::pair<SyncFence, ExecuteFencedInfoCallback>> ArmnnPreparedModel::executeFenced(
478 const Request& request,
479 const std::vector<SyncFence>& waitFor,
480 MeasureTiming measureTiming,
481 const OptionalTimePoint& deadline,
482 const OptionalDuration&,
483 const OptionalDuration&,
484 const std::vector<android::nn::TokenValuePair>& hints,
485 const std::vector<android::nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const
486{
487 VLOG(DRIVER) << "ArmnnPreparedModel::executeFenced()";
488
489 if (!m_PrepareFromCache) {
490 const auto modelRequest = validateRequestForModel(request, m_Model);
491 if (!modelRequest.ok())
492 {
493 return NN_ERROR(ErrorStatus::INVALID_ARGUMENT) << modelRequest.error();
494 }
495 VLOG(DRIVER) << "ArmnnPreparedModel::executeFenced(): " << GetModelSummary(m_Model).c_str();
496 }
497 if (hasDeadlinePassed(deadline))
498 {
499 return NN_ERROR(ErrorStatus::MISSED_DEADLINE_PERSISTENT);
500 }
501
502 CanonicalExecutionContext ctx;
503 if (measureTiming == MeasureTiming::YES)
504 {
505 ctx.measureTimings = measureTiming;
506 ctx.driverStart = Clock::now();
507 }
508
509 // Wait for the dependent events to signal
510 for (const auto& syncFence : waitFor)
511 {
512 if (!syncFence.getSharedHandle())
513 {
514 return NN_ERROR(ErrorStatus::INVALID_ARGUMENT);
515 }
516 if (syncFence.syncWait({}) != SyncFence::FenceState::SIGNALED)
517 {
518 return NN_ERROR(ErrorStatus::GENERAL_FAILURE) << "syncWait failed";
519 }
520 }
521
522 android::nn::TimePoint fenceExecutionStart;
523 if (measureTiming == MeasureTiming::YES)
524 {
525 fenceExecutionStart = Clock::now();
526 }
527
528 // map the memory pool into shared pointers
529 // use a shared memory pools vector on the heap, as it is passed to the request thread
530 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
531
532 // allocate the tensors on the heap, as they are passed to the request thread
533 auto inputTensors = std::make_shared<armnn::InputTensors>();
534 auto outputTensors = std::make_shared<armnn::OutputTensors>();
535
Sadik Armagan8f397a12022-06-17 15:38:22 +0100536 auto isPointerTypeMemory = IsPointerTypeMemory(request);
Sadik Armagan30246502022-06-22 15:20:14 +0100537 ErrorStatus theErrorStatus = PrepareMemoryForIO(*inputTensors,
538 *outputTensors,
539 *memPools,
540 request,
541 isPointerTypeMemory);
Sadik Armagan8f397a12022-06-17 15:38:22 +0100542
543 if (theErrorStatus != ErrorStatus::NONE)
544 {
545 return NN_ERROR(ErrorStatus::INVALID_ARGUMENT) << "executeFenced() failed";
546 }
547
548 Timing timingSinceLaunch = {};
549 Timing timingAfterFence = {};
550 if (measureTiming == MeasureTiming::YES)
551 {
552 timingAfterFence.timeOnDevice = ctx.deviceEnd - ctx.deviceStart;
553 timingAfterFence.timeInDriver = ctx.driverEnd - fenceExecutionStart;
554 VLOG(DRIVER) << "executeFenced timingSinceLaunch = " << timingAfterFence.timeOnDevice;
555 VLOG(DRIVER) << "executeFenced timingAfterFence = " << timingAfterFence.timeInDriver;
556 }
557
558 VLOG(DRIVER) << "ArmnnCanonicalPreparedModel::executeFenced(...) before ExecuteGraph";
Sadik Armagan30246502022-06-22 15:20:14 +0100559 auto errorStatus = ExecuteGraph(memPools, *inputTensors, *outputTensors, ctx, isPointerTypeMemory);
Sadik Armagan8f397a12022-06-17 15:38:22 +0100560 VLOG(DRIVER) << "ArmnnCanonicalPreparedModel::executeFenced(...) after ExecuteGraph";
Sadik Armagan8f397a12022-06-17 15:38:22 +0100561
562 ExecuteFencedInfoCallback armnnFencedExecutionCallback =
563 [timingSinceLaunch, timingAfterFence, errorStatus]() {
564
565 GeneralResult<std::pair<Timing, Timing>> result;
566
567 switch(errorStatus)
568 {
569 case ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
570 result.error().code = (ErrorStatus::OUTPUT_INSUFFICIENT_SIZE);
571 case ErrorStatus::GENERAL_FAILURE:
572 result.error().code = (ErrorStatus::GENERAL_FAILURE);
573 case ErrorStatus::INVALID_ARGUMENT:
574 result.error().code = (ErrorStatus::INVALID_ARGUMENT);
575 default:
576 {
577 result.value() = std::make_pair(timingSinceLaunch, timingAfterFence);
578 }
579 }
580 return result;
581 };
582 return std::make_pair(SyncFence::createAsSignaled(), std::move(armnnFencedExecutionCallback ));
583}
584
585GeneralResult<SharedExecution> ArmnnPreparedModel::createReusableExecution(
586 const Request& request,
587 MeasureTiming measureTiming,
588 const OptionalDuration& loopTimeoutDuration,
589 const std::vector<android::nn::TokenValuePair>& hints,
590 const std::vector<android::nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const
591{
592 VLOG(DRIVER) << "ArmnnPreparedModel::createReusableExecution()";
593 return std::make_shared<DefaultExecution>(shared_from_this(),
594 request,
595 measureTiming,
596 loopTimeoutDuration);
597}
598
599GeneralResult<SharedBurst> ArmnnPreparedModel::configureExecutionBurst() const
600{
Sadik Armagan8f397a12022-06-17 15:38:22 +0100601 return nullptr;
602}
603
604std::any ArmnnPreparedModel::getUnderlyingResource() const
605{
606 return &m_Model;
607}
608
609template<typename TensorBindingCollection>
610void ArmnnPreparedModel::DumpTensorsIfRequired(char const* tensorNamePrefix,
611 const TensorBindingCollection& tensorBindings) const
612{
613 if (!m_RequestInputsAndOutputsDumpDir.empty())
614 {
615 const std::string requestName = std::to_string(m_NetworkId) + ".dump";
616 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
617 {
618 DumpTensor(m_RequestInputsAndOutputsDumpDir,
619 requestName,
620 BuildTensorName(tensorNamePrefix, i),
621 tensorBindings[i].second);
622 }
623 }
624}
625
626ArmnnPreparedModel::~ArmnnPreparedModel()
627{
628 VLOG(DRIVER) << "ArmnnPreparedModel::~ArmnnPreparedModel()";
629 // Get a hold of the profiler used by this model.
630 if (m_GpuProfilingEnabled)
631 {
632 auto profiler = m_Runtime->GetProfiler(m_NetworkId);
633 if (profiler)
634 {
635 // Dump the profiling info to a file if required.
636 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled,
637 m_RequestInputsAndOutputsDumpDir,
638 m_NetworkId,
639 profiler.get());
640 }
641 }
642 // Unload the network associated with this model
643 m_Runtime->UnloadNetwork(m_NetworkId);
644}
645
646bool ArmnnPreparedModel::ExecuteWithDummyInputs(unsigned int numInputs, unsigned int numOutputs) const
647{
648 std::vector<std::vector<char>> storage;
649 armnn::InputTensors inputTensors;
650 for (unsigned int i = 0; i < numInputs; i++)
651 {
652 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
653 // pInputTensors (of type InputTensors) is composed of a vector of ConstTensors.
654 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
655 inputTensorInfo.SetConstant();
656 storage.emplace_back(inputTensorInfo.GetNumBytes());
657 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
658
659 inputTensors.emplace_back(i, inputTensor);
660 }
661
662 armnn::OutputTensors outputTensors;
663 for (unsigned int i = 0; i < numOutputs; i++)
664 {
665 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
666 storage.emplace_back(outputTensorInfo.GetNumBytes());
667 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
668
669 outputTensors.emplace_back(i, outputTensor);
670 }
671 CanonicalExecutionContext ctx;
672 ctx.measureTimings = MeasureTiming::NO;
673 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
674
675 auto errorStatus = ExecuteGraph(memPools,
676 inputTensors,
677 outputTensors,
678 ctx);
679
680 return errorStatus == ErrorStatus::NONE;
681}
682
683} // namespace armnn_driver