From 0c2b2897cb65b562b97014ae748e91d8b9a3d3b4 Mon Sep 17 00:00:00 2001 From: Matteo Martincigh Date: Mon, 5 Aug 2019 14:12:11 +0100 Subject: IVGCVSW-3596 Register the dynamic backends in the BackendRegistry * Added getter for the factory function in the DynamicBackend class * Added new RegisterDynamicBackends method in utils class * Added dynamic backend registration process in the Runtime class * Added new dummy dynamic backend objects for testing * Added unit tests for dynamic backend registration * Added convenience methods to BackendId Change-Id: I01e147d1d6f01bf56747ad946f73f867af5770c4 Signed-off-by: Matteo Martincigh --- include/armnn/BackendId.hpp | 3 + src/armnn/Runtime.cpp | 6 +- src/armnn/Runtime.hpp | 8 +- src/backends/backendsCommon/DynamicBackend.cpp | 34 +- src/backends/backendsCommon/DynamicBackend.hpp | 6 +- .../backendsCommon/DynamicBackendUtils.cpp | 68 +++- .../backendsCommon/DynamicBackendUtils.hpp | 3 + src/backends/backendsCommon/test/CMakeLists.txt | 24 ++ .../backendsCommon/test/DynamicBackendTests.cpp | 5 + .../backendsCommon/test/DynamicBackendTests.hpp | 447 ++++++++++++++++++--- .../backendsCommon/test/TestDynamicBackend.cpp | 15 + .../backendsCommon/test/TestDynamicBackend.hpp | 15 +- 12 files changed, 564 insertions(+), 70 deletions(-) diff --git a/include/armnn/BackendId.hpp b/include/armnn/BackendId.hpp index 7dd1460bc1..59d4ac1d45 100644 --- a/include/armnn/BackendId.hpp +++ b/include/armnn/BackendId.hpp @@ -129,6 +129,9 @@ public: const std::string& Get() const { return m_Id; } + bool IsEmpty() const { return m_Id.empty(); } + bool IsUndefined() const { return m_Id == GetComputeDeviceAsCString(Compute::Undefined); } + private: std::string m_Id; }; diff --git a/src/armnn/Runtime.cpp b/src/armnn/Runtime.cpp index 3505030273..ddfa6b4ffd 100644 --- a/src/armnn/Runtime.cpp +++ b/src/armnn/Runtime.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include @@ -253,7 +252,10 @@ void Runtime::LoadDynamicBackends(const std::string& overrideBackendPath) std::vector sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths); // Create a list of dynamic backends - DynamicBackendUtils::CreateDynamicBackends(sharedObjects); + m_DynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects); + + // Register the dynamic backends in the backend registry + DynamicBackendUtils::RegisterDynamicBackends(m_DynamicBackends); } } // namespace armnn diff --git a/src/armnn/Runtime.hpp b/src/armnn/Runtime.hpp index 624304ec0a..35684f1f78 100644 --- a/src/armnn/Runtime.hpp +++ b/src/armnn/Runtime.hpp @@ -6,11 +6,14 @@ #include "LoadedNetwork.hpp" #include "DeviceSpec.hpp" + #include #include #include #include +#include + #include #include @@ -100,6 +103,9 @@ private: int m_NetworkIdCounter; DeviceSpec m_DeviceSpec; + + /// List of dynamic backends loaded in the runtime + std::vector m_DynamicBackends; }; -} +} // namespace armnn diff --git a/src/backends/backendsCommon/DynamicBackend.cpp b/src/backends/backendsCommon/DynamicBackend.cpp index 06d819b9a7..c576199e1f 100644 --- a/src/backends/backendsCommon/DynamicBackend.cpp +++ b/src/backends/backendsCommon/DynamicBackend.cpp @@ -69,19 +69,23 @@ BackendVersion DynamicBackend::GetBackendVersion() } IBackendInternalUniquePtr DynamicBackend::GetBackend() +{ + // This call throws in case of error + return CreateBackend(); +} + +BackendRegistry::FactoryFunction DynamicBackend::GetFactoryFunction() { if (m_BackendFactoryFunction == nullptr) { - throw RuntimeException("GetBackend error: invalid function pointer"); + throw RuntimeException("GetFactoryFunction error: invalid function pointer"); } - auto backendPointer = reinterpret_cast(m_BackendFactoryFunction()); - if (backendPointer == nullptr) + return [this]() -> IBackendInternalUniquePtr { - throw RuntimeException("GetBackend error: backend instance must not be null"); - } - - return std::unique_ptr(backendPointer); + // This call throws in case of error + return CreateBackend(); + }; } template @@ -108,4 +112,20 @@ BackendFunctionType DynamicBackend::SetFunctionPointer(const std::string& backen return functionPointer; } +IBackendInternalUniquePtr DynamicBackend::CreateBackend() +{ + if (m_BackendFactoryFunction == nullptr) + { + throw RuntimeException("CreateBackend error: invalid function pointer"); + } + + auto backendPointer = reinterpret_cast(m_BackendFactoryFunction()); + if (backendPointer == nullptr) + { + throw RuntimeException("CreateBackend error: backend instance must not be null"); + } + + return std::unique_ptr(backendPointer); +} + } // namespace armnn diff --git a/src/backends/backendsCommon/DynamicBackend.hpp b/src/backends/backendsCommon/DynamicBackend.hpp index b202309c31..34c001958d 100644 --- a/src/backends/backendsCommon/DynamicBackend.hpp +++ b/src/backends/backendsCommon/DynamicBackend.hpp @@ -6,6 +6,7 @@ #pragma once #include "IBackendInternal.hpp" +#include "BackendRegistry.hpp" #include #include @@ -13,7 +14,7 @@ namespace armnn { -class DynamicBackend +class DynamicBackend final { public: using HandleCloser = std::function; @@ -25,10 +26,13 @@ public: BackendId GetBackendId(); BackendVersion GetBackendVersion(); IBackendInternalUniquePtr GetBackend(); + BackendRegistry::FactoryFunction GetFactoryFunction(); private: + /// Private utility functions template BackendFunctionType SetFunctionPointer(const std::string& backendFunctionName); + IBackendInternalUniquePtr CreateBackend(); /// Backend function pointer types using IdFunctionType = const char*(*)(); diff --git a/src/backends/backendsCommon/DynamicBackendUtils.cpp b/src/backends/backendsCommon/DynamicBackendUtils.cpp index 57a605608c..38ac5ad6af 100644 --- a/src/backends/backendsCommon/DynamicBackendUtils.cpp +++ b/src/backends/backendsCommon/DynamicBackendUtils.cpp @@ -281,7 +281,6 @@ std::vector DynamicBackendUtils::CreateDynamicBackends(const { BOOST_LOG_TRIVIAL(warning) << "Invalid dynamic backend object for the shared object file \"" << sharedObject << "\""; - continue; } @@ -292,4 +291,71 @@ std::vector DynamicBackendUtils::CreateDynamicBackends(const return dynamicBackends; } +void DynamicBackendUtils::RegisterDynamicBackends(const std::vector& dynamicBackends) +{ + // Get a reference of the backend registry + BackendRegistry& backendRegistry = BackendRegistryInstance(); + + // Register the dynamic backends in the backend registry + RegisterDynamicBackendsImpl(backendRegistry, dynamicBackends); +} + +void DynamicBackendUtils::RegisterDynamicBackendsImpl(BackendRegistry& backendRegistry, + const std::vector& dynamicBackends) +{ + // Register the dynamic backends in the backend registry + for (const DynamicBackendPtr& dynamicBackend : dynamicBackends) + { + BackendId dynamicBackendId; + try + { + dynamicBackendId = dynamicBackend->GetBackendId(); + } + catch (const RuntimeException& e) + { + BOOST_LOG_TRIVIAL(warning) << "Cannot register dynamic backend, " + << "an error has occurred when getting the backend id: " << e.what(); + continue; + } + if (dynamicBackendId.IsEmpty() || + dynamicBackendId.IsUndefined()) + { + BOOST_LOG_TRIVIAL(warning) << "Cannot register dynamic backend, invalid backend id: " << dynamicBackendId; + continue; + } + + // Check whether the dynamic backend is already registered + bool backendAlreadyRegistered = backendRegistry.IsBackendRegistered(dynamicBackendId); + if (backendAlreadyRegistered) + { + BOOST_LOG_TRIVIAL(warning) << "Cannot register dynamic backend \"" << dynamicBackendId + << "\": backend already registered"; + continue; + } + + // Get the dynamic backend factory function + BackendRegistry::FactoryFunction dynamicBackendFactoryFunction = nullptr; + try + { + dynamicBackendFactoryFunction = dynamicBackend->GetFactoryFunction(); + } + catch (const RuntimeException& e) + { + BOOST_LOG_TRIVIAL(warning) << "Cannot register dynamic backend \"" << dynamicBackendId + << "\": an error has occurred when getting the backend factory function: " + << e.what(); + continue; + } + if (dynamicBackendFactoryFunction == nullptr) + { + BOOST_LOG_TRIVIAL(warning) << "Cannot register dynamic backend \"" << dynamicBackendId + << "\": invalid backend factory function"; + continue; + } + + // Register the dynamic backend + backendRegistry.Register(dynamicBackendId, dynamicBackendFactoryFunction); + } +} + } // namespace armnn diff --git a/src/backends/backendsCommon/DynamicBackendUtils.hpp b/src/backends/backendsCommon/DynamicBackendUtils.hpp index 9c10df7efc..187b0b1eab 100644 --- a/src/backends/backendsCommon/DynamicBackendUtils.hpp +++ b/src/backends/backendsCommon/DynamicBackendUtils.hpp @@ -39,11 +39,14 @@ public: static std::vector GetSharedObjects(const std::vector& backendPaths); static std::vector CreateDynamicBackends(const std::vector& sharedObjects); + static void RegisterDynamicBackends(const std::vector& dynamicBackends); protected: /// Protected methods for testing purposes static bool IsBackendCompatibleImpl(const BackendVersion& backendApiVersion, const BackendVersion& backendVersion); static std::vector GetBackendPathsImpl(const std::string& backendPaths); + static void RegisterDynamicBackendsImpl(BackendRegistry& backendRegistry, + const std::vector& dynamicBackends); private: static std::string GetDlError(); diff --git a/src/backends/backendsCommon/test/CMakeLists.txt b/src/backends/backendsCommon/test/CMakeLists.txt index 6714a20122..f5173564f2 100644 --- a/src/backends/backendsCommon/test/CMakeLists.txt +++ b/src/backends/backendsCommon/test/CMakeLists.txt @@ -215,6 +215,14 @@ target_link_libraries(Arm_TestValid4_backend armnn) set_target_properties(Arm_TestValid4_backend PROPERTIES PREFIX "") set_target_properties(Arm_TestValid4_backend PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath6) +add_library_ex(Arm_TestValid5_backend MODULE ${testDynamicBackend_sources}) +target_compile_definitions(Arm_TestValid5_backend PRIVATE -DVALID_TEST_DYNAMIC_BACKEND_5) +target_include_directories(Arm_TestValid5_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(Arm_TestValid5_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) +target_link_libraries(Arm_TestValid5_backend armnn) +set_target_properties(Arm_TestValid5_backend PROPERTIES PREFIX "") +set_target_properties(Arm_TestValid5_backend PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath6) + add_library_ex(Arm_TestInvalid9_backend MODULE ${testDynamicBackend_sources}) target_compile_definitions(Arm_TestInvalid9_backend PRIVATE -DINVALID_TEST_DYNAMIC_BACKEND_9) target_include_directories(Arm_TestInvalid9_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) @@ -223,4 +231,20 @@ target_link_libraries(Arm_TestInvalid9_backend armnn) set_target_properties(Arm_TestInvalid9_backend PROPERTIES PREFIX "") set_target_properties(Arm_TestInvalid9_backend PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath6) +add_library_ex(Arm_TestInvalid10_backend MODULE ${testDynamicBackend_sources}) +target_compile_definitions(Arm_TestInvalid10_backend PRIVATE -DINVALID_TEST_DYNAMIC_BACKEND_10) +target_include_directories(Arm_TestInvalid10_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(Arm_TestInvalid10_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) +target_link_libraries(Arm_TestInvalid10_backend armnn) +set_target_properties(Arm_TestInvalid10_backend PROPERTIES PREFIX "") +set_target_properties(Arm_TestInvalid10_backend PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath9) + +add_library_ex(Arm_TestInvalid11_backend MODULE ${testDynamicBackend_sources}) +target_compile_definitions(Arm_TestInvalid11_backend PRIVATE -DINVALID_TEST_DYNAMIC_BACKEND_11) +target_include_directories(Arm_TestInvalid11_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(Arm_TestInvalid11_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) +target_link_libraries(Arm_TestInvalid11_backend armnn) +set_target_properties(Arm_TestInvalid11_backend PROPERTIES PREFIX "") +set_target_properties(Arm_TestInvalid11_backend PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath9) + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath7) diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.cpp b/src/backends/backendsCommon/test/DynamicBackendTests.cpp index b5d159ab13..21ce2dbde4 100644 --- a/src/backends/backendsCommon/test/DynamicBackendTests.cpp +++ b/src/backends/backendsCommon/test/DynamicBackendTests.cpp @@ -50,4 +50,9 @@ ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendsNoPaths, CreateDynamicBackendsNoPath ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendsAllInvalid, CreateDynamicBackendsAllInvalidTestImpl); ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendsMixedTypes, CreateDynamicBackendsMixedTypesTestImpl); +ARMNN_SIMPLE_TEST_CASE(RegisterSingleDynamicBackend, RegisterSingleDynamicBackendTestImpl); +ARMNN_SIMPLE_TEST_CASE(RegisterMultipleDynamicBackends, RegisterMultipleDynamicBackendsTestImpl); +ARMNN_SIMPLE_TEST_CASE(RegisterMultipleInvalidDynamicBackends, RegisterMultipleInvalidDynamicBackendsTestImpl); +ARMNN_SIMPLE_TEST_CASE(RegisterMixedDynamicBackends, RegisterMixedDynamicBackendsTestImpl); + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.hpp b/src/backends/backendsCommon/test/DynamicBackendTests.hpp index e3fbe311bc..ae922bc26d 100644 --- a/src/backends/backendsCommon/test/DynamicBackendTests.hpp +++ b/src/backends/backendsCommon/test/DynamicBackendTests.hpp @@ -36,17 +36,43 @@ static std::string g_TestInvalidTestDynamicBackend7FileName = "libInvalidTestDyn static std::string g_TestValidBackend2FileName = "Arm_TestValid2_backend.so"; static std::string g_TestValidBackend3FileName = "Arm_TestValid3_backend.so"; static std::string g_TestValidBackend4FileName = "Arm_TestValid4_backend.so"; +static std::string g_TestValidBackend5FileName = "Arm_TestValid5_backend.so"; static std::string g_TestInvalidBackend8FileName = "Arm_TestInvalid8_backend.so"; static std::string g_TestInvalidBackend9FileName = "Arm_TestInvalid9_backend.so"; +static std::string g_TestInvalidBackend10FileName = "Arm_TestInvalid10_backend.so"; +static std::string g_TestInvalidBackend11FileName = "Arm_TestInvalid11_backend.so"; + +static std::string g_TestDynamicBackendsSubDir1 = "backendsTestPath1/"; +static std::string g_TestDynamicBackendsSubDir2 = "backendsTestPath2/"; +static std::string g_TestDynamicBackendsSubDir3 = "backendsTestPath3/"; +static std::string g_TestDynamicBackendsSubDir4 = "backendsTestPath4/"; +static std::string g_TestDynamicBackendsSubDir5 = "backendsTestPath5/"; +static std::string g_TestDynamicBackendsSubDir6 = "backendsTestPath6/"; +static std::string g_TestDynamicBackendsSubDir7 = "backendsTestPath7/"; +static std::string g_TestDynamicBackendsSubDir8 = "backendsTestPath8/"; +static std::string g_TestDynamicBackendsSubDir9 = "backendsTestPath9/"; + +// Wrapper class used for testing +class TestDynamicBackendUtils : public armnn::DynamicBackendUtils +{ +public: + static bool IsBackendCompatibleTest(const armnn::BackendVersion& backendApiVersion, + const armnn::BackendVersion& backendVersion) + { + return IsBackendCompatibleImpl(backendApiVersion, backendVersion); + } -static std::string g_TestDynamicBackendsFileParsingSubDir1 = "backendsTestPath1/"; -static std::string g_TestDynamicBackendsFileParsingSubDir2 = "backendsTestPath2/"; -static std::string g_TestDynamicBackendsFileParsingSubDir3 = "backendsTestPath3/"; -static std::string g_TestDynamicBackendsFileParsingSubDir4 = "backendsTestPath4/"; -static std::string g_TestDynamicBackendsFileParsingSubDir5 = "backendsTestPath5/"; -static std::string g_TestDynamicBackendsFileParsingSubDir6 = "backendsTestPath6/"; -static std::string g_TestDynamicBackendsFileParsingSubDir7 = "backendsTestPath7/"; -static std::string g_TestDynamicBackendsFileParsingSubDir8 = "backendsTestPath8/"; + static std::vector GetBackendPathsImplTest(const std::string& path) + { + return GetBackendPathsImpl(path); + } + + static void RegisterDynamicBackendsImplTest(armnn::BackendRegistry& backendRegistry, + const std::vector& dynamicBackends) + { + RegisterDynamicBackendsImpl(backendRegistry, dynamicBackends); + } +}; std::string GetTestDirectoryBasePath() { @@ -222,16 +248,6 @@ void BackendVersioningTestImpl() { using namespace armnn; - class TestDynamicBackendUtils : public DynamicBackendUtils - { - public: - static bool IsBackendCompatibleTest(const BackendVersion& backendApiVersion, - const BackendVersion& backendVersion) - { - return IsBackendCompatibleImpl(backendApiVersion, backendVersion); - } - }; - // The backend API version used for the tests BackendVersion backendApiVersion{ 2, 4 }; @@ -297,11 +313,20 @@ void CreateValidDynamicBackendObjectTestImpl() BOOST_CHECK_NO_THROW(dynamicBackendVersion = dynamicBackend->GetBackendVersion()); BOOST_TEST((dynamicBackendVersion == IBackendInternal::GetApiVersion())); - IBackendInternalUniquePtr dynamicBackendInstance; - BOOST_CHECK_NO_THROW(dynamicBackendInstance = dynamicBackend->GetBackend()); - BOOST_TEST((dynamicBackendInstance != nullptr)); + IBackendInternalUniquePtr dynamicBackendInstance1; + BOOST_CHECK_NO_THROW(dynamicBackendInstance1 = dynamicBackend->GetBackend()); + BOOST_TEST((dynamicBackendInstance1 != nullptr)); + + BackendRegistry::FactoryFunction dynamicBackendFactoryFunction = nullptr; + BOOST_CHECK_NO_THROW(dynamicBackendFactoryFunction = dynamicBackend->GetFactoryFunction()); + BOOST_TEST((dynamicBackendFactoryFunction != nullptr)); + + IBackendInternalUniquePtr dynamicBackendInstance2; + BOOST_CHECK_NO_THROW(dynamicBackendInstance2 = dynamicBackendFactoryFunction()); + BOOST_TEST((dynamicBackendInstance2 != nullptr)); - BOOST_TEST((dynamicBackendInstance->GetId() == "ValidTestDynamicBackend")); + BOOST_TEST((dynamicBackendInstance1->GetId() == "ValidTestDynamicBackend")); + BOOST_TEST((dynamicBackendInstance2->GetId() == "ValidTestDynamicBackend")); } void CreateDynamicBackendObjectInvalidHandleTestImpl() @@ -444,9 +469,17 @@ void CreateDynamicBackendObjectInvalidInterface6TestImpl() 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)); + IBackendInternalUniquePtr dynamicBackendInstance1; + BOOST_CHECK_THROW(dynamicBackendInstance1 = dynamicBackend->GetBackend(), RuntimeException); + BOOST_TEST((dynamicBackendInstance1 == nullptr)); + + BackendRegistry::FactoryFunction dynamicBackendFactoryFunction = nullptr; + BOOST_CHECK_NO_THROW(dynamicBackendFactoryFunction = dynamicBackend->GetFactoryFunction()); + BOOST_TEST((dynamicBackendFactoryFunction != nullptr)); + + IBackendInternalUniquePtr dynamicBackendInstance2; + BOOST_CHECK_THROW(dynamicBackendInstance2 = dynamicBackendFactoryFunction(), RuntimeException); + BOOST_TEST((dynamicBackendInstance2 == nullptr)); } void CreateDynamicBackendObjectInvalidInterface7TestImpl() @@ -482,25 +515,16 @@ void GetBackendPathsTestImpl() // ├─ backendsTestPath3/ -> exists, but empty // └─ backendsTestPath4/ -> does not exist - std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir1); - std::string subDir2 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir2); - std::string subDir3 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir3); - std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir4); + std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsSubDir1); + std::string subDir2 = GetTestSubDirectory(g_TestDynamicBackendsSubDir2); + std::string subDir3 = GetTestSubDirectory(g_TestDynamicBackendsSubDir3); + std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsSubDir4); BOOST_CHECK(exists(subDir1)); BOOST_CHECK(exists(subDir2)); BOOST_CHECK(exists(subDir3)); BOOST_CHECK(!exists(subDir4)); - class TestDynamicBackendUtils : public DynamicBackendUtils - { - public: - static std::vector GetBackendPathsImplTest(const std::string& path) - { - return GetBackendPathsImpl(path); - } - }; - // No path BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest("").empty()); @@ -564,8 +588,8 @@ void GetBackendPathsOverrideTestImpl() using namespace armnn; using namespace boost::filesystem; - std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir1); - std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir4); + std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsSubDir1); + std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsSubDir4); BOOST_CHECK(exists(subDir1)); BOOST_CHECK(!exists(subDir4)); @@ -629,10 +653,10 @@ void GetSharedObjectsTestImpl() // // Arm_GpuAcc_backend.so -> valid (but duplicated from backendsTestPath1/) - std::string testDynamicBackendsSubDir1 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir1); - std::string testDynamicBackendsSubDir2 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir2); - std::string testDynamicBackendsSubDir3 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir3); - std::string testDynamicBackendsSubDir4 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir4); + std::string testDynamicBackendsSubDir1 = GetTestSubDirectory(g_TestDynamicBackendsSubDir1); + std::string testDynamicBackendsSubDir2 = GetTestSubDirectory(g_TestDynamicBackendsSubDir2); + std::string testDynamicBackendsSubDir3 = GetTestSubDirectory(g_TestDynamicBackendsSubDir3); + std::string testDynamicBackendsSubDir4 = GetTestSubDirectory(g_TestDynamicBackendsSubDir4); BOOST_CHECK(exists(testDynamicBackendsSubDir1)); BOOST_CHECK(exists(testDynamicBackendsSubDir2)); BOOST_CHECK(exists(testDynamicBackendsSubDir3)); @@ -676,7 +700,7 @@ void CreateDynamicBackendsTestImpl() using namespace armnn; using namespace boost::filesystem; - // The test covers three directories: + // The test covers four directories: // /src/backends/backendsCommon/test/ // ├─ backendsTestPath5/ -> exists, contains files // ├─ backendsTestPath6/ -> exists, contains files @@ -695,14 +719,15 @@ void CreateDynamicBackendsTestImpl() // Arm_TestValid4_backend.so -> valid (it has a different filename, // but it has the same backend id of Arm_TestValid2_backend.so // and the same version) + // Arm_TestValid5_backend.so -> valid (basic backend name) // Arm_TestInvalid9_backend.so -> not valid (it has a different filename, // but it has the same backend id of Arm_TestValid2_backend.so // and a version incompatible with the Backend API) - std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir5); - std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir6); - std::string testDynamicBackendsSubDir7 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir7); - std::string testDynamicBackendsSubDir8 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir8); + std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5); + std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6); + std::string testDynamicBackendsSubDir7 = GetTestSubDirectory(g_TestDynamicBackendsSubDir7); + std::string testDynamicBackendsSubDir8 = GetTestSubDirectory(g_TestDynamicBackendsSubDir8); BOOST_CHECK(exists(testDynamicBackendsSubDir5)); BOOST_CHECK(exists(testDynamicBackendsSubDir6)); BOOST_CHECK(exists(testDynamicBackendsSubDir7)); @@ -718,17 +743,19 @@ void CreateDynamicBackendsTestImpl() std::vector sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths); std::vector dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects); - BOOST_TEST(dynamicBackends.size() == 4); + BOOST_TEST(dynamicBackends.size() == 5); BOOST_TEST((dynamicBackends[0] != nullptr)); BOOST_TEST((dynamicBackends[1] != nullptr)); BOOST_TEST((dynamicBackends[2] != nullptr)); BOOST_TEST((dynamicBackends[3] != nullptr)); + BOOST_TEST((dynamicBackends[4] != nullptr)); // Duplicates are allowed here, they will be skipped later during the backend registration BOOST_TEST((dynamicBackends[0]->GetBackendId() == "TestValid2")); BOOST_TEST((dynamicBackends[1]->GetBackendId() == "TestValid3")); BOOST_TEST((dynamicBackends[2]->GetBackendId() == "TestValid2")); // From duplicate Arm_TestValid2_backend.so BOOST_TEST((dynamicBackends[3]->GetBackendId() == "TestValid2")); // From Arm_TestValid4_backend.so + BOOST_TEST((dynamicBackends[4]->GetBackendId() == "TestValid5")); } void CreateDynamicBackendsNoPathsTestImpl() @@ -760,8 +787,8 @@ void CreateDynamicBackendsMixedTypesTestImpl() using namespace armnn; using namespace boost::filesystem; - std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir5); - std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir6); + std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5); + std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6); BOOST_CHECK(exists(testDynamicBackendsSubDir5)); BOOST_CHECK(exists(testDynamicBackendsSubDir6)); @@ -788,3 +815,319 @@ void CreateDynamicBackendsMixedTypesTestImpl() BOOST_TEST((dynamicBackends[0] != nullptr)); BOOST_TEST((dynamicBackends[0]->GetBackendId() == "TestValid2")); } + +void RegisterSingleDynamicBackendTestImpl() +{ + using namespace armnn; + using namespace boost::filesystem; + + // Register one valid dynamic backend + + // Dummy registry used for testing + BackendRegistry backendRegistry; + BOOST_TEST(backendRegistry.Size() == 0); + + std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5); + BOOST_CHECK(exists(testDynamicBackendsSubDir5)); + + std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend2FileName); + BOOST_CHECK(exists(testValidBackend2FilePath)); + + std::vector sharedObjects{ testValidBackend2FilePath }; + std::vector dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects); + + BOOST_TEST(dynamicBackends.size() == 1); + BOOST_TEST((dynamicBackends[0] != nullptr)); + + BackendId dynamicBackendId = dynamicBackends[0]->GetBackendId(); + BOOST_TEST((dynamicBackendId == "TestValid2")); + + BackendVersion dynamicBackendVersion = dynamicBackends[0]->GetBackendVersion(); + BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion)); + + TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry, dynamicBackends); + BOOST_TEST(backendRegistry.Size() == 1); + + BackendIdSet backendIds = backendRegistry.GetBackendIds(); + BOOST_TEST(backendIds.size() == 1); + BOOST_TEST((backendIds.find(dynamicBackendId) != backendIds.end())); + + auto dynamicBackendFactoryFunction = backendRegistry.GetFactory(dynamicBackendId); + BOOST_TEST((dynamicBackendFactoryFunction != nullptr)); + + IBackendInternalUniquePtr dynamicBackend = dynamicBackendFactoryFunction(); + BOOST_TEST((dynamicBackend != nullptr)); + BOOST_TEST((dynamicBackend->GetId() == dynamicBackendId)); +} + +void RegisterMultipleDynamicBackendsTestImpl() +{ + using namespace armnn; + using namespace boost::filesystem; + + // Register many valid dynamic backends + + std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5); + std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6); + BOOST_CHECK(exists(testDynamicBackendsSubDir5)); + BOOST_CHECK(exists(testDynamicBackendsSubDir6)); + + std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend2FileName); + std::string testValidBackend3FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend3FileName); + std::string testValidBackend5FilePath = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend5FileName); + BOOST_CHECK(exists(testValidBackend2FilePath)); + BOOST_CHECK(exists(testValidBackend3FilePath)); + BOOST_CHECK(exists(testValidBackend5FilePath)); + + std::vector sharedObjects + { + testValidBackend2FilePath, + testValidBackend3FilePath, + testValidBackend5FilePath + }; + std::vector dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects); + + BOOST_TEST(dynamicBackends.size() == 3); + BOOST_TEST((dynamicBackends[0] != nullptr)); + BOOST_TEST((dynamicBackends[1] != nullptr)); + BOOST_TEST((dynamicBackends[2] != nullptr)); + + BackendId dynamicBackendId1 = dynamicBackends[0]->GetBackendId(); + BackendId dynamicBackendId2 = dynamicBackends[1]->GetBackendId(); + BackendId dynamicBackendId3 = dynamicBackends[2]->GetBackendId(); + BOOST_TEST((dynamicBackendId1 == "TestValid2")); + BOOST_TEST((dynamicBackendId2 == "TestValid3")); + BOOST_TEST((dynamicBackendId3 == "TestValid5")); + + for (size_t i = 0; i < dynamicBackends.size(); i++) + { + BackendVersion dynamicBackendVersion = dynamicBackends[i]->GetBackendVersion(); + BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion)); + } + + // Dummy registry used for testing + BackendRegistry backendRegistry; + BOOST_TEST(backendRegistry.Size() == 0); + + TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry, dynamicBackends); + BOOST_TEST(backendRegistry.Size() == 3); + + BackendIdSet backendIds = backendRegistry.GetBackendIds(); + BOOST_TEST(backendIds.size() == 3); + BOOST_TEST((backendIds.find(dynamicBackendId1) != backendIds.end())); + BOOST_TEST((backendIds.find(dynamicBackendId2) != backendIds.end())); + BOOST_TEST((backendIds.find(dynamicBackendId3) != backendIds.end())); + + for (size_t i = 0; i < dynamicBackends.size(); i++) + { + BackendId dynamicBackendId = dynamicBackends[i]->GetBackendId(); + + auto dynamicBackendFactoryFunction = backendRegistry.GetFactory(dynamicBackendId); + BOOST_TEST((dynamicBackendFactoryFunction != nullptr)); + + IBackendInternalUniquePtr dynamicBackend = dynamicBackendFactoryFunction(); + BOOST_TEST((dynamicBackend != nullptr)); + BOOST_TEST((dynamicBackend->GetId() == dynamicBackendId)); + } +} + +void RegisterMultipleInvalidDynamicBackendsTestImpl() +{ + using namespace armnn; + using namespace boost::filesystem; + + // Try to register many invalid dynamic backends + + // The test covers one directory: + // /src/backends/backendsCommon/test/ + // └─ backendsTestPath9/ -> exists, contains files + // + // The test sub-directory backendsTestPath9/ contains the following test files: + // + // Arm_TestInvalid10_backend.so -> not valid (invalid backend id) + // Arm_TestInvalid11_backend.so -> not valid (invalid backend id) + + std::string testDynamicBackendsSubDir9 = GetTestSubDirectory(g_TestDynamicBackendsSubDir9); + BOOST_CHECK(exists(testDynamicBackendsSubDir9)); + + std::string testInvalidBackend10FilePath = GetTestFilePath(testDynamicBackendsSubDir9, + g_TestInvalidBackend10FileName); + std::string testInvalidBackend11FilePath = GetTestFilePath(testDynamicBackendsSubDir9, + g_TestInvalidBackend11FileName); + BOOST_CHECK(exists(testInvalidBackend10FilePath)); + BOOST_CHECK(exists(testInvalidBackend11FilePath)); + + std::vector sharedObjects + { + testInvalidBackend10FilePath, + testInvalidBackend11FilePath, + "InvalidSharedObject" + }; + std::vector dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects); + + BOOST_TEST(dynamicBackends.size() == 2); + BOOST_TEST((dynamicBackends[0] != nullptr)); + BOOST_TEST((dynamicBackends[1] != nullptr)); + + BackendId dynamicBackendId1 = dynamicBackends[0]->GetBackendId(); + BackendId dynamicBackendId2 = dynamicBackends[1]->GetBackendId(); + BOOST_TEST((dynamicBackendId1 == "")); + BOOST_TEST((dynamicBackendId2 == "Unknown")); + + for (size_t i = 0; i < dynamicBackends.size(); i++) + { + BackendVersion dynamicBackendVersion = dynamicBackends[i]->GetBackendVersion(); + BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion)); + } + + // Dummy registry used for testing + BackendRegistry backendRegistry; + BOOST_TEST(backendRegistry.Size() == 0); + + // Check that no dynamic backend got registered + TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry, dynamicBackends); + BOOST_TEST(backendRegistry.Size() == 0); +} + +void RegisterMixedDynamicBackendsTestImpl() +{ + using namespace armnn; + using namespace boost::filesystem; + + // The test covers five directories: + // /src/backends/backendsCommon/test/ + // ├─ backendsTestPath5/ -> exists, contains files + // ├─ backendsTestPath6/ -> exists, contains files + // ├─ backendsTestPath7/ -> exists, but empty + // ├─ backendsTestPath8/ -> does not exist + // └─ backendsTestPath9/ -> exists, contains files + // + // The test sub-directory backendsTestPath5/ contains the following test files: + // + // Arm_TestValid2_backend.so -> valid (basic backend name) + // Arm_TestValid3_backend.so -> valid (basic backend name) + // Arm_TestInvalid8_backend.so -> not valid (invalid backend id) + // + // The test sub-directory backendsTestPath6/ contains the following test files: + // + // Arm_TestValid2_backend.so -> valid (but duplicated from backendsTestPath5/) + // Arm_TestValid4_backend.so -> valid (it has a different filename, + // but it has the same backend id of Arm_TestValid2_backend.so + // and the same version) + // Arm_TestValid5_backend.so -> valid (basic backend name) + // Arm_TestInvalid9_backend.so -> not valid (it has a different filename, + // but it has the same backend id of Arm_TestValid2_backend.so + // and a version incompatible with the Backend API) + // + // The test sub-directory backendsTestPath9/ contains the following test files: + // + // Arm_TestInvalid10_backend.so -> not valid (empty backend id) + // Arm_TestInvalid11_backend.so -> not valid ("Unknown" backend id) + + std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5); + std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6); + std::string testDynamicBackendsSubDir7 = GetTestSubDirectory(g_TestDynamicBackendsSubDir7); + std::string testDynamicBackendsSubDir8 = GetTestSubDirectory(g_TestDynamicBackendsSubDir8); + std::string testDynamicBackendsSubDir9 = GetTestSubDirectory(g_TestDynamicBackendsSubDir9); + BOOST_CHECK(exists(testDynamicBackendsSubDir5)); + BOOST_CHECK(exists(testDynamicBackendsSubDir6)); + BOOST_CHECK(exists(testDynamicBackendsSubDir7)); + BOOST_CHECK(!exists(testDynamicBackendsSubDir8)); + BOOST_CHECK(exists(testDynamicBackendsSubDir9)); + + std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend2FileName); + std::string testValidBackend3FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend3FileName); + std::string testValidBackend2DupFilePath = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend2FileName); + std::string testValidBackend4FilePath = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend4FileName); + std::string testValidBackend5FilePath = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend5FileName); + std::string testInvalidBackend8FilePath = GetTestFilePath(testDynamicBackendsSubDir5, + g_TestInvalidBackend8FileName); + std::string testInvalidBackend9FilePath = GetTestFilePath(testDynamicBackendsSubDir6, + g_TestInvalidBackend9FileName); + std::string testInvalidBackend10FilePath = GetTestFilePath(testDynamicBackendsSubDir9, + g_TestInvalidBackend10FileName); + std::string testInvalidBackend11FilePath = GetTestFilePath(testDynamicBackendsSubDir9, + g_TestInvalidBackend11FileName); + BOOST_CHECK(exists(testValidBackend2FilePath)); + BOOST_CHECK(exists(testValidBackend3FilePath)); + BOOST_CHECK(exists(testValidBackend2DupFilePath)); + BOOST_CHECK(exists(testValidBackend4FilePath)); + BOOST_CHECK(exists(testValidBackend5FilePath)); + BOOST_CHECK(exists(testInvalidBackend8FilePath)); + BOOST_CHECK(exists(testInvalidBackend9FilePath)); + BOOST_CHECK(exists(testInvalidBackend10FilePath)); + BOOST_CHECK(exists(testInvalidBackend11FilePath)); + + std::vector sharedObjects + { + testValidBackend2FilePath, + testValidBackend3FilePath, + testValidBackend2DupFilePath, + testValidBackend4FilePath, + testValidBackend5FilePath, + testInvalidBackend8FilePath, + testInvalidBackend9FilePath, + testInvalidBackend10FilePath, + testInvalidBackend11FilePath, + "InvalidSharedObject" + }; + std::vector dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects); + + BOOST_TEST(dynamicBackends.size() == 7); + BOOST_TEST((dynamicBackends[0] != nullptr)); + BOOST_TEST((dynamicBackends[1] != nullptr)); + BOOST_TEST((dynamicBackends[2] != nullptr)); + BOOST_TEST((dynamicBackends[3] != nullptr)); + BOOST_TEST((dynamicBackends[4] != nullptr)); + BOOST_TEST((dynamicBackends[5] != nullptr)); + BOOST_TEST((dynamicBackends[6] != nullptr)); + + BackendId dynamicBackendId1 = dynamicBackends[0]->GetBackendId(); + BackendId dynamicBackendId2 = dynamicBackends[1]->GetBackendId(); + BackendId dynamicBackendId3 = dynamicBackends[2]->GetBackendId(); + BackendId dynamicBackendId4 = dynamicBackends[3]->GetBackendId(); + BackendId dynamicBackendId5 = dynamicBackends[4]->GetBackendId(); + BackendId dynamicBackendId6 = dynamicBackends[5]->GetBackendId(); + BackendId dynamicBackendId7 = dynamicBackends[6]->GetBackendId(); + BOOST_TEST((dynamicBackendId1 == "TestValid2")); + BOOST_TEST((dynamicBackendId2 == "TestValid3")); + BOOST_TEST((dynamicBackendId3 == "TestValid2")); // From duplicate Arm_TestValid2_backend.so + BOOST_TEST((dynamicBackendId4 == "TestValid2")); // From Arm_TestValid4_backend.so + BOOST_TEST((dynamicBackendId5 == "TestValid5")); + BOOST_TEST((dynamicBackendId6 == "")); + BOOST_TEST((dynamicBackendId7 == "Unknown")); + + for (size_t i = 0; i < dynamicBackends.size(); i++) + { + BackendVersion dynamicBackendVersion = dynamicBackends[i]->GetBackendVersion(); + BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion)); + } + + // Dummy registry used for testing + BackendRegistry backendRegistry; + BOOST_TEST(backendRegistry.Size() == 0); + + std::vector expectedRegisteredbackendIds + { + "TestValid2", + "TestValid3", + "TestValid5" + }; + + TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry, dynamicBackends); + BOOST_TEST(backendRegistry.Size() == expectedRegisteredbackendIds.size()); + + BackendIdSet backendIds = backendRegistry.GetBackendIds(); + BOOST_TEST(backendIds.size() == expectedRegisteredbackendIds.size()); + for (const BackendId& expectedRegisteredbackendId : expectedRegisteredbackendIds) + { + BOOST_TEST((backendIds.find(expectedRegisteredbackendId) != backendIds.end())); + + auto dynamicBackendFactoryFunction = backendRegistry.GetFactory(expectedRegisteredbackendId); + BOOST_TEST((dynamicBackendFactoryFunction != nullptr)); + + IBackendInternalUniquePtr dynamicBackend = dynamicBackendFactoryFunction(); + BOOST_TEST((dynamicBackend != nullptr)); + BOOST_TEST((dynamicBackend->GetId() == expectedRegisteredbackendId)); + } +} diff --git a/src/backends/backendsCommon/test/TestDynamicBackend.cpp b/src/backends/backendsCommon/test/TestDynamicBackend.cpp index bdbc174e5b..7230702984 100644 --- a/src/backends/backendsCommon/test/TestDynamicBackend.cpp +++ b/src/backends/backendsCommon/test/TestDynamicBackend.cpp @@ -28,6 +28,21 @@ constexpr const char* TestDynamicBackendId() // The test dynamic backend 3 is a different backend than the test dynamic backend 2 return "TestValid3"; +#elif defined(VALID_TEST_DYNAMIC_BACKEND_5) + + // The test dynamic backend 5 is a different backend than the test dynamic backend 2 + return "TestValid5"; + +#elif defined(INVALID_TEST_DYNAMIC_BACKEND_10) + + // Empty backend id + return ""; + +#elif defined(INVALID_TEST_DYNAMIC_BACKEND_11) + + // "Unknown" backend id, "Unknown" is a reserved id in ArmNN + return "Unknown"; + #else return "InvalidTestDynamicBackend"; diff --git a/src/backends/backendsCommon/test/TestDynamicBackend.hpp b/src/backends/backendsCommon/test/TestDynamicBackend.hpp index 74ab91b20c..61a6eaf572 100644 --- a/src/backends/backendsCommon/test/TestDynamicBackend.hpp +++ b/src/backends/backendsCommon/test/TestDynamicBackend.hpp @@ -10,7 +10,8 @@ #if defined(VALID_TEST_DYNAMIC_BACKEND_1) || \ defined(VALID_TEST_DYNAMIC_BACKEND_2) || \ defined(VALID_TEST_DYNAMIC_BACKEND_3) || \ - defined(VALID_TEST_DYNAMIC_BACKEND_4) + defined(VALID_TEST_DYNAMIC_BACKEND_4) || \ + defined(VALID_TEST_DYNAMIC_BACKEND_5) // Correct dynamic backend interface extern "C" @@ -50,11 +51,13 @@ void* 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) || \ - defined(INVALID_TEST_DYNAMIC_BACKEND_8) || \ - defined(INVALID_TEST_DYNAMIC_BACKEND_9) +#elif defined(INVALID_TEST_DYNAMIC_BACKEND_5) || \ + defined(INVALID_TEST_DYNAMIC_BACKEND_6) || \ + defined(INVALID_TEST_DYNAMIC_BACKEND_7) || \ + defined(INVALID_TEST_DYNAMIC_BACKEND_8) || \ + defined(INVALID_TEST_DYNAMIC_BACKEND_9) || \ + defined(INVALID_TEST_DYNAMIC_BACKEND_10) || \ + defined(INVALID_TEST_DYNAMIC_BACKEND_11) // The interface is correct, the corresponding invalid changes are in the TestDynamicBackend.cpp file const char* GetBackendId(); -- cgit v1.2.1