xref: /aosp_15_r20/external/armnn/src/backends/reference/RefBackend.cpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1 //
2 // Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "RefBackend.hpp"
7 #include "RefBackendId.hpp"
8 #include "RefWorkloadFactory.hpp"
9 #include "RefLayerSupport.hpp"
10 #include "RefTensorHandleFactory.hpp"
11 
12 #include <armnn/BackendRegistry.hpp>
13 #include <armnn/backends/IBackendContext.hpp>
14 #include <armnn/backends/IMemoryManager.hpp>
15 #include <armnn/utility/PolymorphicDowncast.hpp>
16 #include <backendsCommon/DefaultAllocator.hpp>
17 #include <backendsCommon/SubgraphUtils.hpp>
18 
19 #include <Optimizer.hpp>
20 
21 namespace armnn
22 {
23 
GetIdStatic()24 const BackendId& RefBackend::GetIdStatic()
25 {
26     static const BackendId s_Id{RefBackendId()};
27     return s_Id;
28 }
29 
CreateWorkloadFactory(const IBackendInternal::IMemoryManagerSharedPtr & memoryManager) const30 IBackendInternal::IWorkloadFactoryPtr RefBackend::CreateWorkloadFactory(
31     const IBackendInternal::IMemoryManagerSharedPtr& memoryManager) const
32 {
33     return std::make_unique<RefWorkloadFactory>(PolymorphicPointerDowncast<RefMemoryManager>(memoryManager));
34 }
35 
CreateWorkloadFactory(class TensorHandleFactoryRegistry & tensorHandleFactoryRegistry) const36 IBackendInternal::IWorkloadFactoryPtr RefBackend::CreateWorkloadFactory(
37     class TensorHandleFactoryRegistry& tensorHandleFactoryRegistry) const
38 {
39     auto memoryManager = std::make_shared<RefMemoryManager>();
40 
41     tensorHandleFactoryRegistry.RegisterMemoryManager(memoryManager);
42 
43     std::unique_ptr<RefTensorHandleFactory> factory = std::make_unique<RefTensorHandleFactory>(memoryManager);
44     // Register copy and import factory pair
45     tensorHandleFactoryRegistry.RegisterCopyAndImportFactoryPair(factory->GetId(), factory->GetId());
46     // Register the factory
47     tensorHandleFactoryRegistry.RegisterFactory(std::move(factory));
48 
49     return std::make_unique<RefWorkloadFactory>(PolymorphicPointerDowncast<RefMemoryManager>(memoryManager));
50 }
51 
CreateBackendContext(const IRuntime::CreationOptions &) const52 IBackendInternal::IBackendContextPtr RefBackend::CreateBackendContext(const IRuntime::CreationOptions&) const
53 {
54     return IBackendContextPtr{};
55 }
56 
CreateBackendProfilingContext(const IRuntime::CreationOptions &,IBackendProfilingPtr &)57 IBackendInternal::IBackendProfilingContextPtr RefBackend::CreateBackendProfilingContext(
58     const IRuntime::CreationOptions&, IBackendProfilingPtr&)
59 {
60     return IBackendProfilingContextPtr{};
61 }
62 
CreateMemoryManager() const63 IBackendInternal::IMemoryManagerUniquePtr RefBackend::CreateMemoryManager() const
64 {
65     return std::make_unique<RefMemoryManager>();
66 }
67 
GetLayerSupport() const68 IBackendInternal::ILayerSupportSharedPtr RefBackend::GetLayerSupport() const
69 {
70     static ILayerSupportSharedPtr layerSupport{new RefLayerSupport};
71     return layerSupport;
72 }
73 
OptimizeSubgraphView(const SubgraphView & subgraph,const ModelOptions & modelOptions) const74 OptimizationViews RefBackend::OptimizeSubgraphView(const SubgraphView& subgraph,
75                                                    const ModelOptions& modelOptions) const
76 {
77     OptimizationViews optimizationViews(modelOptions);
78 
79     auto it = subgraph.endIConnectable();
80     std::map<LayerGuid, Layer*> untouched;
81 
82     while (it != subgraph.beginIConnectable())
83     {
84         --it;
85         Layer& base = *(PolymorphicDowncast<Layer*>(*it));
86         untouched.insert({base.GetGuid(), &base});
87     }
88 
89     it = subgraph.endIConnectable();
90     while (it != subgraph.beginIConnectable())
91     {
92         --it;
93         Layer& base = *(PolymorphicDowncast<Layer*>(*it));
94 
95         // Special case to fuse padding into average pooling 2d for quantized datatype.
96         // Required to be done as a backend specific optimization as Neon does not support this special case.
97         if (base.GetType() == LayerType::Pooling2d)
98         {
99             Pooling2dLayer* baseLayer = PolymorphicDowncast<Pooling2dLayer*>(&base);
100             Pooling2dDescriptor poolingDescriptor = baseLayer->GetParameters();
101 
102             if (baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetOwningLayer().GetType() == LayerType::Pad)
103             {
104                 PadLayer* padLayer = PolymorphicDowncast<PadLayer*>(
105                     &baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetOwningLayer());
106                 if (padLayer->GetOutputSlot(0).GetNumConnections() == 1 &&
107                     optimizations::pad_fold::TryFoldPadIntoLayer2d(padLayer->GetParameters(),
108                                                                    poolingDescriptor,
109                                                                    padLayer->GetOutputSlot().GetTensorInfo(),
110                                                                    true))
111                 {
112                     FoldPadIntoAveragePool2d<Pooling2dLayer>(optimizationViews, baseLayer,
113                                                              poolingDescriptor, padLayer);
114                     untouched.erase(baseLayer->GetGuid());
115                     untouched.erase(padLayer->GetGuid());
116                 }
117             }
118         }
119     }
120 
121     if (optimizationViews.GetSubstitutions().empty())
122     {
123         optimizationViews.AddUntouchedSubgraph(SubgraphView(subgraph));
124     }
125     else
126     {
127         ReportUntouchedLayers(optimizationViews, untouched);
128     }
129 
130     return optimizationViews;
131 }
132 
GetHandleFactoryPreferences() const133 std::vector<ITensorHandleFactory::FactoryId> RefBackend::GetHandleFactoryPreferences() const
134 {
135     return std::vector<ITensorHandleFactory::FactoryId> { RefTensorHandleFactory::GetIdStatic() };
136 }
137 
RegisterTensorHandleFactories(class TensorHandleFactoryRegistry & registry)138 void RefBackend::RegisterTensorHandleFactories(class TensorHandleFactoryRegistry& registry)
139 {
140     auto memoryManager = std::make_shared<RefMemoryManager>();
141 
142     registry.RegisterMemoryManager(memoryManager);
143 
144     std::unique_ptr<RefTensorHandleFactory> factory = std::make_unique<RefTensorHandleFactory>(memoryManager);
145 
146     // Register copy and import factory pair
147     registry.RegisterCopyAndImportFactoryPair(factory->GetId(), factory->GetId());
148     // Register the factory
149     registry.RegisterFactory(std::move(factory));
150 }
151 
GetDefaultAllocator() const152 std::unique_ptr<ICustomAllocator> RefBackend::GetDefaultAllocator() const
153 {
154     return std::make_unique<DefaultAllocator>();
155 }
156 
CreateExecutionData(WorkingMemDescriptor & workingMemDescriptor) const157 ExecutionData RefBackend::CreateExecutionData(WorkingMemDescriptor& workingMemDescriptor) const
158 {
159     ExecutionData executionData;
160     executionData.m_Data = &workingMemDescriptor;
161     return executionData;
162 }
163 
UpdateExecutionData(ExecutionData & executionData,WorkingMemDescriptor & workingMemDescriptor) const164 void RefBackend::UpdateExecutionData(ExecutionData& executionData, WorkingMemDescriptor& workingMemDescriptor) const
165 {
166     executionData.m_Data = &workingMemDescriptor;
167 }
168 
169 } // namespace armnn
170