diff options
author | Matteo Martincigh <matteo.martincigh@arm.com> | 2019-08-05 12:16:47 +0100 |
---|---|---|
committer | Matteo Martincigh <matteo.martincigh@arm.com> | 2019-08-05 16:32:05 +0000 |
commit | e7d449893b85a00a063836bd01dce4f925a24dd2 (patch) | |
tree | bff2b2770caa91c3bbf7270db8a21a3f4eb9964f | |
parent | 4fc3c48c2d230d8c55aa01aa98e32b6df7cafc0c (diff) | |
download | armnn-e7d449893b85a00a063836bd01dce4f925a24dd2.tar.gz |
IVGCVSW-3541 Get the paths where to load the dynamic backends from
* Adds GetBackendPaths and IsPathValid to DynamicBackendUtils
* Adds related unit tests
Change-Id: I94e377d92a88a4b5d48026f6ad5b4d5387d20c21
Signed-off-by: Jan Eilers <jan.eilers@arm.com>
Signed-off-by: Matteo Martincigh <matteo.martincigh@arm.com>
-rw-r--r-- | CMakeLists.txt | 8 | ||||
-rw-r--r-- | cmake/GlobalConfig.cmake | 1 | ||||
-rw-r--r-- | include/armnn/IRuntime.hpp | 5 | ||||
-rw-r--r-- | src/backends/backendsCommon/DynamicBackendUtils.cpp | 92 | ||||
-rw-r--r-- | src/backends/backendsCommon/DynamicBackendUtils.hpp | 11 | ||||
-rw-r--r-- | src/backends/backendsCommon/test/DynamicBackendTests.cpp | 3 | ||||
-rw-r--r-- | src/backends/backendsCommon/test/DynamicBackendTests.hpp | 115 |
7 files changed, 233 insertions, 2 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index eaaf2d6813..08c693d30d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,11 @@ foreach(cmake_file ${additional_cmake_files}) include(${cmake_file}) endforeach() +if (DYNAMIC_BACKEND_PATHS) + # It's expected to have the format: DYNAMIC_BACKEND_PATHS="PATH_1:PATH_2...:PATH_N" + add_definitions('-DDYNAMIC_BACKEND_PATHS="${DYNAMIC_BACKEND_PATHS}"') +endif() + include(GNUInstallDirs) add_subdirectory(samples) @@ -451,7 +456,8 @@ endif() install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) -target_link_libraries(armnn ${Boost_LOG_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY}) +target_link_libraries(armnn ${Boost_LOG_LIBRARY} ${Boost_THREAD_LIBRARY} + ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY}) if(ARMCOMPUTENEON OR ARMCOMPUTECL) target_link_libraries(armnn ${ARMCOMPUTE_LIBRARIES}) diff --git a/cmake/GlobalConfig.cmake b/cmake/GlobalConfig.cmake index 26b3ff4d8c..8dad57a297 100644 --- a/cmake/GlobalConfig.cmake +++ b/cmake/GlobalConfig.cmake @@ -19,6 +19,7 @@ option(BUILD_ACCURACY_TOOL "Build Accuracy Tool" OFF) option(FLATC_DIR "Path to Flatbuffers compiler" OFF) option(TF_LITE_GENERATED_PATH "Tensorflow lite generated C++ schema location" OFF) option(FLATBUFFERS_ROOT "Location where the flatbuffers 'include' and 'lib' folders to be found" Off) +option(DYNAMIC_BACKEND_PATHS "Colon seperated list of paths where to load the dynamic backends from" "") include(SelectLibraryConfigurations) diff --git a/include/armnn/IRuntime.hpp b/include/armnn/IRuntime.hpp index 0366663841..3f3c998f3a 100644 --- a/include/armnn/IRuntime.hpp +++ b/include/armnn/IRuntime.hpp @@ -31,6 +31,7 @@ public: CreationOptions() : m_GpuAccTunedParameters(nullptr) , m_EnableGpuProfiling(false) + , m_DynamicBackendsPath("") {} /// If set, uses the GpuAcc tuned parameters from the given object when executing GPU workloads. @@ -39,6 +40,10 @@ public: // Setting this flag will allow the user to obtain GPU profiling information from the runtime. bool m_EnableGpuProfiling; + + // Setting this value will override the paths set by the DYNAMIC_BACKEND_PATHS compiler directive + // Only a single path is allowed for the override + std::string m_DynamicBackendsPath; }; static IRuntime* CreateRaw(const CreationOptions& options); diff --git a/src/backends/backendsCommon/DynamicBackendUtils.cpp b/src/backends/backendsCommon/DynamicBackendUtils.cpp index 0ab02d7c98..ae36a24b30 100644 --- a/src/backends/backendsCommon/DynamicBackendUtils.cpp +++ b/src/backends/backendsCommon/DynamicBackendUtils.cpp @@ -5,6 +5,10 @@ #include "DynamicBackendUtils.hpp" +#include <boost/filesystem/operations.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/log/trivial.hpp> + namespace armnn { @@ -59,4 +63,92 @@ std::string DynamicBackendUtils::GetDlError() return std::string(errorMessage); } +std::vector<std::string> DynamicBackendUtils::GetBackendPaths(const std::string& overrideBackendPath) +{ + // Check if a path where to dynamically load the backends from is given + if (!overrideBackendPath.empty()) + { + if (!IsPathValid(overrideBackendPath)) + { + BOOST_LOG_TRIVIAL(warning) << "WARNING: The given override path for dynamic backends \"" + << overrideBackendPath << "\" is not valid"; + + return {}; + } + + return std::vector<std::string>{ overrideBackendPath }; + } + + // Expects a colon-separated list: DYNAMIC_BACKEND_PATHS="PATH_1:PATH_2:...:PATH_N" + const std::string backendPaths = DYNAMIC_BACKEND_PATHS; + + return GetBackendPathsImpl(backendPaths); +} + +std::vector<std::string> DynamicBackendUtils::GetBackendPathsImpl(const std::string& backendPaths) +{ + std::unordered_set<std::string> uniqueBackendPaths; + std::vector<std::string> tempBackendPaths; + std::vector<std::string> validBackendPaths; + + // Split the given list of paths + boost::split(tempBackendPaths, backendPaths, boost::is_any_of(":")); + + for (const std::string& path : tempBackendPaths) + { + // Check whether the path is valid + if (!IsPathValid(path)) + { + continue; + } + + // Check whether the path is a duplicate + auto it = uniqueBackendPaths.find(path); + if (it != uniqueBackendPaths.end()) + { + // The path is a duplicate + continue; + } + + // Add the path to the set of unique paths + uniqueBackendPaths.insert(path); + + // Add the path to the list of valid paths + validBackendPaths.push_back(path); + } + + return validBackendPaths; +} + +bool DynamicBackendUtils::IsPathValid(const std::string& path) +{ + if (path.empty()) + { + BOOST_LOG_TRIVIAL(warning) << "WARNING: The given backend path is empty"; + return false; + } + + boost::filesystem::path boostPath(path); + + if (!boost::filesystem::exists(boostPath)) + { + BOOST_LOG_TRIVIAL(warning) << "WARNING: The given backend path \"" << path << "\" does not exist"; + return false; + } + + if (!boost::filesystem::is_directory(boostPath)) + { + BOOST_LOG_TRIVIAL(warning) << "WARNING: The given backend path \"" << path << "\" is not a directory"; + return false; + } + + if (!boostPath.is_absolute()) + { + BOOST_LOG_TRIVIAL(warning) << "WARNING: The given backend path \"" << path << "\" is not absolute"; + return false; + } + + return true; +} + } // namespace armnn diff --git a/src/backends/backendsCommon/DynamicBackendUtils.hpp b/src/backends/backendsCommon/DynamicBackendUtils.hpp index 0a2d428fd3..f0bfd3b220 100644 --- a/src/backends/backendsCommon/DynamicBackendUtils.hpp +++ b/src/backends/backendsCommon/DynamicBackendUtils.hpp @@ -11,9 +11,14 @@ #include <string> #include <dlfcn.h> +#include <vector> #include <boost/format.hpp> +#if !defined(DYNAMIC_BACKEND_PATHS) +#define DYNAMIC_BACKEND_PATHS "" +#endif + namespace armnn { @@ -28,9 +33,13 @@ public: static bool IsBackendCompatible(const BackendVersion& backendVersion); + static std::vector<std::string> GetBackendPaths(const std::string& overrideBackendPath = ""); + static bool IsPathValid(const std::string& path); + protected: - /// Protected for testing purposes + /// Protected methods for testing purposes static bool IsBackendCompatibleImpl(const BackendVersion& backendApiVersion, const BackendVersion& backendVersion); + static std::vector<std::string> GetBackendPathsImpl(const std::string& backendPaths); private: static std::string GetDlError(); diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.cpp b/src/backends/backendsCommon/test/DynamicBackendTests.cpp index 10a650af7e..16d07c1a47 100644 --- a/src/backends/backendsCommon/test/DynamicBackendTests.cpp +++ b/src/backends/backendsCommon/test/DynamicBackendTests.cpp @@ -40,4 +40,7 @@ ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendObjectInvalidInterface6, ARMNN_SIMPLE_TEST_CASE(CreateDynamicBackendObjectInvalidInterface7, CreateDynamicBackendObjectInvalidInterface7TestImpl); +ARMNN_SIMPLE_TEST_CASE(GetBackendPaths, GetBackendPathsTestImpl) +ARMNN_SIMPLE_TEST_CASE(GetBackendPathsOverride, GetBackendPathsOverrideTestImpl) + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.hpp b/src/backends/backendsCommon/test/DynamicBackendTests.hpp index 55f90d48eb..32778118c3 100644 --- a/src/backends/backendsCommon/test/DynamicBackendTests.hpp +++ b/src/backends/backendsCommon/test/DynamicBackendTests.hpp @@ -34,6 +34,11 @@ static std::string g_TestInvalidTestDynamicBackend5FileName = "libInvalidTestDyn static std::string g_TestInvalidTestDynamicBackend6FileName = "libInvalidTestDynamicBackend6.so"; static std::string g_TestInvalidTestDynamicBackend7FileName = "libInvalidTestDynamicBackend7.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/"; + std::string GetTestDirectoryBasePath() { using namespace boost::filesystem; @@ -455,3 +460,113 @@ void CreateDynamicBackendObjectInvalidInterface7TestImpl() BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException); BOOST_TEST((dynamicBackend == nullptr)); } + +void GetBackendPathsTestImpl() +{ + using namespace armnn; + using namespace boost::filesystem; + + // 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 + + std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir1); + std::string subDir2 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir2); + std::string subDir3 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir3); + std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir4); + + BOOST_CHECK(exists(subDir1)); + BOOST_CHECK(exists(subDir2)); + BOOST_CHECK(exists(subDir3)); + BOOST_CHECK(!exists(subDir4)); + + class TestDynamicBackendUtils : public DynamicBackendUtils + { + public: + static std::vector<std::string> GetBackendPathsImplTest(const std::string& path) + { + return GetBackendPathsImpl(path); + } + }; + + // No path + BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest("").empty()); + + // Malformed path + std::string malformedDir(subDir1 + "/" + subDir1); + BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(malformedDir).size()==0); + + // Single valid path + std::vector<std::string> DynamicBackendPaths2 = TestDynamicBackendUtils::GetBackendPathsImplTest(subDir1); + BOOST_TEST(DynamicBackendPaths2.size() == 1); + BOOST_TEST(DynamicBackendPaths2[0] == subDir1); + + // Multiple equal and valid paths + std::string multipleEqualDirs(subDir1 + ":" + subDir1); + std::vector<std::string> DynamicBackendPaths3 = TestDynamicBackendUtils::GetBackendPathsImplTest(multipleEqualDirs); + BOOST_TEST(DynamicBackendPaths3.size() == 1); + BOOST_TEST(DynamicBackendPaths3[0] == subDir1); + + // Multiple empty paths + BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(":::").empty()); + + // Multiple valid paths + std::string multipleValidPaths(subDir1 + ":" + subDir2 + ":" + subDir3); + std::vector<std::string> DynamicBackendPaths5 = + TestDynamicBackendUtils::GetBackendPathsImplTest(multipleValidPaths); + BOOST_TEST(DynamicBackendPaths5.size() == 3); + BOOST_TEST(DynamicBackendPaths5[0] == subDir1); + BOOST_TEST(DynamicBackendPaths5[1] == subDir2); + BOOST_TEST(DynamicBackendPaths5[2] == subDir3); + + // Valid among empty paths + std::string validAmongEmptyDirs("::" + subDir1 + ":"); + std::vector<std::string> DynamicBackendPaths6 = + TestDynamicBackendUtils::GetBackendPathsImplTest(validAmongEmptyDirs); + BOOST_TEST(DynamicBackendPaths6.size() == 1); + BOOST_TEST(DynamicBackendPaths6[0] == subDir1); + + // Invalid among empty paths + std::string invalidAmongEmptyDirs(":" + subDir4 + "::"); + BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(invalidAmongEmptyDirs).empty()); + + // Valid, invalid and empty paths + std::string validInvalidEmptyDirs(subDir1 + ":" + subDir4 + ":"); + std::vector<std::string> DynamicBackendPaths8 = + TestDynamicBackendUtils::GetBackendPathsImplTest(validInvalidEmptyDirs); + BOOST_TEST(DynamicBackendPaths8.size() == 1); + BOOST_TEST(DynamicBackendPaths8[0] == subDir1); + + // Mix of duplicates of valid, invalid and empty paths + std::string duplicateValidInvalidEmptyDirs(validInvalidEmptyDirs + ":" + validInvalidEmptyDirs + ":" + + subDir2 + ":" + subDir2); + std::vector<std::string> DynamicBackendPaths9 = + TestDynamicBackendUtils::GetBackendPathsImplTest(duplicateValidInvalidEmptyDirs); + BOOST_TEST(DynamicBackendPaths9.size() == 2); + BOOST_TEST(DynamicBackendPaths9[0] == subDir1); + BOOST_TEST(DynamicBackendPaths9[1] == subDir2); +} + +void GetBackendPathsOverrideTestImpl() +{ + using namespace armnn; + using namespace boost::filesystem; + + std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir1); + std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsFileParsingSubDir4); + + BOOST_CHECK(exists(subDir1)); + BOOST_CHECK(!exists(subDir4)); + + // Override with valid path + std::vector<std::string> validResult = DynamicBackendUtils::GetBackendPaths(subDir1); + BOOST_TEST(validResult.size() == 1); + BOOST_TEST(validResult[0] == subDir1); + + // Override with invalid path + std::vector<std::string> invalidResult = DynamicBackendUtils::GetBackendPaths(subDir4); + BOOST_TEST(invalidResult.empty()); +} |