// // Copyright © 2017 Arm Ltd. All rights reserved. // SPDX-License-Identifier: MIT // #include "MockBackend.hpp" #include "MockBackendId.hpp" #include "armnn/backends/profiling/IBackendProfilingContext.hpp" #include #include #include #include #include #include #include namespace { bool IsLayerSupported(const armnn::Layer* layer) { BOOST_ASSERT(layer != nullptr); armnn::LayerType layerType = layer->GetType(); switch (layerType) { case armnn::LayerType::Input: case armnn::LayerType::Output: case armnn::LayerType::Addition: case armnn::LayerType::Convolution2d: // Layer supported return true; default: // Layer unsupported return false; } } bool IsLayerSupported(const armnn::Layer& layer) { return IsLayerSupported(&layer); } bool IsLayerOptimizable(const armnn::Layer* layer) { BOOST_ASSERT(layer != nullptr); // A Layer is not optimizable if its name contains "unoptimizable" const std::string layerName(layer->GetName()); bool optimizable = layerName.find("unoptimizable") == std::string::npos; return optimizable; } bool IsLayerOptimizable(const armnn::Layer& layer) { return IsLayerOptimizable(&layer); } } // Anonymous namespace namespace armnn { MockBackendInitialiser::MockBackendInitialiser() { BackendRegistryInstance().Register(MockBackend::GetIdStatic(), []() { return IBackendInternalUniquePtr(new MockBackend); }); } MockBackendInitialiser::~MockBackendInitialiser() { try { BackendRegistryInstance().Deregister(MockBackend::GetIdStatic()); } catch (...) { std::cerr << "could not deregister mock backend" << std::endl; } } const BackendId& MockBackend::GetIdStatic() { static const BackendId s_Id{MockBackendId()}; return s_Id; } IBackendInternal::IWorkloadFactoryPtr MockBackend::CreateWorkloadFactory( const IBackendInternal::IMemoryManagerSharedPtr& /*memoryManager*/) const { return IWorkloadFactoryPtr{}; } IBackendInternal::IBackendContextPtr MockBackend::CreateBackendContext(const IRuntime::CreationOptions&) const { return IBackendContextPtr{}; } IBackendInternal::IBackendProfilingContextPtr MockBackend::CreateBackendProfilingContext( const IRuntime::CreationOptions& options, IBackendProfilingPtr& backendProfiling) { boost::ignore_unused(options); IBackendInternal::IBackendProfilingContextPtr context = std::make_shared(MockBackendProfilingContext(backendProfiling)); MockBackendProfilingService::Instance().SetProfilingContextPtr(context); return context; } IBackendInternal::IMemoryManagerUniquePtr MockBackend::CreateMemoryManager() const { return IMemoryManagerUniquePtr{}; } IBackendInternal::Optimizations MockBackend::GetOptimizations() const { return Optimizations{}; } IBackendInternal::ILayerSupportSharedPtr MockBackend::GetLayerSupport() const { static ILayerSupportSharedPtr layerSupport{new MockLayerSupport}; return layerSupport; } OptimizationViews MockBackend::OptimizeSubgraphView(const SubgraphView& subgraph) const { // Prepare the optimization views OptimizationViews optimizationViews; // Get the layers of the input sub-graph const SubgraphView::Layers& subgraphLayers = subgraph.GetLayers(); // Parse the layers SubgraphView::Layers supportedLayers; SubgraphView::Layers unsupportedLayers; SubgraphView::Layers untouchedLayers; std::for_each(subgraphLayers.begin(), subgraphLayers.end(), [&](Layer* layer) { bool supported = IsLayerSupported(layer); if (supported) { // Layer supported, check if it's optimizable bool optimizable = IsLayerOptimizable(layer); if (optimizable) { // Layer fully supported supportedLayers.push_back(layer); } else { // Layer supported but not optimizable untouchedLayers.push_back(layer); } } else { // Layer unsupported unsupportedLayers.push_back(layer); } }); // Check if there are supported layers if (!supportedLayers.empty()) { // Select the layers that are neither inputs or outputs, but that are optimizable auto supportedSubgraphSelector = [](const Layer& layer) { return layer.GetType() != LayerType::Input && layer.GetType() != LayerType::Output && IsLayerSupported(layer) && IsLayerOptimizable(layer); }; // Apply the subgraph selector to the supported layers to group them into sub-graphs were appropriate SubgraphView mutableSubgraph(subgraph); SubgraphViewSelector::Subgraphs supportedSubgraphs = SubgraphViewSelector::SelectSubgraphs(mutableSubgraph, supportedSubgraphSelector); // Create a substitution pair for each supported sub-graph std::for_each(supportedSubgraphs.begin(), supportedSubgraphs.end(), [&optimizationViews](const SubgraphView::SubgraphViewPtr& supportedSubgraph) { BOOST_ASSERT(supportedSubgraph != nullptr); PreCompiledLayer* preCompiledLayer = optimizationViews.GetGraph().AddLayer( PreCompiledDescriptor(supportedSubgraph->GetNumInputSlots(), supportedSubgraph->GetNumOutputSlots()), "pre-compiled"); preCompiledLayer->SetBackendId(MockBackendId()); SubgraphView substitutionSubgraph(*supportedSubgraph); SubgraphView replacementSubgraph(preCompiledLayer); optimizationViews.AddSubstitution({ substitutionSubgraph, replacementSubgraph }); }); } // Check if there are unsupported layers if (!unsupportedLayers.empty()) { // Select the layers that are neither inputs or outputs, and are not optimizable auto unsupportedSubgraphSelector = [](const Layer& layer) { return layer.GetType() != LayerType::Input && layer.GetType() != LayerType::Output && !IsLayerSupported(layer); }; // Apply the subgraph selector to the unsupported layers to group them into sub-graphs were appropriate SubgraphView mutableSubgraph(subgraph); SubgraphViewSelector::Subgraphs unsupportedSubgraphs = SubgraphViewSelector::SelectSubgraphs(mutableSubgraph, unsupportedSubgraphSelector); // Add each unsupported sub-graph to the list of failed sub-graphs in the optimizization views std::for_each(unsupportedSubgraphs.begin(), unsupportedSubgraphs.end(), [&optimizationViews](const SubgraphView::SubgraphViewPtr& unsupportedSubgraph) { BOOST_ASSERT(unsupportedSubgraph != nullptr); optimizationViews.AddFailedSubgraph(SubgraphView(*unsupportedSubgraph)); }); } // Check if there are untouched layers if (!untouchedLayers.empty()) { // Select the layers that are neither inputs or outputs, that are supported but that and are not optimizable auto untouchedSubgraphSelector = [](const Layer& layer) { return layer.GetType() != LayerType::Input && layer.GetType() != LayerType::Output && IsLayerSupported(layer) && !IsLayerOptimizable(layer); }; // Apply the subgraph selector to the untouched layers to group them into sub-graphs were appropriate SubgraphView mutableSubgraph(subgraph); SubgraphViewSelector::Subgraphs untouchedSubgraphs = SubgraphViewSelector::SelectSubgraphs(mutableSubgraph, untouchedSubgraphSelector); // Add each untouched sub-graph to the list of untouched sub-graphs in the optimizization views std::for_each(untouchedSubgraphs.begin(), untouchedSubgraphs.end(), [&optimizationViews](const SubgraphView::SubgraphViewPtr& untouchedSubgraph) { BOOST_ASSERT(untouchedSubgraph != nullptr); optimizationViews.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph)); }); } return optimizationViews; } } // namespace armnn