From e7d449893b85a00a063836bd01dce4f925a24dd2 Mon Sep 17 00:00:00 2001 From: Matteo Martincigh Date: Mon, 5 Aug 2019 12:16:47 +0100 Subject: 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 Signed-off-by: Matteo Martincigh --- CMakeLists.txt | 8 +- cmake/GlobalConfig.cmake | 1 + include/armnn/IRuntime.hpp | 5 + .../backendsCommon/DynamicBackendUtils.cpp | 92 +++++++++++++++++ .../backendsCommon/DynamicBackendUtils.hpp | 11 +- .../backendsCommon/test/DynamicBackendTests.cpp | 3 + .../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 +#include +#include + namespace armnn { @@ -59,4 +63,92 @@ std::string DynamicBackendUtils::GetDlError() return std::string(errorMessage); } +std::vector 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{ 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 DynamicBackendUtils::GetBackendPathsImpl(const std::string& backendPaths) +{ + std::unordered_set uniqueBackendPaths; + std::vector tempBackendPaths; + std::vector 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 #include +#include #include +#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 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 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: + // /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 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 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 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 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 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 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 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 validResult = DynamicBackendUtils::GetBackendPaths(subDir1); + BOOST_TEST(validResult.size() == 1); + BOOST_TEST(validResult[0] == subDir1); + + // Override with invalid path + std::vector invalidResult = DynamicBackendUtils::GetBackendPaths(subDir4); + BOOST_TEST(invalidResult.empty()); +} -- cgit v1.2.1