From 4e73b429ddfebef9beb64872d3e54a14bceccb29 Mon Sep 17 00:00:00 2001 From: Matteo Martincigh Date: Thu, 8 Aug 2019 13:46:32 +0100 Subject: IVGCVSW-3546 Create a reference dynamic backend to use for testing and as an example in the docs * Wrapped the reference backend into a dynamic backend * Moved the static registration code to a separate file, so that it is possible to create the reference dynamic backend that does not register statically into armnn * Added unit test Change-Id: I1074d21b020820f9ac8c7178388be773b447555a Signed-off-by: Matteo Martincigh --- src/backends/backends.cmake | 8 ++ src/backends/backendsCommon/BackendRegistry.cpp | 2 +- .../backendsCommon/test/DynamicBackendTests.cpp | 2 + .../backendsCommon/test/DynamicBackendTests.hpp | 114 ++++++++++++++++++++- src/backends/dynamic/reference/CMakeLists.txt | 28 +++++ .../dynamic/reference/RefDynamicBackend.cpp | 33 ++++++ .../dynamic/reference/RefDynamicBackend.hpp | 15 +++ src/backends/reference/CMakeLists.txt | 1 + src/backends/reference/RefBackend.cpp | 15 --- src/backends/reference/RefRegistryInitializer.cpp | 25 +++++ src/backends/reference/backend.mk | 1 + 11 files changed, 226 insertions(+), 18 deletions(-) create mode 100644 src/backends/dynamic/reference/CMakeLists.txt create mode 100644 src/backends/dynamic/reference/RefDynamicBackend.cpp create mode 100644 src/backends/dynamic/reference/RefDynamicBackend.hpp create mode 100644 src/backends/reference/RefRegistryInitializer.cpp diff --git a/src/backends/backends.cmake b/src/backends/backends.cmake index 438fda3664..473de48030 100644 --- a/src/backends/backends.cmake +++ b/src/backends/backends.cmake @@ -19,3 +19,11 @@ foreach(includeFile ${backendIncludes}) message("Including backend into the build: ${includeFile}") include(${includeFile}) endforeach() + +# parse dynamic backend sub-directories +file(GLOB dynamicBackendDirs ${PROJECT_SOURCE_DIR}/src/backends/dynamic/*) +foreach(dynamicBackendDir ${dynamicBackendDirs}) + if (EXISTS ${dynamicBackendDir} AND IS_DIRECTORY ${dynamicBackendDir}) + add_subdirectory(${dynamicBackendDir}) + endif() +endforeach() diff --git a/src/backends/backendsCommon/BackendRegistry.cpp b/src/backends/backendsCommon/BackendRegistry.cpp index 80ab01ce1b..7078304599 100644 --- a/src/backends/backendsCommon/BackendRegistry.cpp +++ b/src/backends/backendsCommon/BackendRegistry.cpp @@ -17,7 +17,7 @@ BackendRegistry& BackendRegistryInstance() void BackendRegistry::Register(const BackendId& id, BackendRegistry::FactoryFunction factory) { - if (m_Factories.count(id) > 0) + if (m_Factories.find(id) != m_Factories.end()) { throw InvalidArgumentException( std::string(id) + " already registered as IBackend factory", diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.cpp b/src/backends/backendsCommon/test/DynamicBackendTests.cpp index f13c961eaf..e42a08adc7 100644 --- a/src/backends/backendsCommon/test/DynamicBackendTests.cpp +++ b/src/backends/backendsCommon/test/DynamicBackendTests.cpp @@ -61,4 +61,6 @@ ARMNN_SIMPLE_TEST_CASE(RuntimeDuplicateDynamicBackends, RuntimeDuplicateDynamicB ARMNN_SIMPLE_TEST_CASE(RuntimeInvalidDynamicBackends, RuntimeInvalidDynamicBackendsTestImpl); ARMNN_SIMPLE_TEST_CASE(RuntimeInvalidOverridePath, RuntimeInvalidOverridePathTestImpl); +ARMNN_SIMPLE_TEST_CASE(CreateReferenceDynamicBackend, CreateReferenceDynamicBackendTestImpl); + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.hpp b/src/backends/backendsCommon/test/DynamicBackendTests.hpp index 3a44f506d6..74ef6f1ba7 100644 --- a/src/backends/backendsCommon/test/DynamicBackendTests.hpp +++ b/src/backends/backendsCommon/test/DynamicBackendTests.hpp @@ -7,6 +7,12 @@ #include #include +#include +#include + +#include + +#include #include @@ -54,6 +60,10 @@ static std::string g_TestDynamicBackendsSubDir7 = "backendsTestPath7/"; static std::string g_TestDynamicBackendsSubDir8 = "backendsTestPath8/"; static std::string g_TestDynamicBackendsSubDir9 = "backendsTestPath9/"; +static std::string g_DynamicBackendsBaseDir = "src/backends/dynamic"; +static std::string g_ReferenceDynamicBackendSubDir = "reference/"; +static std::string g_ReferenceBackendFileName = "Arm_CpuRef_backend.so"; + // DynamicBackendUtils wrapper class used for testing (allows to directly invoke the protected methods) class TestDynamicBackendUtils : public armnn::DynamicBackendUtils { @@ -94,17 +104,27 @@ private: FactoryStorage m_TempStorage; }; -std::string GetTestDirectoryBasePath() +std::string GetBasePath(const std::string& basePath) { using namespace boost::filesystem; path programLocation = boost::dll::program_location().parent_path(); - path sharedObjectPath = programLocation.append(g_TestBaseDir); + path sharedObjectPath = programLocation.append(basePath); BOOST_CHECK(exists(sharedObjectPath)); return sharedObjectPath.string(); } +std::string GetTestDirectoryBasePath() +{ + return GetBasePath(g_TestBaseDir); +} + +std::string GetDynamicBackendsBasePath() +{ + return GetBasePath(g_DynamicBackendsBaseDir); +} + std::string GetTestSubDirectory(const std::string& subdir) { using namespace boost::filesystem; @@ -117,6 +137,17 @@ std::string GetTestSubDirectory(const std::string& subdir) return testDynamicBackendsSubDir.string(); } +std::string GetTestSubDirectory(const std::string& basePath, const std::string& subdir) +{ + using namespace boost::filesystem; + + path testDynamicBackendsBasePath(basePath); + path testDynamicBackendsSubDir = testDynamicBackendsBasePath.append(subdir); + // Do not check that the sub-directory exists because for testing reasons we may use non-existing paths + + return testDynamicBackendsSubDir.string(); +} + std::string GetTestFilePath(const std::string& directory, const std::string& fileName) { using namespace boost::filesystem; @@ -1268,3 +1299,82 @@ void RuntimeInvalidOverridePathTestImpl() const BackendRegistry& backendRegistry = BackendRegistryInstance(); BOOST_TEST(backendRegistry.Size() == 0); } + +void CreateReferenceDynamicBackendTestImpl() +{ + using namespace armnn; + using namespace boost::filesystem; + + // Swapping the backend registry storage for testing + TestBackendRegistry testBackendRegistry; + + // This directory contains the reference dynamic backend + std::string dynamicBackendsBaseDir = GetDynamicBackendsBasePath(); + std::string referenceDynamicBackendSubDir = GetTestSubDirectory(dynamicBackendsBaseDir, + g_ReferenceDynamicBackendSubDir); + BOOST_CHECK(exists(referenceDynamicBackendSubDir)); + + // Check that the reference dynamic backend file exists + std::string referenceBackendFilePath = GetTestFilePath(referenceDynamicBackendSubDir, + g_ReferenceBackendFileName); + BOOST_CHECK(exists(referenceBackendFilePath)); + + // Using the path override in CreationOptions to load the reference dynamic backend + IRuntime::CreationOptions creationOptions; + creationOptions.m_DynamicBackendsPath = referenceDynamicBackendSubDir; + IRuntimePtr runtime = IRuntime::Create(creationOptions); + + const BackendRegistry& backendRegistry = BackendRegistryInstance(); + BOOST_TEST(backendRegistry.Size() == 1); + + BackendIdSet backendIds = backendRegistry.GetBackendIds(); + BOOST_TEST((backendIds.find("CpuRef") != backendIds.end())); + + // Get the factory function + auto referenceDynamicBackendFactoryFunction = backendRegistry.GetFactory("CpuRef"); + BOOST_TEST((referenceDynamicBackendFactoryFunction != nullptr)); + + // Use the factory function to create an instance of the reference backend + IBackendInternalUniquePtr referenceDynamicBackend = referenceDynamicBackendFactoryFunction(); + BOOST_TEST((referenceDynamicBackend != nullptr)); + BOOST_TEST((referenceDynamicBackend->GetId() == "CpuRef")); + + // Test the backend instance by querying the layer support + IBackendInternal::ILayerSupportSharedPtr referenceLayerSupport = referenceDynamicBackend->GetLayerSupport(); + BOOST_TEST((referenceLayerSupport != nullptr)); + + TensorShape inputShape { 1, 16, 16, 16 }; + TensorShape outputShape{ 1, 16, 16, 16 }; + TensorShape weightShape{ 16, 1, 1, 16 }; + TensorInfo inputInfo (inputShape, DataType::Float32); + TensorInfo outputInfo(outputShape, DataType::Float32); + TensorInfo weightInfo(weightShape, DataType::Float32); + Convolution2dDescriptor convolution2dDescriptor; + bool referenceConvolution2dSupported = + referenceLayerSupport->IsConvolution2dSupported(inputInfo, + outputInfo, + convolution2dDescriptor, + weightInfo, + EmptyOptional()); + BOOST_TEST(referenceConvolution2dSupported); + + // Test the backend instance by creating a workload + IBackendInternal::IWorkloadFactoryPtr referenceWorkloadFactory = referenceDynamicBackend->CreateWorkloadFactory(); + BOOST_TEST((referenceWorkloadFactory != nullptr)); + + // Create dummy settings for the workload + Convolution2dQueueDescriptor convolution2dQueueDescriptor; + WorkloadInfo workloadInfo + { + { inputInfo }, + { outputInfo } + }; + convolution2dQueueDescriptor.m_Inputs.push_back(nullptr); + auto weights = std::make_unique(weightInfo); + convolution2dQueueDescriptor.m_Weight = weights.get(); + + // Create a convolution workload with the dummy settings + auto workload = referenceWorkloadFactory->CreateConvolution2d(convolution2dQueueDescriptor, workloadInfo); + BOOST_TEST((workload != nullptr)); + BOOST_TEST(workload.get() == boost::polymorphic_downcast(workload.get())); +} diff --git a/src/backends/dynamic/reference/CMakeLists.txt b/src/backends/dynamic/reference/CMakeLists.txt new file mode 100644 index 0000000000..e9a94af2fc --- /dev/null +++ b/src/backends/dynamic/reference/CMakeLists.txt @@ -0,0 +1,28 @@ +# +# Copyright © 2017 Arm Ltd. All rights reserved. +# SPDX-License-Identifier: MIT +# + +# File needed to wrap the existing backend into a dynamic one +list(APPEND armnnRefDynamicBackend_sources + RefDynamicBackend.cpp + RefDynamicBackend.hpp +) + +# Set the backend source path +set(RefBackendPath ${PROJECT_SOURCE_DIR}/src/backends/reference) + +# Source files of the backend, taken directly from the source tree +file(GLOB RefBackendBaseFiles ${RefBackendPath}/*.cpp) +set(RefBackendFiles ${RefBackendBaseFiles}) + +# Remove the file that contains the static backend registration +list(REMOVE_ITEM RefBackendFiles ${RefBackendPath}/RefRegistryInitializer.cpp) + +# Create the shared object +add_library(Arm_CpuRef_backend MODULE ${armnnRefDynamicBackend_sources} ${RefBackendFiles}) +target_include_directories(Arm_CpuRef_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(Arm_CpuRef_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnnUtils) +target_include_directories(Arm_CpuRef_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) +set_target_properties(Arm_CpuRef_backend PROPERTIES PREFIX "") +target_link_libraries(Arm_CpuRef_backend armnn) diff --git a/src/backends/dynamic/reference/RefDynamicBackend.cpp b/src/backends/dynamic/reference/RefDynamicBackend.cpp new file mode 100644 index 0000000000..592043268b --- /dev/null +++ b/src/backends/dynamic/reference/RefDynamicBackend.cpp @@ -0,0 +1,33 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "RefDynamicBackend.hpp" + +#include + +using namespace armnn; + +const char* GetBackendId() +{ + return RefBackend::GetIdStatic().Get().c_str(); +} + +void GetVersion(uint32_t* outMajor, uint32_t* outMinor) +{ + if (!outMajor || !outMinor) + { + return; + } + + BackendVersion apiVersion = IBackendInternal::GetApiVersion(); + + *outMajor = apiVersion.m_Major; + *outMinor = apiVersion.m_Minor; +} + +void* BackendFactory() +{ + return new RefBackend(); +} diff --git a/src/backends/dynamic/reference/RefDynamicBackend.hpp b/src/backends/dynamic/reference/RefDynamicBackend.hpp new file mode 100644 index 0000000000..b058cd206c --- /dev/null +++ b/src/backends/dynamic/reference/RefDynamicBackend.hpp @@ -0,0 +1,15 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include + +extern "C" +{ +const char* GetBackendId(); +void GetVersion(uint32_t* outMajor, uint32_t* outMinor); +void* BackendFactory(); +} diff --git a/src/backends/reference/CMakeLists.txt b/src/backends/reference/CMakeLists.txt index 281e91628f..963e64379d 100644 --- a/src/backends/reference/CMakeLists.txt +++ b/src/backends/reference/CMakeLists.txt @@ -13,6 +13,7 @@ list(APPEND armnnRefBackend_sources RefLayerSupport.hpp RefMemoryManager.hpp RefMemoryManager.cpp + RefRegistryInitializer.cpp RefWorkloadFactory.cpp RefWorkloadFactory.hpp ) diff --git a/src/backends/reference/RefBackend.cpp b/src/backends/reference/RefBackend.cpp index 3680831fb3..41438b0151 100644 --- a/src/backends/reference/RefBackend.cpp +++ b/src/backends/reference/RefBackend.cpp @@ -20,21 +20,6 @@ namespace armnn { -namespace -{ - -static BackendRegistry::StaticRegistryInitializer g_RegisterHelper -{ - BackendRegistryInstance(), - RefBackend::GetIdStatic(), - []() - { - return IBackendInternalUniquePtr(new RefBackend); - } -}; - -} - const BackendId& RefBackend::GetIdStatic() { static const BackendId s_Id{RefBackendId()}; diff --git a/src/backends/reference/RefRegistryInitializer.cpp b/src/backends/reference/RefRegistryInitializer.cpp new file mode 100644 index 0000000000..427c7f01ab --- /dev/null +++ b/src/backends/reference/RefRegistryInitializer.cpp @@ -0,0 +1,25 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "RefBackend.hpp" + +#include + +namespace +{ + +using namespace armnn; + +static BackendRegistry::StaticRegistryInitializer g_RegisterHelper +{ + BackendRegistryInstance(), + RefBackend::GetIdStatic(), + []() + { + return IBackendInternalUniquePtr(new RefBackend); + } +}; + +} // Anonymous namespace diff --git a/src/backends/reference/backend.mk b/src/backends/reference/backend.mk index 6e1360a1db..b212995ad1 100644 --- a/src/backends/reference/backend.mk +++ b/src/backends/reference/backend.mk @@ -13,6 +13,7 @@ BACKEND_SOURCES := \ RefMemoryManager.cpp \ RefTensorHandle.cpp \ RefWorkloadFactory.cpp \ + RefRegistryInitializer.cpp \ workloads/Activation.cpp \ workloads/BatchNormImpl.cpp \ workloads/BatchToSpaceNd.cpp \ -- cgit v1.2.1