diff options
author | Derek Lamberti <derek.lamberti@arm.com> | 2019-06-13 11:40:08 +0100 |
---|---|---|
committer | Derek Lamberti <derek.lamberti@arm.com> | 2019-06-24 15:00:15 +0000 |
commit | 84da38b0f11ca3db0a439e510514be780f3933ff (patch) | |
tree | 56532f4842abc1ad00ae57bc20ddc72cada59b4c /src/armnn/test | |
parent | 9515c7ec4f4535fff2c8f2d3f88974474d3f3468 (diff) | |
download | armnn-84da38b0f11ca3db0a439e510514be780f3933ff.tar.gz |
IVGCVSW-3277 Refactor TensorHandle factory API
* Added backend support for multiple types of TensorHandle factories
* Refactored the backend API to enable new tensor strategies
* Added mechanism to determine memory strategies during optimization
* Perform mem-copy only when Direct access is not found
* Explicitly deleted the copy-constructor from OutputSlot to prevent
accidental local copies that would cause the DisconnectAll to be
called by the destructor
Change-Id: I7e812c8e5e6c1c20db1c5932749ac70fd93db7f8
Signed-off-by: Derek Lamberti <derek.lamberti@arm.com>
Signed-off-by: Matteo Martincigh <matteo.martincigh@arm.com>
Diffstat (limited to 'src/armnn/test')
-rw-r--r-- | src/armnn/test/CreateWorkload.hpp | 6 | ||||
-rw-r--r-- | src/armnn/test/GraphTests.cpp | 28 | ||||
-rw-r--r-- | src/armnn/test/TensorHandleStrategyTest.cpp | 274 |
3 files changed, 301 insertions, 7 deletions
diff --git a/src/armnn/test/CreateWorkload.hpp b/src/armnn/test/CreateWorkload.hpp index b07197797c..47af4a89b5 100644 --- a/src/armnn/test/CreateWorkload.hpp +++ b/src/armnn/test/CreateWorkload.hpp @@ -41,11 +41,13 @@ std::unique_ptr<Workload> MakeAndCheckWorkload(Layer& layer, Graph& graph, const } // Helper function to create tensor handlers for workloads, assuming they all use the same factory. -void CreateTensorHandles(armnn::Graph& graph, armnn::IWorkloadFactory& factory) +void CreateTensorHandles(armnn::Graph& graph, + armnn::IWorkloadFactory& factory) { + TensorHandleFactoryRegistry tmpRegistry; for (auto&& layer : graph.TopologicalSort()) { - layer->CreateTensorHandles(graph, factory); + layer->CreateTensorHandles(tmpRegistry, factory); } } diff --git a/src/armnn/test/GraphTests.cpp b/src/armnn/test/GraphTests.cpp index 44cfa2eaec..ae5ff2232b 100644 --- a/src/armnn/test/GraphTests.cpp +++ b/src/armnn/test/GraphTests.cpp @@ -14,6 +14,8 @@ #include <Layer.hpp> #include <backendsCommon/CpuTensorHandle.hpp> +#include <backendsCommon/IBackendInternal.hpp> +#include <backendsCommon/TensorHandleFactoryRegistry.hpp> /// Checks that first comes before second in the order. @@ -477,10 +479,21 @@ struct CopyLayersFixture outputLayer->SetBackendId(armnn::Compute::CpuRef); softmaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + + // Set the memory strategies + inputLayer->GetOutputSlot(0).SetMemoryStrategy(0, MemoryStrategy::DirectCompatibility); + convLayer1->GetOutputSlot(0).SetMemoryStrategy(0, MemoryStrategy::DirectCompatibility); + convLayer1->GetOutputSlot(0).SetMemoryStrategy(1, MemoryStrategy::DirectCompatibility); + convLayer2->GetOutputSlot(0).SetMemoryStrategy(0, MemoryStrategy::DirectCompatibility); + concatLayer->GetOutputSlot(0).SetMemoryStrategy(0, MemoryStrategy::DirectCompatibility); + actLayer->GetOutputSlot(0).SetMemoryStrategy(0, MemoryStrategy::DirectCompatibility); + softmaxLayer->GetOutputSlot(0).SetMemoryStrategy(0, MemoryStrategy::DirectCompatibility); } armnn::TensorInfo m_TensorDesc; armnn::Graph m_Graph; + std::map<armnn::BackendId, std::unique_ptr<armnn::IBackendInternal>> m_Backends; + armnn::TensorHandleFactoryRegistry m_FactoryRegistry; private: @@ -501,26 +514,26 @@ private: BOOST_FIXTURE_TEST_CASE(AddCopyLayers, CopyLayersFixture) { const armnn::Graph origGraph(m_Graph); - m_Graph.AddCopyLayers(); + m_Graph.AddCopyLayers(m_Backends, m_FactoryRegistry); TestGraphAfterAddingCopyLayers(m_Graph, origGraph); } BOOST_FIXTURE_TEST_CASE(AddCopyLayersSeveralTimes, CopyLayersFixture) { - m_Graph.AddCopyLayers(); + m_Graph.AddCopyLayers(m_Backends, m_FactoryRegistry); // Calling AddCopyLayers() several times should not change the connections. const std::vector<Edge> edges = GetEdgeList(m_Graph); for (int i = 0; i < 4; ++i) { - m_Graph.AddCopyLayers(); + m_Graph.AddCopyLayers(m_Backends, m_FactoryRegistry); const std::vector<Edge> otherEdges = GetEdgeList(m_Graph); BOOST_TEST((edges == otherEdges)); } } -BOOST_AUTO_TEST_CASE(CopyLayersAddedBetweenSameLayersHaveDifferentNames) +BOOST_FIXTURE_TEST_CASE(CopyLayersAddedBetweenSameLayersHaveDifferentNames, CopyLayersFixture) { armnn::Graph graph; @@ -542,7 +555,12 @@ BOOST_AUTO_TEST_CASE(CopyLayersAddedBetweenSameLayersHaveDifferentNames) splitterLayer->GetOutputSlot(1).Connect(additionLayer->GetInputSlot(1)); additionLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); - graph.AddCopyLayers(); + inputLayer->GetOutputSlot(0).SetMemoryStrategy(0, armnn::MemoryStrategy::DirectCompatibility); + splitterLayer->GetOutputSlot(0).SetMemoryStrategy(0, armnn::MemoryStrategy::CopyToTarget); + splitterLayer->GetOutputSlot(1).SetMemoryStrategy(0, armnn::MemoryStrategy::CopyToTarget); + additionLayer->GetOutputSlot(0).SetMemoryStrategy(0, armnn::MemoryStrategy::DirectCompatibility); + + graph.AddCopyLayers(m_Backends, m_FactoryRegistry); std::vector<Edge> edges = GetEdgeList(graph); BOOST_CHECK(edges.size() == 6u); diff --git a/src/armnn/test/TensorHandleStrategyTest.cpp b/src/armnn/test/TensorHandleStrategyTest.cpp new file mode 100644 index 0000000000..3bb1c68169 --- /dev/null +++ b/src/armnn/test/TensorHandleStrategyTest.cpp @@ -0,0 +1,274 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// +#include <boost/test/unit_test.hpp> + +#include <armnn/LayerVisitorBase.hpp> + +#include <backendsCommon/IBackendContext.hpp> +#include <backendsCommon/IBackendInternal.hpp> +#include <backendsCommon/IMemoryManager.hpp> +#include <backendsCommon/ITensorHandleFactory.hpp> +#include <backendsCommon/TensorHandleFactoryRegistry.hpp> + +#include <optimizations/Optimization.hpp> + +#include <Network.hpp> + +#include <vector> +#include <string> + +using namespace armnn; + +class TestMemMgr : public IMemoryManager +{ +public: + TestMemMgr() = default; + + void Acquire() override {} + void Release() override {} +}; + +class TestFactory1 : public ITensorHandleFactory +{ +public: + TestFactory1(std::weak_ptr<IMemoryManager> mgr, ITensorHandleFactory::FactoryId id) + : m_Id(id) + , m_MemMgr(mgr) + {} + + std::unique_ptr<ITensorHandle> CreateSubTensorHandle(ITensorHandle& parent, + TensorShape const& subTensorShape, + unsigned int const* subTensorOrigin) const override + { + return nullptr; + } + + std::unique_ptr<ITensorHandle> CreateTensorHandle(const TensorInfo& tensorInfo) const override + { + return nullptr; + } + + virtual const FactoryId GetId() const override { return m_Id; } + + virtual bool SupportsSubTensors() const override { return true; } + +private: + FactoryId m_Id = "UninitializedId"; + + std::weak_ptr<IMemoryManager> m_MemMgr; +}; + +class TestBackendA : public IBackendInternal +{ +public: + TestBackendA() = default; + + const BackendId& GetId() const override { return m_Id; } + + IWorkloadFactoryPtr CreateWorkloadFactory(const IMemoryManagerSharedPtr& memoryManager = nullptr) const override + { + return IWorkloadFactoryPtr{}; + } + + IBackendInternal::ILayerSupportSharedPtr GetLayerSupport() const override + { + return ILayerSupportSharedPtr{}; + } + + std::vector<ITensorHandleFactory::FactoryId> GetHandleFactoryPreferences() const override + { + return std::vector<ITensorHandleFactory::FactoryId> + { + "TestHandleFactoryA1", + "TestHandleFactoryA2", + "TestHandleFactoryB1" + }; + } + + void RegisterTensorHandleFactories(TensorHandleFactoryRegistry& registry) override + { + auto mgr = std::make_shared<TestMemMgr>(); + + registry.RegisterMemoryManager(mgr); + registry.RegisterFactory(std::make_unique<TestFactory1>(mgr, "TestHandleFactoryA1")); + registry.RegisterFactory(std::make_unique<TestFactory1>(mgr, "TestHandleFactoryA2")); + } + +private: + BackendId m_Id = "BackendA"; +}; + +class TestBackendB : public IBackendInternal +{ +public: + TestBackendB() = default; + + const BackendId& GetId() const override { return m_Id; } + + IWorkloadFactoryPtr CreateWorkloadFactory(const IMemoryManagerSharedPtr& memoryManager = nullptr) const override + { + return IWorkloadFactoryPtr{}; + } + + IBackendInternal::ILayerSupportSharedPtr GetLayerSupport() const override + { + return ILayerSupportSharedPtr{}; + } + + std::vector<ITensorHandleFactory::FactoryId> GetHandleFactoryPreferences() const override + { + return std::vector<ITensorHandleFactory::FactoryId> + { + "TestHandleFactoryB1" + }; + } + + void RegisterTensorHandleFactories(TensorHandleFactoryRegistry& registry) override + { + auto mgr = std::make_shared<TestMemMgr>(); + + registry.RegisterMemoryManager(mgr); + registry.RegisterFactory(std::make_unique<TestFactory1>(mgr, "TestHandleFactoryB1")); + } + +private: + BackendId m_Id = "BackendB"; +}; + +class TestBackendC : public IBackendInternal +{ +public: + TestBackendC() = default; + + const BackendId& GetId() const override { return m_Id; } + + IWorkloadFactoryPtr CreateWorkloadFactory(const IMemoryManagerSharedPtr& memoryManager = nullptr) const override + { + return IWorkloadFactoryPtr{}; + } + + IBackendInternal::ILayerSupportSharedPtr GetLayerSupport() const override + { + return ILayerSupportSharedPtr{}; + } + + std::vector<ITensorHandleFactory::FactoryId> GetHandleFactoryPreferences() const override + { + return std::vector<ITensorHandleFactory::FactoryId>{ + "TestHandleFactoryC1" + }; + } + + void RegisterTensorHandleFactories(TensorHandleFactoryRegistry& registry) override + { + auto mgr = std::make_shared<TestMemMgr>(); + + registry.RegisterMemoryManager(mgr); + registry.RegisterFactory(std::make_unique<TestFactory1>(mgr, "TestHandleFactoryC1")); + } + +private: + BackendId m_Id = "BackendC"; +}; + + +BOOST_AUTO_TEST_SUITE(TensorHandle) + +BOOST_AUTO_TEST_CASE(RegisterFactories) +{ + TestBackendA backendA; + TestBackendB backendB; + + BOOST_TEST(backendA.GetHandleFactoryPreferences()[0] == "TestHandleFactoryA1"); + BOOST_TEST(backendA.GetHandleFactoryPreferences()[1] == "TestHandleFactoryA2"); + BOOST_TEST(backendA.GetHandleFactoryPreferences()[2] == "TestHandleFactoryB1"); + + TensorHandleFactoryRegistry registry; + backendA.RegisterTensorHandleFactories(registry); + backendB.RegisterTensorHandleFactories(registry); + + BOOST_TEST((registry.GetFactory("Non-existing Backend") == nullptr)); + BOOST_TEST((registry.GetFactory("TestHandleFactoryA1") != nullptr)); + BOOST_TEST((registry.GetFactory("TestHandleFactoryA2") != nullptr)); + BOOST_TEST((registry.GetFactory("TestHandleFactoryB1") != nullptr)); +} + +BOOST_AUTO_TEST_CASE(TensorHandleSelectionStrategy) +{ + auto backendA = std::make_unique<TestBackendA>(); + auto backendB = std::make_unique<TestBackendB>(); + auto backendC = std::make_unique<TestBackendC>(); + + TensorHandleFactoryRegistry registry; + backendA->RegisterTensorHandleFactories(registry); + backendB->RegisterTensorHandleFactories(registry); + backendC->RegisterTensorHandleFactories(registry); + + BackendsMap backends; + backends["BackendA"] = std::move(backendA); + backends["BackendB"] = std::move(backendB); + backends["BackendC"] = std::move(backendC); + + armnn::Graph graph; + + armnn::InputLayer* const inputLayer = graph.AddLayer<armnn::InputLayer>(0, "input"); + inputLayer->SetBackendId("BackendA"); + + armnn::SoftmaxDescriptor smDesc; + armnn::SoftmaxLayer* const softmaxLayer1 = graph.AddLayer<armnn::SoftmaxLayer>(smDesc, "softmax1"); + softmaxLayer1->SetBackendId("BackendA"); + + armnn::SoftmaxLayer* const softmaxLayer2 = graph.AddLayer<armnn::SoftmaxLayer>(smDesc, "softmax2"); + softmaxLayer2->SetBackendId("BackendB"); + + armnn::SoftmaxLayer* const softmaxLayer3 = graph.AddLayer<armnn::SoftmaxLayer>(smDesc, "softmax3"); + softmaxLayer3->SetBackendId("BackendC"); + + armnn::OutputLayer* const outputLayer = graph.AddLayer<armnn::OutputLayer>(0, "output"); + outputLayer->SetBackendId("BackendA"); + + inputLayer->GetOutputSlot(0).Connect(softmaxLayer1->GetInputSlot(0)); + softmaxLayer1->GetOutputSlot(0).Connect(softmaxLayer2->GetInputSlot(0)); + softmaxLayer2->GetOutputSlot(0).Connect(softmaxLayer3->GetInputSlot(0)); + softmaxLayer3->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + + graph.TopologicalSort(); + + std::vector<std::string> errors; + auto result = SelectTensorHandleStrategy(graph, backends, registry, errors); + + BOOST_TEST(result.m_Error == false); + BOOST_TEST(result.m_Warning == false); + + OutputSlot& inputLayerOut = inputLayer->GetOutputSlot(0); + OutputSlot& softmaxLayer1Out = softmaxLayer1->GetOutputSlot(0); + OutputSlot& softmaxLayer2Out = softmaxLayer2->GetOutputSlot(0); + OutputSlot& softmaxLayer3Out = softmaxLayer3->GetOutputSlot(0); + + // Check that the correct factory was selected + BOOST_TEST(inputLayerOut.GetTensorHandleFactoryId() == "TestHandleFactoryA1"); + BOOST_TEST(softmaxLayer1Out.GetTensorHandleFactoryId() == "TestHandleFactoryB1"); + BOOST_TEST(softmaxLayer2Out.GetTensorHandleFactoryId() == "TestHandleFactoryB1"); + BOOST_TEST(softmaxLayer3Out.GetTensorHandleFactoryId() == "TestHandleFactoryC1"); + + // Check that the correct strategy was selected + BOOST_TEST((inputLayerOut.GetMemoryStrategyForConnection(0) == MemoryStrategy::DirectCompatibility)); + BOOST_TEST((softmaxLayer1Out.GetMemoryStrategyForConnection(0) == MemoryStrategy::DirectCompatibility)); + BOOST_TEST((softmaxLayer2Out.GetMemoryStrategyForConnection(0) == MemoryStrategy::CopyToTarget)); + BOOST_TEST((softmaxLayer3Out.GetMemoryStrategyForConnection(0) == MemoryStrategy::DirectCompatibility)); + + graph.AddCopyLayers(backends, registry); + int count= 0; + graph.ForEachLayer([&count](Layer* layer) + { + if (layer->GetType() == LayerType::MemCopy) + { + count++; + } + }); + BOOST_TEST(count == 1); +} + +BOOST_AUTO_TEST_SUITE_END() |