ArmNN
 24.02
DynamicBackendUtils Class Reference

#include <DynamicBackendUtils.hpp>

Static Public Member Functions

static void * OpenHandle (const std::string &sharedObjectPath)
 
static void CloseHandle (const void *sharedObjectHandle)
 
template<typename EntryPointType >
static EntryPointType GetEntryPoint (const void *sharedObjectHandle, const char *symbolName)
 
static bool IsBackendCompatible (const BackendVersion &backendVersion)
 
static std::vector< std::string > GetBackendPaths (const std::string &overrideBackendPath="")
 
static bool IsPathValid (const std::string &path)
 
static std::vector< std::string > GetSharedObjects (const std::vector< std::string > &backendPaths)
 
static std::vector< DynamicBackendPtrCreateDynamicBackends (const std::vector< std::string > &sharedObjects)
 
static BackendIdSet RegisterDynamicBackends (const std::vector< DynamicBackendPtr > &dynamicBackends)
 
static void DeregisterDynamicBackends (const BackendIdSet &dynamicBackends)
 

Static Protected Member Functions

static bool IsBackendCompatibleImpl (const BackendVersion &backendApiVersion, const BackendVersion &backendVersion)
 Protected methods for testing purposes. More...
 
static std::vector< std::string > GetBackendPathsImpl (const std::string &backendPaths)
 
static BackendIdSet RegisterDynamicBackendsImpl (BackendRegistry &backendRegistry, const std::vector< DynamicBackendPtr > &dynamicBackends)
 

Detailed Description

Definition at line 28 of file DynamicBackendUtils.hpp.

Member Function Documentation

◆ CloseHandle()

void CloseHandle ( const void *  sharedObjectHandle)
static

Definition at line 37 of file DynamicBackendUtils.cpp.

38 {
39 #if defined(__unix__) || defined(__APPLE__)
40  if (!sharedObjectHandle)
41  {
42  return;
43  }
44 
45  dlclose(const_cast<void*>(sharedObjectHandle));
46 #else
47  armnn::IgnoreUnused(sharedObjectHandle);
48  throw RuntimeException("Dynamic backends not supported on this platform");
49 #endif
50 }

References armnn::IgnoreUnused().

◆ CreateDynamicBackends()

std::vector< DynamicBackendPtr > CreateDynamicBackends ( const std::vector< std::string > &  sharedObjects)
static

Definition at line 269 of file DynamicBackendUtils.cpp.

270 {
271  // Create a list of dynamic backends
272  std::vector<DynamicBackendPtr> dynamicBackends;
273  for (const std::string& sharedObject : sharedObjects)
274  {
275  // Create a handle to the shared object
276  void* sharedObjectHandle = nullptr;
277  try
278  {
279  sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObject);
280  }
281  catch (const RuntimeException& e)
282  {
283  ARMNN_LOG(warning) << "Cannot create a handle to the shared object file \""
284  << sharedObject << "\": " << e.what();
285  continue;
286  }
287  if (!sharedObjectHandle)
288  {
289  ARMNN_LOG(warning) << "Invalid handle to the shared object file \"" << sharedObject << "\"";
290 
291  continue;
292  }
293 
294  // Create a dynamic backend object
295  DynamicBackendPtr dynamicBackend;
296  try
297  {
298  dynamicBackend.reset(new DynamicBackend(sharedObjectHandle));
299  }
300  catch (const Exception& e)
301  {
302  ARMNN_LOG(warning) << "Cannot create a valid dynamic backend from the shared object file \""
303  << sharedObject << "\": " << e.what();
304  continue;
305  }
306  if (!dynamicBackend)
307  {
308  ARMNN_LOG(warning) << "Invalid dynamic backend object for the shared object file \""
309  << sharedObject << "\"";
310  continue;
311  }
312 
313  // Append the newly created dynamic backend to the list
314  dynamicBackends.push_back(std::move(dynamicBackend));
315  }
316 
317  return dynamicBackends;
318 }

References ARMNN_LOG, DynamicBackendUtils::OpenHandle(), armnn::warning, and Exception::what().

◆ DeregisterDynamicBackends()

void DeregisterDynamicBackends ( const BackendIdSet dynamicBackends)
static

Definition at line 320 of file DynamicBackendUtils.cpp.

321 {
322  // Get a reference of the backend registry
323  BackendRegistry& backendRegistry = BackendRegistryInstance();
324 
325  for (const auto& id : dynamicBackends)
326  {
327  backendRegistry.Deregister(id);
328  }
329 
330 }

References armnn::BackendRegistryInstance(), and BackendRegistry::Deregister().

Referenced by RuntimeImpl::RuntimeImpl(), and RuntimeImpl::~RuntimeImpl().

◆ GetBackendPaths()

std::vector< std::string > GetBackendPaths ( const std::string &  overrideBackendPath = "")
static

Definition at line 81 of file DynamicBackendUtils.cpp.

82 {
83  // Check if a path where to dynamically load the backends from is given
84  if (!overrideBackendPath.empty())
85  {
86  if (!IsPathValid(overrideBackendPath))
87  {
88  ARMNN_LOG(warning) << "WARNING: The given override path for dynamic backends \""
89  << overrideBackendPath << "\" is not valid";
90 
91  return {};
92  }
93 
94  return std::vector<std::string>{ overrideBackendPath };
95  }
96 
97  // Expects a colon-separated list: DYNAMIC_BACKEND_PATHS="PATH_1:PATH_2:...:PATH_N"
98  const std::string backendPaths = DYNAMIC_BACKEND_PATHS;
99 
100  return GetBackendPathsImpl(backendPaths);
101 }

References ARMNN_LOG, DYNAMIC_BACKEND_PATHS, DynamicBackendUtils::GetBackendPathsImpl(), DynamicBackendUtils::IsPathValid(), and armnn::warning.

◆ GetBackendPathsImpl()

std::vector< std::string > GetBackendPathsImpl ( const std::string &  backendPaths)
staticprotected

Definition at line 103 of file DynamicBackendUtils.cpp.

104 {
105  // Check if there's any path to process at all
106  if (backendPaths.empty())
107  {
108  // Silently return without issuing a warning as no paths have been passed, so
109  // the whole dynamic backend loading feature can be considered as disabled
110  return {};
111  }
112 
113  std::unordered_set<std::string> uniqueBackendPaths;
114  std::vector<std::string> validBackendPaths;
115 
116  // Split the given list of paths
117  std::vector<std::string> tempBackendPaths = armnn::stringUtils::StringTokenizer(backendPaths, ":");
118 
119  for (const std::string& path : tempBackendPaths)
120  {
121  // Check whether the path is valid
122  if (!IsPathValid(path))
123  {
124  continue;
125  }
126 
127  // Check whether the path is a duplicate
128  auto it = uniqueBackendPaths.find(path);
129  if (it != uniqueBackendPaths.end())
130  {
131  // The path is a duplicate
132  continue;
133  }
134 
135  // Add the path to the set of unique paths
136  uniqueBackendPaths.insert(path);
137 
138  // Add the path to the list of valid paths
139  validBackendPaths.push_back(path);
140  }
141 
142  return validBackendPaths;
143 }

References DynamicBackendUtils::IsPathValid(), and armnn::stringUtils::StringTokenizer().

Referenced by DynamicBackendUtils::GetBackendPaths().

◆ GetEntryPoint()

EntryPointType GetEntryPoint ( const void *  sharedObjectHandle,
const char *  symbolName 
)
static

Definition at line 62 of file DynamicBackendUtils.hpp.

63 {
64 #if defined(__unix__) || defined(__APPLE__)
65  if (sharedObjectHandle == nullptr)
66  {
67  throw RuntimeException("GetEntryPoint error: invalid handle");
68  }
69 
70  if (symbolName == nullptr)
71  {
72  throw RuntimeException("GetEntryPoint error: invalid symbol");
73  }
74 
75  auto entryPoint = reinterpret_cast<EntryPointType>(dlsym(const_cast<void*>(sharedObjectHandle), symbolName));
76  if (!entryPoint)
77  {
78  throw RuntimeException(fmt::format("GetEntryPoint error: {}", GetDlError()));
79  }
80 
81  return entryPoint;
82 #else
83  armnn::IgnoreUnused(sharedObjectHandle);
84  armnn::IgnoreUnused(symbolName);
85  throw RuntimeException("Dynamic backends not supported on this platform");
86 #endif
87 }

References armnn::IgnoreUnused().

◆ GetSharedObjects()

std::vector< std::string > GetSharedObjects ( const std::vector< std::string > &  backendPaths)
static

Definition at line 178 of file DynamicBackendUtils.cpp.

179 {
180  std::unordered_set<std::string> uniqueSharedObjects;
181  std::vector<std::string> sharedObjects;
182 
183 #if !defined(ARMNN_DISABLE_FILESYSTEM)
184  for (const std::string& backendPath : backendPaths)
185  {
186  using namespace fs;
187 
188  // Check if the path is valid. In case of error, IsValidPath will log an error message
189  if (!IsPathValid(backendPath))
190  {
191  continue;
192  }
193 
194  // Get all the files in the current path in alphabetical order
195  std::vector<path> backendPathFiles;
196  std::copy(directory_iterator(backendPath), directory_iterator(), std::back_inserter(backendPathFiles));
197  std::sort(backendPathFiles.begin(), backendPathFiles.end());
198 
199  // Go through all the files in the current backend path
200  for (const path& backendPathFile : backendPathFiles)
201  {
202  // Get only the name of the file (without the full path)
203  std::string filename = backendPathFile.filename().string();
204 
205  if (filename.empty())
206  {
207  // Empty filename
208  continue;
209  }
210 
211  path canonicalPath;
212  try
213  {
214  // Get the canonical path for the current file, it will throw if for example the file is a
215  // symlink that cannot be resolved
216  canonicalPath = canonical(backendPathFile);
217  }
218  catch (const filesystem_error& e)
219  {
220  ARMNN_LOG(warning) << "GetSharedObjects warning: " << e.what();
221  }
222  if (canonicalPath.empty())
223  {
224  // No such file or perhaps a symlink that couldn't be resolved
225  continue;
226  }
227 
228  // Check if the current filename matches the expected naming convention
229  // The expected format is: <vendor>_<name>_backend.so[<version>]
230  // e.g. "Arm_GpuAcc_backend.so" or "Arm_GpuAcc_backend.so.1.2"
231  const std::regex dynamicBackendRegex("^[a-zA-Z0-9]+_[a-zA-Z0-9]+_backend.so(\\.[0-9]+)*$");
232 
233  bool filenameMatch = false;
234  try
235  {
236  // Match the filename to the expected naming scheme
237  filenameMatch = std::regex_match(filename, dynamicBackendRegex);
238  }
239  catch (const std::exception& e)
240  {
241  ARMNN_LOG(warning) << "GetSharedObjects warning: " << e.what();
242  }
243  if (!filenameMatch)
244  {
245  // Filename does not match the expected naming scheme (or an error has occurred)
246  continue;
247  }
248 
249  // Append the valid canonical path to the output list only if it's not a duplicate
250  std::string validCanonicalPath = canonicalPath.string();
251  auto it = uniqueSharedObjects.find(validCanonicalPath);
252  if (it == uniqueSharedObjects.end())
253  {
254  // Not a duplicate, append the canonical path to the output list
255  sharedObjects.push_back(validCanonicalPath);
256 
257  // Add the canonical path to the collection of unique shared objects
258  uniqueSharedObjects.insert(validCanonicalPath);
259  }
260  }
261  }
262 #else
263  armnn::IgnoreUnused(backendPaths);
264 #endif // !defined(ARMNN_DISABLE_FILESYSTEM)
265 
266  return sharedObjects;
267 }

References ARMNN_LOG, armnn::IgnoreUnused(), DynamicBackendUtils::IsPathValid(), and armnn::warning.

◆ IsBackendCompatible()

bool IsBackendCompatible ( const BackendVersion backendVersion)
static

Definition at line 52 of file DynamicBackendUtils.cpp.

53 {
54  BackendVersion backendApiVersion = IBackendInternal::GetApiVersion();
55 
56  return IsBackendCompatibleImpl(backendApiVersion, backendVersion);
57 }

References IBackendInternal::GetApiVersion(), and DynamicBackendUtils::IsBackendCompatibleImpl().

Referenced by DynamicBackend::DynamicBackend().

◆ IsBackendCompatibleImpl()

bool IsBackendCompatibleImpl ( const BackendVersion backendApiVersion,
const BackendVersion backendVersion 
)
staticprotected

Protected methods for testing purposes.

Definition at line 59 of file DynamicBackendUtils.cpp.

61 {
62  return backendVersion.m_Major == backendApiVersion.m_Major &&
63  backendVersion.m_Minor <= backendApiVersion.m_Minor;
64 }

References BackendVersion::m_Major, and BackendVersion::m_Minor.

Referenced by DynamicBackendUtils::IsBackendCompatible().

◆ IsPathValid()

bool IsPathValid ( const std::string &  path)
static

Definition at line 145 of file DynamicBackendUtils.cpp.

146 {
147  if (path.empty())
148  {
149  ARMNN_LOG(warning) << "WARNING: The given backend path is empty";
150  return false;
151  }
152 
153 #if !defined(ARMNN_DISABLE_FILESYSTEM)
154  fs::path fsPath(path);
155 
156  if (!fs::exists(fsPath))
157  {
158  ARMNN_LOG(warning) << "WARNING: The given backend path \"" << path << "\" does not exist";
159  return false;
160  }
161 
162  if (!fs::is_directory(fsPath))
163  {
164  ARMNN_LOG(warning) << "WARNING: The given backend path \"" << path << "\" is not a directory";
165  return false;
166  }
167 
168  if (!fsPath.is_absolute())
169  {
170  ARMNN_LOG(warning) << "WARNING: The given backend path \"" << path << "\" is not absolute";
171  return false;
172  }
173 #endif // !defined(ARMNN_DISABLE_FILESYSTEM)
174 
175  return true;
176 }

References ARMNN_LOG, and armnn::warning.

Referenced by DynamicBackendUtils::GetBackendPaths(), DynamicBackendUtils::GetBackendPathsImpl(), and DynamicBackendUtils::GetSharedObjects().

◆ OpenHandle()

void * OpenHandle ( const std::string &  sharedObjectPath)
static

Definition at line 16 of file DynamicBackendUtils.cpp.

17 {
18 #if defined(__unix__) || defined(__APPLE__)
19  if (sharedObjectPath.empty())
20  {
21  throw RuntimeException("OpenHandle error: shared object path must not be empty");
22  }
23 
24  void* sharedObjectHandle = dlopen(sharedObjectPath.c_str(), RTLD_LAZY);
25  if (!sharedObjectHandle)
26  {
27  throw RuntimeException(fmt::format("OpenHandle error: {}", GetDlError()));
28  }
29 
30  return sharedObjectHandle;
31 #else
32  armnn::IgnoreUnused(sharedObjectPath);
33  throw RuntimeException("Dynamic backends not supported on this platform");
34 #endif
35 }

References armnn::IgnoreUnused().

Referenced by DynamicBackendUtils::CreateDynamicBackends().

◆ RegisterDynamicBackends()

BackendIdSet RegisterDynamicBackends ( const std::vector< DynamicBackendPtr > &  dynamicBackends)
static

Definition at line 332 of file DynamicBackendUtils.cpp.

333 {
334  // Get a reference of the backend registry
335  BackendRegistry& backendRegistry = BackendRegistryInstance();
336 
337  // Register the dynamic backends in the backend registry, and return a list of registered backend ids
338  return RegisterDynamicBackendsImpl(backendRegistry, dynamicBackends);
339 }

References armnn::BackendRegistryInstance(), and DynamicBackendUtils::RegisterDynamicBackendsImpl().

◆ RegisterDynamicBackendsImpl()

BackendIdSet RegisterDynamicBackendsImpl ( BackendRegistry backendRegistry,
const std::vector< DynamicBackendPtr > &  dynamicBackends 
)
staticprotected

Definition at line 341 of file DynamicBackendUtils.cpp.

343 {
344  // Initialize the list of registered backend ids
345  BackendIdSet registeredBackendIds;
346 
347  // Register the dynamic backends in the backend registry
348  for (const DynamicBackendPtr& dynamicBackend : dynamicBackends)
349  {
350  // Get the id of the dynamic backend
351  BackendId dynamicBackendId;
352  try
353  {
354  dynamicBackendId = dynamicBackend->GetBackendId();
355  }
356  catch (const RuntimeException& e)
357  {
358  ARMNN_LOG(warning) << "Cannot register dynamic backend, "
359  << "an error has occurred when getting the backend id: " << e.what();
360  continue;
361  }
362  if (dynamicBackendId.IsEmpty() ||
363  dynamicBackendId.IsUndefined())
364  {
365  ARMNN_LOG(warning) << "Cannot register dynamic backend, invalid backend id: " << dynamicBackendId;
366  continue;
367  }
368 
369  // Check whether the dynamic backend is already registered
370  bool backendAlreadyRegistered = backendRegistry.IsBackendRegistered(dynamicBackendId);
371  if (backendAlreadyRegistered)
372  {
373  ARMNN_LOG(warning) << "Cannot register dynamic backend \"" << dynamicBackendId
374  << "\": backend already registered";
375  continue;
376  }
377 
378  // Get the dynamic backend factory function
379  BackendRegistry::FactoryFunction dynamicBackendFactoryFunction = nullptr;
380  try
381  {
382  dynamicBackendFactoryFunction = dynamicBackend->GetFactoryFunction();
383  }
384  catch (const RuntimeException& e)
385  {
386  ARMNN_LOG(warning) << "Cannot register dynamic backend \"" << dynamicBackendId
387  << "\": an error has occurred when getting the backend factory function: "
388  << e.what();
389  continue;
390  }
391  if (dynamicBackendFactoryFunction == nullptr)
392  {
393  ARMNN_LOG(warning) << "Cannot register dynamic backend \"" << dynamicBackendId
394  << "\": invalid backend factory function";
395  continue;
396  }
397 
398  // Register the dynamic backend
399  try
400  {
401  backendRegistry.Register(dynamicBackendId, dynamicBackendFactoryFunction);
402  }
403  catch (const InvalidArgumentException& e)
404  {
405  ARMNN_LOG(warning) << "An error has occurred when registering the dynamic backend \""
406  << dynamicBackendId << "\": " << e.what();
407  continue;
408  }
409 
410  // Add the id of the dynamic backend just registered to the list of registered backend ids
411  registeredBackendIds.insert(dynamicBackendId);
412  }
413 
414  return registeredBackendIds;
415 }

References ARMNN_LOG, BackendRegistry::IsBackendRegistered(), BackendId::IsEmpty(), BackendId::IsUndefined(), BackendRegistry::Register(), armnn::warning, and Exception::what().

Referenced by DynamicBackendUtils::RegisterDynamicBackends().


The documentation for this class was generated from the following files:
armnn::DynamicBackendPtr
std::unique_ptr< DynamicBackend > DynamicBackendPtr
Definition: DynamicBackend.hpp:54
DYNAMIC_BACKEND_PATHS
#define DYNAMIC_BACKEND_PATHS
Definition: DynamicBackendUtils.hpp:22
armnn::BackendIdSet
std::unordered_set< BackendId > BackendIdSet
Definition: BackendId.hpp:193
armnn::DynamicBackendUtils::IsBackendCompatibleImpl
static bool IsBackendCompatibleImpl(const BackendVersion &backendApiVersion, const BackendVersion &backendVersion)
Protected methods for testing purposes.
Definition: DynamicBackendUtils.cpp:59
armnn::DynamicBackendUtils::OpenHandle
static void * OpenHandle(const std::string &sharedObjectPath)
Definition: DynamicBackendUtils.cpp:16
armnn::BackendRegistry::FactoryFunction
std::function< PointerType()> FactoryFunction
Definition: BackendRegistry.hpp:39
armnn::DynamicBackendUtils::RegisterDynamicBackendsImpl
static BackendIdSet RegisterDynamicBackendsImpl(BackendRegistry &backendRegistry, const std::vector< DynamicBackendPtr > &dynamicBackends)
Definition: DynamicBackendUtils.cpp:341
ARMNN_LOG
#define ARMNN_LOG(severity)
Definition: Logging.hpp:212
armnn::BackendRegistryInstance
BackendRegistry & BackendRegistryInstance()
Definition: BackendRegistry.cpp:15
armnn::DynamicBackendUtils::IsPathValid
static bool IsPathValid(const std::string &path)
Definition: DynamicBackendUtils.cpp:145
armnn::IBackendInternal::GetApiVersion
static constexpr BackendVersion GetApiVersion()
Returns the version of the Backend API.
Definition: IBackendInternal.hpp:167
armnn::IgnoreUnused
void IgnoreUnused(Ts &&...)
Definition: IgnoreUnused.hpp:14
armnn::DynamicBackendUtils::GetBackendPathsImpl
static std::vector< std::string > GetBackendPathsImpl(const std::string &backendPaths)
Definition: DynamicBackendUtils.cpp:103
armnn::stringUtils::StringTokenizer
std::vector< std::string > StringTokenizer(const std::string &str, const char *delimiters, bool tokenCompression=true)
Function to take a string and a list of delimiters and split the string into tokens based on those de...
Definition: StringUtils.hpp:23