diff options
author | Francis Murtagh <francis.murtagh@arm.com> | 2021-01-25 10:18:10 +0000 |
---|---|---|
committer | Francis Murtagh <francis.murtagh@arm.com> | 2021-01-25 10:18:20 +0000 |
commit | 5dc64fe99227efece77eb7cd14abc47474a48fb8 (patch) | |
tree | 09de113127e07707ad8edb20075463696055f736 | |
parent | 2686849118217ba692439407adb53ec3849d48ac (diff) | |
download | armnn-5dc64fe99227efece77eb7cd14abc47474a48fb8.tar.gz |
IVGCVSW-5525 Handle Neon optionality on 32 bit linux platforms
* Add neon detection for linux using HWCAPs
* Add test to check for backend throwing BackendUnavailable exception
Signed-off-by: Francis Murtagh <francis.murtagh@arm.com>
Change-Id: Ib74aeb06abe5f88f21ecdd1edb2a1cd20ee2019d
-rw-r--r-- | include/armnn/Utils.hpp | 2 | ||||
-rw-r--r-- | src/armnn/Utils.cpp | 48 | ||||
-rw-r--r-- | src/backends/backendsCommon/test/BackendRegistryTests.cpp | 44 | ||||
-rw-r--r-- | src/backends/neon/NeonRegistryInitializer.cpp | 12 |
4 files changed, 105 insertions, 1 deletions
diff --git a/include/armnn/Utils.hpp b/include/armnn/Utils.hpp index 773a4036e2..efd3d218e3 100644 --- a/include/armnn/Utils.hpp +++ b/include/armnn/Utils.hpp @@ -35,4 +35,6 @@ void ConfigureLogging(bool printToStandardOutput, bool printToDebugOutput, LogSe # define ARMNN_FALLTHROUGH ((void)0) #endif +bool NeonDetected(); + } // namespace armnn diff --git a/src/armnn/Utils.cpp b/src/armnn/Utils.cpp index 13bf3025f2..62c8ae6262 100644 --- a/src/armnn/Utils.cpp +++ b/src/armnn/Utils.cpp @@ -5,6 +5,13 @@ #include "armnn/Logging.hpp" #include "armnn/Utils.hpp" +#if !defined(BARE_METAL) && (defined(__arm__) || defined(__aarch64__)) + +#include <sys/auxv.h> +#include <asm/hwcap.h> + +#endif + namespace armnn { void ConfigureLogging(bool printToStandardOutput, bool printToDebugOutput, LogSeverity severity) @@ -25,4 +32,45 @@ struct DefaultLoggingConfiguration static DefaultLoggingConfiguration g_DefaultLoggingConfiguration; +// Detect the presence of Neon on Linux +bool NeonDetected() +{ +#if !defined(BARE_METAL) && (defined(__arm__) || defined(__aarch64__)) + auto hwcaps= getauxval(AT_HWCAP); +#endif + +#if !defined(BARE_METAL) && defined(__aarch64__) + + if (hwcaps & HWCAP_ASIMD) + { + // On an arm64 device with Neon. + return true; + } + else + { + // On an arm64 device without Neon. + return false; + } + +#endif +#if !defined(BARE_METAL) && defined(__arm__) + + if (hwcaps & HWCAP_NEON) + { + // On an armhf device with Neon. + return true; + } + else + { + // On an armhf device without Neon. + return false; + } + +#endif + + // This method of Neon detection is only supported on Linux so in order to prevent a false negative + // we will return true in cases where detection did not run. + return true; +} + } // namespace armnn
\ No newline at end of file diff --git a/src/backends/backendsCommon/test/BackendRegistryTests.cpp b/src/backends/backendsCommon/test/BackendRegistryTests.cpp index 213d114248..ce8acbbf2a 100644 --- a/src/backends/backendsCommon/test/BackendRegistryTests.cpp +++ b/src/backends/backendsCommon/test/BackendRegistryTests.cpp @@ -7,6 +7,7 @@ #include <armnn/BackendRegistry.hpp> #include <armnn/backends/IBackendInternal.hpp> +#include <reference/RefBackend.hpp> #include <boost/test/unit_test.hpp> @@ -103,4 +104,47 @@ BOOST_AUTO_TEST_CASE(TestDirectCallToRegistry) BackendRegistryInstance().Deregister("HelloWorld"); } +// Test that backends can throw exceptions during their factory function to prevent loading in an unsuitable +// environment. For example Neon Backend loading on armhf device without neon support. +// In reality the dynamic backend is loaded in during the LoadDynamicBackends(options.m_DynamicBackendsPath) +// step of runtime constructor, then the factory function is called to check if supported, in case +// of Neon not being detected the exception is raised and so the backend is not added to the supportedBackends +// list + +BOOST_AUTO_TEST_CASE(ThrowBackendUnavailableException) +{ + using namespace armnn; + + const BackendId mockBackendId("MockDynamicBackend"); + + const std::string exceptionMessage("Neon support not found on device, could not register CpuAcc Backend.\n"); + + // Register the mock backend with a factory function lambda equivalent to NeonRegisterInitializer + BackendRegistryInstance().Register(mockBackendId, + [exceptionMessage]() + { + if (false) + { + return IBackendInternalUniquePtr(new RefBackend); + } + ARMNN_LOG(info) << "Neon support not found on device, could not register CpuAcc Backend."; + throw armnn::BackendUnavailableException(exceptionMessage); + }); + + // Get the factory function of the mock backend + auto factoryFunc = BackendRegistryInstance().GetFactory(mockBackendId); + + try + { + // Call the factory function as done during runtime backend registering + auto backend = factoryFunc(); + } + catch (const BackendUnavailableException& e) + { + // Caught + BOOST_CHECK_EQUAL(e.what(), exceptionMessage); + BOOST_TEST_MESSAGE("ThrowBackendUnavailableExceptionImpl: BackendUnavailableException caught."); + } +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/backends/neon/NeonRegistryInitializer.cpp b/src/backends/neon/NeonRegistryInitializer.cpp index fd2e84dd5f..fc981ab270 100644 --- a/src/backends/neon/NeonRegistryInitializer.cpp +++ b/src/backends/neon/NeonRegistryInitializer.cpp @@ -6,6 +6,7 @@ #include "NeonBackend.hpp" #include <armnn/BackendRegistry.hpp> +#include <armnn/Utils.hpp> namespace { @@ -18,7 +19,16 @@ static BackendRegistry::StaticRegistryInitializer g_RegisterHelper NeonBackend::GetIdStatic(), []() { - return IBackendInternalUniquePtr(new NeonBackend); + // Check if device supports Neon. + if (NeonDetected()) + { + return IBackendInternalUniquePtr(new NeonBackend); + } + + // If device does not support Neon throw exception so the Backend is not added to supportedBackends + ARMNN_LOG(info) << "Neon support not found on device, could not register CpuAcc Backend."; + throw armnn::BackendUnavailableException( + "Neon support not found on device, could not register CpuAcc Backend.\n"); } }; |