IVGCVSW-3595 Implement the LoadDynamicBackends function in the Runtime class
authorMatteo Martincigh <matteo.martincigh@arm.com>
Mon, 5 Aug 2019 13:12:11 +0000 (14:12 +0100)
committerMatteo Martincigh <matteo.martincigh@arm.com>
Wed, 7 Aug 2019 14:04:51 +0000 (15:04 +0100)
 * 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 <matteo.martincigh@arm.com>
12 files changed:
Android.mk
src/armnn/Runtime.cpp
src/armnn/Runtime.hpp
src/backends/backendsCommon/DynamicBackend.hpp
src/backends/backendsCommon/DynamicBackendUtils.cpp
src/backends/backendsCommon/DynamicBackendUtils.hpp
src/backends/backendsCommon/common.mk
src/backends/backendsCommon/test/CMakeLists.txt
src/backends/backendsCommon/test/DynamicBackendTests.cpp
src/backends/backendsCommon/test/DynamicBackendTests.hpp
src/backends/backendsCommon/test/TestDynamicBackend.cpp
src/backends/backendsCommon/test/TestDynamicBackend.hpp

index bb7ed86..e590ba5 100644 (file)
@@ -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
index f8b2462..3505030 100644 (file)
@@ -5,8 +5,11 @@
 #include "Runtime.hpp"
 
 #include <armnn/Version.hpp>
+
 #include <backendsCommon/BackendRegistry.hpp>
 #include <backendsCommon/IBackendContext.hpp>
+#include <backendsCommon/DynamicBackendUtils.hpp>
+#include <backendsCommon/DynamicBackend.hpp>
 
 #include <iostream>
 
@@ -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<std::string> backendPaths = DynamicBackendUtils::GetBackendPaths(overrideBackendPath);
+
+    // Get the shared objects to try to load as dynamic backends
+    std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
+
+    // Create a list of dynamic backends
+    DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
 }
+
+} // namespace armnn
index 10383bc..624304e 100644 (file)
@@ -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<NetworkId, std::unique_ptr<LoadedNetwork>> m_LoadedNetworks;
index 0665529..b202309 100644 (file)
@@ -44,4 +44,6 @@ private:
     HandlePtr m_Handle;
 };
 
+using DynamicBackendPtr = std::unique_ptr<DynamicBackend>;
+
 } // namespace armnn
index 1dea802..57a6056 100644 (file)
@@ -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<std::string> DynamicBackendUtils::GetSharedObjects(const std::vector
             continue;
         }
 
+        // Get all the files in the current path in alphabetical order
+        std::vector<path> 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<std::string> 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<std::string> DynamicBackendUtils::GetSharedObjects(const std::vector
     return sharedObjects;
 }
 
+std::vector<DynamicBackendPtr> DynamicBackendUtils::CreateDynamicBackends(const std::vector<std::string>& sharedObjects)
+{
+    // Create a list of dynamic backends
+    std::vector<DynamicBackendPtr> 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
index b327a9e..9c10df7 100644 (file)
@@ -6,6 +6,7 @@
 #pragma once
 
 #include "IBackendInternal.hpp"
+#include "DynamicBackend.hpp"
 
 #include <armnn/Exceptions.hpp>
 
@@ -37,6 +38,8 @@ public:
     static bool IsPathValid(const std::string& path);
     static std::vector<std::string> GetSharedObjects(const std::vector<std::string>& backendPaths);
 
+    static std::vector<DynamicBackendPtr> CreateDynamicBackends(const std::vector<std::string>& sharedObjects);
+
 protected:
     /// Protected methods for testing purposes
     static bool IsBackendCompatibleImpl(const BackendVersion& backendApiVersion, const BackendVersion& backendVersion);
index eee1dae..0ac7cfe 100644 (file)
@@ -10,6 +10,8 @@
 COMMON_SOURCES := \
     BackendRegistry.cpp \
     CpuTensorHandle.cpp \
+    DynamicBackend.cpp \
+    DynamicBackendUtils.cpp \
     IBackendInternal.cpp \
     ITensorHandleFactory.cpp \
     LayerSupportBase.cpp \
index 3c6eb19..6714a20 100644 (file)
@@ -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 $<TARGET_FILE:Arm_TestValid2_backend> ${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)
index a467b0e..b5d159a 100644 (file)
@@ -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()
index b4af705..e3fbe31 100644 (file)
@@ -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> 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> 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> 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> 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> 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> 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> 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> 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> 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:
     // <unit test path>/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:
+    // <unit test path>/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<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
-    std::unordered_set<std::string> expectedSharedObjects
+    std::vector<std::string> 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:
+    // <unit test path>/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<std::string> backendPaths
+    {
+        testDynamicBackendsSubDir5,
+        testDynamicBackendsSubDir6,
+        testDynamicBackendsSubDir7,
+        testDynamicBackendsSubDir8
+    };
+    std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
+    std::vector<DynamicBackendPtr> 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<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends({});
+
+    BOOST_TEST(dynamicBackends.empty());
+}
+
+void CreateDynamicBackendsAllInvalidTestImpl()
+{
+    using namespace armnn;
+
+    std::vector<std::string> sharedObjects
     {
-        auto it = expectedSharedObjects.find(sharedObject);
-        BOOST_TEST((it != expectedSharedObjects.end()));
-    }
+        "InvalidSharedObject1",
+        "InvalidSharedObject2",
+        "InvalidSharedObject3",
+    };
+    std::vector<DynamicBackendPtr> 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<std::string> 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<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
+
+    BOOST_TEST(dynamicBackends.size() == 1);
+    BOOST_TEST((dynamicBackends[0] != nullptr));
+    BOOST_TEST((dynamicBackends[0]->GetBackendId() == "TestValid2"));
 }
index 7fd996f..bdbc174 100644 (file)
@@ -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
 }
index 599ca16..74ab91b 100644 (file)
@@ -7,7 +7,10 @@
 
 #include <cstdint>
 
-#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();