From bc2e210785a63e8360839e4ded5d2c15c2dffaf5 Mon Sep 17 00:00:00 2001 From: Matteo Martincigh Date: Wed, 24 Jul 2019 14:56:13 +0100 Subject: IVGCVSW-3561 Test the DynamicBackend class * Added unit test for valid dynamic backends * Added unit tests for various cases of invalid dynamic backends (invalid handle, malformed backends, incompatible version, etc.) Signed-off-by: Matteo Martincigh Change-Id: I4c3b33702bb0faac2bbebe224f69908639b4fc54 --- src/backends/backendsCommon/DynamicBackend.cpp | 8 +- src/backends/backendsCommon/test/CMakeLists.txt | 49 +++++ .../backendsCommon/test/DynamicBackendTests.cpp | 21 +++ .../backendsCommon/test/DynamicBackendTests.hpp | 209 ++++++++++++++++++++- .../backendsCommon/test/TestDynamicBackend.cpp | 95 ++++++++++ .../backendsCommon/test/TestDynamicBackend.hpp | 67 +++++++ 6 files changed, 445 insertions(+), 4 deletions(-) create mode 100644 src/backends/backendsCommon/test/TestDynamicBackend.cpp create mode 100644 src/backends/backendsCommon/test/TestDynamicBackend.hpp diff --git a/src/backends/backendsCommon/DynamicBackend.cpp b/src/backends/backendsCommon/DynamicBackend.cpp index 410265eb38..06d819b9a7 100644 --- a/src/backends/backendsCommon/DynamicBackend.cpp +++ b/src/backends/backendsCommon/DynamicBackend.cpp @@ -45,7 +45,13 @@ BackendId DynamicBackend::GetBackendId() throw RuntimeException("GetBackendId error: invalid function pointer"); } - return BackendId(m_BackendIdFunction()); + const char* backendId = m_BackendIdFunction(); + if (backendId == nullptr) + { + throw RuntimeException("GetBackendId error: invalid backend id"); + } + + return BackendId(backendId); } BackendVersion DynamicBackend::GetBackendVersion() diff --git a/src/backends/backendsCommon/test/CMakeLists.txt b/src/backends/backendsCommon/test/CMakeLists.txt index 4131b9e787..8c9644ff94 100644 --- a/src/backends/backendsCommon/test/CMakeLists.txt +++ b/src/backends/backendsCommon/test/CMakeLists.txt @@ -75,3 +75,52 @@ list(APPEND armnnTestSharedObject_sources add_library_ex(armnnTestSharedObject SHARED ${armnnTestSharedObject_sources}) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/libarmnnNoSharedObject.txt "This is not a shared object") + +# Dummy dynamic backends for testing. +# Both a valid and a number of invalid dummy dynamic backends (covering various use cases) share the +# same source code. The various test cases are put together in the code using compiler directives. + +list(APPEND armnnTestDynamicBackend_sources + TestDynamicBackend.cpp + TestDynamicBackend.hpp +) + +add_library_ex(armnnValidTestDynamicBackend SHARED ${armnnTestDynamicBackend_sources}) +target_compile_definitions(armnnValidTestDynamicBackend PRIVATE -DVALID_TEST_DYNAMIC_BACKEND) +target_include_directories(armnnValidTestDynamicBackend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(armnnValidTestDynamicBackend PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) + +add_library_ex(armnnInvalidTestDynamicBackend1 SHARED ${armnnTestDynamicBackend_sources}) +target_compile_definitions(armnnInvalidTestDynamicBackend1 PRIVATE -DINVALID_TEST_DYNAMIC_BACKEND_1) +target_include_directories(armnnInvalidTestDynamicBackend1 PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(armnnInvalidTestDynamicBackend1 PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) + +add_library_ex(armnnInvalidTestDynamicBackend2 SHARED ${armnnTestDynamicBackend_sources}) +target_compile_definitions(armnnInvalidTestDynamicBackend2 PRIVATE -DINVALID_TEST_DYNAMIC_BACKEND_2) +target_include_directories(armnnInvalidTestDynamicBackend2 PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(armnnInvalidTestDynamicBackend2 PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) + +add_library_ex(armnnInvalidTestDynamicBackend3 SHARED ${armnnTestDynamicBackend_sources}) +target_compile_definitions(armnnInvalidTestDynamicBackend3 PRIVATE -DINVALID_TEST_DYNAMIC_BACKEND_3) +target_include_directories(armnnInvalidTestDynamicBackend3 PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(armnnInvalidTestDynamicBackend3 PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) + +add_library_ex(armnnInvalidTestDynamicBackend4 SHARED ${armnnTestDynamicBackend_sources}) +target_compile_definitions(armnnInvalidTestDynamicBackend4 PRIVATE -DINVALID_TEST_DYNAMIC_BACKEND_4) +target_include_directories(armnnInvalidTestDynamicBackend4 PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(armnnInvalidTestDynamicBackend4 PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) + +add_library_ex(armnnInvalidTestDynamicBackend5 SHARED ${armnnTestDynamicBackend_sources}) +target_compile_definitions(armnnInvalidTestDynamicBackend5 PRIVATE -DINVALID_TEST_DYNAMIC_BACKEND_5) +target_include_directories(armnnInvalidTestDynamicBackend5 PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(armnnInvalidTestDynamicBackend5 PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) + +add_library_ex(armnnInvalidTestDynamicBackend6 SHARED ${armnnTestDynamicBackend_sources}) +target_compile_definitions(armnnInvalidTestDynamicBackend6 PRIVATE -DINVALID_TEST_DYNAMIC_BACKEND_6) +target_include_directories(armnnInvalidTestDynamicBackend6 PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(armnnInvalidTestDynamicBackend6 PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) + +add_library_ex(armnnInvalidTestDynamicBackend7 SHARED ${armnnTestDynamicBackend_sources}) +target_compile_definitions(armnnInvalidTestDynamicBackend7 PRIVATE -DINVALID_TEST_DYNAMIC_BACKEND_7) +target_include_directories(armnnInvalidTestDynamicBackend7 PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(armnnInvalidTestDynamicBackend7 PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.cpp b/src/backends/backendsCommon/test/DynamicBackendTests.cpp index 30622b6b3b..10a650af7e 100644 --- a/src/backends/backendsCommon/test/DynamicBackendTests.cpp +++ b/src/backends/backendsCommon/test/DynamicBackendTests.cpp @@ -5,6 +5,8 @@ #include "DynamicBackendTests.hpp" +#include + BOOST_AUTO_TEST_SUITE(DynamicBackendTests) ARMNN_SIMPLE_TEST_CASE(OpenCloseHandle, OpenCloseHandleTestImpl); @@ -19,4 +21,23 @@ ARMNN_SIMPLE_TEST_CASE(GetNotExistingEntryPoint, GetNotExistingEntryPointTestImp ARMNN_SIMPLE_TEST_CASE(BackendVersioning, BackendVersioningTestImpl); +ARMNN_SIMPLE_TEST_CASE(CreateValidDynamicBackendObject, CreateValidDynamicBackendObjectTestImpl); + +ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendObjectInvalidHandle, + CreateDynamicBackendObjectInvalidHandleTestImpl); +ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendObjectInvalidInterface1, + CreateDynamicBackendObjectInvalidInterface1TestImpl); +ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendObjectInvalidInterface2, + CreateDynamicBackendObjectInvalidInterface2TestImpl); +ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendObjectInvalidInterface3, + CreateDynamicBackendObjectInvalidInterface3TestImpl); +ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendObjectInvalidInterface4, + CreateDynamicBackendObjectInvalidInterface4TestImpl); +ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendObjectInvalidInterface5, + CreateDynamicBackendObjectInvalidInterface5TestImpl); +ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendObjectInvalidInterface6, + CreateDynamicBackendObjectInvalidInterface6TestImpl); +ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendObjectInvalidInterface7, + CreateDynamicBackendObjectInvalidInterface7TestImpl); + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.hpp b/src/backends/backendsCommon/test/DynamicBackendTests.hpp index 9835113458..1b3edc5e22 100644 --- a/src/backends/backendsCommon/test/DynamicBackendTests.hpp +++ b/src/backends/backendsCommon/test/DynamicBackendTests.hpp @@ -5,17 +5,27 @@ #pragma once +#include #include -#include +#include +#include #include #include #include -static std::string g_TestSharedObjectSubDir = "src/backends/backendsCommon/test/"; -static std::string g_TestSharedObjectFileName = "libarmnnTestSharedObject.so"; +static std::string g_TestSharedObjectSubDir = "src/backends/backendsCommon/test/"; +static std::string g_TestSharedObjectFileName = "libarmnnTestSharedObject.so"; +static std::string g_TestValidTestDynamicBackendFileName = "libarmnnValidTestDynamicBackend.so"; +static std::string g_TestInvalidTestDynamicBackend1FileName = "libarmnnInvalidTestDynamicBackend1.so"; +static std::string g_TestInvalidTestDynamicBackend2FileName = "libarmnnInvalidTestDynamicBackend2.so"; +static std::string g_TestInvalidTestDynamicBackend3FileName = "libarmnnInvalidTestDynamicBackend3.so"; +static std::string g_TestInvalidTestDynamicBackend4FileName = "libarmnnInvalidTestDynamicBackend4.so"; +static std::string g_TestInvalidTestDynamicBackend5FileName = "libarmnnInvalidTestDynamicBackend5.so"; +static std::string g_TestInvalidTestDynamicBackend6FileName = "libarmnnInvalidTestDynamicBackend6.so"; +static std::string g_TestInvalidTestDynamicBackend7FileName = "libarmnnInvalidTestDynamicBackend7.so"; std::string GetTestFilePath(const std::string& fileName) { @@ -209,3 +219,196 @@ void BackendVersioningTestImpl() BOOST_TEST(earlierMinorBackendVersion <= backendApiVersion); BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, earlierMinorBackendVersion) == true); } + +void CreateValidDynamicBackendObjectTestImpl() +{ + // Valid shared object handle + // Correct name mangling + // Correct interface + // Correct backend implementation + + using namespace armnn; + + std::string sharedObjectFilePath = GetTestFilePath(g_TestValidTestDynamicBackendFileName); + + void* sharedObjectHandle = nullptr; + BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath)); + BOOST_TEST((sharedObjectHandle != nullptr)); + + std::unique_ptr dynamicBackend; + BOOST_CHECK_NO_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle))); + BOOST_TEST((dynamicBackend != nullptr)); + + BackendId dynamicBackendId; + BOOST_CHECK_NO_THROW(dynamicBackendId = dynamicBackend->GetBackendId()); + BOOST_TEST((dynamicBackendId == "ValidTestDynamicBackend")); + + BackendVersion dynamicBackendVersion; + BOOST_CHECK_NO_THROW(dynamicBackendVersion = dynamicBackend->GetBackendVersion()); + BOOST_TEST((dynamicBackendVersion == BackendVersion({ 1, 0 }))); + + IBackendInternalUniquePtr dynamicBackendInstance; + BOOST_CHECK_NO_THROW(dynamicBackendInstance = dynamicBackend->GetBackend()); + BOOST_TEST((dynamicBackendInstance != nullptr)); + + BOOST_TEST((dynamicBackendInstance->GetId() == "ValidTestDynamicBackend")); +} + +void CreateDynamicBackendObjectInvalidHandleTestImpl() +{ + // Invalid (null) shared object handle + + using namespace armnn; + + void* sharedObjectHandle = nullptr; + std::unique_ptr dynamicBackend; + BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), InvalidArgumentException); + BOOST_TEST((dynamicBackend == nullptr)); +} + +void CreateDynamicBackendObjectInvalidInterface1TestImpl() +{ + // Valid shared object handle + // Wrong (not C-style) name mangling + + using namespace armnn; + + std::string sharedObjectFilePath = GetTestFilePath(g_TestInvalidTestDynamicBackend1FileName); + + void* sharedObjectHandle = nullptr; + BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath)); + BOOST_TEST((sharedObjectHandle != nullptr)); + + std::unique_ptr dynamicBackend; + BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException); + BOOST_TEST((dynamicBackend == nullptr)); +} + +void CreateDynamicBackendObjectInvalidInterface2TestImpl() +{ + // Valid shared object handle + // Correct name mangling + // Wrong interface (missing GetBackendId()) + + using namespace armnn; + + std::string sharedObjectFilePath = GetTestFilePath(g_TestInvalidTestDynamicBackend2FileName); + + void* sharedObjectHandle = nullptr; + BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath)); + BOOST_TEST((sharedObjectHandle != nullptr)); + + std::unique_ptr dynamicBackend; + BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException); + BOOST_TEST((dynamicBackend == nullptr)); +} + +void CreateDynamicBackendObjectInvalidInterface3TestImpl() +{ + // Valid shared object handle + // Correct name mangling + // Wrong interface (missing GetVersion()) + + using namespace armnn; + + std::string sharedObjectFilePath = GetTestFilePath(g_TestInvalidTestDynamicBackend3FileName); + + void* sharedObjectHandle = nullptr; + BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath)); + BOOST_TEST((sharedObjectHandle != nullptr)); + + std::unique_ptr dynamicBackend; + BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException); + BOOST_TEST((dynamicBackend == nullptr)); +} + +void CreateDynamicBackendObjectInvalidInterface4TestImpl() +{ + // Valid shared object handle + // Correct name mangling + // Wrong interface (missing BackendFactory()) + + using namespace armnn; + + std::string sharedObjectFilePath = GetTestFilePath(g_TestInvalidTestDynamicBackend4FileName); + + void* sharedObjectHandle = nullptr; + BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath)); + BOOST_TEST((sharedObjectHandle != nullptr)); + + std::unique_ptr dynamicBackend; + BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException); + BOOST_TEST((dynamicBackend == nullptr)); +} + +void CreateDynamicBackendObjectInvalidInterface5TestImpl() +{ + // Valid shared object handle + // Correct name mangling + // Correct interface + // Invalid (null) backend id returned by GetBackendId() + + using namespace armnn; + + std::string sharedObjectFilePath = GetTestFilePath(g_TestInvalidTestDynamicBackend5FileName); + + void* sharedObjectHandle = nullptr; + BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath)); + BOOST_TEST((sharedObjectHandle != nullptr)); + + std::unique_ptr dynamicBackend; + BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException); + BOOST_TEST((dynamicBackend == nullptr)); +} + +void CreateDynamicBackendObjectInvalidInterface6TestImpl() +{ + // Valid shared object handle + // Correct name mangling + // Correct interface + // Invalid (null) backend instance returned by BackendFactory() + + using namespace armnn; + + std::string sharedObjectFilePath = GetTestFilePath(g_TestInvalidTestDynamicBackend6FileName); + + void* sharedObjectHandle = nullptr; + BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath)); + BOOST_TEST((sharedObjectHandle != nullptr)); + + std::unique_ptr dynamicBackend; + BOOST_CHECK_NO_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle))); + BOOST_TEST((dynamicBackend != nullptr)); + + BackendId dynamicBackendId; + BOOST_CHECK_NO_THROW(dynamicBackendId = dynamicBackend->GetBackendId()); + BOOST_TEST((dynamicBackendId == "InvalidTestDynamicBackend")); + + BackendVersion dynamicBackendVersion; + BOOST_CHECK_NO_THROW(dynamicBackendVersion = dynamicBackend->GetBackendVersion()); + BOOST_TEST((dynamicBackendVersion == BackendVersion({ 1, 0 }))); + + IBackendInternalUniquePtr dynamicBackendInstance; + BOOST_CHECK_THROW(dynamicBackendInstance = dynamicBackend->GetBackend(), RuntimeException); + BOOST_TEST((dynamicBackendInstance == nullptr)); +} + +void CreateDynamicBackendObjectInvalidInterface7TestImpl() +{ + // Valid shared object handle + // Correct name mangling + // Correct interface + // Invalid (incompatible backend API version) backend instance returned by BackendFactory() + + using namespace armnn; + + std::string sharedObjectFilePath = GetTestFilePath(g_TestInvalidTestDynamicBackend7FileName); + + void* sharedObjectHandle = nullptr; + BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath)); + BOOST_TEST((sharedObjectHandle != nullptr)); + + std::unique_ptr dynamicBackend; + BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException); + BOOST_TEST((dynamicBackend == nullptr)); +} diff --git a/src/backends/backendsCommon/test/TestDynamicBackend.cpp b/src/backends/backendsCommon/test/TestDynamicBackend.cpp new file mode 100644 index 0000000000..7fd996fae8 --- /dev/null +++ b/src/backends/backendsCommon/test/TestDynamicBackend.cpp @@ -0,0 +1,95 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "TestDynamicBackend.hpp" + +#include + +constexpr const char* TestDynamicBackendId() +{ +#if defined(VALID_TEST_DYNAMIC_BACKEND) + + return "ValidTestDynamicBackend"; + +#else + + return "InvalidTestDynamicBackend"; + +#endif +} + +class TestDynamicBackend : public armnn::IBackendInternal +{ +public: + TestDynamicBackend() + : m_BackendId(TestDynamicBackendId()) + {} + + const armnn::BackendId& GetId() const override + { + return m_BackendId; + } + IWorkloadFactoryPtr CreateWorkloadFactory(const IMemoryManagerSharedPtr& memoryManager) const override + { + return IWorkloadFactoryPtr{}; + } + ILayerSupportSharedPtr GetLayerSupport() const override + { + return ILayerSupportSharedPtr{}; + } + +private: + armnn::BackendId m_BackendId; +}; + +const char* GetBackendId() +{ +#if defined(INVALID_TEST_DYNAMIC_BACKEND_5) + + // Return an invalid backend id + return nullptr; + +#else + + // Return a valid backend id + return TestDynamicBackendId(); + +#endif +} + +void GetVersion(uint32_t* outMajor, uint32_t* outMinor) +{ + if (!outMajor || !outMinor) + { + return; + } + +#if defined(INVALID_TEST_DYNAMIC_BACKEND_7) + + *outMajor = 0; + *outMinor = 7; + +#else + + *outMajor = 1; + *outMinor = 0; + +#endif +} + +void* BackendFactory() +{ +#if defined(INVALID_TEST_DYNAMIC_BACKEND_6) + + // Return an invalid backend instance + return nullptr; + +#else + + // Return a non-null backend instance + return new TestDynamicBackend(); + +#endif +} diff --git a/src/backends/backendsCommon/test/TestDynamicBackend.hpp b/src/backends/backendsCommon/test/TestDynamicBackend.hpp new file mode 100644 index 0000000000..599ca16636 --- /dev/null +++ b/src/backends/backendsCommon/test/TestDynamicBackend.hpp @@ -0,0 +1,67 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include + +#if defined(VALID_TEST_DYNAMIC_BACKEND) + +// Correct dynamic backend interface +extern "C" +{ +const char* GetBackendId(); +void GetVersion(uint32_t* outMajor, uint32_t* outMinor); +void* BackendFactory(); +} + +#elif defined(INVALID_TEST_DYNAMIC_BACKEND_1) + +// Wrong external linkage: expected C-style name mangling +extern const char* GetBackendId(); +extern void GetVersion(uint32_t* outMajor, uint32_t* outMinor); +extern void* BackendFactory(); + +#else + +extern "C" +{ + +#if defined(INVALID_TEST_DYNAMIC_BACKEND_2) + +// Invalid interface: missing "GetBackendId()" +void GetVersion(uint32_t* outMajor, uint32_t* outMinor); +void* BackendFactory(); + +#elif defined(INVALID_TEST_DYNAMIC_BACKEND_3) + +// Invalid interface: missing "GetVersion()" +const char* GetBackendId(); +void* BackendFactory(); + +#elif defined(INVALID_TEST_DYNAMIC_BACKEND_4) + +// Invalid interface: missing "BackendFactory()" +const char* GetBackendId(); +void GetVersion(uint32_t* outMajor, uint32_t* outMinor); + +#elif defined(INVALID_TEST_DYNAMIC_BACKEND_5) || \ + defined(INVALID_TEST_DYNAMIC_BACKEND_6) || \ + defined(INVALID_TEST_DYNAMIC_BACKEND_7) + +// The interface is correct, the corresponding invalid changes are in the TestDynamicBackend.cpp file +const char* GetBackendId(); +void GetVersion(uint32_t* outMajor, uint32_t* outMinor); +void* BackendFactory(); + +#else + +#error "Invalid or missing configuration macro for the TestDynamicBackend object" + +#endif + +} + +#endif -- cgit v1.2.1