xref: /aosp_15_r20/external/armnn/delegate/opaque/src/armnn_delegate.cpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1 //
2 // Copyright © 2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include <armnn_delegate.hpp>
7 #include <OpaqueDelegateUtils.hpp>
8 
9 #include <Version.hpp>
10 
11 #include "Activation.hpp"
12 #include "ArgMinMax.hpp"
13 #include "BatchMatMul.hpp"
14 #include "BatchSpace.hpp"
15 #include "Comparison.hpp"
16 #include "Convolution.hpp"
17 #include "Control.hpp"
18 #include "ElementwiseBinary.hpp"
19 #include "ElementwiseUnary.hpp"
20 #include "Fill.hpp"
21 #include "FullyConnected.hpp"
22 #include "Gather.hpp"
23 #include "GatherNd.hpp"
24 #include "LogicalBinary.hpp"
25 #include "Lstm.hpp"
26 #include "Normalization.hpp"
27 #include "Pack.hpp"
28 #include "Pad.hpp"
29 #include "Pooling.hpp"
30 #include "Prelu.hpp"
31 #include "Quantization.hpp"
32 #include "Redefine.hpp"
33 #include "Reduce.hpp"
34 #include "Resize.hpp"
35 #include "Round.hpp"
36 #include "Shape.hpp"
37 #include "Slice.hpp"
38 #include "StridedSlice.hpp"
39 #include "Softmax.hpp"
40 #include "SpaceDepth.hpp"
41 #include "Split.hpp"
42 #include "Transpose.hpp"
43 #include "UnidirectionalSequenceLstm.hpp"
44 #include "Unpack.hpp"
45 
46 #include <armnn/utility/IgnoreUnused.hpp>
47 #include <armnnUtils/Filesystem.hpp>
48 #include <armnn/utility/Timer.hpp>
49 #include <flatbuffers/flatbuffers.h>
50 #include <tensorflow/lite/context_util.h>
51 #include <tensorflow/lite/schema/schema_generated.h>
52 #include <tensorflow/lite/minimal_logging.h>
53 #include <tensorflow/lite/logger.h>
54 
55 #include <algorithm>
56 #include <iostream>
57 #include <sstream>
58 
59 namespace armnnOpaqueDelegate
60 {
61 
62 const TfLiteStableDelegate TFL_TheStableDelegate =
63 {
64     /*delegate_abi_version=*/ TFL_STABLE_DELEGATE_ABI_VERSION,
65     /*delegate_name=*/        "ArmnnDelegatePlugin",
66     /*delegate_version=*/     "1.0.0",
67     /*delegate_plugin=*/      GetArmnnDelegatePluginApi()
68 };
69 
ArmnnOpaqueDelegate(armnnDelegate::DelegateOptions options)70 ArmnnOpaqueDelegate::ArmnnOpaqueDelegate(armnnDelegate::DelegateOptions options)
71     : m_Options(std::move(options))
72 {
73     // Configures logging for ARMNN
74     if (m_Options.IsLoggingEnabled())
75     {
76         armnn::ConfigureLogging(true, true, m_Options.GetLoggingSeverity());
77     }
78     // Create/Get the static ArmNN Runtime. Note that the m_Runtime will be shared by all armnn_delegate
79     // instances so the RuntimeOptions cannot be altered for different armnn_delegate instances.
80     m_Runtime = GetRuntime(m_Options.GetRuntimeOptions());
81     std::vector<armnn::BackendId> backends;
82     if (m_Runtime)
83     {
84         const armnn::BackendIdSet supportedDevices = m_Runtime->GetDeviceSpec().GetSupportedBackends();
85         for (auto& backend : m_Options.GetBackends())
86         {
87             if (std::find(supportedDevices.cbegin(), supportedDevices.cend(), backend) == supportedDevices.cend())
88             {
89                 TFLITE_LOG_PROD(tflite::TFLITE_LOG_INFO,
90                                 "TfLiteArmnnDelegate: Requested unknown backend %s", backend.Get().c_str());
91             }
92             else
93             {
94                 backends.push_back(backend);
95             }
96         }
97     }
98 
99     if (backends.empty())
100     {
101         // No known backend specified
102         throw armnn::InvalidArgumentException("TfLiteArmnnOpaqueDelegate: No known backend specified.");
103     }
104     m_Options.SetBackends(backends);
105 
106     TFLITE_LOG_PROD_ONCE(tflite::TFLITE_LOG_INFO, "TfLiteArmnnOpaqueDelegate: Created TfLite ArmNN delegate.");
107 }
108 
DoPrepare(TfLiteOpaqueContext * tfLiteContext,TfLiteOpaqueDelegate * tfLiteDelegate,void * data)109 TfLiteStatus DoPrepare(TfLiteOpaqueContext* tfLiteContext, TfLiteOpaqueDelegate* tfLiteDelegate, void* data)
110 {
111     // We are required to have the void* data parameter in the function signature, but we don't actually use it.
112     armnn::IgnoreUnused(data);
113 
114     TfLiteIntArray* supportedOperators =
115             static_cast<::armnnOpaqueDelegate::ArmnnOpaqueDelegate*>
116                     (TfLiteOpaqueDelegateGetData(tfLiteDelegate))->IdentifyOperatorsToDelegate(tfLiteContext);
117     if(supportedOperators == nullptr)
118     {
119         return kTfLiteError;
120     }
121 
122     // ArmNN Opaque Delegate Registration
123     TfLiteRegistrationExternal* kernelRegistration =
124             TfLiteRegistrationExternalCreate(kTfLiteBuiltinDelegate, "TfLiteArmNNOpaqueDelegate", /*version=*/1);
125     if(kernelRegistration == nullptr)
126     {
127         return kTfLiteError;
128     }
129 
130     TfLiteRegistrationExternalSetInit(
131             kernelRegistration,
132             [](TfLiteOpaqueContext* tfLiteContext, const char* buffer, size_t length) -> void*
133             {
134                 armnn::IgnoreUnused(length);
135                 const TfLiteOpaqueDelegateParams* parameters =
136                         reinterpret_cast<const TfLiteOpaqueDelegateParams*>(buffer);
137                 if(parameters == nullptr)
138                 {
139                     TF_LITE_OPAQUE_KERNEL_LOG(tfLiteContext,
140                                               "TfLiteArmnnOpaqueDelegate: Unable to get parameters.");
141                     return nullptr;
142                 }
143 
144                 return static_cast<void*>(
145                         ArmnnSubgraph::Create(tfLiteContext,
146                                               parameters,
147                                               static_cast<::armnnOpaqueDelegate::ArmnnOpaqueDelegate*>(
148                                                       parameters->delegate->opaque_delegate_builder->data)));
149             }
150     );
151 
152     TfLiteRegistrationExternalSetFree(
153             kernelRegistration,
154             [](TfLiteOpaqueContext* tfLiteContext, void* buffer) -> void
155             {
156                 armnn::IgnoreUnused(tfLiteContext);
157                 if (buffer != nullptr)
158                 {
159                     delete static_cast<ArmnnSubgraph*>(buffer);
160                 }
161             }
162     );
163 
164     TfLiteRegistrationExternalSetPrepare(
165             kernelRegistration,
166             [](TfLiteOpaqueContext* tfLiteContext, TfLiteOpaqueNode* tfLiteNode) -> TfLiteStatus
167             {
168                 void* userData = TfLiteOpaqueNodeGetUserData(tfLiteNode);
169                 if (userData == nullptr)
170                 {
171                     return kTfLiteError;
172                 }
173                 return static_cast<ArmnnSubgraph*>(userData)->Prepare(tfLiteContext);
174             }
175     );
176 
177     TfLiteRegistrationExternalSetInvoke(
178             kernelRegistration,
179             [](TfLiteOpaqueContext* tfLiteContext, TfLiteOpaqueNode* tfLiteNode) -> TfLiteStatus
180             {
181                 void* userData = TfLiteOpaqueNodeGetUserData(tfLiteNode);
182                 if (userData == nullptr)
183                 {
184                     return kTfLiteError;
185                 }
186 
187                 return static_cast<ArmnnSubgraph*>(userData)->Invoke(tfLiteContext, tfLiteNode);
188             }
189     );
190 
191     const TfLiteStatus status =
192             TfLiteOpaqueContextReplaceNodeSubsetsWithDelegateKernels(
193                     tfLiteContext, kernelRegistration, supportedOperators, tfLiteDelegate);
194 
195     TfLiteIntArrayFree(supportedOperators);
196     return status;
197 }
198 
TfLiteArmnnOpaqueDelegateCreate(const void * settings)199 TfLiteOpaqueDelegate* TfLiteArmnnOpaqueDelegateCreate(const void* settings)
200 {
201     // This method will always create Opaque Delegate with default settings until
202     // we have a DelegateOptions Constructor which can parse the void* settings
203     armnn::IgnoreUnused(settings);
204     auto options = TfLiteArmnnDelegateOptionsDefault();
205     auto* armnnDelegate = new ::armnnOpaqueDelegate::ArmnnOpaqueDelegate(options);
206     return TfLiteOpaqueDelegateCreate(armnnDelegate->GetDelegateBuilder());
207 }
208 
TfLiteArmnnDelegateOptionsDefault()209 ::armnnDelegate::DelegateOptions TfLiteArmnnDelegateOptionsDefault()
210 {
211     ::armnnDelegate::DelegateOptions options(armnn::Compute::CpuRef);
212     return options;
213 }
214 
TfLiteArmnnOpaqueDelegateDelete(TfLiteOpaqueDelegate * tfLiteDelegate)215 void TfLiteArmnnOpaqueDelegateDelete(TfLiteOpaqueDelegate* tfLiteDelegate)
216 {
217     if (tfLiteDelegate != nullptr)
218     {
219         delete static_cast<::armnnOpaqueDelegate::ArmnnOpaqueDelegate*>(TfLiteOpaqueDelegateGetData(tfLiteDelegate));
220         TfLiteOpaqueDelegateDelete(tfLiteDelegate);
221     }
222 }
223 
GetArmnnDelegatePluginApi()224 const TfLiteOpaqueDelegatePlugin* GetArmnnDelegatePluginApi()
225 {
226     static constexpr TfLiteOpaqueDelegatePlugin armnnPlugin{
227             TfLiteArmnnOpaqueDelegateCreate, TfLiteArmnnOpaqueDelegateDelete, TfLiteArmnnOpaqueDelegateErrno};
228     return &armnnPlugin;
229 }
230 
GetVersion()231 const std::string ArmnnOpaqueDelegate::GetVersion() {
232     return OPAQUE_DELEGATE_VERSION;
233 }
234 
IdentifyOperatorsToDelegate(TfLiteOpaqueContext * tfLiteContext)235 TfLiteIntArray* ArmnnOpaqueDelegate::IdentifyOperatorsToDelegate(TfLiteOpaqueContext* tfLiteContext)
236 {
237     TfLiteIntArray* executionPlan = nullptr;
238     if (TfLiteOpaqueContextGetExecutionPlan(tfLiteContext, &executionPlan) != kTfLiteOk)
239     {
240         TF_LITE_OPAQUE_KERNEL_LOG(tfLiteContext, "TfLiteArmnnOpaqueDelegate: Unable to get graph execution plan.");
241         return nullptr;
242     }
243 
244     // Delegate data with null network
245     DelegateData delegateData(m_Options.GetBackends());
246 
247     TfLiteIntArray* nodesToDelegate = TfLiteIntArrayCreate(executionPlan->size);
248     if (nodesToDelegate == nullptr)
249     {
250         TF_LITE_OPAQUE_KERNEL_LOG(tfLiteContext,
251                                   "TfLiteArmnnOpaqueDelegate: Unable to create int array from execution plan.");
252         return nullptr;
253     }
254     nodesToDelegate->size = 0;
255 
256     std::set<int32_t> unsupportedOperators;
257 
258     for (int i = 0; i < executionPlan->size; ++i)
259     {
260         const int nodeIndex = executionPlan->data[i];
261 
262         // If TfLiteOpaqueNodes can be delegated to ArmNN
263         TfLiteOpaqueNode* tfLiteNode = nullptr;
264         TfLiteRegistrationExternal* tfLiteRegistration = nullptr;
265 
266         if (TfLiteOpaqueContextGetNodeAndRegistration(
267                 tfLiteContext, nodeIndex, &tfLiteNode, &tfLiteRegistration) != kTfLiteOk)
268         {
269             TF_LITE_OPAQUE_KERNEL_LOG(tfLiteContext,
270                                       "TfLiteArmnnOpaqueDelegate: Unable to get node and registration for node %d.",
271                                       nodeIndex);
272             continue;
273         }
274 
275         TfLiteStatus visitStatus;
276         try
277         {
278             visitStatus = ArmnnSubgraph::VisitNode(
279                     delegateData, tfLiteContext, tfLiteRegistration, tfLiteNode, nodeIndex);
280         }
281         catch(std::exception& ex)
282         {
283             ARMNN_LOG(error) << "ArmNN Failed to visit node with error: " << ex.what();
284             visitStatus = kTfLiteError;
285         }
286 
287         if (visitStatus != kTfLiteOk)
288         {
289             // node is not supported by ArmNN
290             unsupportedOperators.insert(TfLiteRegistrationExternalGetBuiltInCode(tfLiteRegistration));
291             continue;
292         }
293 
294         nodesToDelegate->data[nodesToDelegate->size++] = nodeIndex;
295     }
296 
297     for (std::set<int32_t>::iterator it=unsupportedOperators.begin(); it!=unsupportedOperators.end(); ++it)
298     {
299         TF_LITE_OPAQUE_KERNEL_LOG(tfLiteContext,
300                                   "Operator %s [%d] is not supported by armnn_opaque_delegate.",
301                                   tflite::EnumNameBuiltinOperator(tflite::BuiltinOperator(*it)),
302                                   *it);
303     }
304 
305     if (!unsupportedOperators.empty() && m_Options.TfLiteRuntimeFallbackDisabled())
306     {
307         std::stringstream exMessage;
308         exMessage << "TfLiteArmnnOpaqueDelegate: There are unsupported operators in the model. ";
309         exMessage << "Not falling back to TfLite Runtime as fallback is disabled. ";
310         exMessage << "This should only be disabled under test conditions.";
311         throw armnn::Exception(exMessage.str());
312     }
313     if (nodesToDelegate->size == 0)
314     {
315         ARMNN_LOG(info) << "No operators in this model are supported by the Arm NN TfLite delegate." <<
316                         " The model will be executed entirely by TfLite runtime.";
317     }
318 
319     std::sort(&nodesToDelegate->data[0], &nodesToDelegate->data[nodesToDelegate->size]);
320     return nodesToDelegate;
321 }
322 
AddInputLayer(DelegateData & delegateData,TfLiteOpaqueContext * tfLiteContext,const TfLiteIntArray * inputs,std::vector<armnn::BindingPointInfo> & inputBindings)323 TfLiteStatus ArmnnSubgraph::AddInputLayer(DelegateData& delegateData,
324                                           TfLiteOpaqueContext* tfLiteContext,
325                                           const TfLiteIntArray* inputs,
326                                           std::vector<armnn::BindingPointInfo>& inputBindings)
327 {
328     const size_t numInputs = static_cast<size_t>(inputs->size);
329     for (unsigned int i = 0; i < numInputs; ++i)
330     {
331         const int32_t tensorId = inputs->data[i];
332         const TfLiteOpaqueTensor* tensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, tensorId);
333 
334         if(!tensor)
335         {
336             return kTfLiteError;
337         }
338 
339         // Do not create bindings for constant inputs
340         if (TfLiteOpaqueTensorGetAllocationType(tensor) == kTfLiteMmapRo)
341         {
342             continue;
343         }
344 
345         auto bindingId = static_cast<armnn::LayerBindingId>((tensorId));
346         armnn::IConnectableLayer* layer = delegateData.m_Network->AddInputLayer(bindingId);
347 
348         auto tensorInfo = GetTensorInfoForTfLiteOpaqueTensor(tensor);
349         armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(0);
350         outputSlot.SetTensorInfo(tensorInfo);
351 
352         // Store for creating connections
353         delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tensorId)] = &outputSlot;
354 
355         inputBindings.push_back(std::make_pair(bindingId, tensorInfo));
356     }
357 
358     return kTfLiteOk;
359 }
360 
AddOutputLayer(DelegateData & delegateData,TfLiteOpaqueContext * tfLiteContext,const TfLiteIntArray * outputs,std::vector<armnn::BindingPointInfo> & outputBindings)361 TfLiteStatus ArmnnSubgraph::AddOutputLayer(DelegateData& delegateData,
362                                            TfLiteOpaqueContext* tfLiteContext,
363                                            const TfLiteIntArray* outputs,
364                                            std::vector<armnn::BindingPointInfo>& outputBindings)
365 {
366     const size_t numOutputs = static_cast<size_t>(outputs->size);
367     for (unsigned int i = 0; i < numOutputs; ++i)
368     {
369         const int32_t tensorId = outputs->data[i];
370         const TfLiteOpaqueTensor* tensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, tensorId);
371 
372         if(!IsValid(tensor))
373         {
374             return kTfLiteError;
375         }
376 
377         auto bindingId = static_cast<armnn::LayerBindingId>((tensorId));
378         armnn::IConnectableLayer* layer = delegateData.m_Network->AddOutputLayer(bindingId);
379 
380         auto tensorInfo = GetTensorInfoForTfLiteOpaqueTensor(tensor);
381         ARMNN_ASSERT(delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tensorId)] != nullptr);
382         delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tensorId)]->Connect(layer->GetInputSlot(0));
383         outputBindings.push_back(std::make_pair(bindingId, tensorInfo));
384     }
385 
386     return kTfLiteOk;
387 }
388 
Create(TfLiteOpaqueContext * tfLiteContext,const TfLiteOpaqueDelegateParams * parameters,const ArmnnOpaqueDelegate * delegate)389 ArmnnSubgraph* ArmnnSubgraph::Create(TfLiteOpaqueContext* tfLiteContext,
390                                      const TfLiteOpaqueDelegateParams* parameters,
391                                      const ArmnnOpaqueDelegate* delegate)
392 {
393     const auto startTime = armnn::GetTimeNow();
394     ARMNN_LOG(info) << "ArmnnSubgraph creation";
395 
396     TfLiteIntArray* executionPlan;
397     if (TfLiteOpaqueContextGetExecutionPlan(tfLiteContext, &executionPlan) != kTfLiteOk)
398     {
399         return nullptr;
400     }
401 
402     // Initialize DelegateData holds network and output slots information
403     DelegateData delegateData(delegate->m_Options.GetBackends());
404 
405     // Build ArmNN Network
406     armnn::NetworkOptions networkOptions = delegate->m_Options.GetOptimizerOptions().GetModelOptions();
407     armnn::NetworkId networkId;
408     delegateData.m_Network = armnn::INetwork::Create(networkOptions);
409 
410     delegateData.m_OutputSlotForNode = std::vector<armnn::IOutputSlot*>(
411                                                             TfLiteOpaqueContextGetNumTensors(tfLiteContext), nullptr);
412 
413     std::vector<armnn::BindingPointInfo> inputBindings;
414     std::vector<armnn::BindingPointInfo> outputBindings;
415 
416     // Add input layer
417     if (AddInputLayer(delegateData, tfLiteContext, parameters->input_tensors, inputBindings) != kTfLiteOk)
418     {
419         throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Unable to add Inputs to the network!");
420     }
421 
422     // Parse TfLite delegate nodes to ArmNN
423     const auto parseStartTime = armnn::GetTimeNow();
424     for (int i = 0; i < parameters->nodes_to_replace->size; ++i)
425     {
426         const int nodeIndex = parameters->nodes_to_replace->data[i];
427 
428         TfLiteOpaqueNode* tfLiteNode = nullptr;
429         TfLiteRegistrationExternal* tfLiteRegistration = nullptr;
430         if (TfLiteOpaqueContextGetNodeAndRegistration(
431             tfLiteContext, nodeIndex, &tfLiteNode, &tfLiteRegistration) != kTfLiteOk)
432         {
433             throw armnn::Exception(&"TfLiteArmnnOpaqueDelegate: Unable to get node registration: " [ nodeIndex]);
434         }
435 
436         if (VisitNode(delegateData, tfLiteContext, tfLiteRegistration, tfLiteNode, nodeIndex) != kTfLiteOk)
437         {
438             throw armnn::Exception(&"TfLiteArmnnOpaqueDelegate: Unable to parse node: " [ nodeIndex]);
439         }
440     }
441     ARMNN_LOG(info) << "Parse nodes to ArmNN time: " << std::setprecision(2)
442                     << std::fixed << armnn::GetTimeDuration(parseStartTime).count() << " ms";
443 
444     // Add Output layer
445     if (AddOutputLayer(delegateData, tfLiteContext, parameters->output_tensors, outputBindings) != kTfLiteOk)
446     {
447         throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Unable to add Outputs to the network!");
448     }
449 
450     // Optimize ArmNN network
451     armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr);
452     try
453     {
454         const auto optimizeStartTime = armnn::GetTimeNow();
455         optNet = armnn::Optimize(*(delegateData.m_Network.get()),
456                                  delegate->m_Options.GetBackends(),
457                                  delegate->m_Runtime->GetDeviceSpec(),
458                                  delegate->m_Options.GetOptimizerOptions());
459         ARMNN_LOG(info) << "Optimize ArmnnSubgraph time: " << std::setprecision(2)
460                         << std::fixed << armnn::GetTimeDuration(optimizeStartTime).count() << " ms";
461     }
462     catch (std::exception& ex)
463     {
464         std::stringstream exMessage;
465         exMessage << "TfLiteArmnnOpaqueDelegate: Exception (" << ex.what() << ") caught from optimize.";
466         throw armnn::Exception(exMessage.str());
467     }
468     if (!optNet)
469     {
470         // Optimize failed
471         throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Unable to optimize the network!");
472     }
473 
474     // If set, we will serialize the optimized model into a dot file.
475     const std::string serializeToDotFile = delegate->m_Options.GetSerializeToDot();
476     if (!serializeToDotFile.empty())
477     {
478         ARMNN_LOG(info) << "Writing graph to dot file: " << serializeToDotFile;
479         fs::path filename = serializeToDotFile;
480         std::fstream file(filename.c_str(), std::ios_base::out);
481         optNet->SerializeToDot(file);
482     }
483 
484     try
485     {
486         const auto loadStartTime = armnn::GetTimeNow();
487 
488         // Load graph into runtime
489         std::string errorMessage;
490         armnn::Status loadingStatus;
491         armnn::MemorySource inputSource = armnn::MemorySource::Undefined;
492         armnn::MemorySource outputSource = armnn::MemorySource::Undefined;
493         // There's a bit of an assumption here that the delegate will only support Malloc memory source.
494         if (delegate->m_Options.GetOptimizerOptions().GetImportEnabled())
495         {
496             inputSource = armnn::MemorySource::Malloc;
497         }
498         if (delegate->m_Options.GetOptimizerOptions().GetExportEnabled())
499         {
500             outputSource = armnn::MemorySource::Malloc;
501         }
502         armnn::INetworkProperties networkProperties(false,
503                                                     inputSource,
504                                                     outputSource,
505                                                     delegate->m_Options.GetInternalProfilingState(),
506                                                     delegate->m_Options.GetInternalProfilingDetail());
507         loadingStatus = delegate->m_Runtime->LoadNetwork(networkId,
508                                                          std::move(optNet),
509                                                          errorMessage,
510                                                          networkProperties);
511         if (loadingStatus != armnn::Status::Success)
512         {
513             // Network load failed.
514             throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Network could not be loaded: " + errorMessage);
515         }
516 
517         ARMNN_LOG(info) << "Load ArmnnSubgraph time: " << std::setprecision(2)
518                         << std::fixed << armnn::GetTimeDuration(loadStartTime).count() << " ms";
519     }
520     catch (std::exception& ex)
521     {
522         std::stringstream exMessage;
523         exMessage << "TfLiteArmnnOpaqueDelegate: Exception (" << ex.what() << ") caught from LoadNetwork.";
524         throw armnn::Exception(exMessage.str());
525     }
526 
527     // Register debug callback function
528     if (delegate->m_Options.GetDebugCallbackFunction().has_value())
529     {
530         delegate->m_Runtime->RegisterDebugCallback(networkId, delegate->m_Options.GetDebugCallbackFunction().value());
531     }
532 
533     ARMNN_LOG(info) << "Overall ArmnnSubgraph creation time: " << std::setprecision(2)
534                     << std::fixed << armnn::GetTimeDuration(startTime).count() << " ms\n";
535 
536     // Create a new SubGraph with networkId and runtime
537     return new ArmnnSubgraph(networkId, delegate->m_Runtime, inputBindings, outputBindings);
538 }
539 
Prepare(TfLiteOpaqueContext * tfLiteContext)540 TfLiteStatus ArmnnSubgraph::Prepare(TfLiteOpaqueContext* tfLiteContext)
541 {
542     armnn::IgnoreUnused(tfLiteContext);
543     return kTfLiteOk;
544 }
545 
Invoke(TfLiteOpaqueContext * tfLiteContext,TfLiteOpaqueNode * tfLiteNode)546 TfLiteStatus ArmnnSubgraph::Invoke(TfLiteOpaqueContext* tfLiteContext, TfLiteOpaqueNode* tfLiteNode)
547 {
548     // Get array of input indices, inputIndexArray is set from the TfLiteOpaqueNodeInputs function
549     // This function turns inputIndexArray into an int array of indices. These indices point to the tensors for
550     // each input slot in the node.
551     const int* inputIndexArray;
552     int numInputs;
553     if(TfLiteOpaqueNodeInputs(tfLiteNode, &inputIndexArray, &numInputs) != kTfLiteOk)
554     {
555         throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Unable to load subgraph inputs!");
556     }
557     // Prepare inputs
558     armnn::InputTensors inputTensors;
559     size_t inputIndex = 0;
560     for (int inputIdx = 0; inputIdx < numInputs; inputIdx++)
561     {
562         TfLiteOpaqueTensor* tensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, inputIndexArray[inputIdx]);
563 
564         if(!IsValid(tensor))
565         {
566             return kTfLiteError;
567         }
568         // If tensor is not read only
569         if (TfLiteOpaqueTensorGetAllocationType(tensor) != kTfLiteMmapRo)
570         {
571             const armnn::BindingPointInfo& inputBinding = m_InputBindings[inputIndex];
572             armnn::TensorInfo inputTensorInfo = inputBinding.second;
573             inputTensorInfo.SetConstant(true);
574             const armnn::ConstTensor inputTensor(inputTensorInfo, TfLiteOpaqueTensorData(tensor));
575             inputTensors.emplace_back(inputIdx, inputTensor);
576 
577             ++inputIndex;
578         }
579     }
580 
581     // Get array of output indices, outputIndexArray is set from the TfLiteOpaqueNodeOutputs function
582     // This function turns outputIndexArray into an int array of indices. These indices point to the tensors for
583     // each output slot in the node.
584     const int* outputIndexArray;
585     int numOutputs;
586     if(TfLiteOpaqueNodeOutputs(tfLiteNode, &outputIndexArray, &numOutputs) != kTfLiteOk)
587     {
588         throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Unable to load subgraph outputs!");
589     }
590     // Assign the tensors from the outputIndexArray to the armnn BindingPointInfo
591     armnn::OutputTensors outputTensors;
592     for (int outputIdx = 0; outputIdx < numOutputs; outputIdx++)
593     {
594         const armnn::BindingPointInfo& outputBinding = m_OutputBindings[outputIdx];
595         TfLiteOpaqueTensor* tensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, outputIndexArray[outputIdx]);
596         if(!IsValid(tensor))
597         {
598             return kTfLiteError;
599         }
600 
601         const armnn::Tensor outputTensor(outputBinding.second, reinterpret_cast<TfLiteTensor*>(tensor)->data
602         .data);
603         outputTensors.emplace_back(outputIndexArray[outputIdx], outputTensor);
604     }
605 
606     // Run graph
607     auto status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
608     // The delegate holds its own Arm NN runtime so this is our last chance to print internal profiling data.
609     std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
610     if (profiler && profiler->IsProfilingEnabled())
611     {
612         profiler->Print(std::cout);
613     }
614     return (status == armnn::Status::Success) ? kTfLiteOk : kTfLiteError;
615 }
616 
VisitNode(DelegateData & delegateData,TfLiteOpaqueContext * tfLiteContext,TfLiteRegistrationExternal * tfLiteRegistration,TfLiteOpaqueNode * tfLiteNode,int nodeIndex)617 TfLiteStatus ArmnnSubgraph::VisitNode(DelegateData& delegateData,
618                                       TfLiteOpaqueContext* tfLiteContext,
619                                       TfLiteRegistrationExternal* tfLiteRegistration,
620                                       TfLiteOpaqueNode* tfLiteNode,
621                                       int nodeIndex)
622 {
623     switch (TfLiteRegistrationExternalGetBuiltInCode(tfLiteRegistration))
624     {
625         case kTfLiteBuiltinCast:
626             return VisitCastOperator(delegateData,
627                                      tfLiteContext,
628                                      tfLiteNode,
629                                      nodeIndex,
630                                      kTfLiteBuiltinCast);
631         default:
632             return kTfLiteError;
633     }
634 }
635 } // armnnOpaqueDelegate namespace