From 03c7ff3f6188240baaeaeb405a357a0c58195fec Mon Sep 17 00:00:00 2001 From: Nikhil Raj Date: Tue, 22 Aug 2023 12:00:04 +0100 Subject: IVGCVSW-7702 Update Doxygen Docu for 23.08 Signed-off-by: Nikhil Raj Change-Id: I357a9f7e47614589327c1ac5d95b6224ff77103d --- latest/_dynamic_backend_utils_8cpp_source.html | 570 +++++++++++++++++++++++++ 1 file changed, 570 insertions(+) create mode 100644 latest/_dynamic_backend_utils_8cpp_source.html (limited to 'latest/_dynamic_backend_utils_8cpp_source.html') diff --git a/latest/_dynamic_backend_utils_8cpp_source.html b/latest/_dynamic_backend_utils_8cpp_source.html new file mode 100644 index 0000000000..444850f338 --- /dev/null +++ b/latest/_dynamic_backend_utils_8cpp_source.html @@ -0,0 +1,570 @@ + + + + + + + + +Arm NN: src/backends/backendsCommon/DynamicBackendUtils.cpp Source File + + + + + + + + + + + + + + + + +
+
+ + + + ArmNN + + + +
+
+  23.08 +
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
DynamicBackendUtils.cpp
+
+
+Go to the documentation of this file.
1 //
+
2 // Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
+
3 // SPDX-License-Identifier: MIT
+
4 //
+
5 
+
6 #include <armnn/Logging.hpp>
+ + + +
10 
+
11 #include <regex>
+
12 
+
13 namespace armnn
+
14 {
+
15 
+
16 void* DynamicBackendUtils::OpenHandle(const std::string& sharedObjectPath)
+
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 }
+
36 
+
37 void DynamicBackendUtils::CloseHandle(const void* sharedObjectHandle)
+
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 }
+
51 
+ +
53 {
+
54  BackendVersion backendApiVersion = IBackendInternal::GetApiVersion();
+
55 
+
56  return IsBackendCompatibleImpl(backendApiVersion, backendVersion);
+
57 }
+
58 
+ +
60  const BackendVersion &backendVersion)
+
61 {
+
62  return backendVersion.m_Major == backendApiVersion.m_Major &&
+
63  backendVersion.m_Minor <= backendApiVersion.m_Minor;
+
64 }
+
65 
+
66 std::string DynamicBackendUtils::GetDlError()
+
67 {
+
68 #if defined(__unix__) || defined(__APPLE__)
+
69  const char* errorMessage = dlerror();
+
70  if (!errorMessage)
+
71  {
+
72  return "";
+
73  }
+
74 
+
75  return std::string(errorMessage);
+
76 #else
+
77  throw RuntimeException("Dynamic backends not supported on this platform");
+
78 #endif
+
79 }
+
80 
+
81 std::vector<std::string> DynamicBackendUtils::GetBackendPaths(const std::string& overrideBackendPath)
+
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 }
+
102 
+
103 std::vector<std::string> DynamicBackendUtils::GetBackendPathsImpl(const std::string& backendPaths)
+
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 }
+
144 
+
145 bool DynamicBackendUtils::IsPathValid(const std::string& path)
+
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 }
+
177 
+
178 std::vector<std::string> DynamicBackendUtils::GetSharedObjects(const std::vector<std::string>& backendPaths)
+
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 }
+
268 
+
269 std::vector<DynamicBackendPtr> DynamicBackendUtils::CreateDynamicBackends(const std::vector<std::string>& sharedObjects)
+
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 }
+
319 
+ +
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 }
+
331 
+
332 BackendIdSet DynamicBackendUtils::RegisterDynamicBackends(const std::vector<DynamicBackendPtr>& dynamicBackends)
+
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 }
+
340 
+ +
342  const std::vector<DynamicBackendPtr>& dynamicBackends)
+
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 }
+
416 
+
417 } // namespace armnn
+
+
+ +
static std::vector< DynamicBackendPtr > CreateDynamicBackends(const std::vector< std::string > &sharedObjects)
+
bool IsUndefined() const
Definition: BackendId.hpp:141
+
std::unique_ptr< DynamicBackend > DynamicBackendPtr
+
#define DYNAMIC_BACKEND_PATHS
+
void Deregister(const BackendId &id)
+
std::unordered_set< BackendId > BackendIdSet
Definition: BackendId.hpp:193
+
bool IsEmpty() const
Definition: BackendId.hpp:140
+
static bool IsBackendCompatibleImpl(const BackendVersion &backendApiVersion, const BackendVersion &backendVersion)
Protected methods for testing purposes.
+
static void * OpenHandle(const std::string &sharedObjectPath)
+ +
std::function< PointerType()> FactoryFunction
+ +
static BackendIdSet RegisterDynamicBackendsImpl(BackendRegistry &backendRegistry, const std::vector< DynamicBackendPtr > &dynamicBackends)
+ +
virtual const char * what() const noexcept override
Definition: Exceptions.cpp:32
+
#define ARMNN_LOG(severity)
Definition: Logging.hpp:212
+ +
static std::vector< std::string > GetSharedObjects(const std::vector< std::string > &backendPaths)
+
BackendRegistry & BackendRegistryInstance()
+ +
static bool IsPathValid(const std::string &path)
+ +
static void CloseHandle(const void *sharedObjectHandle)
+
Base class for all ArmNN exceptions so that users can filter to just those.
Definition: Exceptions.hpp:46
+ +
bool IsBackendRegistered(const BackendId &id) const
+
static constexpr BackendVersion GetApiVersion()
Returns the version of the Backend API.
+
static BackendIdSet RegisterDynamicBackends(const std::vector< DynamicBackendPtr > &dynamicBackends)
+
static void DeregisterDynamicBackends(const BackendIdSet &dynamicBackends)
+
void Register(const BackendId &id, FactoryFunction factory)
+
void IgnoreUnused(Ts &&...)
+ + +
static std::vector< std::string > GetBackendPaths(const std::string &overrideBackendPath="")
+
Copyright (c) 2021 ARM Limited and Contributors.
+ +
static std::vector< std::string > GetBackendPathsImpl(const std::string &backendPaths)
+
static bool IsBackendCompatible(const BackendVersion &backendVersion)
+
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
+ + + + + + -- cgit v1.2.1