// // Copyright © 2017 Arm Ltd. All rights reserved. // SPDX-License-Identifier: MIT // #include #include #include #include #include namespace { class SwapRegistryStorage : public armnn::BackendRegistry { public: SwapRegistryStorage() : armnn::BackendRegistry() { Swap(armnn::BackendRegistryInstance(), m_TempStorage); } ~SwapRegistryStorage() { Swap(armnn::BackendRegistryInstance(),m_TempStorage); } private: FactoryStorage m_TempStorage; }; } BOOST_AUTO_TEST_SUITE(BackendRegistryTests) BOOST_AUTO_TEST_CASE(SwapRegistry) { using namespace armnn; auto nFactories = BackendRegistryInstance().Size(); { SwapRegistryStorage helper; BOOST_TEST(BackendRegistryInstance().Size() == 0); } BOOST_TEST(BackendRegistryInstance().Size() == nFactories); } BOOST_AUTO_TEST_CASE(TestRegistryHelper) { using namespace armnn; SwapRegistryStorage helper; bool called = false; BackendRegistry::StaticRegistryInitializer factoryHelper( BackendRegistryInstance(), "HelloWorld", [&called]() { called = true; return armnn::IBackendInternalUniquePtr(nullptr); } ); // sanity check: the factory has not been called yet BOOST_TEST(called == false); auto factoryFunction = BackendRegistryInstance().GetFactory("HelloWorld"); // sanity check: the factory still not called BOOST_TEST(called == false); factoryFunction(); BOOST_TEST(called == true); BackendRegistryInstance().Deregister("HelloWorld"); } BOOST_AUTO_TEST_CASE(TestDirectCallToRegistry) { using namespace armnn; SwapRegistryStorage helper; bool called = false; BackendRegistryInstance().Register( "HelloWorld", [&called]() { called = true; return armnn::IBackendInternalUniquePtr(nullptr); } ); // sanity check: the factory has not been called yet BOOST_TEST(called == false); auto factoryFunction = BackendRegistryInstance().GetFactory("HelloWorld"); // sanity check: the factory still not called BOOST_TEST(called == false); factoryFunction(); BOOST_TEST(called == true); 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()