IVGCVSW-3605 Add direct compatibility between Cl and Neon backends
authorJan Eilers <jan.eilers@arm.com>
Fri, 16 Aug 2019 09:45:30 +0000 (10:45 +0100)
committerÁron Virginás-Tar <aron.virginas-tar@arm.com>
Tue, 27 Aug 2019 09:15:37 +0000 (09:15 +0000)
* Adds compatibility between Cl and Neon
* Adds related unit test

Signed-off-by: Jan Eilers <jan.eilers@arm.com>
Signed-off-by: Mike Kelly <mike.kelly@arm.com>
Change-Id: Iaa454ea2a6392c89c0a83836c3156d4ddb354879

src/backends/backendsCommon/test/CMakeLists.txt
src/backends/backendsCommon/test/CompatibilityTests.cpp [new file with mode: 0644]
src/backends/neon/NeonBackend.cpp

index d6f8a6f..293e5b5 100644 (file)
@@ -66,6 +66,11 @@ if (ARMCOMPUTEREF)
         )
 endif()
 
+if(ARMCOMPUTENEON AND ARMCOMPUTECL)
+    list(APPEND armnnBackendsCommonUnitTests_sources
+        CompatibilityTests.cpp)
+endif()
+
 add_library(armnnBackendsCommonUnitTests OBJECT ${armnnBackendsCommonUnitTests_sources})
 target_include_directories(armnnBackendsCommonUnitTests PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn)
 target_include_directories(armnnBackendsCommonUnitTests PRIVATE ${PROJECT_SOURCE_DIR}/src/armnnUtils)
diff --git a/src/backends/backendsCommon/test/CompatibilityTests.cpp b/src/backends/backendsCommon/test/CompatibilityTests.cpp
new file mode 100644 (file)
index 0000000..599c984
--- /dev/null
@@ -0,0 +1,117 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <boost/test/unit_test.hpp>
+
+#include <cl/ClBackend.hpp>
+#include <neon/NeonBackend.hpp>
+
+#include <Network.hpp>
+
+#include <vector>
+#include <string>
+
+using namespace armnn;
+
+BOOST_AUTO_TEST_SUITE(BackendsCompatibility)
+
+BOOST_AUTO_TEST_CASE(Neon_Cl_DirectCompatibility_Test)
+{
+    auto neonBackend = std::make_unique<NeonBackend>();
+    auto clBackend = std::make_unique<ClBackend>();
+
+    TensorHandleFactoryRegistry registry;
+    neonBackend->RegisterTensorHandleFactories(registry);
+    clBackend->RegisterTensorHandleFactories(registry);
+
+    const BackendId& neonBackendId = neonBackend->GetId();
+    const BackendId& clBackendId = clBackend->GetId();
+
+    BackendsMap backends;
+    backends[neonBackendId] = std::move(neonBackend);
+    backends[clBackendId] = std::move(clBackend);
+
+    armnn::Graph graph;
+
+    armnn::InputLayer* const inputLayer = graph.AddLayer<armnn::InputLayer>(0, "input");
+
+    inputLayer->SetBackendId(neonBackendId);
+
+    armnn::SoftmaxDescriptor smDesc;
+    armnn::SoftmaxLayer* const softmaxLayer1 = graph.AddLayer<armnn::SoftmaxLayer>(smDesc, "softmax1");
+    softmaxLayer1->SetBackendId(clBackendId);
+
+    armnn::SoftmaxLayer* const softmaxLayer2 = graph.AddLayer<armnn::SoftmaxLayer>(smDesc, "softmax2");
+    softmaxLayer2->SetBackendId(neonBackendId);
+
+    armnn::SoftmaxLayer* const softmaxLayer3 = graph.AddLayer<armnn::SoftmaxLayer>(smDesc, "softmax3");
+    softmaxLayer3->SetBackendId(clBackendId);
+
+    armnn::SoftmaxLayer* const softmaxLayer4 = graph.AddLayer<armnn::SoftmaxLayer>(smDesc, "softmax4");
+    softmaxLayer4->SetBackendId(neonBackendId);
+
+    armnn::OutputLayer* const outputLayer = graph.AddLayer<armnn::OutputLayer>(0, "output");
+    outputLayer->SetBackendId(clBackendId);
+
+    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(softmaxLayer4->GetInputSlot(0));
+    softmaxLayer4->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);
+    OutputSlot& softmaxLayer4Out = softmaxLayer4->GetOutputSlot(0);
+
+    // Check that the correct factory was selected
+    BOOST_TEST(inputLayerOut.GetTensorHandleFactoryId()    == "Arm/Cl/TensorHandleFactory");
+    BOOST_TEST(softmaxLayer1Out.GetTensorHandleFactoryId() == "Arm/Cl/TensorHandleFactory");
+    BOOST_TEST(softmaxLayer2Out.GetTensorHandleFactoryId() == "Arm/Cl/TensorHandleFactory");
+    BOOST_TEST(softmaxLayer3Out.GetTensorHandleFactoryId() == "Arm/Cl/TensorHandleFactory");
+    BOOST_TEST(softmaxLayer4Out.GetTensorHandleFactoryId() == "Arm/Cl/TensorHandleFactory");
+
+    // Check that the correct strategy was selected
+    BOOST_TEST((inputLayerOut.GetEdgeStrategyForConnection(0) == EdgeStrategy::DirectCompatibility));
+    BOOST_TEST((softmaxLayer1Out.GetEdgeStrategyForConnection(0) == EdgeStrategy::DirectCompatibility));
+    BOOST_TEST((softmaxLayer2Out.GetEdgeStrategyForConnection(0) == EdgeStrategy::DirectCompatibility));
+    BOOST_TEST((softmaxLayer3Out.GetEdgeStrategyForConnection(0) == EdgeStrategy::DirectCompatibility));
+    BOOST_TEST((softmaxLayer4Out.GetEdgeStrategyForConnection(0) == EdgeStrategy::DirectCompatibility));
+
+    graph.AddCompatibilityLayers(backends, registry);
+
+    // Test for copy layers
+    int copyCount= 0;
+    graph.ForEachLayer([&copyCount](Layer* layer)
+    {
+        if (layer->GetType() == LayerType::MemCopy)
+        {
+            copyCount++;
+        }
+    });
+    BOOST_TEST(copyCount == 0);
+
+    // Test for import layers
+    int importCount= 0;
+    graph.ForEachLayer([&importCount](Layer *layer)
+    {
+        if (layer->GetType() == LayerType::MemImport)
+        {
+            importCount++;
+        }
+    });
+    BOOST_TEST(importCount == 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
index 60f8ba6..63529c9 100644 (file)
@@ -82,7 +82,8 @@ OptimizationViews NeonBackend::OptimizeSubgraphView(const SubgraphView& subgraph
 
 std::vector<ITensorHandleFactory::FactoryId> NeonBackend::GetHandleFactoryPreferences() const
 {
-    return std::vector<ITensorHandleFactory::FactoryId>() = {NeonTensorHandleFactory::GetIdStatic()};
+    return std::vector<ITensorHandleFactory::FactoryId>() = {"Arm/Neon/TensorHandleFactory",
+                                                             "Arm/Cl/TensorHandleFactory"};
 }
 
 void NeonBackend::RegisterTensorHandleFactories(class TensorHandleFactoryRegistry& registry)