ArmNN
 24.02
MockBackend.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
8 #include <armnnTestUtils/MockBackend.hpp>
9 #include <armnnTestUtils/MockTensorHandle.hpp>
11 #include <backendsCommon/test/MockBackendId.hpp>
12 #include <SubgraphViewSelector.hpp>
13 
14 #include "Layer.hpp"
15 
16 namespace armnn
17 {
18 
19 const BackendId& MockBackend::GetIdStatic()
20 {
21  static const BackendId s_Id{MockBackendId()};
22  return s_Id;
23 }
24 
25 namespace
26 {
27 static const BackendId s_Id{ MockBackendId() };
28 }
29 
30 MockWorkloadFactory::MockWorkloadFactory(const std::shared_ptr<MockMemoryManager>& memoryManager)
31  : m_MemoryManager(memoryManager)
32 {}
33 
34 MockWorkloadFactory::MockWorkloadFactory()
35  : m_MemoryManager(new MockMemoryManager())
36 {}
37 
38 const BackendId& MockWorkloadFactory::GetBackendId() const
39 {
40  return s_Id;
41 }
42 
43 std::unique_ptr<IWorkload> MockWorkloadFactory::CreateWorkload(LayerType type,
44  const QueueDescriptor& descriptor,
45  const WorkloadInfo& info) const
46 {
47  switch (type)
48  {
49  case LayerType::MemCopy: {
50  auto memCopyQueueDescriptor = PolymorphicDowncast<const MemCopyQueueDescriptor*>(&descriptor);
51  if (descriptor.m_Inputs.empty())
52  {
53  throw InvalidArgumentException("MockWorkloadFactory: CreateMemCopy() expected an input tensor.");
54  }
55  return std::make_unique<CopyMemGenericWorkload>(*memCopyQueueDescriptor, info);
56  }
57  default:
58  return nullptr;
59  }
60 }
61 
62 bool IsLayerSupported(const armnn::Layer* layer)
63 {
64  ARMNN_ASSERT(layer != nullptr);
65 
66  armnn::LayerType layerType = layer->GetType();
67  switch (layerType)
68  {
75  // Layer supported
76  return true;
77  default:
78  // Layer unsupported
79  return false;
80  }
81 }
82 
83 bool IsLayerSupported(const armnn::Layer& layer)
84 {
85  return IsLayerSupported(&layer);
86 }
87 
88 bool IsLayerOptimizable(const armnn::Layer* layer)
89 {
90  ARMNN_ASSERT(layer != nullptr);
91 
92  // A Layer is not optimizable if its name contains "unoptimizable"
93  const std::string layerName(layer->GetName());
94  bool optimizable = layerName.find("unoptimizable") == std::string::npos;
95 
96  return optimizable;
97 }
98 
99 bool IsLayerOptimizable(const armnn::Layer& layer)
100 {
101  return IsLayerOptimizable(&layer);
102 }
103 
104 } // Anonymous namespace
105 
106 namespace armnn
107 {
108 
109 MockBackendInitialiser::MockBackendInitialiser()
110 {
111  BackendRegistryInstance().Register(MockBackend::GetIdStatic(),
112  []()
113  {
114  return IBackendInternalUniquePtr(new MockBackend);
115  });
116 }
117 
118 MockBackendInitialiser::~MockBackendInitialiser()
119 {
120  try
121  {
122  BackendRegistryInstance().Deregister(MockBackend::GetIdStatic());
123  }
124  catch (...)
125  {
126  std::cerr << "could not deregister mock backend" << std::endl;
127  }
128 }
129 
130 IBackendInternal::IWorkloadFactoryPtr MockBackend::CreateWorkloadFactory(
131  const IBackendInternal::IMemoryManagerSharedPtr& /*memoryManager*/) const
132 {
133  return IWorkloadFactoryPtr{};
134 }
135 
136 IBackendInternal::IBackendContextPtr MockBackend::CreateBackendContext(const IRuntime::CreationOptions&) const
137 {
138  return IBackendContextPtr{};
139 }
140 
141 IBackendInternal::IBackendProfilingContextPtr MockBackend::CreateBackendProfilingContext(
142  const IRuntime::CreationOptions& options, IBackendProfilingPtr& backendProfiling)
143 {
144  IgnoreUnused(options);
145  std::shared_ptr<armnn::MockBackendProfilingContext> context =
146  std::make_shared<MockBackendProfilingContext>(backendProfiling);
147  MockBackendProfilingService::Instance().SetProfilingContextPtr(context);
148  return context;
149 }
150 
151 IBackendInternal::IMemoryManagerUniquePtr MockBackend::CreateMemoryManager() const
152 {
153  return IMemoryManagerUniquePtr{};
154 }
155 
156 IBackendInternal::ILayerSupportSharedPtr MockBackend::GetLayerSupport() const
157 {
158  static ILayerSupportSharedPtr layerSupport{new MockLayerSupport};
159  return layerSupport;
160 }
161 
162 OptimizationViews MockBackend::OptimizeSubgraphView(const SubgraphView& subgraph) const
163 {
164  // Prepare the optimization views
165  OptimizationViews optimizationViews;
166 
167  // Get the layers of the input sub-graph
168  const SubgraphView::IConnectableLayers& subgraphLayers = subgraph.GetIConnectableLayers();
169 
170  // Parse the layers
171  SubgraphView::IConnectableLayers supportedLayers;
172  SubgraphView::IConnectableLayers unsupportedLayers;
173  SubgraphView::IConnectableLayers untouchedLayers;
174  std::for_each(subgraphLayers.begin(),
175  subgraphLayers.end(),
176  [&](IConnectableLayer* layer)
177  {
178  bool supported = IsLayerSupported(PolymorphicDowncast<Layer*>(layer));
179  if (supported)
180  {
181  // Layer supported, check if it's optimizable
182  bool optimizable = IsLayerOptimizable(PolymorphicDowncast<Layer*>(layer));
183  if (optimizable)
184  {
185  // Layer fully supported
186  supportedLayers.push_back(layer);
187  }
188  else
189  {
190  // Layer supported but not optimizable
191  untouchedLayers.push_back(layer);
192  }
193  }
194  else
195  {
196  // Layer unsupported
197  unsupportedLayers.push_back(layer);
198  }
199  });
200 
201  // Check if there are supported layers
202  if (!supportedLayers.empty())
203  {
204  // Select the layers that are neither inputs or outputs, but that are optimizable
205  auto supportedSubgraphSelector = [](const Layer& layer)
206  {
207  return layer.GetType() != LayerType::Input &&
208  layer.GetType() != LayerType::Output &&
209  IsLayerSupported(layer) &&
210  IsLayerOptimizable(layer);
211  };
212 
213  // Apply the subgraph selector to the supported layers to group them into sub-graphs were appropriate
214  SubgraphView mutableSubgraph(subgraph);
215  SubgraphViewSelector::Subgraphs supportedSubgraphs =
216  SubgraphViewSelector::SelectSubgraphs(mutableSubgraph, supportedSubgraphSelector);
217 
218  // Create a substitution pair for each supported sub-graph
219  std::for_each(supportedSubgraphs.begin(),
220  supportedSubgraphs.end(),
221  [&optimizationViews](const SubgraphView::SubgraphViewPtr& supportedSubgraph)
222  {
223  ARMNN_ASSERT(supportedSubgraph != nullptr);
224 
225  CompiledBlobPtr blobPtr;
226  BackendId backend = MockBackendId();
227 
228  IConnectableLayer* preCompiledLayer =
229  optimizationViews.GetINetwork()->AddPrecompiledLayer(
230  PreCompiledDescriptor(supportedSubgraph->GetNumInputSlots(),
231  supportedSubgraph->GetNumOutputSlots()),
232  std::move(blobPtr),
233  backend,
234  nullptr);
235 
236  SubgraphView substitutionSubgraph(*supportedSubgraph);
237  SubgraphView replacementSubgraph(preCompiledLayer);
238 
239  optimizationViews.AddSubstitution({ substitutionSubgraph, replacementSubgraph });
240  });
241  }
242 
243  // Check if there are unsupported layers
244  if (!unsupportedLayers.empty())
245  {
246  // Select the layers that are neither inputs or outputs, and are not optimizable
247  auto unsupportedSubgraphSelector = [](const Layer& layer)
248  {
249  return layer.GetType() != LayerType::Input &&
250  layer.GetType() != LayerType::Output &&
251  !IsLayerSupported(layer);
252  };
253 
254  // Apply the subgraph selector to the unsupported layers to group them into sub-graphs were appropriate
255  SubgraphView mutableSubgraph(subgraph);
256  SubgraphViewSelector::Subgraphs unsupportedSubgraphs =
257  SubgraphViewSelector::SelectSubgraphs(mutableSubgraph, unsupportedSubgraphSelector);
258 
259  // Add each unsupported sub-graph to the list of failed sub-graphs in the optimizization views
260  std::for_each(unsupportedSubgraphs.begin(),
261  unsupportedSubgraphs.end(),
262  [&optimizationViews](const SubgraphView::SubgraphViewPtr& unsupportedSubgraph)
263  {
264  ARMNN_ASSERT(unsupportedSubgraph != nullptr);
265 
266  optimizationViews.AddFailedSubgraph(SubgraphView(*unsupportedSubgraph));
267  });
268  }
269 
270  // Check if there are untouched layers
271  if (!untouchedLayers.empty())
272  {
273  // Select the layers that are neither inputs or outputs, that are supported but that and are not optimizable
274  auto untouchedSubgraphSelector = [](const Layer& layer)
275  {
276  return layer.GetType() != LayerType::Input &&
277  layer.GetType() != LayerType::Output &&
278  IsLayerSupported(layer) &&
279  !IsLayerOptimizable(layer);
280  };
281 
282  // Apply the subgraph selector to the untouched layers to group them into sub-graphs were appropriate
283  SubgraphView mutableSubgraph(subgraph);
284  SubgraphViewSelector::Subgraphs untouchedSubgraphs =
285  SubgraphViewSelector::SelectSubgraphs(mutableSubgraph, untouchedSubgraphSelector);
286 
287  // Add each untouched sub-graph to the list of untouched sub-graphs in the optimizization views
288  std::for_each(untouchedSubgraphs.begin(),
289  untouchedSubgraphs.end(),
290  [&optimizationViews](const SubgraphView::SubgraphViewPtr& untouchedSubgraph)
291  {
292  ARMNN_ASSERT(untouchedSubgraph != nullptr);
293 
294  optimizationViews.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph));
295  });
296  }
297 
298  return optimizationViews;
299 }
300 
301 std::unique_ptr<ICustomAllocator> MockBackend::GetDefaultAllocator() const
302 {
303  return std::make_unique<DefaultAllocator>();
304 }
305 
306 } // namespace armnn
ARMNN_ASSERT
#define ARMNN_ASSERT(COND)
Definition: Assert.hpp:14
SubgraphViewSelector.hpp
armnn::IMemoryManagerUniquePtr
std::unique_ptr< IMemoryManager > IMemoryManagerUniquePtr
Definition: IMemoryManager.hpp:24
DefaultAllocator.hpp
armnn::BackendRegistry::Deregister
void Deregister(const BackendId &id)
Definition: BackendRegistry.cpp:41
armnn::IBackendInternal::IMemoryManagerSharedPtr
std::shared_ptr< IMemoryManager > IMemoryManagerSharedPtr
Definition: IBackendInternal.hpp:99
armnn::IsLayerOptimizable
bool IsLayerOptimizable(const armnn::Layer &layer)
Definition: MockBackend.cpp:99
BackendRegistry.hpp
armnn::IBackendInternal::IBackendContextPtr
std::unique_ptr< IBackendContext > IBackendContextPtr
Definition: IBackendInternal.hpp:90
armnn::LayerType::ElementwiseBinary
@ ElementwiseBinary
armnn::Layer::GetName
const char * GetName() const override
Returns the name of the layer.
Definition: Layer.hpp:332
armnn::Layer
Definition: Layer.hpp:230
armnn::SubgraphView::IConnectableLayers
std::list< IConnectableLayer * > IConnectableLayers
Definition: SubgraphView.hpp:62
armnn::SubgraphViewSelector::SelectSubgraphs
static Subgraphs SelectSubgraphs(Graph &graph, const LayerSelectorFunction &selector)
Selects subgraphs from a graph based on the selector function and the algorithm.
Definition: SubgraphViewSelector.cpp:259
armnn::BackendRegistryInstance
BackendRegistry & BackendRegistryInstance()
Definition: BackendRegistry.cpp:15
armnn::IsLayerOptimizable
bool IsLayerOptimizable(const armnn::Layer *layer)
Definition: MockBackend.cpp:88
armnn::SubgraphView::SubgraphViewPtr
std::shared_ptr< SubgraphView > SubgraphViewPtr
Definition: SubgraphView.hpp:56
armnn::LayerType::Addition
@ Addition
armnn::IsLayerSupported
bool IsLayerSupported(const armnn::Layer &layer)
Definition: MockBackend.cpp:83
armnn::IBackendInternal::IBackendProfilingContextPtr
std::shared_ptr< arm::pipe::IBackendProfilingContext > IBackendProfilingContextPtr
This is the bridge between backend and backend profiling we'll keep it in the backend namespace.
Definition: IBackendInternal.hpp:92
armnn::Layer::GetType
LayerType GetType() const override
Returns the armnn::LayerType of this layer.
Definition: Layer.hpp:286
armnn::BackendRegistry::Register
void Register(const BackendId &id, FactoryFunction factory)
Definition: BackendRegistry.cpp:21
armnn::IBackendInternal::IMemoryManagerUniquePtr
std::unique_ptr< IMemoryManager > IMemoryManagerUniquePtr
Definition: IBackendInternal.hpp:98
MemCopyWorkload.hpp
armnn::IgnoreUnused
void IgnoreUnused(Ts &&...)
Definition: IgnoreUnused.hpp:14
armnn::IsLayerSupported
bool IsLayerSupported(const armnn::Layer *layer)
Definition: MockBackend.cpp:62
armnn
Copyright (c) 2021 ARM Limited and Contributors.
Definition: 01_00_quick_start.dox:6
GetBackendId
const char * GetBackendId()
Definition: RefDynamicBackend.cpp:12
Layer.hpp
armnn::IBackendInternal::ILayerSupportSharedPtr
std::shared_ptr< ILayerSupport > ILayerSupportSharedPtr
Definition: IBackendInternal.hpp:94
armnn::ILayerSupportSharedPtr
std::shared_ptr< ILayerSupport > ILayerSupportSharedPtr
Definition: ILayerSupport.hpp:40
armnn::LayerType::Input
@ Input
armnn::LayerType::Convolution2d
@ Convolution2d
armnn::IBackendInternal::IWorkloadFactoryPtr
std::unique_ptr< IWorkloadFactory > IWorkloadFactoryPtr
Definition: IBackendInternal.hpp:89
armnn::IBackendInternalUniquePtr
std::unique_ptr< IBackendInternal > IBackendInternalUniquePtr
Definition: BackendRegistry.hpp:32
armnn::LayerType
LayerType
When adding a new layer, adapt also the LastLayer enum value in the enum class LayerType below.
Definition: Types.hpp:491
armnn::SubgraphViewSelector::Subgraphs
std::vector< SubgraphView::SubgraphViewPtr > Subgraphs
Definition: SubgraphViewSelector.hpp:24
armnn::LayerType::Output
@ Output
armnn::LayerType::Constant
@ Constant