1*89c4ff92SAndroid Build Coastguard Worker // 2*89c4ff92SAndroid Build Coastguard Worker // Copyright © 2017 Arm Ltd. All rights reserved. 3*89c4ff92SAndroid Build Coastguard Worker // SPDX-License-Identifier: MIT 4*89c4ff92SAndroid Build Coastguard Worker // 5*89c4ff92SAndroid Build Coastguard Worker 6*89c4ff92SAndroid Build Coastguard Worker #include <armnn/backends/DynamicBackend.hpp> 7*89c4ff92SAndroid Build Coastguard Worker #include <backendsCommon/DynamicBackendUtils.hpp> 8*89c4ff92SAndroid Build Coastguard Worker 9*89c4ff92SAndroid Build Coastguard Worker namespace armnn 10*89c4ff92SAndroid Build Coastguard Worker { 11*89c4ff92SAndroid Build Coastguard Worker DynamicBackend(const void * sharedObjectHandle)12*89c4ff92SAndroid Build Coastguard WorkerDynamicBackend::DynamicBackend(const void* sharedObjectHandle) 13*89c4ff92SAndroid Build Coastguard Worker : m_BackendIdFunction(nullptr) 14*89c4ff92SAndroid Build Coastguard Worker , m_BackendVersionFunction(nullptr) 15*89c4ff92SAndroid Build Coastguard Worker , m_BackendFactoryFunction(nullptr) 16*89c4ff92SAndroid Build Coastguard Worker , m_Handle(const_cast<void*>(sharedObjectHandle), &DynamicBackendUtils::CloseHandle) 17*89c4ff92SAndroid Build Coastguard Worker { 18*89c4ff92SAndroid Build Coastguard Worker if (m_Handle == nullptr) 19*89c4ff92SAndroid Build Coastguard Worker { 20*89c4ff92SAndroid Build Coastguard Worker throw InvalidArgumentException("Cannot create a DynamicBackend object from an invalid shared object handle"); 21*89c4ff92SAndroid Build Coastguard Worker } 22*89c4ff92SAndroid Build Coastguard Worker 23*89c4ff92SAndroid Build Coastguard Worker // These calls will throw in case of error 24*89c4ff92SAndroid Build Coastguard Worker m_BackendIdFunction = SetFunctionPointer<IdFunctionType>("GetBackendId"); 25*89c4ff92SAndroid Build Coastguard Worker m_BackendVersionFunction = SetFunctionPointer<VersionFunctionType>("GetVersion"); 26*89c4ff92SAndroid Build Coastguard Worker m_BackendFactoryFunction = SetFunctionPointer<FactoryFunctionType>("BackendFactory"); 27*89c4ff92SAndroid Build Coastguard Worker 28*89c4ff92SAndroid Build Coastguard Worker // Check that the backend is compatible with the current Backend API 29*89c4ff92SAndroid Build Coastguard Worker BackendId backendId = GetBackendId(); 30*89c4ff92SAndroid Build Coastguard Worker BackendVersion backendVersion = GetBackendVersion(); 31*89c4ff92SAndroid Build Coastguard Worker if (!DynamicBackendUtils::IsBackendCompatible(backendVersion)) 32*89c4ff92SAndroid Build Coastguard Worker { 33*89c4ff92SAndroid Build Coastguard Worker // This exception message could not be formatted simply using fmt::format 34*89c4ff92SAndroid Build Coastguard Worker std::stringstream message; 35*89c4ff92SAndroid Build Coastguard Worker message << "The dynamic backend " << backendId << " (version " << backendVersion << 36*89c4ff92SAndroid Build Coastguard Worker ") is not compatible with the current Backend API (version " << IBackendInternal::GetApiVersion() << ")"; 37*89c4ff92SAndroid Build Coastguard Worker 38*89c4ff92SAndroid Build Coastguard Worker throw RuntimeException(message.str()); 39*89c4ff92SAndroid Build Coastguard Worker } 40*89c4ff92SAndroid Build Coastguard Worker } 41*89c4ff92SAndroid Build Coastguard Worker GetBackendId()42*89c4ff92SAndroid Build Coastguard WorkerBackendId DynamicBackend::GetBackendId() 43*89c4ff92SAndroid Build Coastguard Worker { 44*89c4ff92SAndroid Build Coastguard Worker if (m_BackendIdFunction == nullptr) 45*89c4ff92SAndroid Build Coastguard Worker { 46*89c4ff92SAndroid Build Coastguard Worker throw RuntimeException("GetBackendId error: invalid function pointer"); 47*89c4ff92SAndroid Build Coastguard Worker } 48*89c4ff92SAndroid Build Coastguard Worker 49*89c4ff92SAndroid Build Coastguard Worker const char* backendId = m_BackendIdFunction(); 50*89c4ff92SAndroid Build Coastguard Worker if (backendId == nullptr) 51*89c4ff92SAndroid Build Coastguard Worker { 52*89c4ff92SAndroid Build Coastguard Worker throw RuntimeException("GetBackendId error: invalid backend id"); 53*89c4ff92SAndroid Build Coastguard Worker } 54*89c4ff92SAndroid Build Coastguard Worker 55*89c4ff92SAndroid Build Coastguard Worker return BackendId(backendId); 56*89c4ff92SAndroid Build Coastguard Worker } 57*89c4ff92SAndroid Build Coastguard Worker GetBackendVersion()58*89c4ff92SAndroid Build Coastguard WorkerBackendVersion DynamicBackend::GetBackendVersion() 59*89c4ff92SAndroid Build Coastguard Worker { 60*89c4ff92SAndroid Build Coastguard Worker if (m_BackendVersionFunction == nullptr) 61*89c4ff92SAndroid Build Coastguard Worker { 62*89c4ff92SAndroid Build Coastguard Worker throw RuntimeException("GetBackendVersion error: invalid function pointer"); 63*89c4ff92SAndroid Build Coastguard Worker } 64*89c4ff92SAndroid Build Coastguard Worker 65*89c4ff92SAndroid Build Coastguard Worker uint32_t major = 0; 66*89c4ff92SAndroid Build Coastguard Worker uint32_t minor = 0; 67*89c4ff92SAndroid Build Coastguard Worker m_BackendVersionFunction(&major, &minor); 68*89c4ff92SAndroid Build Coastguard Worker 69*89c4ff92SAndroid Build Coastguard Worker return BackendVersion{ major, minor }; 70*89c4ff92SAndroid Build Coastguard Worker } 71*89c4ff92SAndroid Build Coastguard Worker GetBackend()72*89c4ff92SAndroid Build Coastguard WorkerIBackendInternalUniquePtr DynamicBackend::GetBackend() 73*89c4ff92SAndroid Build Coastguard Worker { 74*89c4ff92SAndroid Build Coastguard Worker // This call throws in case of error 75*89c4ff92SAndroid Build Coastguard Worker return CreateBackend(); 76*89c4ff92SAndroid Build Coastguard Worker } 77*89c4ff92SAndroid Build Coastguard Worker GetFactoryFunction()78*89c4ff92SAndroid Build Coastguard WorkerBackendRegistry::FactoryFunction DynamicBackend::GetFactoryFunction() 79*89c4ff92SAndroid Build Coastguard Worker { 80*89c4ff92SAndroid Build Coastguard Worker if (m_BackendFactoryFunction == nullptr) 81*89c4ff92SAndroid Build Coastguard Worker { 82*89c4ff92SAndroid Build Coastguard Worker throw RuntimeException("GetFactoryFunction error: invalid function pointer"); 83*89c4ff92SAndroid Build Coastguard Worker } 84*89c4ff92SAndroid Build Coastguard Worker 85*89c4ff92SAndroid Build Coastguard Worker return [this]() -> IBackendInternalUniquePtr 86*89c4ff92SAndroid Build Coastguard Worker { 87*89c4ff92SAndroid Build Coastguard Worker // This call throws in case of error 88*89c4ff92SAndroid Build Coastguard Worker return CreateBackend(); 89*89c4ff92SAndroid Build Coastguard Worker }; 90*89c4ff92SAndroid Build Coastguard Worker } 91*89c4ff92SAndroid Build Coastguard Worker 92*89c4ff92SAndroid Build Coastguard Worker template<typename BackendFunctionType> SetFunctionPointer(const std::string & backendFunctionName)93*89c4ff92SAndroid Build Coastguard WorkerBackendFunctionType DynamicBackend::SetFunctionPointer(const std::string& backendFunctionName) 94*89c4ff92SAndroid Build Coastguard Worker { 95*89c4ff92SAndroid Build Coastguard Worker if (m_Handle == nullptr) 96*89c4ff92SAndroid Build Coastguard Worker { 97*89c4ff92SAndroid Build Coastguard Worker throw RuntimeException("SetFunctionPointer error: invalid shared object handle"); 98*89c4ff92SAndroid Build Coastguard Worker } 99*89c4ff92SAndroid Build Coastguard Worker 100*89c4ff92SAndroid Build Coastguard Worker if (backendFunctionName.empty()) 101*89c4ff92SAndroid Build Coastguard Worker { 102*89c4ff92SAndroid Build Coastguard Worker throw RuntimeException("SetFunctionPointer error: backend function name must not be empty"); 103*89c4ff92SAndroid Build Coastguard Worker } 104*89c4ff92SAndroid Build Coastguard Worker 105*89c4ff92SAndroid Build Coastguard Worker // This call will throw in case of error 106*89c4ff92SAndroid Build Coastguard Worker auto functionPointer = DynamicBackendUtils::GetEntryPoint<BackendFunctionType>(m_Handle.get(), 107*89c4ff92SAndroid Build Coastguard Worker backendFunctionName.c_str()); 108*89c4ff92SAndroid Build Coastguard Worker if (!functionPointer) 109*89c4ff92SAndroid Build Coastguard Worker { 110*89c4ff92SAndroid Build Coastguard Worker throw RuntimeException("SetFunctionPointer error: invalid backend function pointer returned"); 111*89c4ff92SAndroid Build Coastguard Worker } 112*89c4ff92SAndroid Build Coastguard Worker 113*89c4ff92SAndroid Build Coastguard Worker return functionPointer; 114*89c4ff92SAndroid Build Coastguard Worker } 115*89c4ff92SAndroid Build Coastguard Worker CreateBackend()116*89c4ff92SAndroid Build Coastguard WorkerIBackendInternalUniquePtr DynamicBackend::CreateBackend() 117*89c4ff92SAndroid Build Coastguard Worker { 118*89c4ff92SAndroid Build Coastguard Worker if (m_BackendFactoryFunction == nullptr) 119*89c4ff92SAndroid Build Coastguard Worker { 120*89c4ff92SAndroid Build Coastguard Worker throw RuntimeException("CreateBackend error: invalid function pointer"); 121*89c4ff92SAndroid Build Coastguard Worker } 122*89c4ff92SAndroid Build Coastguard Worker 123*89c4ff92SAndroid Build Coastguard Worker auto backendPointer = reinterpret_cast<IBackendInternal*>(m_BackendFactoryFunction()); 124*89c4ff92SAndroid Build Coastguard Worker if (backendPointer == nullptr) 125*89c4ff92SAndroid Build Coastguard Worker { 126*89c4ff92SAndroid Build Coastguard Worker throw RuntimeException("CreateBackend error: backend instance must not be null"); 127*89c4ff92SAndroid Build Coastguard Worker } 128*89c4ff92SAndroid Build Coastguard Worker 129*89c4ff92SAndroid Build Coastguard Worker return std::unique_ptr<IBackendInternal>(backendPointer); 130*89c4ff92SAndroid Build Coastguard Worker } 131*89c4ff92SAndroid Build Coastguard Worker 132*89c4ff92SAndroid Build Coastguard Worker } // namespace armnn 133