From e54aa06ec19813b737513ecb8224285d98e871ba Mon Sep 17 00:00:00 2001 From: Matteo Martincigh Date: Mon, 5 Aug 2019 14:12:11 +0100 Subject: IVGCVSW-3595 Implement the LoadDynamicBackends function in the Runtime class * Changed the way the handle is acquired, loaded symbols are now kept local * Updated the makefiles to add more test files for the dynamic backends * Fixed the GetSharedObjects method so that the files are parsed in alphabetical order * Updated the unit tests to make them more strict wrt the order of the files * Created a new CreateDynamicBackends method in the utils class * Added new unit tests for the new function * Added LoadDynamicBackends in the Runtime class !android-nn-driver:1707 Change-Id: I1ef9ff3d5455ca6a7fd51cb7cfb3819686234f70 Signed-off-by: Matteo Martincigh --- Android.mk | 4 +- src/armnn/Runtime.cpp | 19 +++ src/armnn/Runtime.hpp | 3 + src/backends/backendsCommon/DynamicBackend.hpp | 2 + .../backendsCommon/DynamicBackendUtils.cpp | 67 +++++++- .../backendsCommon/DynamicBackendUtils.hpp | 3 + src/backends/backendsCommon/common.mk | 2 + src/backends/backendsCommon/test/CMakeLists.txt | 49 +++++- .../backendsCommon/test/DynamicBackendTests.cpp | 5 + .../backendsCommon/test/DynamicBackendTests.hpp | 180 ++++++++++++++++++--- .../backendsCommon/test/TestDynamicBackend.cpp | 38 ++++- .../backendsCommon/test/TestDynamicBackend.hpp | 9 +- 12 files changed, 346 insertions(+), 35 deletions(-) diff --git a/Android.mk b/Android.mk index bb7ed86283..e590ba5988 100644 --- a/Android.mk +++ b/Android.mk @@ -167,7 +167,8 @@ LOCAL_STATIC_LIBRARIES := \ armnn-arm_compute \ libboost_log \ libboost_system \ - libboost_thread + libboost_thread \ + libboost_filesystem LOCAL_SHARED_LIBRARIES := \ liblog @@ -286,6 +287,7 @@ LOCAL_STATIC_LIBRARIES := \ libboost_system \ libboost_unit_test_framework \ libboost_thread \ + libboost_filesystem \ armnn-arm_compute LOCAL_WHOLE_STATIC_LIBRARIES := libarmnn diff --git a/src/armnn/Runtime.cpp b/src/armnn/Runtime.cpp index f8b2462f96..3505030273 100644 --- a/src/armnn/Runtime.cpp +++ b/src/armnn/Runtime.cpp @@ -5,8 +5,11 @@ #include "Runtime.hpp" #include + #include #include +#include +#include #include @@ -134,6 +137,10 @@ Runtime::Runtime(const CreationOptions& options) { BOOST_LOG_TRIVIAL(info) << "ArmNN v" << ARMNN_VERSION << "\n"; + // Load any available/compatible dynamic backend before the runtime + // goes through the backend registry + LoadDynamicBackends(options.m_DynamicBackendsPath); + for (const auto& id : BackendRegistryInstance().GetBackendIds()) { // Store backend contexts for the supported ones @@ -237,4 +244,16 @@ void Runtime::RegisterDebugCallback(NetworkId networkId, const DebugCallbackFunc loadedNetwork->RegisterDebugCallback(func); } +void Runtime::LoadDynamicBackends(const std::string& overrideBackendPath) +{ + // Get the paths where to load the dynamic backends from + std::vector backendPaths = DynamicBackendUtils::GetBackendPaths(overrideBackendPath); + + // Get the shared objects to try to load as dynamic backends + std::vector sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths); + + // Create a list of dynamic backends + DynamicBackendUtils::CreateDynamicBackends(sharedObjects); } + +} // namespace armnn diff --git a/src/armnn/Runtime.hpp b/src/armnn/Runtime.hpp index 10383bc970..624304ec0a 100644 --- a/src/armnn/Runtime.hpp +++ b/src/armnn/Runtime.hpp @@ -89,6 +89,9 @@ private: } } + /// Loads any available/compatible dynamic backend in the runtime. + void LoadDynamicBackends(const std::string& overrideBackendPath); + mutable std::mutex m_Mutex; std::unordered_map> m_LoadedNetworks; diff --git a/src/backends/backendsCommon/DynamicBackend.hpp b/src/backends/backendsCommon/DynamicBackend.hpp index 06655293e7..b202309c31 100644 --- a/src/backends/backendsCommon/DynamicBackend.hpp +++ b/src/backends/backendsCommon/DynamicBackend.hpp @@ -44,4 +44,6 @@ private: HandlePtr m_Handle; }; +using DynamicBackendPtr = std::unique_ptr; + } // namespace armnn diff --git a/src/backends/backendsCommon/DynamicBackendUtils.cpp b/src/backends/backendsCommon/DynamicBackendUtils.cpp index 1dea802016..57a605608c 100644 --- a/src/backends/backendsCommon/DynamicBackendUtils.cpp +++ b/src/backends/backendsCommon/DynamicBackendUtils.cpp @@ -21,7 +21,7 @@ void* DynamicBackendUtils::OpenHandle(const std::string& sharedObjectPath) throw RuntimeException("OpenHandle error: shared object path must not be empty"); } - void* sharedObjectHandle = dlopen(sharedObjectPath.c_str(), RTLD_LAZY | RTLD_GLOBAL); + void* sharedObjectHandle = dlopen(sharedObjectPath.c_str(), RTLD_LAZY); if (!sharedObjectHandle) { throw RuntimeException(boost::str(boost::format("OpenHandle error: %1%") % GetDlError())); @@ -168,11 +168,16 @@ std::vector DynamicBackendUtils::GetSharedObjects(const std::vector continue; } + // Get all the files in the current path in alphabetical order + std::vector backendPathFiles; + std::copy(directory_iterator(backendPath), directory_iterator(), std::back_inserter(backendPathFiles)); + std::sort(backendPathFiles.begin(), backendPathFiles.end()); + // Go through all the files in the current backend path - for (directory_iterator fileIterator(backendPath); fileIterator != directory_iterator(); fileIterator++) + for (const path& backendPathFile : backendPathFiles) { - path filePath = *fileIterator; - std::string filename = filePath.filename().string(); + // Get only the name of the file (without the full path) + std::string filename = backendPathFile.filename().string(); if (filename.empty()) { @@ -185,7 +190,7 @@ std::vector DynamicBackendUtils::GetSharedObjects(const std::vector { // Get the canonical path for the current file, it will throw if for example the file is a // symlink that cannot be resolved - canonicalPath = canonical(filePath); + canonicalPath = canonical(backendPathFile); } catch (const filesystem_error& e) { @@ -235,4 +240,56 @@ std::vector DynamicBackendUtils::GetSharedObjects(const std::vector return sharedObjects; } +std::vector DynamicBackendUtils::CreateDynamicBackends(const std::vector& sharedObjects) +{ + // Create a list of dynamic backends + std::vector dynamicBackends; + for (const std::string& sharedObject : sharedObjects) + { + // Create a handle to the shared object + void* sharedObjectHandle = nullptr; + try + { + sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObject); + } + catch (const RuntimeException& e) + { + BOOST_LOG_TRIVIAL(warning) << "Cannot create a handle to the shared object file \"" + << sharedObject << "\": " << e.what(); + continue; + } + if (!sharedObjectHandle) + { + BOOST_LOG_TRIVIAL(warning) << "Invalid handle to the shared object file \"" << sharedObject << "\""; + + continue; + } + + // Create a dynamic backend object + DynamicBackendPtr dynamicBackend; + try + { + dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)); + } + catch (const Exception& e) + { + BOOST_LOG_TRIVIAL(warning) << "Cannot create a valid dynamic backend from the shared object file \"" + << sharedObject << "\": " << e.what(); + continue; + } + if (!dynamicBackend) + { + BOOST_LOG_TRIVIAL(warning) << "Invalid dynamic backend object for the shared object file \"" + << sharedObject << "\""; + + continue; + } + + // Append the newly created dynamic backend to the list + dynamicBackends.push_back(std::move(dynamicBackend)); + } + + return dynamicBackends; +} + } // namespace armnn diff --git a/src/backends/backendsCommon/DynamicBackendUtils.hpp b/src/backends/backendsCommon/DynamicBackendUtils.hpp index b327a9ea60..9c10df7efc 100644 --- a/src/backends/backendsCommon/DynamicBackendUtils.hpp +++ b/src/backends/backendsCommon/DynamicBackendUtils.hpp @@ -6,6 +6,7 @@ #pragma once #include "IBackendInternal.hpp" +#include "DynamicBackend.hpp" #include @@ -37,6 +38,8 @@ public: static bool IsPathValid(const std::string& path); static std::vector GetSharedObjects(const std::vector& backendPaths); + static std::vector CreateDynamicBackends(const std::vector& sharedObjects); + protected: /// Protected methods for testing purposes static bool IsBackendCompatibleImpl(const BackendVersion& backendApiVersion, const BackendVersion& backendVersion); diff --git a/src/backends/backendsCommon/common.mk b/src/backends/backendsCommon/common.mk index eee1dae0ff..0ac7cfeada 100644 --- a/src/backends/backendsCommon/common.mk +++ b/src/backends/backendsCommon/common.mk @@ -10,6 +10,8 @@ COMMON_SOURCES := \ BackendRegistry.cpp \ CpuTensorHandle.cpp \ + DynamicBackend.cpp \ + DynamicBackendUtils.cpp \ IBackendInternal.cpp \ ITensorHandleFactory.cpp \ LayerSupportBase.cpp \ diff --git a/src/backends/backendsCommon/test/CMakeLists.txt b/src/backends/backendsCommon/test/CMakeLists.txt index 3c6eb19e88..6714a20122 100644 --- a/src/backends/backendsCommon/test/CMakeLists.txt +++ b/src/backends/backendsCommon/test/CMakeLists.txt @@ -87,7 +87,7 @@ list(APPEND testDynamicBackend_sources ) add_library_ex(ValidTestDynamicBackend MODULE ${testDynamicBackend_sources}) -target_compile_definitions(ValidTestDynamicBackend PRIVATE -DVALID_TEST_DYNAMIC_BACKEND) +target_compile_definitions(ValidTestDynamicBackend PRIVATE -DVALID_TEST_DYNAMIC_BACKEND_1) target_include_directories(ValidTestDynamicBackend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) target_include_directories(ValidTestDynamicBackend PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) target_link_libraries(ValidTestDynamicBackend armnn) @@ -177,3 +177,50 @@ add_custom_target(link_dummy_dynamic_backend ALL file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath2/Arm_GpuAcc_backend.so "Test file for dynamic backend file parsing") file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath3) + +# Dummy dynamic backends for testing. +# These shared objects are used to test the creation of dynamic backend instances in ArmNN. + +add_library_ex(Arm_TestValid2_backend MODULE ${testDynamicBackend_sources}) +target_compile_definitions(Arm_TestValid2_backend PRIVATE -DVALID_TEST_DYNAMIC_BACKEND_2) +target_include_directories(Arm_TestValid2_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(Arm_TestValid2_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) +target_link_libraries(Arm_TestValid2_backend armnn) +set_target_properties(Arm_TestValid2_backend PROPERTIES PREFIX "") +set_target_properties(Arm_TestValid2_backend PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath5) +add_custom_command(TARGET Arm_TestValid2_backend POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath6) + +add_library_ex(Arm_TestValid3_backend MODULE ${testDynamicBackend_sources}) +target_compile_definitions(Arm_TestValid3_backend PRIVATE -DVALID_TEST_DYNAMIC_BACKEND_3) +target_include_directories(Arm_TestValid3_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(Arm_TestValid3_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) +target_link_libraries(Arm_TestValid3_backend armnn) +set_target_properties(Arm_TestValid3_backend PROPERTIES PREFIX "") +set_target_properties(Arm_TestValid3_backend PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath5) + +add_library_ex(Arm_TestInvalid8_backend MODULE ${testDynamicBackend_sources}) +target_compile_definitions(Arm_TestInvalid8_backend PRIVATE -DINVALID_TEST_DYNAMIC_BACKEND_8) +target_include_directories(Arm_TestInvalid8_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(Arm_TestInvalid8_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) +target_link_libraries(Arm_TestInvalid8_backend armnn) +set_target_properties(Arm_TestInvalid8_backend PROPERTIES PREFIX "") +set_target_properties(Arm_TestInvalid8_backend PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/backendsTestPath5) + +add_library_ex(Arm_TestValid4_backend MODULE ${testDynamicBackend_sources}) +target_compile_definitions(Arm_TestValid4_backend PRIVATE -DVALID_TEST_DYNAMIC_BACKEND_4) +target_include_directories(Arm_TestValid4_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/armnn) +target_include_directories(Arm_TestValid4_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) +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_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) +target_include_directories(Arm_TestInvalid9_backend PRIVATE ${PROJECT_SOURCE_DIR}/src/backends) +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) + +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 a467b0e645..b5d159ab13 100644 --- a/src/backends/backendsCommon/test/DynamicBackendTests.cpp +++ b/src/backends/backendsCommon/test/DynamicBackendTests.cpp @@ -45,4 +45,9 @@ ARMNN_SIMPLE_TEST_CASE(GetBackendPathsOverride, GetBackendPathsOverrideTestImpl) ARMNN_SIMPLE_TEST_CASE(GetSharedObjects, GetSharedObjectsTestImpl); +ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackends, CreateDynamicBackendsTestImpl); +ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendsNoPaths, CreateDynamicBackendsNoPathsTestImpl); +ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendsAllInvalid, CreateDynamicBackendsAllInvalidTestImpl); +ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendsMixedTypes, CreateDynamicBackendsMixedTypesTestImpl); + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.hpp b/src/backends/backendsCommon/test/DynamicBackendTests.hpp index b4af705fcd..e3fbe311bc 100644 --- a/src/backends/backendsCommon/test/DynamicBackendTests.hpp +++ b/src/backends/backendsCommon/test/DynamicBackendTests.hpp @@ -33,10 +33,20 @@ static std::string g_TestInvalidTestDynamicBackend5FileName = "libInvalidTestDyn static std::string g_TestInvalidTestDynamicBackend6FileName = "libInvalidTestDynamicBackend6.so"; static std::string g_TestInvalidTestDynamicBackend7FileName = "libInvalidTestDynamicBackend7.so"; +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_TestInvalidBackend8FileName = "Arm_TestInvalid8_backend.so"; +static std::string g_TestInvalidBackend9FileName = "Arm_TestInvalid9_backend.so"; + 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/"; std::string GetTestDirectoryBasePath() { @@ -275,7 +285,7 @@ void CreateValidDynamicBackendObjectTestImpl() BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath)); BOOST_TEST((sharedObjectHandle != nullptr)); - std::unique_ptr dynamicBackend; + DynamicBackendPtr dynamicBackend; BOOST_CHECK_NO_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle))); BOOST_TEST((dynamicBackend != nullptr)); @@ -285,7 +295,7 @@ void CreateValidDynamicBackendObjectTestImpl() BackendVersion dynamicBackendVersion; BOOST_CHECK_NO_THROW(dynamicBackendVersion = dynamicBackend->GetBackendVersion()); - BOOST_TEST((dynamicBackendVersion == BackendVersion({ 1, 0 }))); + BOOST_TEST((dynamicBackendVersion == IBackendInternal::GetApiVersion())); IBackendInternalUniquePtr dynamicBackendInstance; BOOST_CHECK_NO_THROW(dynamicBackendInstance = dynamicBackend->GetBackend()); @@ -301,7 +311,7 @@ void CreateDynamicBackendObjectInvalidHandleTestImpl() using namespace armnn; void* sharedObjectHandle = nullptr; - std::unique_ptr dynamicBackend; + DynamicBackendPtr dynamicBackend; BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), InvalidArgumentException); BOOST_TEST((dynamicBackend == nullptr)); } @@ -320,7 +330,7 @@ void CreateDynamicBackendObjectInvalidInterface1TestImpl() BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath)); BOOST_TEST((sharedObjectHandle != nullptr)); - std::unique_ptr dynamicBackend; + DynamicBackendPtr dynamicBackend; BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException); BOOST_TEST((dynamicBackend == nullptr)); } @@ -340,7 +350,7 @@ void CreateDynamicBackendObjectInvalidInterface2TestImpl() BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath)); BOOST_TEST((sharedObjectHandle != nullptr)); - std::unique_ptr dynamicBackend; + DynamicBackendPtr dynamicBackend; BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException); BOOST_TEST((dynamicBackend == nullptr)); } @@ -360,7 +370,7 @@ void CreateDynamicBackendObjectInvalidInterface3TestImpl() BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath)); BOOST_TEST((sharedObjectHandle != nullptr)); - std::unique_ptr dynamicBackend; + DynamicBackendPtr dynamicBackend; BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException); BOOST_TEST((dynamicBackend == nullptr)); } @@ -380,7 +390,7 @@ void CreateDynamicBackendObjectInvalidInterface4TestImpl() BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath)); BOOST_TEST((sharedObjectHandle != nullptr)); - std::unique_ptr dynamicBackend; + DynamicBackendPtr dynamicBackend; BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException); BOOST_TEST((dynamicBackend == nullptr)); } @@ -401,7 +411,7 @@ void CreateDynamicBackendObjectInvalidInterface5TestImpl() BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath)); BOOST_TEST((sharedObjectHandle != nullptr)); - std::unique_ptr dynamicBackend; + DynamicBackendPtr dynamicBackend; BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException); BOOST_TEST((dynamicBackend == nullptr)); } @@ -422,7 +432,7 @@ void CreateDynamicBackendObjectInvalidInterface6TestImpl() BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath)); BOOST_TEST((sharedObjectHandle != nullptr)); - std::unique_ptr dynamicBackend; + DynamicBackendPtr dynamicBackend; BOOST_CHECK_NO_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle))); BOOST_TEST((dynamicBackend != nullptr)); @@ -455,7 +465,7 @@ void CreateDynamicBackendObjectInvalidInterface7TestImpl() BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath)); BOOST_TEST((sharedObjectHandle != nullptr)); - std::unique_ptr dynamicBackend; + DynamicBackendPtr dynamicBackend; BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException); BOOST_TEST((dynamicBackend == nullptr)); } @@ -467,10 +477,10 @@ void GetBackendPathsTestImpl() // The test covers four directories: // /src/backends/backendsCommon/test/ - // ├─ backendsTestPath1/ -> existing, contains files - // ├─ backendsTestPath2/ -> existing, contains files - // ├─ backendsTestPath3/ -> existing, but empty - // └─ backendsTestPath4/ -> not existing + // ├─ backendsTestPath1/ -> exists, contains files + // ├─ backendsTestPath2/ -> exists, contains files + // ├─ backendsTestPath3/ -> exists, but empty + // └─ backendsTestPath4/ -> does not exist std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir1); std::string subDir2 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir2); @@ -575,6 +585,12 @@ void GetSharedObjectsTestImpl() using namespace armnn; using namespace boost::filesystem; + // The test covers four directories: + // /src/backends/backendsCommon/test/ + // ├─ backendsTestPath1/ -> exists, contains files + // ├─ backendsTestPath2/ -> exists, contains files + // ├─ backendsTestPath3/ -> exists, but empty + // └─ backendsTestPath4/ -> does not exist // // The test sub-directory backendsTestPath1/ contains the following test files: // @@ -630,23 +646,145 @@ void GetSharedObjectsTestImpl() testDynamicBackendsSubDir4 }; std::vector sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths); - std::unordered_set expectedSharedObjects + std::vector expectedSharedObjects { + testDynamicBackendsSubDir1 + "Arm123_GpuAcc_backend.so", // Digits in vendor name are allowed + testDynamicBackendsSubDir1 + "Arm_GpuAcc456_backend.so", // Digits in backend id are allowed testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so", // Basic backend name testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1", // Single field version number testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1.2", // Multiple field version number testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1.2.3", // Multiple field version number testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.10.1.27", // Multiple digit version - testDynamicBackendsSubDir1 + "Arm123_GpuAcc_backend.so", // Digits in vendor name are allowed - testDynamicBackendsSubDir1 + "Arm_GpuAcc456_backend.so", // Digits in backend id are allowed testDynamicBackendsSubDir2 + "Arm_CpuAcc_backend.so", // Duplicate symlinks removed testDynamicBackendsSubDir2 + "Arm_GpuAcc_backend.so" // Duplicates on different paths are allowed }; BOOST_TEST(sharedObjects.size() == expectedSharedObjects.size()); - for (const std::string& sharedObject : sharedObjects) + BOOST_TEST(sharedObjects[0] == expectedSharedObjects[0]); + BOOST_TEST(sharedObjects[1] == expectedSharedObjects[1]); + BOOST_TEST(sharedObjects[2] == expectedSharedObjects[2]); + BOOST_TEST(sharedObjects[3] == expectedSharedObjects[3]); + BOOST_TEST(sharedObjects[4] == expectedSharedObjects[4]); + BOOST_TEST(sharedObjects[5] == expectedSharedObjects[5]); + BOOST_TEST(sharedObjects[6] == expectedSharedObjects[6]); + BOOST_TEST(sharedObjects[7] == expectedSharedObjects[7]); + BOOST_TEST(sharedObjects[8] == expectedSharedObjects[8]); +} + +void CreateDynamicBackendsTestImpl() +{ + using namespace armnn; + using namespace boost::filesystem; + + // The test covers three directories: + // /src/backends/backendsCommon/test/ + // ├─ backendsTestPath5/ -> exists, contains files + // ├─ backendsTestPath6/ -> exists, contains files + // ├─ backendsTestPath7/ -> exists, but empty + // └─ backendsTestPath8/ -> does not exist + // + // 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_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); + BOOST_CHECK(exists(testDynamicBackendsSubDir5)); + BOOST_CHECK(exists(testDynamicBackendsSubDir6)); + BOOST_CHECK(exists(testDynamicBackendsSubDir7)); + BOOST_CHECK(!exists(testDynamicBackendsSubDir8)); + + std::vector backendPaths + { + testDynamicBackendsSubDir5, + testDynamicBackendsSubDir6, + testDynamicBackendsSubDir7, + testDynamicBackendsSubDir8 + }; + std::vector sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths); + std::vector dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects); + + BOOST_TEST(dynamicBackends.size() == 4); + BOOST_TEST((dynamicBackends[0] != nullptr)); + BOOST_TEST((dynamicBackends[1] != nullptr)); + BOOST_TEST((dynamicBackends[2] != nullptr)); + BOOST_TEST((dynamicBackends[3] != 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 +} + +void CreateDynamicBackendsNoPathsTestImpl() +{ + using namespace armnn; + + std::vector dynamicBackends = DynamicBackendUtils::CreateDynamicBackends({}); + + BOOST_TEST(dynamicBackends.empty()); +} + +void CreateDynamicBackendsAllInvalidTestImpl() +{ + using namespace armnn; + + std::vector sharedObjects { - auto it = expectedSharedObjects.find(sharedObject); - BOOST_TEST((it != expectedSharedObjects.end())); - } + "InvalidSharedObject1", + "InvalidSharedObject2", + "InvalidSharedObject3", + }; + std::vector dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects); + + BOOST_TEST(dynamicBackends.empty()); +} + +void CreateDynamicBackendsMixedTypesTestImpl() +{ + using namespace armnn; + using namespace boost::filesystem; + + std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir5); + std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir6); + BOOST_CHECK(exists(testDynamicBackendsSubDir5)); + BOOST_CHECK(exists(testDynamicBackendsSubDir6)); + + std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5, + g_TestValidBackend2FileName); + std::string testInvalidBackend8FilePath = GetTestFilePath(testDynamicBackendsSubDir5, + g_TestInvalidBackend8FileName); + std::string testInvalidBackend9FilePath = GetTestFilePath(testDynamicBackendsSubDir6, + g_TestInvalidBackend9FileName); + BOOST_CHECK(exists(testValidBackend2FilePath)); + BOOST_CHECK(exists(testInvalidBackend8FilePath)); + BOOST_CHECK(exists(testInvalidBackend9FilePath)); + + std::vector sharedObjects + { + testValidBackend2FilePath, // Arm_TestValid2_backend.so -> valid (basic backend name) + testInvalidBackend8FilePath, // Arm_TestInvalid8_backend.so -> not valid (invalid backend id) + testInvalidBackend9FilePath, // Arm_TestInvalid9_backend.so -> not valid (incompatible version) + "InvalidSharedObject", // The file does not exist + }; + std::vector dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects); + + BOOST_TEST(dynamicBackends.size() == 1); + BOOST_TEST((dynamicBackends[0] != nullptr)); + BOOST_TEST((dynamicBackends[0]->GetBackendId() == "TestValid2")); } diff --git a/src/backends/backendsCommon/test/TestDynamicBackend.cpp b/src/backends/backendsCommon/test/TestDynamicBackend.cpp index 7fd996fae8..bdbc174e5b 100644 --- a/src/backends/backendsCommon/test/TestDynamicBackend.cpp +++ b/src/backends/backendsCommon/test/TestDynamicBackend.cpp @@ -9,10 +9,25 @@ constexpr const char* TestDynamicBackendId() { -#if defined(VALID_TEST_DYNAMIC_BACKEND) +#if defined(VALID_TEST_DYNAMIC_BACKEND_1) return "ValidTestDynamicBackend"; +#elif defined(VALID_TEST_DYNAMIC_BACKEND_2) || \ + defined(VALID_TEST_DYNAMIC_BACKEND_4) || \ + defined(INVALID_TEST_DYNAMIC_BACKEND_9) + + // This backend id is shared among different test dynamic backends for testing purposes: + // the test dynamic backend 4 is actually a duplicate of the test dynamic backend 2 (with the same version), + // the test dynamic backend 9 is actually a duplicate of the test dynamic backend 2 (but with a version + // incompatible with the current Backend API) + return "TestValid2"; + +#elif defined(VALID_TEST_DYNAMIC_BACKEND_3) + + // The test dynamic backend 3 is a different backend than the test dynamic backend 2 + return "TestValid3"; + #else return "InvalidTestDynamicBackend"; @@ -46,7 +61,8 @@ private: const char* GetBackendId() { -#if defined(INVALID_TEST_DYNAMIC_BACKEND_5) +#if defined(INVALID_TEST_DYNAMIC_BACKEND_5) || \ + defined(INVALID_TEST_DYNAMIC_BACKEND_8) // Return an invalid backend id return nullptr; @@ -66,15 +82,27 @@ void GetVersion(uint32_t* outMajor, uint32_t* outMinor) return; } -#if defined(INVALID_TEST_DYNAMIC_BACKEND_7) +#if defined(INVALID_TEST_DYNAMIC_BACKEND_7) || \ + defined(INVALID_TEST_DYNAMIC_BACKEND_8) *outMajor = 0; *outMinor = 7; #else - *outMajor = 1; - *outMinor = 0; + armnn::BackendVersion apiVersion = armnn::IBackendInternal::GetApiVersion(); + + *outMajor = apiVersion.m_Major; + +#if defined(INVALID_TEST_DYNAMIC_BACKEND_9) + + *outMinor = apiVersion.m_Minor + 1; + +#else + + *outMinor = apiVersion.m_Minor; + +#endif #endif } diff --git a/src/backends/backendsCommon/test/TestDynamicBackend.hpp b/src/backends/backendsCommon/test/TestDynamicBackend.hpp index 599ca16636..74ab91b20c 100644 --- a/src/backends/backendsCommon/test/TestDynamicBackend.hpp +++ b/src/backends/backendsCommon/test/TestDynamicBackend.hpp @@ -7,7 +7,10 @@ #include -#if defined(VALID_TEST_DYNAMIC_BACKEND) +#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) // Correct dynamic backend interface extern "C" @@ -49,7 +52,9 @@ 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_7) || \ + defined(INVALID_TEST_DYNAMIC_BACKEND_8) || \ + defined(INVALID_TEST_DYNAMIC_BACKEND_9) // The interface is correct, the corresponding invalid changes are in the TestDynamicBackend.cpp file const char* GetBackendId(); -- cgit v1.2.1