xref: /aosp_15_r20/external/armnn/src/backends/backendsCommon/DynamicBackendUtils.cpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1*89c4ff92SAndroid Build Coastguard Worker //
2*89c4ff92SAndroid Build Coastguard Worker // Copyright © 2017 Arm Ltd and Contributors. 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/Logging.hpp>
7*89c4ff92SAndroid Build Coastguard Worker #include <backendsCommon/DynamicBackendUtils.hpp>
8*89c4ff92SAndroid Build Coastguard Worker #include "armnn/utility/StringUtils.hpp"
9*89c4ff92SAndroid Build Coastguard Worker #include <armnnUtils/Filesystem.hpp>
10*89c4ff92SAndroid Build Coastguard Worker 
11*89c4ff92SAndroid Build Coastguard Worker #include <regex>
12*89c4ff92SAndroid Build Coastguard Worker 
13*89c4ff92SAndroid Build Coastguard Worker namespace armnn
14*89c4ff92SAndroid Build Coastguard Worker {
15*89c4ff92SAndroid Build Coastguard Worker 
OpenHandle(const std::string & sharedObjectPath)16*89c4ff92SAndroid Build Coastguard Worker void* DynamicBackendUtils::OpenHandle(const std::string& sharedObjectPath)
17*89c4ff92SAndroid Build Coastguard Worker {
18*89c4ff92SAndroid Build Coastguard Worker #if defined(__unix__) || defined(__APPLE__)
19*89c4ff92SAndroid Build Coastguard Worker     if (sharedObjectPath.empty())
20*89c4ff92SAndroid Build Coastguard Worker     {
21*89c4ff92SAndroid Build Coastguard Worker         throw RuntimeException("OpenHandle error: shared object path must not be empty");
22*89c4ff92SAndroid Build Coastguard Worker     }
23*89c4ff92SAndroid Build Coastguard Worker 
24*89c4ff92SAndroid Build Coastguard Worker     void* sharedObjectHandle = dlopen(sharedObjectPath.c_str(), RTLD_LAZY);
25*89c4ff92SAndroid Build Coastguard Worker     if (!sharedObjectHandle)
26*89c4ff92SAndroid Build Coastguard Worker     {
27*89c4ff92SAndroid Build Coastguard Worker         throw RuntimeException(fmt::format("OpenHandle error: {}", GetDlError()));
28*89c4ff92SAndroid Build Coastguard Worker     }
29*89c4ff92SAndroid Build Coastguard Worker 
30*89c4ff92SAndroid Build Coastguard Worker     return sharedObjectHandle;
31*89c4ff92SAndroid Build Coastguard Worker #else
32*89c4ff92SAndroid Build Coastguard Worker     armnn::IgnoreUnused(sharedObjectPath);
33*89c4ff92SAndroid Build Coastguard Worker     throw RuntimeException("Dynamic backends not supported on this platform");
34*89c4ff92SAndroid Build Coastguard Worker #endif
35*89c4ff92SAndroid Build Coastguard Worker }
36*89c4ff92SAndroid Build Coastguard Worker 
CloseHandle(const void * sharedObjectHandle)37*89c4ff92SAndroid Build Coastguard Worker void DynamicBackendUtils::CloseHandle(const void* sharedObjectHandle)
38*89c4ff92SAndroid Build Coastguard Worker {
39*89c4ff92SAndroid Build Coastguard Worker #if defined(__unix__) || defined(__APPLE__)
40*89c4ff92SAndroid Build Coastguard Worker     if (!sharedObjectHandle)
41*89c4ff92SAndroid Build Coastguard Worker     {
42*89c4ff92SAndroid Build Coastguard Worker         return;
43*89c4ff92SAndroid Build Coastguard Worker     }
44*89c4ff92SAndroid Build Coastguard Worker 
45*89c4ff92SAndroid Build Coastguard Worker     dlclose(const_cast<void*>(sharedObjectHandle));
46*89c4ff92SAndroid Build Coastguard Worker #else
47*89c4ff92SAndroid Build Coastguard Worker     armnn::IgnoreUnused(sharedObjectHandle);
48*89c4ff92SAndroid Build Coastguard Worker     throw RuntimeException("Dynamic backends not supported on this platform");
49*89c4ff92SAndroid Build Coastguard Worker #endif
50*89c4ff92SAndroid Build Coastguard Worker }
51*89c4ff92SAndroid Build Coastguard Worker 
IsBackendCompatible(const BackendVersion & backendVersion)52*89c4ff92SAndroid Build Coastguard Worker bool DynamicBackendUtils::IsBackendCompatible(const BackendVersion &backendVersion)
53*89c4ff92SAndroid Build Coastguard Worker {
54*89c4ff92SAndroid Build Coastguard Worker     BackendVersion backendApiVersion = IBackendInternal::GetApiVersion();
55*89c4ff92SAndroid Build Coastguard Worker 
56*89c4ff92SAndroid Build Coastguard Worker     return IsBackendCompatibleImpl(backendApiVersion, backendVersion);
57*89c4ff92SAndroid Build Coastguard Worker }
58*89c4ff92SAndroid Build Coastguard Worker 
IsBackendCompatibleImpl(const BackendVersion & backendApiVersion,const BackendVersion & backendVersion)59*89c4ff92SAndroid Build Coastguard Worker bool DynamicBackendUtils::IsBackendCompatibleImpl(const BackendVersion &backendApiVersion,
60*89c4ff92SAndroid Build Coastguard Worker                                                   const BackendVersion &backendVersion)
61*89c4ff92SAndroid Build Coastguard Worker {
62*89c4ff92SAndroid Build Coastguard Worker     return backendVersion.m_Major == backendApiVersion.m_Major &&
63*89c4ff92SAndroid Build Coastguard Worker            backendVersion.m_Minor <= backendApiVersion.m_Minor;
64*89c4ff92SAndroid Build Coastguard Worker }
65*89c4ff92SAndroid Build Coastguard Worker 
GetDlError()66*89c4ff92SAndroid Build Coastguard Worker std::string DynamicBackendUtils::GetDlError()
67*89c4ff92SAndroid Build Coastguard Worker {
68*89c4ff92SAndroid Build Coastguard Worker #if defined(__unix__) || defined(__APPLE__)
69*89c4ff92SAndroid Build Coastguard Worker     const char* errorMessage = dlerror();
70*89c4ff92SAndroid Build Coastguard Worker     if (!errorMessage)
71*89c4ff92SAndroid Build Coastguard Worker     {
72*89c4ff92SAndroid Build Coastguard Worker         return "";
73*89c4ff92SAndroid Build Coastguard Worker     }
74*89c4ff92SAndroid Build Coastguard Worker 
75*89c4ff92SAndroid Build Coastguard Worker     return std::string(errorMessage);
76*89c4ff92SAndroid Build Coastguard Worker #else
77*89c4ff92SAndroid Build Coastguard Worker     throw RuntimeException("Dynamic backends not supported on this platform");
78*89c4ff92SAndroid Build Coastguard Worker #endif
79*89c4ff92SAndroid Build Coastguard Worker }
80*89c4ff92SAndroid Build Coastguard Worker 
GetBackendPaths(const std::string & overrideBackendPath)81*89c4ff92SAndroid Build Coastguard Worker std::vector<std::string> DynamicBackendUtils::GetBackendPaths(const std::string& overrideBackendPath)
82*89c4ff92SAndroid Build Coastguard Worker {
83*89c4ff92SAndroid Build Coastguard Worker     // Check if a path where to dynamically load the backends from is given
84*89c4ff92SAndroid Build Coastguard Worker     if (!overrideBackendPath.empty())
85*89c4ff92SAndroid Build Coastguard Worker     {
86*89c4ff92SAndroid Build Coastguard Worker         if (!IsPathValid(overrideBackendPath))
87*89c4ff92SAndroid Build Coastguard Worker         {
88*89c4ff92SAndroid Build Coastguard Worker             ARMNN_LOG(warning) << "WARNING: The given override path for dynamic backends \""
89*89c4ff92SAndroid Build Coastguard Worker                                << overrideBackendPath << "\" is not valid";
90*89c4ff92SAndroid Build Coastguard Worker 
91*89c4ff92SAndroid Build Coastguard Worker             return {};
92*89c4ff92SAndroid Build Coastguard Worker         }
93*89c4ff92SAndroid Build Coastguard Worker 
94*89c4ff92SAndroid Build Coastguard Worker         return std::vector<std::string>{ overrideBackendPath };
95*89c4ff92SAndroid Build Coastguard Worker     }
96*89c4ff92SAndroid Build Coastguard Worker 
97*89c4ff92SAndroid Build Coastguard Worker     // Expects a colon-separated list: DYNAMIC_BACKEND_PATHS="PATH_1:PATH_2:...:PATH_N"
98*89c4ff92SAndroid Build Coastguard Worker     const std::string backendPaths = DYNAMIC_BACKEND_PATHS;
99*89c4ff92SAndroid Build Coastguard Worker 
100*89c4ff92SAndroid Build Coastguard Worker     return GetBackendPathsImpl(backendPaths);
101*89c4ff92SAndroid Build Coastguard Worker }
102*89c4ff92SAndroid Build Coastguard Worker 
GetBackendPathsImpl(const std::string & backendPaths)103*89c4ff92SAndroid Build Coastguard Worker std::vector<std::string> DynamicBackendUtils::GetBackendPathsImpl(const std::string& backendPaths)
104*89c4ff92SAndroid Build Coastguard Worker {
105*89c4ff92SAndroid Build Coastguard Worker     // Check if there's any path to process at all
106*89c4ff92SAndroid Build Coastguard Worker     if (backendPaths.empty())
107*89c4ff92SAndroid Build Coastguard Worker     {
108*89c4ff92SAndroid Build Coastguard Worker         // Silently return without issuing a warning as no paths have been passed, so
109*89c4ff92SAndroid Build Coastguard Worker         // the whole dynamic backend loading feature can be considered as disabled
110*89c4ff92SAndroid Build Coastguard Worker         return {};
111*89c4ff92SAndroid Build Coastguard Worker     }
112*89c4ff92SAndroid Build Coastguard Worker 
113*89c4ff92SAndroid Build Coastguard Worker     std::unordered_set<std::string> uniqueBackendPaths;
114*89c4ff92SAndroid Build Coastguard Worker     std::vector<std::string> validBackendPaths;
115*89c4ff92SAndroid Build Coastguard Worker 
116*89c4ff92SAndroid Build Coastguard Worker     // Split the given list of paths
117*89c4ff92SAndroid Build Coastguard Worker     std::vector<std::string> tempBackendPaths = armnn::stringUtils::StringTokenizer(backendPaths, ":");
118*89c4ff92SAndroid Build Coastguard Worker 
119*89c4ff92SAndroid Build Coastguard Worker     for (const std::string& path : tempBackendPaths)
120*89c4ff92SAndroid Build Coastguard Worker     {
121*89c4ff92SAndroid Build Coastguard Worker         // Check whether the path is valid
122*89c4ff92SAndroid Build Coastguard Worker         if (!IsPathValid(path))
123*89c4ff92SAndroid Build Coastguard Worker         {
124*89c4ff92SAndroid Build Coastguard Worker             continue;
125*89c4ff92SAndroid Build Coastguard Worker         }
126*89c4ff92SAndroid Build Coastguard Worker 
127*89c4ff92SAndroid Build Coastguard Worker         // Check whether the path is a duplicate
128*89c4ff92SAndroid Build Coastguard Worker         auto it = uniqueBackendPaths.find(path);
129*89c4ff92SAndroid Build Coastguard Worker         if (it != uniqueBackendPaths.end())
130*89c4ff92SAndroid Build Coastguard Worker         {
131*89c4ff92SAndroid Build Coastguard Worker             // The path is a duplicate
132*89c4ff92SAndroid Build Coastguard Worker             continue;
133*89c4ff92SAndroid Build Coastguard Worker         }
134*89c4ff92SAndroid Build Coastguard Worker 
135*89c4ff92SAndroid Build Coastguard Worker         // Add the path to the set of unique paths
136*89c4ff92SAndroid Build Coastguard Worker         uniqueBackendPaths.insert(path);
137*89c4ff92SAndroid Build Coastguard Worker 
138*89c4ff92SAndroid Build Coastguard Worker         // Add the path to the list of valid paths
139*89c4ff92SAndroid Build Coastguard Worker         validBackendPaths.push_back(path);
140*89c4ff92SAndroid Build Coastguard Worker     }
141*89c4ff92SAndroid Build Coastguard Worker 
142*89c4ff92SAndroid Build Coastguard Worker     return validBackendPaths;
143*89c4ff92SAndroid Build Coastguard Worker }
144*89c4ff92SAndroid Build Coastguard Worker 
IsPathValid(const std::string & path)145*89c4ff92SAndroid Build Coastguard Worker bool DynamicBackendUtils::IsPathValid(const std::string& path)
146*89c4ff92SAndroid Build Coastguard Worker {
147*89c4ff92SAndroid Build Coastguard Worker     if (path.empty())
148*89c4ff92SAndroid Build Coastguard Worker     {
149*89c4ff92SAndroid Build Coastguard Worker         ARMNN_LOG(warning) << "WARNING: The given backend path is empty";
150*89c4ff92SAndroid Build Coastguard Worker         return false;
151*89c4ff92SAndroid Build Coastguard Worker     }
152*89c4ff92SAndroid Build Coastguard Worker 
153*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_FILESYSTEM)
154*89c4ff92SAndroid Build Coastguard Worker     fs::path fsPath(path);
155*89c4ff92SAndroid Build Coastguard Worker 
156*89c4ff92SAndroid Build Coastguard Worker     if (!fs::exists(fsPath))
157*89c4ff92SAndroid Build Coastguard Worker     {
158*89c4ff92SAndroid Build Coastguard Worker         ARMNN_LOG(warning) << "WARNING: The given backend path \"" << path << "\" does not exist";
159*89c4ff92SAndroid Build Coastguard Worker         return false;
160*89c4ff92SAndroid Build Coastguard Worker     }
161*89c4ff92SAndroid Build Coastguard Worker 
162*89c4ff92SAndroid Build Coastguard Worker     if (!fs::is_directory(fsPath))
163*89c4ff92SAndroid Build Coastguard Worker     {
164*89c4ff92SAndroid Build Coastguard Worker         ARMNN_LOG(warning) << "WARNING: The given backend path \"" << path << "\" is not a directory";
165*89c4ff92SAndroid Build Coastguard Worker         return false;
166*89c4ff92SAndroid Build Coastguard Worker     }
167*89c4ff92SAndroid Build Coastguard Worker 
168*89c4ff92SAndroid Build Coastguard Worker     if (!fsPath.is_absolute())
169*89c4ff92SAndroid Build Coastguard Worker     {
170*89c4ff92SAndroid Build Coastguard Worker         ARMNN_LOG(warning) << "WARNING: The given backend path \"" << path << "\" is not absolute";
171*89c4ff92SAndroid Build Coastguard Worker         return false;
172*89c4ff92SAndroid Build Coastguard Worker     }
173*89c4ff92SAndroid Build Coastguard Worker #endif // !defined(ARMNN_DISABLE_FILESYSTEM)
174*89c4ff92SAndroid Build Coastguard Worker 
175*89c4ff92SAndroid Build Coastguard Worker     return true;
176*89c4ff92SAndroid Build Coastguard Worker }
177*89c4ff92SAndroid Build Coastguard Worker 
GetSharedObjects(const std::vector<std::string> & backendPaths)178*89c4ff92SAndroid Build Coastguard Worker std::vector<std::string> DynamicBackendUtils::GetSharedObjects(const std::vector<std::string>& backendPaths)
179*89c4ff92SAndroid Build Coastguard Worker {
180*89c4ff92SAndroid Build Coastguard Worker     std::unordered_set<std::string> uniqueSharedObjects;
181*89c4ff92SAndroid Build Coastguard Worker     std::vector<std::string> sharedObjects;
182*89c4ff92SAndroid Build Coastguard Worker 
183*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_FILESYSTEM)
184*89c4ff92SAndroid Build Coastguard Worker     for (const std::string& backendPath : backendPaths)
185*89c4ff92SAndroid Build Coastguard Worker     {
186*89c4ff92SAndroid Build Coastguard Worker         using namespace fs;
187*89c4ff92SAndroid Build Coastguard Worker 
188*89c4ff92SAndroid Build Coastguard Worker         // Check if the path is valid. In case of error, IsValidPath will log an error message
189*89c4ff92SAndroid Build Coastguard Worker         if (!IsPathValid(backendPath))
190*89c4ff92SAndroid Build Coastguard Worker         {
191*89c4ff92SAndroid Build Coastguard Worker             continue;
192*89c4ff92SAndroid Build Coastguard Worker         }
193*89c4ff92SAndroid Build Coastguard Worker 
194*89c4ff92SAndroid Build Coastguard Worker         // Get all the files in the current path in alphabetical order
195*89c4ff92SAndroid Build Coastguard Worker         std::vector<path> backendPathFiles;
196*89c4ff92SAndroid Build Coastguard Worker         std::copy(directory_iterator(backendPath), directory_iterator(), std::back_inserter(backendPathFiles));
197*89c4ff92SAndroid Build Coastguard Worker         std::sort(backendPathFiles.begin(), backendPathFiles.end());
198*89c4ff92SAndroid Build Coastguard Worker 
199*89c4ff92SAndroid Build Coastguard Worker         // Go through all the files in the current backend path
200*89c4ff92SAndroid Build Coastguard Worker         for (const path& backendPathFile : backendPathFiles)
201*89c4ff92SAndroid Build Coastguard Worker         {
202*89c4ff92SAndroid Build Coastguard Worker             // Get only the name of the file (without the full path)
203*89c4ff92SAndroid Build Coastguard Worker             std::string filename = backendPathFile.filename().string();
204*89c4ff92SAndroid Build Coastguard Worker 
205*89c4ff92SAndroid Build Coastguard Worker             if (filename.empty())
206*89c4ff92SAndroid Build Coastguard Worker             {
207*89c4ff92SAndroid Build Coastguard Worker                 // Empty filename
208*89c4ff92SAndroid Build Coastguard Worker                 continue;
209*89c4ff92SAndroid Build Coastguard Worker             }
210*89c4ff92SAndroid Build Coastguard Worker 
211*89c4ff92SAndroid Build Coastguard Worker             path canonicalPath;
212*89c4ff92SAndroid Build Coastguard Worker             try
213*89c4ff92SAndroid Build Coastguard Worker             {
214*89c4ff92SAndroid Build Coastguard Worker                 // Get the canonical path for the current file, it will throw if for example the file is a
215*89c4ff92SAndroid Build Coastguard Worker                 // symlink that cannot be resolved
216*89c4ff92SAndroid Build Coastguard Worker                 canonicalPath = canonical(backendPathFile);
217*89c4ff92SAndroid Build Coastguard Worker             }
218*89c4ff92SAndroid Build Coastguard Worker             catch (const filesystem_error& e)
219*89c4ff92SAndroid Build Coastguard Worker             {
220*89c4ff92SAndroid Build Coastguard Worker                 ARMNN_LOG(warning) << "GetSharedObjects warning: " << e.what();
221*89c4ff92SAndroid Build Coastguard Worker             }
222*89c4ff92SAndroid Build Coastguard Worker             if (canonicalPath.empty())
223*89c4ff92SAndroid Build Coastguard Worker             {
224*89c4ff92SAndroid Build Coastguard Worker                 // No such file or perhaps a symlink that couldn't be resolved
225*89c4ff92SAndroid Build Coastguard Worker                 continue;
226*89c4ff92SAndroid Build Coastguard Worker             }
227*89c4ff92SAndroid Build Coastguard Worker 
228*89c4ff92SAndroid Build Coastguard Worker             // Check if the current filename matches the expected naming convention
229*89c4ff92SAndroid Build Coastguard Worker             // The expected format is: <vendor>_<name>_backend.so[<version>]
230*89c4ff92SAndroid Build Coastguard Worker             // e.g. "Arm_GpuAcc_backend.so" or "Arm_GpuAcc_backend.so.1.2"
231*89c4ff92SAndroid Build Coastguard Worker             const std::regex dynamicBackendRegex("^[a-zA-Z0-9]+_[a-zA-Z0-9]+_backend.so(\\.[0-9]+)*$");
232*89c4ff92SAndroid Build Coastguard Worker 
233*89c4ff92SAndroid Build Coastguard Worker             bool filenameMatch = false;
234*89c4ff92SAndroid Build Coastguard Worker             try
235*89c4ff92SAndroid Build Coastguard Worker             {
236*89c4ff92SAndroid Build Coastguard Worker                 // Match the filename to the expected naming scheme
237*89c4ff92SAndroid Build Coastguard Worker                 filenameMatch = std::regex_match(filename, dynamicBackendRegex);
238*89c4ff92SAndroid Build Coastguard Worker             }
239*89c4ff92SAndroid Build Coastguard Worker             catch (const std::exception& e)
240*89c4ff92SAndroid Build Coastguard Worker             {
241*89c4ff92SAndroid Build Coastguard Worker                 ARMNN_LOG(warning) << "GetSharedObjects warning: " << e.what();
242*89c4ff92SAndroid Build Coastguard Worker             }
243*89c4ff92SAndroid Build Coastguard Worker             if (!filenameMatch)
244*89c4ff92SAndroid Build Coastguard Worker             {
245*89c4ff92SAndroid Build Coastguard Worker                 // Filename does not match the expected naming scheme (or an error has occurred)
246*89c4ff92SAndroid Build Coastguard Worker                 continue;
247*89c4ff92SAndroid Build Coastguard Worker             }
248*89c4ff92SAndroid Build Coastguard Worker 
249*89c4ff92SAndroid Build Coastguard Worker             // Append the valid canonical path to the output list only if it's not a duplicate
250*89c4ff92SAndroid Build Coastguard Worker             std::string validCanonicalPath = canonicalPath.string();
251*89c4ff92SAndroid Build Coastguard Worker             auto it = uniqueSharedObjects.find(validCanonicalPath);
252*89c4ff92SAndroid Build Coastguard Worker             if (it == uniqueSharedObjects.end())
253*89c4ff92SAndroid Build Coastguard Worker             {
254*89c4ff92SAndroid Build Coastguard Worker                 // Not a duplicate, append the canonical path to the output list
255*89c4ff92SAndroid Build Coastguard Worker                 sharedObjects.push_back(validCanonicalPath);
256*89c4ff92SAndroid Build Coastguard Worker 
257*89c4ff92SAndroid Build Coastguard Worker                 // Add the canonical path to the collection of unique shared objects
258*89c4ff92SAndroid Build Coastguard Worker                 uniqueSharedObjects.insert(validCanonicalPath);
259*89c4ff92SAndroid Build Coastguard Worker             }
260*89c4ff92SAndroid Build Coastguard Worker         }
261*89c4ff92SAndroid Build Coastguard Worker     }
262*89c4ff92SAndroid Build Coastguard Worker #else
263*89c4ff92SAndroid Build Coastguard Worker     armnn::IgnoreUnused(backendPaths);
264*89c4ff92SAndroid Build Coastguard Worker #endif // !defined(ARMNN_DISABLE_FILESYSTEM)
265*89c4ff92SAndroid Build Coastguard Worker 
266*89c4ff92SAndroid Build Coastguard Worker     return sharedObjects;
267*89c4ff92SAndroid Build Coastguard Worker }
268*89c4ff92SAndroid Build Coastguard Worker 
CreateDynamicBackends(const std::vector<std::string> & sharedObjects)269*89c4ff92SAndroid Build Coastguard Worker std::vector<DynamicBackendPtr> DynamicBackendUtils::CreateDynamicBackends(const std::vector<std::string>& sharedObjects)
270*89c4ff92SAndroid Build Coastguard Worker {
271*89c4ff92SAndroid Build Coastguard Worker     // Create a list of dynamic backends
272*89c4ff92SAndroid Build Coastguard Worker     std::vector<DynamicBackendPtr> dynamicBackends;
273*89c4ff92SAndroid Build Coastguard Worker     for (const std::string& sharedObject : sharedObjects)
274*89c4ff92SAndroid Build Coastguard Worker     {
275*89c4ff92SAndroid Build Coastguard Worker         // Create a handle to the shared object
276*89c4ff92SAndroid Build Coastguard Worker         void* sharedObjectHandle = nullptr;
277*89c4ff92SAndroid Build Coastguard Worker         try
278*89c4ff92SAndroid Build Coastguard Worker         {
279*89c4ff92SAndroid Build Coastguard Worker             sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObject);
280*89c4ff92SAndroid Build Coastguard Worker         }
281*89c4ff92SAndroid Build Coastguard Worker         catch (const RuntimeException& e)
282*89c4ff92SAndroid Build Coastguard Worker         {
283*89c4ff92SAndroid Build Coastguard Worker             ARMNN_LOG(warning) << "Cannot create a handle to the shared object file \""
284*89c4ff92SAndroid Build Coastguard Worker                                << sharedObject << "\": " << e.what();
285*89c4ff92SAndroid Build Coastguard Worker             continue;
286*89c4ff92SAndroid Build Coastguard Worker         }
287*89c4ff92SAndroid Build Coastguard Worker         if (!sharedObjectHandle)
288*89c4ff92SAndroid Build Coastguard Worker         {
289*89c4ff92SAndroid Build Coastguard Worker             ARMNN_LOG(warning) << "Invalid handle to the shared object file \"" << sharedObject << "\"";
290*89c4ff92SAndroid Build Coastguard Worker 
291*89c4ff92SAndroid Build Coastguard Worker             continue;
292*89c4ff92SAndroid Build Coastguard Worker         }
293*89c4ff92SAndroid Build Coastguard Worker 
294*89c4ff92SAndroid Build Coastguard Worker         // Create a dynamic backend object
295*89c4ff92SAndroid Build Coastguard Worker         DynamicBackendPtr dynamicBackend;
296*89c4ff92SAndroid Build Coastguard Worker         try
297*89c4ff92SAndroid Build Coastguard Worker         {
298*89c4ff92SAndroid Build Coastguard Worker             dynamicBackend.reset(new DynamicBackend(sharedObjectHandle));
299*89c4ff92SAndroid Build Coastguard Worker         }
300*89c4ff92SAndroid Build Coastguard Worker         catch (const Exception& e)
301*89c4ff92SAndroid Build Coastguard Worker         {
302*89c4ff92SAndroid Build Coastguard Worker             ARMNN_LOG(warning) << "Cannot create a valid dynamic backend from the shared object file \""
303*89c4ff92SAndroid Build Coastguard Worker                                << sharedObject << "\": " << e.what();
304*89c4ff92SAndroid Build Coastguard Worker             continue;
305*89c4ff92SAndroid Build Coastguard Worker         }
306*89c4ff92SAndroid Build Coastguard Worker         if (!dynamicBackend)
307*89c4ff92SAndroid Build Coastguard Worker         {
308*89c4ff92SAndroid Build Coastguard Worker             ARMNN_LOG(warning) << "Invalid dynamic backend object for the shared object file \""
309*89c4ff92SAndroid Build Coastguard Worker                                << sharedObject << "\"";
310*89c4ff92SAndroid Build Coastguard Worker             continue;
311*89c4ff92SAndroid Build Coastguard Worker         }
312*89c4ff92SAndroid Build Coastguard Worker 
313*89c4ff92SAndroid Build Coastguard Worker         // Append the newly created dynamic backend to the list
314*89c4ff92SAndroid Build Coastguard Worker         dynamicBackends.push_back(std::move(dynamicBackend));
315*89c4ff92SAndroid Build Coastguard Worker     }
316*89c4ff92SAndroid Build Coastguard Worker 
317*89c4ff92SAndroid Build Coastguard Worker     return dynamicBackends;
318*89c4ff92SAndroid Build Coastguard Worker }
319*89c4ff92SAndroid Build Coastguard Worker 
DeregisterDynamicBackends(const BackendIdSet & dynamicBackends)320*89c4ff92SAndroid Build Coastguard Worker void DynamicBackendUtils::DeregisterDynamicBackends(const BackendIdSet& dynamicBackends)
321*89c4ff92SAndroid Build Coastguard Worker {
322*89c4ff92SAndroid Build Coastguard Worker     // Get a reference of the backend registry
323*89c4ff92SAndroid Build Coastguard Worker     BackendRegistry& backendRegistry = BackendRegistryInstance();
324*89c4ff92SAndroid Build Coastguard Worker 
325*89c4ff92SAndroid Build Coastguard Worker     for (const auto& id : dynamicBackends)
326*89c4ff92SAndroid Build Coastguard Worker     {
327*89c4ff92SAndroid Build Coastguard Worker         backendRegistry.Deregister(id);
328*89c4ff92SAndroid Build Coastguard Worker     }
329*89c4ff92SAndroid Build Coastguard Worker 
330*89c4ff92SAndroid Build Coastguard Worker }
331*89c4ff92SAndroid Build Coastguard Worker 
RegisterDynamicBackends(const std::vector<DynamicBackendPtr> & dynamicBackends)332*89c4ff92SAndroid Build Coastguard Worker BackendIdSet DynamicBackendUtils::RegisterDynamicBackends(const std::vector<DynamicBackendPtr>& dynamicBackends)
333*89c4ff92SAndroid Build Coastguard Worker {
334*89c4ff92SAndroid Build Coastguard Worker     // Get a reference of the backend registry
335*89c4ff92SAndroid Build Coastguard Worker     BackendRegistry& backendRegistry = BackendRegistryInstance();
336*89c4ff92SAndroid Build Coastguard Worker 
337*89c4ff92SAndroid Build Coastguard Worker     // Register the dynamic backends in the backend registry, and return a list of registered backend ids
338*89c4ff92SAndroid Build Coastguard Worker     return RegisterDynamicBackendsImpl(backendRegistry, dynamicBackends);
339*89c4ff92SAndroid Build Coastguard Worker }
340*89c4ff92SAndroid Build Coastguard Worker 
RegisterDynamicBackendsImpl(BackendRegistry & backendRegistry,const std::vector<DynamicBackendPtr> & dynamicBackends)341*89c4ff92SAndroid Build Coastguard Worker BackendIdSet DynamicBackendUtils::RegisterDynamicBackendsImpl(BackendRegistry& backendRegistry,
342*89c4ff92SAndroid Build Coastguard Worker                                                               const std::vector<DynamicBackendPtr>& dynamicBackends)
343*89c4ff92SAndroid Build Coastguard Worker {
344*89c4ff92SAndroid Build Coastguard Worker     // Initialize the list of registered backend ids
345*89c4ff92SAndroid Build Coastguard Worker     BackendIdSet registeredBackendIds;
346*89c4ff92SAndroid Build Coastguard Worker 
347*89c4ff92SAndroid Build Coastguard Worker     // Register the dynamic backends in the backend registry
348*89c4ff92SAndroid Build Coastguard Worker     for (const DynamicBackendPtr& dynamicBackend : dynamicBackends)
349*89c4ff92SAndroid Build Coastguard Worker     {
350*89c4ff92SAndroid Build Coastguard Worker         // Get the id of the dynamic backend
351*89c4ff92SAndroid Build Coastguard Worker         BackendId dynamicBackendId;
352*89c4ff92SAndroid Build Coastguard Worker         try
353*89c4ff92SAndroid Build Coastguard Worker         {
354*89c4ff92SAndroid Build Coastguard Worker             dynamicBackendId = dynamicBackend->GetBackendId();
355*89c4ff92SAndroid Build Coastguard Worker         }
356*89c4ff92SAndroid Build Coastguard Worker         catch (const RuntimeException& e)
357*89c4ff92SAndroid Build Coastguard Worker         {
358*89c4ff92SAndroid Build Coastguard Worker             ARMNN_LOG(warning) << "Cannot register dynamic backend, "
359*89c4ff92SAndroid Build Coastguard Worker                                << "an error has occurred when getting the backend id: " << e.what();
360*89c4ff92SAndroid Build Coastguard Worker             continue;
361*89c4ff92SAndroid Build Coastguard Worker         }
362*89c4ff92SAndroid Build Coastguard Worker         if (dynamicBackendId.IsEmpty() ||
363*89c4ff92SAndroid Build Coastguard Worker             dynamicBackendId.IsUndefined())
364*89c4ff92SAndroid Build Coastguard Worker         {
365*89c4ff92SAndroid Build Coastguard Worker             ARMNN_LOG(warning) << "Cannot register dynamic backend, invalid backend id: " << dynamicBackendId;
366*89c4ff92SAndroid Build Coastguard Worker             continue;
367*89c4ff92SAndroid Build Coastguard Worker         }
368*89c4ff92SAndroid Build Coastguard Worker 
369*89c4ff92SAndroid Build Coastguard Worker         // Check whether the dynamic backend is already registered
370*89c4ff92SAndroid Build Coastguard Worker         bool backendAlreadyRegistered = backendRegistry.IsBackendRegistered(dynamicBackendId);
371*89c4ff92SAndroid Build Coastguard Worker         if (backendAlreadyRegistered)
372*89c4ff92SAndroid Build Coastguard Worker         {
373*89c4ff92SAndroid Build Coastguard Worker             ARMNN_LOG(warning) << "Cannot register dynamic backend \"" << dynamicBackendId
374*89c4ff92SAndroid Build Coastguard Worker                                << "\": backend already registered";
375*89c4ff92SAndroid Build Coastguard Worker             continue;
376*89c4ff92SAndroid Build Coastguard Worker         }
377*89c4ff92SAndroid Build Coastguard Worker 
378*89c4ff92SAndroid Build Coastguard Worker         // Get the dynamic backend factory function
379*89c4ff92SAndroid Build Coastguard Worker         BackendRegistry::FactoryFunction dynamicBackendFactoryFunction = nullptr;
380*89c4ff92SAndroid Build Coastguard Worker         try
381*89c4ff92SAndroid Build Coastguard Worker         {
382*89c4ff92SAndroid Build Coastguard Worker             dynamicBackendFactoryFunction = dynamicBackend->GetFactoryFunction();
383*89c4ff92SAndroid Build Coastguard Worker         }
384*89c4ff92SAndroid Build Coastguard Worker         catch (const RuntimeException& e)
385*89c4ff92SAndroid Build Coastguard Worker         {
386*89c4ff92SAndroid Build Coastguard Worker             ARMNN_LOG(warning) << "Cannot register dynamic backend \"" << dynamicBackendId
387*89c4ff92SAndroid Build Coastguard Worker                                << "\": an error has occurred when getting the backend factory function: "
388*89c4ff92SAndroid Build Coastguard Worker                                << e.what();
389*89c4ff92SAndroid Build Coastguard Worker             continue;
390*89c4ff92SAndroid Build Coastguard Worker         }
391*89c4ff92SAndroid Build Coastguard Worker         if (dynamicBackendFactoryFunction == nullptr)
392*89c4ff92SAndroid Build Coastguard Worker         {
393*89c4ff92SAndroid Build Coastguard Worker             ARMNN_LOG(warning) << "Cannot register dynamic backend \"" << dynamicBackendId
394*89c4ff92SAndroid Build Coastguard Worker                                << "\": invalid backend factory function";
395*89c4ff92SAndroid Build Coastguard Worker             continue;
396*89c4ff92SAndroid Build Coastguard Worker         }
397*89c4ff92SAndroid Build Coastguard Worker 
398*89c4ff92SAndroid Build Coastguard Worker         // Register the dynamic backend
399*89c4ff92SAndroid Build Coastguard Worker         try
400*89c4ff92SAndroid Build Coastguard Worker         {
401*89c4ff92SAndroid Build Coastguard Worker             backendRegistry.Register(dynamicBackendId, dynamicBackendFactoryFunction);
402*89c4ff92SAndroid Build Coastguard Worker         }
403*89c4ff92SAndroid Build Coastguard Worker         catch (const InvalidArgumentException& e)
404*89c4ff92SAndroid Build Coastguard Worker         {
405*89c4ff92SAndroid Build Coastguard Worker             ARMNN_LOG(warning) << "An error has occurred when registering the dynamic backend \""
406*89c4ff92SAndroid Build Coastguard Worker                                << dynamicBackendId << "\": " << e.what();
407*89c4ff92SAndroid Build Coastguard Worker             continue;
408*89c4ff92SAndroid Build Coastguard Worker         }
409*89c4ff92SAndroid Build Coastguard Worker 
410*89c4ff92SAndroid Build Coastguard Worker         // Add the id of the dynamic backend just registered to the list of registered backend ids
411*89c4ff92SAndroid Build Coastguard Worker         registeredBackendIds.insert(dynamicBackendId);
412*89c4ff92SAndroid Build Coastguard Worker     }
413*89c4ff92SAndroid Build Coastguard Worker 
414*89c4ff92SAndroid Build Coastguard Worker     return registeredBackendIds;
415*89c4ff92SAndroid Build Coastguard Worker }
416*89c4ff92SAndroid Build Coastguard Worker 
417*89c4ff92SAndroid Build Coastguard Worker } // namespace armnn
418