ArmNN
 21.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 36 of file DynamicBackendUtils.cpp.

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

◆ CreateDynamicBackends()

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

Definition at line 261 of file DynamicBackendUtils.cpp.

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

Referenced by RuntimeImpl::RegisterDebugCallback().

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

◆ DeregisterDynamicBackends()

void DeregisterDynamicBackends ( const BackendIdSet dynamicBackends)
static

Definition at line 312 of file DynamicBackendUtils.cpp.

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

Referenced by RuntimeImpl::~RuntimeImpl().

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

◆ GetBackendPaths()

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

Definition at line 79 of file DynamicBackendUtils.cpp.

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

Referenced by RuntimeImpl::RegisterDebugCallback().

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

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

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

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

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

Referenced by RuntimeImpl::RegisterDebugCallback().

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

◆ IsBackendCompatible()

bool IsBackendCompatible ( const BackendVersion backendVersion)
static

Definition at line 50 of file DynamicBackendUtils.cpp.

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

Referenced by DynamicBackend::DynamicBackend().

51 {
52  BackendVersion backendApiVersion = IBackendInternal::GetApiVersion();
53 
54  return IsBackendCompatibleImpl(backendApiVersion, backendVersion);
55 }
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 57 of file DynamicBackendUtils.cpp.

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

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

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

◆ IsPathValid()

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

Definition at line 143 of file DynamicBackendUtils.cpp.

References ARMNN_LOG, and armnn::warning.

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

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

◆ OpenHandle()

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

Definition at line 16 of file DynamicBackendUtils.cpp.

Referenced by DynamicBackendUtils::CreateDynamicBackends().

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  throw RuntimeException("Dynamic backends not supported on this platform");
33 #endif
34 }

◆ RegisterDynamicBackends()

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

Definition at line 324 of file DynamicBackendUtils.cpp.

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

Referenced by RuntimeImpl::RegisterDebugCallback().

325 {
326  // Get a reference of the backend registry
327  BackendRegistry& backendRegistry = BackendRegistryInstance();
328 
329  // Register the dynamic backends in the backend registry, and return a list of registered backend ids
330  return RegisterDynamicBackendsImpl(backendRegistry, dynamicBackends);
331 }
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 333 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().

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

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