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/backendsCommon/BackendRegistry.cpp | 2 +- .../backendsCommon/test/DynamicBackendTests.cpp | 2 + .../backendsCommon/test/DynamicBackendTests.hpp | 114 ++++++++++++++++++++- 3 files changed, 115 insertions(+), 3 deletions(-) (limited to 'src/backends/backendsCommon') 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())); +} -- cgit v1.2.1