ArmNN
 20.02
DynamicBackendUtils Class Reference

#include <DynamicBackendUtils.hpp>

Inheritance diagram for DynamicBackendUtils:
TestDynamicBackendUtils

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__)
40  if (!sharedObjectHandle)
41  {
42  return;
43  }
44 
45  dlclose(const_cast<void*>(sharedObjectHandle));
46 #else
47  throw RuntimeException("Dynamic backends not supported on this platform");
48 #endif
49 }

◆ CreateDynamicBackends()

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

Definition at line 263 of file DynamicBackendUtils.cpp.

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

Referenced by Runtime::RegisterDebugCallback().

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

◆ DeregisterDynamicBackends()

void DeregisterDynamicBackends ( const BackendIdSet dynamicBackends)
static

Definition at line 314 of file DynamicBackendUtils.cpp.

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

Referenced by Runtime::~Runtime().

315 {
316  // Get a reference of the backend registry
317  BackendRegistry& backendRegistry = BackendRegistryInstance();
318 
319  for (const auto& id : dynamicBackends)
320  {
321  backendRegistry.Deregister(id);
322  }
323 
324 }
BackendRegistry & BackendRegistryInstance()

◆ GetBackendPaths()

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

Definition at line 80 of file DynamicBackendUtils.cpp.

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

Referenced by Runtime::RegisterDebugCallback().

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

◆ GetBackendPathsImpl()

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

Definition at line 102 of file DynamicBackendUtils.cpp.

References DynamicBackendUtils::IsPathValid().

Referenced by DynamicBackendUtils::GetBackendPaths(), and TestDynamicBackendUtils::GetBackendPathsImplTest().

103 {
104  // Check if there's any path to process at all
105  if (backendPaths.empty())
106  {
107  // Silently return without issuing a warning as no paths have been passed, so
108  // the whole dynamic backend loading feature can be considered as disabled
109  return {};
110  }
111 
112  std::unordered_set<std::string> uniqueBackendPaths;
113  std::vector<std::string> tempBackendPaths;
114  std::vector<std::string> validBackendPaths;
115 
116  // Split the given list of paths
117  boost::split(tempBackendPaths, backendPaths, boost::is_any_of(":"));
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 }
static bool IsPathValid(const std::string &path)

◆ GetEntryPoint()

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

Definition at line 62 of file DynamicBackendUtils.hpp.

63 {
64 #if defined(__unix__)
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(boost::str(boost::format("GetEntryPoint error: %1%") % GetDlError()));
79  }
80 
81  return entryPoint;
82 #else
83  throw RuntimeException("Dynamic backends not supported on this platform");
84 #endif
85 }

◆ GetSharedObjects()

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

Definition at line 176 of file DynamicBackendUtils.cpp.

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

Referenced by Runtime::RegisterDebugCallback().

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

◆ IsBackendCompatible()

bool IsBackendCompatible ( const BackendVersion backendVersion)
static

Definition at line 51 of file DynamicBackendUtils.cpp.

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

Referenced by DynamicBackend::DynamicBackend().

52 {
53  BackendVersion backendApiVersion = IBackendInternal::GetApiVersion();
54 
55  return IsBackendCompatibleImpl(backendApiVersion, backendVersion);
56 }
static constexpr BackendVersion GetApiVersion()
Returns the version of the Backend API.
static bool IsBackendCompatibleImpl(const BackendVersion &backendApiVersion, const BackendVersion &backendVersion)
Protected methods for testing purposes.

◆ IsBackendCompatibleImpl()

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

Protected methods for testing purposes.

Definition at line 58 of file DynamicBackendUtils.cpp.

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

Referenced by DynamicBackendUtils::IsBackendCompatible(), and TestDynamicBackendUtils::IsBackendCompatibleTest().

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

◆ IsPathValid()

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

Definition at line 145 of file DynamicBackendUtils.cpp.

References ARMNN_LOG, and armnn::warning.

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

146 {
147  if (path.empty())
148  {
149  ARMNN_LOG(warning) << "WARNING: The given backend path is empty";
150  return false;
151  }
152 
153  boost::filesystem::path boostPath(path);
154 
155  if (!boost::filesystem::exists(boostPath))
156  {
157  ARMNN_LOG(warning) << "WARNING: The given backend path \"" << path << "\" does not exist";
158  return false;
159  }
160 
161  if (!boost::filesystem::is_directory(boostPath))
162  {
163  ARMNN_LOG(warning) << "WARNING: The given backend path \"" << path << "\" is not a directory";
164  return false;
165  }
166 
167  if (!boostPath.is_absolute())
168  {
169  ARMNN_LOG(warning) << "WARNING: The given backend path \"" << path << "\" is not absolute";
170  return false;
171  }
172 
173  return true;
174 }
#define ARMNN_LOG(severity)
Definition: Logging.hpp:163

◆ OpenHandle()

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

Definition at line 17 of file DynamicBackendUtils.cpp.

Referenced by DynamicBackendUtils::CreateDynamicBackends().

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

◆ RegisterDynamicBackends()

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

Definition at line 326 of file DynamicBackendUtils.cpp.

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

Referenced by Runtime::RegisterDebugCallback().

327 {
328  // Get a reference of the backend registry
329  BackendRegistry& backendRegistry = BackendRegistryInstance();
330 
331  // Register the dynamic backends in the backend registry, and return a list of registered backend ids
332  return RegisterDynamicBackendsImpl(backendRegistry, dynamicBackends);
333 }
BackendRegistry & BackendRegistryInstance()
static BackendIdSet RegisterDynamicBackendsImpl(BackendRegistry &backendRegistry, const std::vector< DynamicBackendPtr > &dynamicBackends)

◆ RegisterDynamicBackendsImpl()

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

Definition at line 335 of file DynamicBackendUtils.cpp.

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

Referenced by DynamicBackendUtils::RegisterDynamicBackends(), and TestDynamicBackendUtils::RegisterDynamicBackendsImplTest().

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

The documentation for this class was generated from the following files: