From 88054f855792514f033d9c3bfe0d5e4e93cac528 Mon Sep 17 00:00:00 2001 From: Matteo Martincigh Date: Fri, 17 May 2019 12:15:30 +0100 Subject: IVGCVSW-3030 Add a mock backend for unit testing * Added a mock implementation of an ArmNN backend for unit testing * Implemented a mock version of OptimizeSubgraphView * Fixed a typo in the Optimization API Change-Id: Ic7acf7cc5c2a76a918e94cdc356baae7c7597a6d Signed-off-by: Matteo Martincigh --- src/backends/backendsCommon/IBackendInternal.hpp | 2 +- src/backends/backendsCommon/OptimizationViews.hpp | 2 +- src/backends/backendsCommon/test/CMakeLists.txt | 3 + src/backends/backendsCommon/test/MockBackend.cpp | 249 +++++++++++++++++++++ src/backends/backendsCommon/test/MockBackend.hpp | 36 +++ src/backends/backendsCommon/test/MockBackendId.hpp | 13 ++ 6 files changed, 303 insertions(+), 2 deletions(-) create mode 100644 src/backends/backendsCommon/test/MockBackend.cpp create mode 100644 src/backends/backendsCommon/test/MockBackend.hpp create mode 100644 src/backends/backendsCommon/test/MockBackendId.hpp diff --git a/src/backends/backendsCommon/IBackendInternal.hpp b/src/backends/backendsCommon/IBackendInternal.hpp index 826730a800..634e2aba94 100644 --- a/src/backends/backendsCommon/IBackendInternal.hpp +++ b/src/backends/backendsCommon/IBackendInternal.hpp @@ -83,7 +83,7 @@ public: { if (optSubgraph) { - result.AddSubstituion({subgraph, SubgraphView(*optSubgraph.get())}); + result.AddSubstitution({subgraph, SubgraphView(*optSubgraph.get())}); } else { diff --git a/src/backends/backendsCommon/OptimizationViews.hpp b/src/backends/backendsCommon/OptimizationViews.hpp index e96c11aaba..a63fdf1ffb 100644 --- a/src/backends/backendsCommon/OptimizationViews.hpp +++ b/src/backends/backendsCommon/OptimizationViews.hpp @@ -30,7 +30,7 @@ public: using Subgraphs = std::vector; using Substitutions = std::vector; - void AddSubstituion(SubstitutionPair&& substitution) + void AddSubstitution(SubstitutionPair&& substitution) { m_SuccesfulOptimizations.emplace_back(substitution); } diff --git a/src/backends/backendsCommon/test/CMakeLists.txt b/src/backends/backendsCommon/test/CMakeLists.txt index bc190dd818..ab63679268 100644 --- a/src/backends/backendsCommon/test/CMakeLists.txt +++ b/src/backends/backendsCommon/test/CMakeLists.txt @@ -30,6 +30,9 @@ list(APPEND armnnBackendsCommonUnitTests_sources LstmTestImpl.hpp NormTestImpl.hpp MergerTestImpl.hpp + MockBackend.cpp + MockBackend.hpp + MockBackendId.hpp OptimizedNetworkTests.cpp PermuteTestImpl.hpp Pooling2dTestImpl.hpp diff --git a/src/backends/backendsCommon/test/MockBackend.cpp b/src/backends/backendsCommon/test/MockBackend.cpp new file mode 100644 index 0000000000..eca38cdddf --- /dev/null +++ b/src/backends/backendsCommon/test/MockBackend.cpp @@ -0,0 +1,249 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "MockBackend.hpp" +#include "MockBackendId.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::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 +{ + +namespace +{ + +static BackendRegistry::StaticRegistryInitializer g_RegisterHelper +{ + BackendRegistryInstance(), + MockBackend::GetIdStatic(), + []() + { + return IBackendInternalUniquePtr(new MockBackend); + } +}; + +} + +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::IMemoryManagerUniquePtr MockBackend::CreateMemoryManager() const +{ + return IMemoryManagerUniquePtr{}; +} + +IBackendInternal::Optimizations MockBackend::GetOptimizations() const +{ + return Optimizations{}; +} + +IBackendInternal::ILayerSupportSharedPtr MockBackend::GetLayerSupport() const +{ + return ILayerSupportSharedPtr{}; +} + +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 diff --git a/src/backends/backendsCommon/test/MockBackend.hpp b/src/backends/backendsCommon/test/MockBackend.hpp new file mode 100644 index 0000000000..d0a3de8682 --- /dev/null +++ b/src/backends/backendsCommon/test/MockBackend.hpp @@ -0,0 +1,36 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include +#include + +namespace armnn +{ + +class MockBackend : public IBackendInternal +{ +public: + MockBackend() = default; + ~MockBackend() = default; + + static const BackendId& GetIdStatic(); + const BackendId& GetId() const override { return GetIdStatic(); } + + IBackendInternal::IMemoryManagerUniquePtr CreateMemoryManager() const override; + + IBackendInternal::IWorkloadFactoryPtr CreateWorkloadFactory( + const IBackendInternal::IMemoryManagerSharedPtr& memoryManager = nullptr) const override; + + IBackendInternal::IBackendContextPtr CreateBackendContext(const IRuntime::CreationOptions&) const override; + + IBackendInternal::Optimizations GetOptimizations() const override; + IBackendInternal::ILayerSupportSharedPtr GetLayerSupport() const override; + + OptimizationViews OptimizeSubgraphView(const SubgraphView& subgraph) const override; +}; + +} // namespace armnn diff --git a/src/backends/backendsCommon/test/MockBackendId.hpp b/src/backends/backendsCommon/test/MockBackendId.hpp new file mode 100644 index 0000000000..724ce60c1b --- /dev/null +++ b/src/backends/backendsCommon/test/MockBackendId.hpp @@ -0,0 +1,13 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +namespace armnn +{ + +constexpr const char* MockBackendId() { return "MockAcc"; } + +} // namespace armnn -- cgit v1.2.1