blob: 54a019004c6f6b30913a722538ca35186c5f33e7 [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
235 //TODO: Need to check for Request::Argument::LifeTime::POINTER
236 if (outputArg.lifetime == Request::Argument::LifeTime::POOL)
237 {
238 size_t bufferSize = memPools.at(outputArg.location.poolIndex).getSize();
239 if (bufferSize < outputSize)
240 {
241 VLOG(DRIVER) << "ArmnnPreparedModel::Execute failed bufferSize "
242 << std::to_string(outputArg.location.length).c_str()
243 << " < outputSize " << std::to_string(outputSize).c_str();
244 outputShapes[i].isSufficient = false;
245 return ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
246 }
247 }
248 }
249 return ErrorStatus::NONE;
250}
251
252ErrorStatus ArmnnPreparedModel::PrepareMemoryForIO(armnn::InputTensors& inputs,
253 armnn::OutputTensors& outputs,
254 std::vector<android::nn::RunTimePoolInfo>& memPools,
Sadik Armagan30246502022-06-22 15:20:14 +0100255 const Request& request,
256 const bool pointerMemory) const
Sadik Armagan8f397a12022-06-17 15:38:22 +0100257{
258 //Check memory pools are not empty
259 // add the inputs and outputs with their data
260 try
261 {
Sadik Armagan30246502022-06-22 15:20:14 +0100262 if (!pointerMemory && !setRunTimePoolInfosFromMemoryPools(&memPools, request.pools))
Sadik Armagan8f397a12022-06-17 15:38:22 +0100263 {
264 return ErrorStatus::INVALID_ARGUMENT;
265 }
266
267 if (PrepareMemoryForInputs(inputs, request, memPools) != ErrorStatus::NONE)
268 {
269 VLOG(DRIVER) << "Failed when preparing memory for Inputs";
270 return ErrorStatus::GENERAL_FAILURE;
271 }
272
273 std::vector<OutputShape> outputShapes(request.outputs.size());
274
275 auto errorStatus = PrepareMemoryForOutputs(outputs, outputShapes, request, memPools);
276 if (errorStatus != ErrorStatus::NONE)
277 {
278 return errorStatus;
279 }
280 }
281 catch (armnn::Exception& e)
282 {
283 VLOG(DRIVER) << "armnn::Exception caught while preparing for EnqueueWorkload: " << e.what();
284 return ErrorStatus::GENERAL_FAILURE;
285 }
286 catch (std::exception& e)
287 {
288 VLOG(DRIVER) << "std::exception caught while preparing for EnqueueWorkload: " << e.what();
289 return ErrorStatus::GENERAL_FAILURE;
290 }
291
292 return ErrorStatus::NONE;
293}
294
295ExecutionResult<std::pair<std::vector<OutputShape>, Timing>> ArmnnPreparedModel::execute(
296 const Request& request,
297 MeasureTiming measureTiming,
298 const OptionalTimePoint& deadline,
299 const OptionalDuration&,
300 const std::vector<android::nn::TokenValuePair>& hints,
301 const std::vector<android::nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const
302{
303 VLOG(DRIVER) << "CanonicalDriver::PreparedModel::execute()";
304
305 CanonicalExecutionContext ctx;
306 if (measureTiming == MeasureTiming::YES)
307 {
308 ctx.measureTimings = measureTiming;
309 ctx.driverStart = Clock::now();
310 }
311
312 if (!m_PrepareFromCache)
313 {
314 const auto modelRequest = validateRequestForModel(request, m_Model);
315 if (!modelRequest.ok())
316 {
317 return NN_ERROR(ErrorStatus::INVALID_ARGUMENT) << modelRequest.error();
318 }
319 VLOG(DRIVER) << "ArmnnPreparedModel::execute(): " << GetModelSummary(m_Model).c_str();
320 }
Sadik Armagana045ac02022-07-01 14:32:05 +0100321 if (hasDeadlinePassed(deadline))
322 {
Sadik Armagan8f397a12022-06-17 15:38:22 +0100323 return NN_ERROR(ErrorStatus::MISSED_DEADLINE_PERSISTENT);
324 }
325
326 // map the memory pool into shared pointers
327 // use a shared memory pools vector on the heap, as it is passed to the request thread
328 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
329
330 // allocate the tensors on the heap, as they are passed to the request thread
331 auto inputTensors = std::make_shared<armnn::InputTensors>();
332 auto outputTensors = std::make_shared<armnn::OutputTensors>();
333
Sadik Armagan8f397a12022-06-17 15:38:22 +0100334 auto isPointerTypeMemory = IsPointerTypeMemory(request);
Sadik Armagan30246502022-06-22 15:20:14 +0100335 ErrorStatus theErrorStatus = PrepareMemoryForIO(*inputTensors,
336 *outputTensors,
337 *memPools,
338 request,
339 isPointerTypeMemory);
Sadik Armagan8f397a12022-06-17 15:38:22 +0100340
341 switch(theErrorStatus)
342 {
343 case ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
344 return NN_ERROR(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE);
345 case ErrorStatus::GENERAL_FAILURE:
346 return NN_ERROR(ErrorStatus::GENERAL_FAILURE);
347 case ErrorStatus::INVALID_ARGUMENT:
348 return NN_ERROR(ErrorStatus::INVALID_ARGUMENT);
349 default:
350 {}
351 }
352
353 std::vector<OutputShape> outputShapes(outputTensors->size());
354 for (unsigned int i = 0; i < outputTensors->size(); i++)
355 {
356 std::pair<int, armnn::Tensor> outputTensorPair = (*outputTensors)[i];
357 const armnn::Tensor outputTensor = outputTensorPair.second;
358 const armnn::TensorInfo outputTensorInfo = outputTensor.GetInfo();
359
360 outputShapes[i] = ComputeShape(outputTensorInfo);
361 }
362 Timing theTiming;
363
364 VLOG(DRIVER) << "ArmnnPreparedModel::execute(...) before ExecuteGraph";
Sadik Armagan30246502022-06-22 15:20:14 +0100365 auto errorStatus = ExecuteGraph(memPools, *inputTensors, *outputTensors, ctx, isPointerTypeMemory);
Sadik Armagan8f397a12022-06-17 15:38:22 +0100366 if (errorStatus != ErrorStatus::NONE)
367 {
368 return NN_ERROR(errorStatus) << "execute() failed";
369 }
370 VLOG(DRIVER) << "ArmnnPreparedModel::execute(...) after ExecuteGraph";
Sadik Armagan8f397a12022-06-17 15:38:22 +0100371
372 return std::make_pair(outputShapes, theTiming);
373}
374
375ErrorStatus ArmnnPreparedModel::ExecuteGraph(
376 std::shared_ptr<std::vector<android::nn::RunTimePoolInfo>>& pMemPools,
377 armnn::InputTensors& inputTensors,
378 armnn::OutputTensors& outputTensors,
Sadik Armagan30246502022-06-22 15:20:14 +0100379 CanonicalExecutionContext ctx,
380 const bool pointerMemory) const
Sadik Armagan8f397a12022-06-17 15:38:22 +0100381{
382 VLOG(DRIVER) << "ArmnnPreparedModel::ExecuteGraph(...)";
383
384 DumpTensorsIfRequired("Input", inputTensors);
Sadik Armagana045ac02022-07-01 14:32:05 +0100385 std::vector<armnn::ImportedInputId> importedInputIds;
386 std::vector<armnn::ImportedOutputId> importedOutputIds;
Sadik Armagan8f397a12022-06-17 15:38:22 +0100387 try
388 {
389 if (ctx.measureTimings == MeasureTiming::YES)
390 {
391 ctx.deviceStart = Clock::now();
392 }
393 armnn::Status status;
394 VLOG(DRIVER) << "ArmnnPreparedModel::ExecuteGraph m_AsyncModelExecutionEnabled false";
Sadik Armagana045ac02022-07-01 14:32:05 +0100395 importedInputIds = m_Runtime->ImportInputs(m_NetworkId, inputTensors, armnn::MemorySource::Malloc);
396 importedOutputIds = m_Runtime->ImportOutputs(m_NetworkId, outputTensors, armnn::MemorySource::Malloc);
397 status = m_Runtime->EnqueueWorkload(m_NetworkId,
398 inputTensors,
399 outputTensors,
400 importedInputIds,
401 importedOutputIds);
Sadik Armagan8f397a12022-06-17 15:38:22 +0100402
403 if (ctx.measureTimings == MeasureTiming::YES)
404 {
405 ctx.deviceEnd = Clock::now();
406 }
407 if (status != armnn::Status::Success)
408 {
409 VLOG(DRIVER) << "ArmnnPreparedModel:ExecuteGraph EnqueueWorkload failed";
410 return ErrorStatus::GENERAL_FAILURE;
411 }
412 }
413 catch (armnn::Exception& e)
414 {
415 VLOG(DRIVER) << "armnn:Exception caught from EnqueueWorkload: " << e.what();
416 return ErrorStatus::GENERAL_FAILURE;
417 }
418 catch (std::exception& e)
419 {
420 VLOG(DRIVER) << "std::exception caught from EnqueueWorkload: " << e.what();
421 return ErrorStatus::GENERAL_FAILURE;
422 }
423
Sadik Armagana045ac02022-07-01 14:32:05 +0100424 if (!pointerMemory && (!importedInputIds.empty() || !importedOutputIds.empty()))
Sadik Armagan30246502022-06-22 15:20:14 +0100425 {
426 CommitPools(*pMemPools);
427 }
Sadik Armagan8f397a12022-06-17 15:38:22 +0100428 DumpTensorsIfRequired("Output", outputTensors);
429
430 if (ctx.measureTimings == MeasureTiming::YES)
431 {
432 ctx.driverEnd = Clock::now();
433 Timing timing;
434 timing.timeOnDevice = ctx.deviceEnd - ctx.deviceStart;
435 timing.timeInDriver = ctx.driverEnd - ctx.driverStart;
436 VLOG(DRIVER) << "ArmnnPreparedModel::execute timing - Device = "
437 << timing.timeOnDevice << "Driver = " << timing.timeInDriver;
438 }
439 return ErrorStatus::NONE;
440}
441
442Priority ArmnnPreparedModel::GetModelPriority() const
443{
444 return m_ModelPriority;
445}
446
447
448GeneralResult<std::pair<SyncFence, ExecuteFencedInfoCallback>> ArmnnPreparedModel::executeFenced(
449 const Request& request,
450 const std::vector<SyncFence>& waitFor,
451 MeasureTiming measureTiming,
452 const OptionalTimePoint& deadline,
453 const OptionalDuration&,
454 const OptionalDuration&,
455 const std::vector<android::nn::TokenValuePair>& hints,
456 const std::vector<android::nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const
457{
458 VLOG(DRIVER) << "ArmnnPreparedModel::executeFenced()";
459
460 if (!m_PrepareFromCache) {
461 const auto modelRequest = validateRequestForModel(request, m_Model);
462 if (!modelRequest.ok())
463 {
464 return NN_ERROR(ErrorStatus::INVALID_ARGUMENT) << modelRequest.error();
465 }
466 VLOG(DRIVER) << "ArmnnPreparedModel::executeFenced(): " << GetModelSummary(m_Model).c_str();
467 }
468 if (hasDeadlinePassed(deadline))
469 {
470 return NN_ERROR(ErrorStatus::MISSED_DEADLINE_PERSISTENT);
471 }
472
473 CanonicalExecutionContext ctx;
474 if (measureTiming == MeasureTiming::YES)
475 {
476 ctx.measureTimings = measureTiming;
477 ctx.driverStart = Clock::now();
478 }
479
480 // Wait for the dependent events to signal
481 for (const auto& syncFence : waitFor)
482 {
483 if (!syncFence.getSharedHandle())
484 {
485 return NN_ERROR(ErrorStatus::INVALID_ARGUMENT);
486 }
487 if (syncFence.syncWait({}) != SyncFence::FenceState::SIGNALED)
488 {
489 return NN_ERROR(ErrorStatus::GENERAL_FAILURE) << "syncWait failed";
490 }
491 }
492
493 android::nn::TimePoint fenceExecutionStart;
494 if (measureTiming == MeasureTiming::YES)
495 {
496 fenceExecutionStart = Clock::now();
497 }
498
499 // map the memory pool into shared pointers
500 // use a shared memory pools vector on the heap, as it is passed to the request thread
501 auto memPools = std::make_shared<std::vector<android::nn::RunTimePoolInfo>>();
502
503 // allocate the tensors on the heap, as they are passed to the request thread
504 auto inputTensors = std::make_shared<armnn::InputTensors>();
505 auto outputTensors = std::make_shared<armnn::OutputTensors>();
506
Sadik Armagan8f397a12022-06-17 15:38:22 +0100507 auto isPointerTypeMemory = IsPointerTypeMemory(request);
Sadik Armagan30246502022-06-22 15:20:14 +0100508 ErrorStatus theErrorStatus = PrepareMemoryForIO(*inputTensors,
509 *outputTensors,
510 *memPools,
511 request,
512 isPointerTypeMemory);
Sadik Armagan8f397a12022-06-17 15:38:22 +0100513
514 if (theErrorStatus != ErrorStatus::NONE)
515 {
516 return NN_ERROR(ErrorStatus::INVALID_ARGUMENT) << "executeFenced() failed";
517 }
518
519 Timing timingSinceLaunch = {};
520 Timing timingAfterFence = {};
521 if (measureTiming == MeasureTiming::YES)
522 {
523 timingAfterFence.timeOnDevice = ctx.deviceEnd - ctx.deviceStart;
524 timingAfterFence.timeInDriver = ctx.driverEnd - fenceExecutionStart;
525 VLOG(DRIVER) << "executeFenced timingSinceLaunch = " << timingAfterFence.timeOnDevice;
526 VLOG(DRIVER) << "executeFenced timingAfterFence = " << timingAfterFence.timeInDriver;
527 }
528
529 VLOG(DRIVER) << "ArmnnCanonicalPreparedModel::executeFenced(...) before ExecuteGraph";
Sadik Armagan30246502022-06-22 15:20:14 +0100530 auto errorStatus = ExecuteGraph(memPools, *inputTensors, *outputTensors, ctx, isPointerTypeMemory);
Sadik Armagan8f397a12022-06-17 15:38:22 +0100531 VLOG(DRIVER) << "ArmnnCanonicalPreparedModel::executeFenced(...) after ExecuteGraph";
Sadik Armagan8f397a12022-06-17 15:38:22 +0100532
533 ExecuteFencedInfoCallback armnnFencedExecutionCallback =
534 [timingSinceLaunch, timingAfterFence, errorStatus]() {
535
536 GeneralResult<std::pair<Timing, Timing>> result;
537
538 switch(errorStatus)
539 {
540 case ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
541 result.error().code = (ErrorStatus::OUTPUT_INSUFFICIENT_SIZE);
542 case ErrorStatus::GENERAL_FAILURE:
543 result.error().code = (ErrorStatus::GENERAL_FAILURE);
544 case ErrorStatus::INVALID_ARGUMENT:
545 result.error().code = (ErrorStatus::INVALID_ARGUMENT);
546 default:
547 {
548 result.value() = std::make_pair(timingSinceLaunch, timingAfterFence);
549 }
550 }
551 return result;
552 };
553 return std::make_pair(SyncFence::createAsSignaled(), std::move(armnnFencedExecutionCallback ));
554}
555
556GeneralResult<SharedExecution> ArmnnPreparedModel::createReusableExecution(
557 const Request& request,
558 MeasureTiming measureTiming,
559 const OptionalDuration& loopTimeoutDuration,
560 const std::vector<android::nn::TokenValuePair>& hints,
561 const std::vector<android::nn::ExtensionNameAndPrefix>& extensionNameToPrefix) const
562{
563 VLOG(DRIVER) << "ArmnnPreparedModel::createReusableExecution()";
564 return std::make_shared<DefaultExecution>(shared_from_this(),
565 request,
566 measureTiming,
567 loopTimeoutDuration);
568}
569
570GeneralResult<SharedBurst> ArmnnPreparedModel::configureExecutionBurst() const
571{
572 // TODO: Implement BURST
573 return nullptr;
574}
575
576std::any ArmnnPreparedModel::getUnderlyingResource() const
577{
578 return &m_Model;
579}
580
581template<typename TensorBindingCollection>
582void ArmnnPreparedModel::DumpTensorsIfRequired(char const* tensorNamePrefix,
583 const TensorBindingCollection& tensorBindings) const
584{
585 if (!m_RequestInputsAndOutputsDumpDir.empty())
586 {
587 const std::string requestName = std::to_string(m_NetworkId) + ".dump";
588 for (std::size_t i = 0u; i < tensorBindings.size(); ++i)
589 {
590 DumpTensor(m_RequestInputsAndOutputsDumpDir,
591 requestName,
592 BuildTensorName(tensorNamePrefix, i),
593 tensorBindings[i].second);
594 }
595 }
596}
597
598ArmnnPreparedModel::~ArmnnPreparedModel()
599{
600 VLOG(DRIVER) << "ArmnnPreparedModel::~ArmnnPreparedModel()";
601 // Get a hold of the profiler used by this model.
602 if (m_GpuProfilingEnabled)
603 {
604 auto profiler = m_Runtime->GetProfiler(m_NetworkId);
605 if (profiler)
606 {
607 // Dump the profiling info to a file if required.
608 DumpJsonProfilingIfRequired(m_GpuProfilingEnabled,
609 m_RequestInputsAndOutputsDumpDir,
610 m_NetworkId,
611 profiler.get());
612 }
613 }
614 // Unload the network associated with this model
615 m_Runtime->UnloadNetwork(m_NetworkId);
616}
617
618bool ArmnnPreparedModel::ExecuteWithDummyInputs(unsigned int numInputs, unsigned int numOutputs) const
619{
620 std::vector<std::vector<char>> storage;
621 armnn::InputTensors inputTensors;
622 for (unsigned int i = 0; i < numInputs; i++)
623 {
624 armnn::TensorInfo inputTensorInfo = m_Runtime->GetInputTensorInfo(m_NetworkId, i);
625 // pInputTensors (of type InputTensors) is composed of a vector of ConstTensors.
626 // Therefore, set all TensorInfo isConstant parameters of input Tensors to true.
627 inputTensorInfo.SetConstant();
628 storage.emplace_back(inputTensorInfo.GetNumBytes());
629 const armnn::ConstTensor inputTensor(inputTensorInfo, storage.back().data());
630
631 inputTensors.emplace_back(i, inputTensor);
632 }
633
634 armnn::OutputTensors outputTensors;
635 for (unsigned int i = 0; i < numOutputs; i++)
636 {
637 const armnn::TensorInfo outputTensorInfo = m_Runtime->GetOutputTensorInfo(m_NetworkId, i);
638 storage.emplace_back(outputTensorInfo.GetNumBytes());
639 const armnn::Tensor outputTensor(outputTensorInfo, storage.back().data());
640
641 outputTensors.emplace_back(i, outputTensor);
642 }
643 CanonicalExecutionContext ctx;
644 ctx.measureTimings = MeasureTiming::NO;
645 auto memPools = std::make_shared<std::vector<::android::nn::RunTimePoolInfo>>();
646
647 auto errorStatus = ExecuteGraph(memPools,
648 inputTensors,
649 outputTensors,
650 ctx);
651
652 return errorStatus == ErrorStatus::NONE;
653}
654
655} // namespace armnn_driver