ArmNN
 20.08
DynamicBackendTests.hpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #pragma once
7 
10 #include <armnn/ILayerSupport.hpp>
14 #include <Filesystem.hpp>
16 #include <Runtime.hpp>
17 
18 #include <string>
19 #include <memory>
20 
21 #include <boost/test/unit_test.hpp>
22 
23 #if !defined(DYNAMIC_BACKEND_BUILD_DIR)
24 #define DYNAMIC_BACKEND_BUILD_DIR fs::path("./")
25 #endif
26 
27 static std::string g_TestDirCLI = "--dynamic-backend-build-dir";
28 static std::string g_TestBaseDir = "src/backends/backendsCommon/test/";
29 
30 static std::string g_TestSharedObjectSubDir = "testSharedObject/";
31 static std::string g_TestDynamicBackendSubDir = "testDynamicBackend/";
32 
33 static std::string g_TestSharedObjectFileName = "libTestSharedObject.so";
34 static std::string g_TestNoSharedObjectFileName = "libNoSharedObject.txt";
35 
36 static std::string g_TestValidTestDynamicBackendFileName = "libValidTestDynamicBackend.so";
37 static std::string g_TestInvalidTestDynamicBackend1FileName = "libInvalidTestDynamicBackend1.so";
38 static std::string g_TestInvalidTestDynamicBackend2FileName = "libInvalidTestDynamicBackend2.so";
39 static std::string g_TestInvalidTestDynamicBackend3FileName = "libInvalidTestDynamicBackend3.so";
40 static std::string g_TestInvalidTestDynamicBackend4FileName = "libInvalidTestDynamicBackend4.so";
41 static std::string g_TestInvalidTestDynamicBackend5FileName = "libInvalidTestDynamicBackend5.so";
42 static std::string g_TestInvalidTestDynamicBackend6FileName = "libInvalidTestDynamicBackend6.so";
43 static std::string g_TestInvalidTestDynamicBackend7FileName = "libInvalidTestDynamicBackend7.so";
44 
45 static std::string g_TestValidBackend2FileName = "Arm_TestValid2_backend.so";
46 static std::string g_TestValidBackend3FileName = "Arm_TestValid3_backend.so";
47 static std::string g_TestValidBackend4FileName = "Arm_TestValid4_backend.so";
48 static std::string g_TestValidBackend5FileName = "Arm_TestValid5_backend.so";
49 static std::string g_TestInvalidBackend8FileName = "Arm_TestInvalid8_backend.so";
50 static std::string g_TestInvalidBackend9FileName = "Arm_TestInvalid9_backend.so";
51 static std::string g_TestInvalidBackend10FileName = "Arm_TestInvalid10_backend.so";
52 static std::string g_TestInvalidBackend11FileName = "Arm_TestInvalid11_backend.so";
53 
54 static std::string g_TestDynamicBackendsSubDir1 = "backendsTestPath1/";
55 static std::string g_TestDynamicBackendsSubDir2 = "backendsTestPath2/";
56 static std::string g_TestDynamicBackendsSubDir3 = "backendsTestPath3/";
57 static std::string g_TestDynamicBackendsSubDir4 = "backendsTestPath4/";
58 static std::string g_TestDynamicBackendsSubDir5 = "backendsTestPath5/";
59 static std::string g_TestDynamicBackendsSubDir6 = "backendsTestPath6/";
60 static std::string g_TestDynamicBackendsSubDir7 = "backendsTestPath7/";
61 static std::string g_TestDynamicBackendsSubDir8 = "backendsTestPath8/";
62 static std::string g_TestDynamicBackendsSubDir9 = "backendsTestPath9/";
63 
64 static std::string g_DynamicBackendsBaseDir = "src/backends/dynamic";
65 static std::string g_ReferenceDynamicBackendSubDir = "reference/";
66 static std::string g_ReferenceBackendFileName = "Arm_CpuRef_backend.so";
67 
68 // DynamicBackendUtils wrapper class used for testing (allows to directly invoke the protected methods)
70 {
71 public:
72  static bool IsBackendCompatibleTest(const armnn::BackendVersion& backendApiVersion,
73  const armnn::BackendVersion& backendVersion)
74  {
75  return IsBackendCompatibleImpl(backendApiVersion, backendVersion);
76  }
77 
78  static std::vector<std::string> GetBackendPathsImplTest(const std::string& path)
79  {
80  return GetBackendPathsImpl(path);
81  }
82 
84  armnn::BackendRegistry& backendRegistry,
85  const std::vector<armnn::DynamicBackendPtr>& dynamicBackends)
86  {
87  return RegisterDynamicBackendsImpl(backendRegistry, dynamicBackends);
88  }
89 };
90 
91 // BackendRegistry wrapper class used for testing (swaps the underlying factory storage)
93 {
94 public:
95  TestBackendRegistry() : armnn::BackendRegistry()
96  {
97  Swap(armnn::BackendRegistryInstance(), m_TempStorage);
98  }
99 
101  {
102  Swap(armnn::BackendRegistryInstance(), m_TempStorage);
103  }
104 
105 private:
106  FactoryStorage m_TempStorage;
107 };
108 
109 std::string GetBasePath(const std::string& basePath)
110 {
111  using namespace fs;
112  // What we're looking for here is the location of the UnitTests executable.
113  // In the normal build environment there are a series of files and
114  // directories created by cmake. If the executable has been relocated they
115  // may not be there. The search hierarchy is:
116  // * User specified --dynamic-backend-build-dir
117  // * Compile time value of DYNAMIC_BACKEND_BUILD_DIR.
118  // * Arg0 location.
119  // * Fall back value of current directory.
120  path programLocation = DYNAMIC_BACKEND_BUILD_DIR;
121  // Look for the specific argument --dynamic-backend-build-dir?
122  if (boost::unit_test::framework::master_test_suite().argc == 3)
123  {
124  // Boost custom arguments begin after a '--' on the command line.
125  if (g_TestDirCLI.compare(boost::unit_test::framework::master_test_suite().argv[1]) == 0)
126  {
127  // Then the next argument is the path.
128  programLocation = boost::unit_test::framework::master_test_suite().argv[2];
129  }
130  }
131  else
132  {
133  // Start by checking if DYNAMIC_BACKEND_BUILD_DIR value exist.
134  if (!exists(programLocation))
135  {
136  // That doesn't exist try looking at arg[0].
137  path arg0Path(boost::unit_test::framework::master_test_suite().argv[0]);
138  arg0Path.remove_filename();
139  path arg0SharedObjectPath(arg0Path);
140  arg0SharedObjectPath.append(basePath);
141  if (exists(arg0SharedObjectPath))
142  {
143  // Yeah arg0 worked.
144  programLocation = arg0Path;
145  }
146  }
147  }
148  // This is the base path from the build where the test libraries were built.
149  path sharedObjectPath = programLocation.append(basePath);
150  BOOST_REQUIRE_MESSAGE(exists(sharedObjectPath), "Base path for shared objects does not exist: " +
151  sharedObjectPath.string() + "\nTo specify the root of this base path on the " +
152  "command line add: \'-- --dynamic-backend-build-dir <path>\'");
153  return sharedObjectPath.string();
154 }
155 
157 {
158  return GetBasePath(g_TestBaseDir);
159 }
160 
162 {
163  return GetBasePath(g_DynamicBackendsBaseDir);
164 }
165 
166 std::string GetTestSubDirectory(const std::string& subdir)
167 {
168  using namespace fs;
169 
170  std::string testDynamicBackendsBaseDir = GetTestDirectoryBasePath();
171  path testDynamicBackendsBasePath(testDynamicBackendsBaseDir);
172  path testDynamicBackendsSubDir = testDynamicBackendsBasePath.append(subdir);
173  // Do not check that the sub-directory exists because for testing reasons we may use non-existing paths
174 
175  return testDynamicBackendsSubDir.string();
176 }
177 
178 std::string GetTestSubDirectory(const std::string& basePath, const std::string& subdir)
179 {
180  using namespace fs;
181 
182  path testDynamicBackendsBasePath(basePath);
183  path testDynamicBackendsSubDir = testDynamicBackendsBasePath.append(subdir);
184  // Do not check that the sub-directory exists because for testing reasons we may use non-existing paths
185 
186  return testDynamicBackendsSubDir.string();
187 }
188 
189 std::string GetTestFilePath(const std::string& directory, const std::string& fileName)
190 {
191  using namespace fs;
192 
193  path directoryPath(directory);
194  path fileNamePath = directoryPath.append(fileName);
195  BOOST_CHECK(exists(fileNamePath));
196 
197  return fileNamePath.string();
198 }
199 
201 {
202  using namespace armnn;
203 
204  std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
205  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
206 
207  void* sharedObjectHandle = nullptr;
208  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
209  BOOST_TEST((sharedObjectHandle != nullptr));
210 
211  DynamicBackendUtils::CloseHandle(sharedObjectHandle);
212 }
213 
215 {
216  using namespace armnn;
217 
218  // This calls must silently handle invalid handles and complete successfully (no segfaults, etc.)
219  DynamicBackendUtils::CloseHandle(nullptr);
220 }
221 
223 {
224  using namespace armnn;
225 
226  void* sharedObjectHandle = nullptr;
227  BOOST_CHECK_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(""), RuntimeException);
228  BOOST_TEST((sharedObjectHandle == nullptr));
229 }
230 
232 {
233  using namespace armnn;
234 
235  void* sharedObjectHandle = nullptr;
236  BOOST_CHECK_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle("NotExistingFileName"), RuntimeException);
237  BOOST_TEST((sharedObjectHandle == nullptr));
238 }
239 
241 {
242  using namespace armnn;
243 
244  std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
245  std::string notSharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestNoSharedObjectFileName);
246 
247  void* sharedObjectHandle = nullptr;
248  BOOST_CHECK_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(notSharedObjectFilePath), RuntimeException);
249  BOOST_TEST((sharedObjectHandle == nullptr));
250 }
251 
253 {
254  using namespace armnn;
255 
256  std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
257  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
258 
259  void* sharedObjectHandle = nullptr;
260  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
261  BOOST_TEST((sharedObjectHandle != nullptr));
262 
263  using TestFunctionType = int(*)(int);
264  TestFunctionType testFunctionPointer = nullptr;
265  BOOST_CHECK_NO_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
266  "TestFunction1"));
267  BOOST_TEST((testFunctionPointer != nullptr));
268  BOOST_TEST(testFunctionPointer(7) == 7);
269 
270  DynamicBackendUtils::CloseHandle(sharedObjectHandle);
271 }
272 
274 {
275  using namespace armnn;
276 
277  std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
278  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
279 
280  void* sharedObjectHandle = nullptr;
281  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
282  BOOST_TEST((sharedObjectHandle != nullptr));
283 
284  using TestFunctionType = int(*)(int);
285  TestFunctionType testFunctionPointer = nullptr;
286  BOOST_CHECK_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
287  "TestFunction2"),
289  BOOST_TEST((testFunctionPointer == nullptr));
290 
291  DynamicBackendUtils::CloseHandle(sharedObjectHandle);
292 }
293 
295 {
296  using namespace armnn;
297 
298  std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
299  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
300 
301  void* sharedObjectHandle = nullptr;
302  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
303  BOOST_TEST((sharedObjectHandle != nullptr));
304 
305  using TestFunctionType = int(*)(int);
306  TestFunctionType testFunctionPointer = nullptr;
307  BOOST_CHECK_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
308  "TestFunction3"),
310  BOOST_TEST((testFunctionPointer == nullptr));
311 
312  DynamicBackendUtils::CloseHandle(sharedObjectHandle);
313 }
314 
316 {
317  using namespace armnn;
318 
319  std::string testSubDirectory = GetTestSubDirectory(g_TestSharedObjectSubDir);
320  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestSharedObjectFileName);
321 
322  void* sharedObjectHandle = nullptr;
323  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
324  BOOST_TEST((sharedObjectHandle != nullptr));
325 
326  using TestFunctionType = int(*)(int);
327  TestFunctionType testFunctionPointer = nullptr;
328  BOOST_CHECK_THROW(testFunctionPointer = DynamicBackendUtils::GetEntryPoint<TestFunctionType>(sharedObjectHandle,
329  "TestFunction4"),
331  BOOST_TEST((testFunctionPointer == nullptr));
332 
333  DynamicBackendUtils::CloseHandle(sharedObjectHandle);
334 }
335 
337 {
338  using namespace armnn;
339 
340  // The backend API version used for the tests
341  BackendVersion backendApiVersion{ 2, 4 };
342 
343  // Same backend and backend API versions are compatible with the backend API
344  BackendVersion sameBackendVersion{ 2, 4 };
345  BOOST_TEST(sameBackendVersion == backendApiVersion);
346  BOOST_TEST(sameBackendVersion <= backendApiVersion);
347  BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, sameBackendVersion) == true);
348 
349  // Backend versions that differ from the backend API version by major revision are not compatible
350  // with the backend API
351  BackendVersion laterMajorBackendVersion{ 3, 4 };
352  BOOST_TEST(!(laterMajorBackendVersion == backendApiVersion));
353  BOOST_TEST(!(laterMajorBackendVersion <= backendApiVersion));
354  BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, laterMajorBackendVersion) == false);
355 
356  BackendVersion earlierMajorBackendVersion{ 1, 4 };
357  BOOST_TEST(!(earlierMajorBackendVersion == backendApiVersion));
358  BOOST_TEST(earlierMajorBackendVersion <= backendApiVersion);
359  BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion,
360  earlierMajorBackendVersion) == false);
361 
362  // Backend versions with the same major revision but later minor revision than
363  // the backend API version are not compatible with the backend API
364  BackendVersion laterMinorBackendVersion{ 2, 5 };
365  BOOST_TEST(!(laterMinorBackendVersion == backendApiVersion));
366  BOOST_TEST(!(laterMinorBackendVersion <= backendApiVersion));
367  BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, laterMinorBackendVersion) == false);
368 
369  // Backend versions with the same major revision but earlier minor revision than
370  // the backend API version are compatible with the backend API
371  BackendVersion earlierMinorBackendVersion{ 2, 3 };
372  BOOST_TEST(!(earlierMinorBackendVersion == backendApiVersion));
373  BOOST_TEST(earlierMinorBackendVersion <= backendApiVersion);
374  BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatibleTest(backendApiVersion, earlierMinorBackendVersion) == true);
375 }
376 
378 {
379  // Valid shared object handle
380  // Correct name mangling
381  // Correct interface
382  // Correct backend implementation
383 
384  using namespace armnn;
385 
386  std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
387 
388  // We expect this path to exists so we can load a valid dynamic backend.
389  BOOST_CHECK_MESSAGE(fs::exists(testSubDirectory),
390  "Base path for shared objects does not exist: " + testSubDirectory);
391 
392  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestValidTestDynamicBackendFileName);
393 
394  void* sharedObjectHandle = nullptr;
395  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
396  BOOST_TEST((sharedObjectHandle != nullptr));
397 
398  DynamicBackendPtr dynamicBackend;
399  BOOST_CHECK_NO_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)));
400  BOOST_TEST((dynamicBackend != nullptr));
401 
402  BackendId dynamicBackendId;
403  BOOST_CHECK_NO_THROW(dynamicBackendId = dynamicBackend->GetBackendId());
404  BOOST_TEST((dynamicBackendId == "ValidTestDynamicBackend"));
405 
406  BackendVersion dynamicBackendVersion;
407  BOOST_CHECK_NO_THROW(dynamicBackendVersion = dynamicBackend->GetBackendVersion());
408  BOOST_TEST((dynamicBackendVersion == IBackendInternal::GetApiVersion()));
409 
410  IBackendInternalUniquePtr dynamicBackendInstance1;
411  BOOST_CHECK_NO_THROW(dynamicBackendInstance1 = dynamicBackend->GetBackend());
412  BOOST_TEST((dynamicBackendInstance1 != nullptr));
413 
414  BackendRegistry::FactoryFunction dynamicBackendFactoryFunction = nullptr;
415  BOOST_CHECK_NO_THROW(dynamicBackendFactoryFunction = dynamicBackend->GetFactoryFunction());
416  BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
417 
418  IBackendInternalUniquePtr dynamicBackendInstance2;
419  BOOST_CHECK_NO_THROW(dynamicBackendInstance2 = dynamicBackendFactoryFunction());
420  BOOST_TEST((dynamicBackendInstance2 != nullptr));
421 
422  BOOST_TEST((dynamicBackendInstance1->GetId() == "ValidTestDynamicBackend"));
423  BOOST_TEST((dynamicBackendInstance2->GetId() == "ValidTestDynamicBackend"));
424 }
425 
427 {
428  // Invalid (null) shared object handle
429 
430  using namespace armnn;
431 
432  void* sharedObjectHandle = nullptr;
433  DynamicBackendPtr dynamicBackend;
434  BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), InvalidArgumentException);
435  BOOST_TEST((dynamicBackend == nullptr));
436 }
437 
439 {
440  // Valid shared object handle
441  // Wrong (not C-style) name mangling
442 
443  using namespace armnn;
444 
445  std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
446  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend1FileName);
447 
448  void* sharedObjectHandle = nullptr;
449  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
450  BOOST_TEST((sharedObjectHandle != nullptr));
451 
452  DynamicBackendPtr dynamicBackend;
453  BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
454  BOOST_TEST((dynamicBackend == nullptr));
455 }
456 
458 {
459  // Valid shared object handle
460  // Correct name mangling
461  // Wrong interface (missing GetBackendId())
462 
463  using namespace armnn;
464 
465  std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
466  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend2FileName);
467 
468  void* sharedObjectHandle = nullptr;
469  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
470  BOOST_TEST((sharedObjectHandle != nullptr));
471 
472  DynamicBackendPtr dynamicBackend;
473  BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
474  BOOST_TEST((dynamicBackend == nullptr));
475 }
476 
478 {
479  // Valid shared object handle
480  // Correct name mangling
481  // Wrong interface (missing GetVersion())
482 
483  using namespace armnn;
484 
485  std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
486  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend3FileName);
487 
488  void* sharedObjectHandle = nullptr;
489  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
490  BOOST_TEST((sharedObjectHandle != nullptr));
491 
492  DynamicBackendPtr dynamicBackend;
493  BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
494  BOOST_TEST((dynamicBackend == nullptr));
495 }
496 
498 {
499  // Valid shared object handle
500  // Correct name mangling
501  // Wrong interface (missing BackendFactory())
502 
503  using namespace armnn;
504 
505  std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
506  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend4FileName);
507 
508  void* sharedObjectHandle = nullptr;
509  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
510  BOOST_TEST((sharedObjectHandle != nullptr));
511 
512  DynamicBackendPtr dynamicBackend;
513  BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
514  BOOST_TEST((dynamicBackend == nullptr));
515 }
516 
518 {
519  // Valid shared object handle
520  // Correct name mangling
521  // Correct interface
522  // Invalid (null) backend id returned by GetBackendId()
523 
524  using namespace armnn;
525 
526  std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
527  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend5FileName);
528 
529  void* sharedObjectHandle = nullptr;
530  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
531  BOOST_TEST((sharedObjectHandle != nullptr));
532 
533  DynamicBackendPtr dynamicBackend;
534  BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
535  BOOST_TEST((dynamicBackend == nullptr));
536 }
537 
539 {
540  // Valid shared object handle
541  // Correct name mangling
542  // Correct interface
543  // Invalid (null) backend instance returned by BackendFactory()
544 
545  using namespace armnn;
546 
547  std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
548  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend6FileName);
549 
550  void* sharedObjectHandle = nullptr;
551  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
552  BOOST_TEST((sharedObjectHandle != nullptr));
553 
554  DynamicBackendPtr dynamicBackend;
555  BOOST_CHECK_NO_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)));
556  BOOST_TEST((dynamicBackend != nullptr));
557 
558  BackendId dynamicBackendId;
559  BOOST_CHECK_NO_THROW(dynamicBackendId = dynamicBackend->GetBackendId());
560  BOOST_TEST((dynamicBackendId == "InvalidTestDynamicBackend"));
561 
562  BackendVersion dynamicBackendVersion;
563  BOOST_CHECK_NO_THROW(dynamicBackendVersion = dynamicBackend->GetBackendVersion());
564  BOOST_TEST((dynamicBackendVersion == BackendVersion({ 1, 0 })));
565 
566  IBackendInternalUniquePtr dynamicBackendInstance1;
567  BOOST_CHECK_THROW(dynamicBackendInstance1 = dynamicBackend->GetBackend(), RuntimeException);
568  BOOST_TEST((dynamicBackendInstance1 == nullptr));
569 
570  BackendRegistry::FactoryFunction dynamicBackendFactoryFunction = nullptr;
571  BOOST_CHECK_NO_THROW(dynamicBackendFactoryFunction = dynamicBackend->GetFactoryFunction());
572  BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
573 
574  IBackendInternalUniquePtr dynamicBackendInstance2;
575  BOOST_CHECK_THROW(dynamicBackendInstance2 = dynamicBackendFactoryFunction(), RuntimeException);
576  BOOST_TEST((dynamicBackendInstance2 == nullptr));
577 }
578 
580 {
581  // Valid shared object handle
582  // Correct name mangling
583  // Correct interface
584  // Invalid (incompatible backend API version) backend instance returned by BackendFactory()
585 
586  using namespace armnn;
587 
588  std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
589  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend7FileName);
590 
591  void* sharedObjectHandle = nullptr;
592  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
593  BOOST_TEST((sharedObjectHandle != nullptr));
594 
595  DynamicBackendPtr dynamicBackend;
596  BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
597  BOOST_TEST((dynamicBackend == nullptr));
598 }
599 
601 {
602  using namespace armnn;
603  using namespace fs;
604 
605  // The test covers four directories:
606  // <unit test path>/src/backends/backendsCommon/test/
607  // ├─ backendsTestPath1/ -> exists, contains files
608  // ├─ backendsTestPath2/ -> exists, contains files
609  // ├─ backendsTestPath3/ -> exists, but empty
610  // └─ backendsTestPath4/ -> does not exist
611 
612  std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsSubDir1);
613  std::string subDir2 = GetTestSubDirectory(g_TestDynamicBackendsSubDir2);
614  std::string subDir3 = GetTestSubDirectory(g_TestDynamicBackendsSubDir3);
615  std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsSubDir4);
616 
617  BOOST_CHECK(exists(subDir1));
618  BOOST_CHECK(exists(subDir2));
619  BOOST_CHECK(exists(subDir3));
620  BOOST_CHECK(!exists(subDir4));
621 
622  // No path
623  BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest("").empty());
624 
625  // Malformed path
626  std::string malformedDir(subDir1 + "/" + subDir1);
627  BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(malformedDir).size()==0);
628 
629  // Single valid path
630  std::vector<std::string> DynamicBackendPaths2 = TestDynamicBackendUtils::GetBackendPathsImplTest(subDir1);
631  BOOST_TEST(DynamicBackendPaths2.size() == 1);
632  BOOST_TEST(DynamicBackendPaths2[0] == subDir1);
633 
634  // Multiple equal and valid paths
635  std::string multipleEqualDirs(subDir1 + ":" + subDir1);
636  std::vector<std::string> DynamicBackendPaths3 = TestDynamicBackendUtils::GetBackendPathsImplTest(multipleEqualDirs);
637  BOOST_TEST(DynamicBackendPaths3.size() == 1);
638  BOOST_TEST(DynamicBackendPaths3[0] == subDir1);
639 
640  // Multiple empty paths
641  BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(":::").empty());
642 
643  // Multiple valid paths
644  std::string multipleValidPaths(subDir1 + ":" + subDir2 + ":" + subDir3);
645  std::vector<std::string> DynamicBackendPaths5 =
647  BOOST_TEST(DynamicBackendPaths5.size() == 3);
648  BOOST_TEST(DynamicBackendPaths5[0] == subDir1);
649  BOOST_TEST(DynamicBackendPaths5[1] == subDir2);
650  BOOST_TEST(DynamicBackendPaths5[2] == subDir3);
651 
652  // Valid among empty paths
653  std::string validAmongEmptyDirs("::" + subDir1 + ":");
654  std::vector<std::string> DynamicBackendPaths6 =
656  BOOST_TEST(DynamicBackendPaths6.size() == 1);
657  BOOST_TEST(DynamicBackendPaths6[0] == subDir1);
658 
659  // Invalid among empty paths
660  std::string invalidAmongEmptyDirs(":" + subDir4 + "::");
661  BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(invalidAmongEmptyDirs).empty());
662 
663  // Valid, invalid and empty paths
664  std::string validInvalidEmptyDirs(subDir1 + ":" + subDir4 + ":");
665  std::vector<std::string> DynamicBackendPaths8 =
667  BOOST_TEST(DynamicBackendPaths8.size() == 1);
668  BOOST_TEST(DynamicBackendPaths8[0] == subDir1);
669 
670  // Mix of duplicates of valid, invalid and empty paths
671  std::string duplicateValidInvalidEmptyDirs(validInvalidEmptyDirs + ":" + validInvalidEmptyDirs + ":" +
672  subDir2 + ":" + subDir2);
673  std::vector<std::string> DynamicBackendPaths9 =
674  TestDynamicBackendUtils::GetBackendPathsImplTest(duplicateValidInvalidEmptyDirs);
675  BOOST_TEST(DynamicBackendPaths9.size() == 2);
676  BOOST_TEST(DynamicBackendPaths9[0] == subDir1);
677  BOOST_TEST(DynamicBackendPaths9[1] == subDir2);
678 }
679 
681 {
682  using namespace armnn;
683  using namespace fs;
684 
685  std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsSubDir1);
686  std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsSubDir4);
687 
688  BOOST_CHECK(exists(subDir1));
689  BOOST_CHECK(!exists(subDir4));
690 
691  // Override with valid path
692  std::vector<std::string> validResult = DynamicBackendUtils::GetBackendPaths(subDir1);
693  BOOST_TEST(validResult.size() == 1);
694  BOOST_TEST(validResult[0] == subDir1);
695 
696  // Override with invalid path
697  std::vector<std::string> invalidResult = DynamicBackendUtils::GetBackendPaths(subDir4);
698  BOOST_TEST(invalidResult.empty());
699 }
700 
702 {
703  using namespace armnn;
704  using namespace fs;
705 
706  // The test covers four directories:
707  // <unit test path>/src/backends/backendsCommon/test/
708  // ├─ backendsTestPath1/ -> exists, contains files
709  // ├─ backendsTestPath2/ -> exists, contains files
710  // ├─ backendsTestPath3/ -> exists, but empty
711  // └─ backendsTestPath4/ -> does not exist
712  //
713  // The test sub-directory backendsTestPath1/ contains the following test files:
714  //
715  // Arm_GpuAcc_backend.so -> valid (basic backend name)
716  // Arm_GpuAcc_backend.so.1 -> valid (single field version number)
717  // Arm_GpuAcc_backend.so.1.2 -> valid (multiple field version number)
718  // Arm_GpuAcc_backend.so.1.2.3 -> valid (multiple field version number)
719  // Arm_GpuAcc_backend.so.10.1.27 -> valid (Multiple digit version)
720  // Arm_GpuAcc_backend.so.10.1.33. -> not valid (dot not followed by version number)
721  // Arm_GpuAcc_backend.so.3.4..5 -> not valid (dot not followed by version number)
722  // Arm_GpuAcc_backend.so.1,1.1 -> not valid (comma instead of dot in the version)
723  //
724  // Arm123_GpuAcc_backend.so -> valid (digits in vendor name are allowed)
725  // Arm_GpuAcc456_backend.so -> valid (digits in backend id are allowed)
726  // Arm%Co_GpuAcc_backend.so -> not valid (invalid character in vendor name)
727  // Arm_Gpu.Acc_backend.so -> not valid (invalid character in backend id)
728  //
729  // GpuAcc_backend.so -> not valid (missing vendor name)
730  // _GpuAcc_backend.so -> not valid (missing vendor name)
731  // Arm__backend.so -> not valid (missing backend id)
732  // Arm_GpuAcc.so -> not valid (missing "backend" at the end)
733  // __backend.so -> not valid (missing vendor name and backend id)
734  // __.so -> not valid (missing all fields)
735  //
736  // Arm_GpuAcc_backend -> not valid (missing at least ".so" at the end)
737  // Arm_GpuAcc_backend_v1.2.so -> not valid (extra version info at the end)
738  //
739  // The test sub-directory backendsTestPath1/ contains the following test files:
740  //
741  // Arm_CpuAcc_backend.so -> valid (basic backend name)
742  // Arm_CpuAcc_backend.so.1 -> Arm_CpuAcc_backend.so -> valid (symlink to valid backend file)
743  // Arm_CpuAcc_backend.so.1.2 -> Arm_CpuAcc_backend.so.1 -> valid (symlink to valid symlink)
744  // Arm_CpuAcc_backend.so.1.2.3 -> Arm_CpuAcc_backend.so.1.2 -> valid (symlink to valid symlink)
745  //
746  // Arm_no_backend.so -> nothing -> not valid (symlink resolves to non-existent file)
747  //
748  // Arm_GpuAcc_backend.so -> valid (but duplicated from backendsTestPath1/)
749 
750  std::string testDynamicBackendsSubDir1 = GetTestSubDirectory(g_TestDynamicBackendsSubDir1);
751  std::string testDynamicBackendsSubDir2 = GetTestSubDirectory(g_TestDynamicBackendsSubDir2);
752  std::string testDynamicBackendsSubDir3 = GetTestSubDirectory(g_TestDynamicBackendsSubDir3);
753  std::string testDynamicBackendsSubDir4 = GetTestSubDirectory(g_TestDynamicBackendsSubDir4);
754  BOOST_CHECK(exists(testDynamicBackendsSubDir1));
755  BOOST_CHECK(exists(testDynamicBackendsSubDir2));
756  BOOST_CHECK(exists(testDynamicBackendsSubDir3));
757  BOOST_CHECK(!exists(testDynamicBackendsSubDir4));
758 
759  std::vector<std::string> backendPaths
760  {
761  testDynamicBackendsSubDir1,
762  testDynamicBackendsSubDir2,
763  testDynamicBackendsSubDir3,
764  testDynamicBackendsSubDir4
765  };
766  std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
767  std::vector<fs::path> expectedSharedObjects
768  {
769  path(testDynamicBackendsSubDir1 + "Arm123_GpuAcc_backend.so"), // Digits in vendor name are allowed
770  path(testDynamicBackendsSubDir1 + "Arm_GpuAcc456_backend.so"), // Digits in backend id are allowed
771  path(testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so"), // Basic backend name
772  path(testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1"), // Single field version number
773  path(testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1.2"), // Multiple field version number
774  path(testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1.2.3"), // Multiple field version number
775  path(testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.10.1.27"), // Multiple digit version
776  path(testDynamicBackendsSubDir2 + "Arm_CpuAcc_backend.so"), // Duplicate symlinks removed
777  path(testDynamicBackendsSubDir2 + "Arm_GpuAcc_backend.so") // Duplicates on different paths are allowed
778  };
779 
780  BOOST_TEST(sharedObjects.size() == expectedSharedObjects.size());
781  BOOST_TEST(fs::equivalent(path(sharedObjects[0]), expectedSharedObjects[0]));
782  BOOST_TEST(fs::equivalent(path(sharedObjects[1]), expectedSharedObjects[1]));
783  BOOST_TEST(fs::equivalent(path(sharedObjects[2]), expectedSharedObjects[2]));
784  BOOST_TEST(fs::equivalent(path(sharedObjects[3]), expectedSharedObjects[3]));
785  BOOST_TEST(fs::equivalent(path(sharedObjects[4]), expectedSharedObjects[4]));
786  BOOST_TEST(fs::equivalent(path(sharedObjects[5]), expectedSharedObjects[5]));
787  BOOST_TEST(fs::equivalent(path(sharedObjects[6]), expectedSharedObjects[6]));
788  BOOST_TEST(fs::equivalent(path(sharedObjects[7]), expectedSharedObjects[7]));
789  BOOST_TEST(fs::equivalent(path(sharedObjects[8]), expectedSharedObjects[8]));
790 }
791 
793 {
794  using namespace armnn;
795  using namespace fs;
796 
797  // The test covers four directories:
798  // <unit test path>/src/backends/backendsCommon/test/
799  // ├─ backendsTestPath5/ -> exists, contains files
800  // ├─ backendsTestPath6/ -> exists, contains files
801  // ├─ backendsTestPath7/ -> exists, but empty
802  // └─ backendsTestPath8/ -> does not exist
803  //
804  // The test sub-directory backendsTestPath5/ contains the following test files:
805  //
806  // Arm_TestValid2_backend.so -> valid (basic backend name)
807  // Arm_TestValid3_backend.so -> valid (basic backend name)
808  // Arm_TestInvalid8_backend.so -> not valid (invalid backend id)
809  //
810  // The test sub-directory backendsTestPath6/ contains the following test files:
811  //
812  // Arm_TestValid2_backend.so -> valid (but duplicated from backendsTestPath5/)
813  // Arm_TestValid4_backend.so -> valid (it has a different filename,
814  // but it has the same backend id of Arm_TestValid2_backend.so
815  // and the same version)
816  // Arm_TestValid5_backend.so -> valid (basic backend name)
817  // Arm_TestInvalid9_backend.so -> not valid (it has a different filename,
818  // but it has the same backend id of Arm_TestValid2_backend.so
819  // and a version incompatible with the Backend API)
820 
821  std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
822  std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
823  std::string testDynamicBackendsSubDir7 = GetTestSubDirectory(g_TestDynamicBackendsSubDir7);
824  std::string testDynamicBackendsSubDir8 = GetTestSubDirectory(g_TestDynamicBackendsSubDir8);
825  BOOST_CHECK(exists(testDynamicBackendsSubDir5));
826  BOOST_CHECK(exists(testDynamicBackendsSubDir6));
827  BOOST_CHECK(exists(testDynamicBackendsSubDir7));
828  BOOST_CHECK(!exists(testDynamicBackendsSubDir8));
829 
830  std::vector<std::string> backendPaths
831  {
832  testDynamicBackendsSubDir5,
833  testDynamicBackendsSubDir6,
834  testDynamicBackendsSubDir7,
835  testDynamicBackendsSubDir8
836  };
837  std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
838  std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
839 
840  BOOST_TEST(dynamicBackends.size() == 5);
841  BOOST_TEST((dynamicBackends[0] != nullptr));
842  BOOST_TEST((dynamicBackends[1] != nullptr));
843  BOOST_TEST((dynamicBackends[2] != nullptr));
844  BOOST_TEST((dynamicBackends[3] != nullptr));
845  BOOST_TEST((dynamicBackends[4] != nullptr));
846 
847  // Duplicates are allowed here, they will be skipped later during the backend registration
848  BOOST_TEST((dynamicBackends[0]->GetBackendId() == "TestValid2"));
849  BOOST_TEST((dynamicBackends[1]->GetBackendId() == "TestValid3"));
850  BOOST_TEST((dynamicBackends[2]->GetBackendId() == "TestValid2")); // From duplicate Arm_TestValid2_backend.so
851  BOOST_TEST((dynamicBackends[3]->GetBackendId() == "TestValid2")); // From Arm_TestValid4_backend.so
852  BOOST_TEST((dynamicBackends[4]->GetBackendId() == "TestValid5"));
853 }
854 
856 {
857  using namespace armnn;
858 
859  std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends({});
860 
861  BOOST_TEST(dynamicBackends.empty());
862 }
863 
865 {
866  using namespace armnn;
867 
868  std::vector<std::string> sharedObjects
869  {
870  "InvalidSharedObject1",
871  "InvalidSharedObject2",
872  "InvalidSharedObject3",
873  };
874  std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
875 
876  BOOST_TEST(dynamicBackends.empty());
877 }
878 
880 {
881  using namespace armnn;
882  using namespace fs;
883 
884  std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
885  std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
886  BOOST_CHECK(exists(testDynamicBackendsSubDir5));
887  BOOST_CHECK(exists(testDynamicBackendsSubDir6));
888 
889  std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5,
890  g_TestValidBackend2FileName);
891  std::string testInvalidBackend8FilePath = GetTestFilePath(testDynamicBackendsSubDir5,
892  g_TestInvalidBackend8FileName);
893  std::string testInvalidBackend9FilePath = GetTestFilePath(testDynamicBackendsSubDir6,
894  g_TestInvalidBackend9FileName);
895  BOOST_CHECK(exists(testValidBackend2FilePath));
896  BOOST_CHECK(exists(testInvalidBackend8FilePath));
897  BOOST_CHECK(exists(testInvalidBackend9FilePath));
898 
899  std::vector<std::string> sharedObjects
900  {
901  testValidBackend2FilePath, // Arm_TestValid2_backend.so -> valid (basic backend name)
902  testInvalidBackend8FilePath, // Arm_TestInvalid8_backend.so -> not valid (invalid backend id)
903  testInvalidBackend9FilePath, // Arm_TestInvalid9_backend.so -> not valid (incompatible version)
904  "InvalidSharedObject", // The file does not exist
905  };
906  std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
907 
908  BOOST_TEST(dynamicBackends.size() == 1);
909  BOOST_TEST((dynamicBackends[0] != nullptr));
910  BOOST_TEST((dynamicBackends[0]->GetBackendId() == "TestValid2"));
911 }
912 
914 {
915  using namespace armnn;
916  using namespace fs;
917 
918  // Register one valid dynamic backend
919 
920  // Dummy registry used for testing
921  BackendRegistry backendRegistry;
922  BOOST_TEST(backendRegistry.Size() == 0);
923 
924  std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
925  BOOST_CHECK(exists(testDynamicBackendsSubDir5));
926 
927  std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend2FileName);
928  BOOST_CHECK(exists(testValidBackend2FilePath));
929 
930  std::vector<std::string> sharedObjects{ testValidBackend2FilePath };
931  std::vector<DynamicBackendPtr> dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects);
932 
933  BOOST_TEST(dynamicBackends.size() == 1);
934  BOOST_TEST((dynamicBackends[0] != nullptr));
935 
936  BackendId dynamicBackendId = dynamicBackends[0]->GetBackendId();
937  BOOST_TEST((dynamicBackendId == "TestValid2"));
938 
939  BackendVersion dynamicBackendVersion = dynamicBackends[0]->GetBackendVersion();
940  BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion));
941 
942  BackendIdSet registeredBackendIds = TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry,
943  dynamicBackends);
944  BOOST_TEST(backendRegistry.Size() == 1);
945  BOOST_TEST(registeredBackendIds.size() == 1);
946 
947  BackendIdSet backendIds = backendRegistry.GetBackendIds();
948  BOOST_TEST(backendIds.size() == 1);
949  BOOST_TEST((backendIds.find(dynamicBackendId) != backendIds.end()));
950  BOOST_TEST((registeredBackendIds.find(dynamicBackendId) != registeredBackendIds.end()));
951 
952  auto dynamicBackendFactoryFunction = backendRegistry.GetFactory(dynamicBackendId);
953  BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
954 
955  IBackendInternalUniquePtr dynamicBackend = dynamicBackendFactoryFunction();
956  BOOST_TEST((dynamicBackend != nullptr));
957  BOOST_TEST((dynamicBackend->GetId() == dynamicBackendId));
958 }
959 
961 {
962  using namespace armnn;
963  using namespace fs;
964 
965  // Register many valid dynamic backends
966 
967  std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
968  std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
969  BOOST_CHECK(exists(testDynamicBackendsSubDir5));
970  BOOST_CHECK(exists(testDynamicBackendsSubDir6));
971 
972  std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend2FileName);
973  std::string testValidBackend3FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend3FileName);
974  std::string testValidBackend5FilePath = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend5FileName);
975  BOOST_CHECK(exists(testValidBackend2FilePath));
976  BOOST_CHECK(exists(testValidBackend3FilePath));
977  BOOST_CHECK(exists(testValidBackend5FilePath));
978 
979  std::vector<std::string> sharedObjects
980  {
981  testValidBackend2FilePath,
982  testValidBackend3FilePath,
983  testValidBackend5FilePath
984  };
985  std::vector<DynamicBackendPtr> dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects);
986 
987  BOOST_TEST(dynamicBackends.size() == 3);
988  BOOST_TEST((dynamicBackends[0] != nullptr));
989  BOOST_TEST((dynamicBackends[1] != nullptr));
990  BOOST_TEST((dynamicBackends[2] != nullptr));
991 
992  BackendId dynamicBackendId1 = dynamicBackends[0]->GetBackendId();
993  BackendId dynamicBackendId2 = dynamicBackends[1]->GetBackendId();
994  BackendId dynamicBackendId3 = dynamicBackends[2]->GetBackendId();
995  BOOST_TEST((dynamicBackendId1 == "TestValid2"));
996  BOOST_TEST((dynamicBackendId2 == "TestValid3"));
997  BOOST_TEST((dynamicBackendId3 == "TestValid5"));
998 
999  for (size_t i = 0; i < dynamicBackends.size(); i++)
1000  {
1001  BackendVersion dynamicBackendVersion = dynamicBackends[i]->GetBackendVersion();
1002  BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion));
1003  }
1004 
1005  // Dummy registry used for testing
1006  BackendRegistry backendRegistry;
1007  BOOST_TEST(backendRegistry.Size() == 0);
1008 
1009  BackendIdSet registeredBackendIds = TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry,
1010  dynamicBackends);
1011  BOOST_TEST(backendRegistry.Size() == 3);
1012  BOOST_TEST(registeredBackendIds.size() == 3);
1013 
1014  BackendIdSet backendIds = backendRegistry.GetBackendIds();
1015  BOOST_TEST(backendIds.size() == 3);
1016  BOOST_TEST((backendIds.find(dynamicBackendId1) != backendIds.end()));
1017  BOOST_TEST((backendIds.find(dynamicBackendId2) != backendIds.end()));
1018  BOOST_TEST((backendIds.find(dynamicBackendId3) != backendIds.end()));
1019  BOOST_TEST((registeredBackendIds.find(dynamicBackendId1) != registeredBackendIds.end()));
1020  BOOST_TEST((registeredBackendIds.find(dynamicBackendId2) != registeredBackendIds.end()));
1021  BOOST_TEST((registeredBackendIds.find(dynamicBackendId3) != registeredBackendIds.end()));
1022 
1023  for (size_t i = 0; i < dynamicBackends.size(); i++)
1024  {
1025  BackendId dynamicBackendId = dynamicBackends[i]->GetBackendId();
1026 
1027  auto dynamicBackendFactoryFunction = backendRegistry.GetFactory(dynamicBackendId);
1028  BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
1029 
1030  IBackendInternalUniquePtr dynamicBackend = dynamicBackendFactoryFunction();
1031  BOOST_TEST((dynamicBackend != nullptr));
1032  BOOST_TEST((dynamicBackend->GetId() == dynamicBackendId));
1033  }
1034 }
1035 
1037 {
1038  using namespace armnn;
1039  using namespace fs;
1040 
1041  // Try to register many invalid dynamic backends
1042 
1043  // The test covers one directory:
1044  // <unit test path>/src/backends/backendsCommon/test/
1045  // └─ backendsTestPath9/ -> exists, contains files
1046  //
1047  // The test sub-directory backendsTestPath9/ contains the following test files:
1048  //
1049  // Arm_TestInvalid10_backend.so -> not valid (invalid backend id)
1050  // Arm_TestInvalid11_backend.so -> not valid (invalid backend id)
1051 
1052  std::string testDynamicBackendsSubDir9 = GetTestSubDirectory(g_TestDynamicBackendsSubDir9);
1053  BOOST_CHECK(exists(testDynamicBackendsSubDir9));
1054 
1055  std::string testInvalidBackend10FilePath = GetTestFilePath(testDynamicBackendsSubDir9,
1056  g_TestInvalidBackend10FileName);
1057  std::string testInvalidBackend11FilePath = GetTestFilePath(testDynamicBackendsSubDir9,
1058  g_TestInvalidBackend11FileName);
1059  BOOST_CHECK(exists(testInvalidBackend10FilePath));
1060  BOOST_CHECK(exists(testInvalidBackend11FilePath));
1061 
1062  std::vector<std::string> sharedObjects
1063  {
1064  testInvalidBackend10FilePath,
1065  testInvalidBackend11FilePath,
1066  "InvalidSharedObject"
1067  };
1068  std::vector<DynamicBackendPtr> dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects);
1069 
1070  BOOST_TEST(dynamicBackends.size() == 2);
1071  BOOST_TEST((dynamicBackends[0] != nullptr));
1072  BOOST_TEST((dynamicBackends[1] != nullptr));
1073 
1074  BackendId dynamicBackendId1 = dynamicBackends[0]->GetBackendId();
1075  BackendId dynamicBackendId2 = dynamicBackends[1]->GetBackendId();
1076  BOOST_TEST((dynamicBackendId1 == ""));
1077  BOOST_TEST((dynamicBackendId2 == "Unknown"));
1078 
1079  for (size_t i = 0; i < dynamicBackends.size(); i++)
1080  {
1081  BackendVersion dynamicBackendVersion = dynamicBackends[i]->GetBackendVersion();
1082  BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion));
1083  }
1084 
1085  // Dummy registry used for testing
1086  BackendRegistry backendRegistry;
1087  BOOST_TEST(backendRegistry.Size() == 0);
1088 
1089  // Check that no dynamic backend got registered
1090  BackendIdSet registeredBackendIds = TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry,
1091  dynamicBackends);
1092  BOOST_TEST(backendRegistry.Size() == 0);
1093  BOOST_TEST(registeredBackendIds.empty());
1094 }
1095 
1097 {
1098  using namespace armnn;
1099  using namespace fs;
1100 
1101  // The test covers five directories:
1102  // <unit test path>/src/backends/backendsCommon/test/
1103  // ├─ backendsTestPath5/ -> exists, contains files
1104  // ├─ backendsTestPath6/ -> exists, contains files
1105  // ├─ backendsTestPath7/ -> exists, but empty
1106  // ├─ backendsTestPath8/ -> does not exist
1107  // └─ backendsTestPath9/ -> exists, contains files
1108  //
1109  // The test sub-directory backendsTestPath5/ contains the following test files:
1110  //
1111  // Arm_TestValid2_backend.so -> valid (basic backend name)
1112  // Arm_TestValid3_backend.so -> valid (basic backend name)
1113  // Arm_TestInvalid8_backend.so -> not valid (invalid backend id)
1114  //
1115  // The test sub-directory backendsTestPath6/ contains the following test files:
1116  //
1117  // Arm_TestValid2_backend.so -> valid (but duplicated from backendsTestPath5/)
1118  // Arm_TestValid4_backend.so -> valid (it has a different filename,
1119  // but it has the same backend id of Arm_TestValid2_backend.so
1120  // and the same version)
1121  // Arm_TestValid5_backend.so -> valid (basic backend name)
1122  // Arm_TestInvalid9_backend.so -> not valid (it has a different filename,
1123  // but it has the same backend id of Arm_TestValid2_backend.so
1124  // and a version incompatible with the Backend API)
1125  //
1126  // The test sub-directory backendsTestPath9/ contains the following test files:
1127  //
1128  // Arm_TestInvalid10_backend.so -> not valid (empty backend id)
1129  // Arm_TestInvalid11_backend.so -> not valid ("Unknown" backend id)
1130 
1131  std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
1132  std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
1133  std::string testDynamicBackendsSubDir7 = GetTestSubDirectory(g_TestDynamicBackendsSubDir7);
1134  std::string testDynamicBackendsSubDir8 = GetTestSubDirectory(g_TestDynamicBackendsSubDir8);
1135  std::string testDynamicBackendsSubDir9 = GetTestSubDirectory(g_TestDynamicBackendsSubDir9);
1136  BOOST_CHECK(exists(testDynamicBackendsSubDir5));
1137  BOOST_CHECK(exists(testDynamicBackendsSubDir6));
1138  BOOST_CHECK(exists(testDynamicBackendsSubDir7));
1139  BOOST_CHECK(!exists(testDynamicBackendsSubDir8));
1140  BOOST_CHECK(exists(testDynamicBackendsSubDir9));
1141 
1142  std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend2FileName);
1143  std::string testValidBackend3FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend3FileName);
1144  std::string testValidBackend2DupFilePath = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend2FileName);
1145  std::string testValidBackend4FilePath = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend4FileName);
1146  std::string testValidBackend5FilePath = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend5FileName);
1147  std::string testInvalidBackend8FilePath = GetTestFilePath(testDynamicBackendsSubDir5,
1148  g_TestInvalidBackend8FileName);
1149  std::string testInvalidBackend9FilePath = GetTestFilePath(testDynamicBackendsSubDir6,
1150  g_TestInvalidBackend9FileName);
1151  std::string testInvalidBackend10FilePath = GetTestFilePath(testDynamicBackendsSubDir9,
1152  g_TestInvalidBackend10FileName);
1153  std::string testInvalidBackend11FilePath = GetTestFilePath(testDynamicBackendsSubDir9,
1154  g_TestInvalidBackend11FileName);
1155  BOOST_CHECK(exists(testValidBackend2FilePath));
1156  BOOST_CHECK(exists(testValidBackend3FilePath));
1157  BOOST_CHECK(exists(testValidBackend2DupFilePath));
1158  BOOST_CHECK(exists(testValidBackend4FilePath));
1159  BOOST_CHECK(exists(testValidBackend5FilePath));
1160  BOOST_CHECK(exists(testInvalidBackend8FilePath));
1161  BOOST_CHECK(exists(testInvalidBackend9FilePath));
1162  BOOST_CHECK(exists(testInvalidBackend10FilePath));
1163  BOOST_CHECK(exists(testInvalidBackend11FilePath));
1164 
1165  std::vector<std::string> sharedObjects
1166  {
1167  testValidBackend2FilePath,
1168  testValidBackend3FilePath,
1169  testValidBackend2DupFilePath,
1170  testValidBackend4FilePath,
1171  testValidBackend5FilePath,
1172  testInvalidBackend8FilePath,
1173  testInvalidBackend9FilePath,
1174  testInvalidBackend10FilePath,
1175  testInvalidBackend11FilePath,
1176  "InvalidSharedObject"
1177  };
1178  std::vector<DynamicBackendPtr> dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects);
1179 
1180  BOOST_TEST(dynamicBackends.size() == 7);
1181  BOOST_TEST((dynamicBackends[0] != nullptr));
1182  BOOST_TEST((dynamicBackends[1] != nullptr));
1183  BOOST_TEST((dynamicBackends[2] != nullptr));
1184  BOOST_TEST((dynamicBackends[3] != nullptr));
1185  BOOST_TEST((dynamicBackends[4] != nullptr));
1186  BOOST_TEST((dynamicBackends[5] != nullptr));
1187  BOOST_TEST((dynamicBackends[6] != nullptr));
1188 
1189  BackendId dynamicBackendId1 = dynamicBackends[0]->GetBackendId();
1190  BackendId dynamicBackendId2 = dynamicBackends[1]->GetBackendId();
1191  BackendId dynamicBackendId3 = dynamicBackends[2]->GetBackendId();
1192  BackendId dynamicBackendId4 = dynamicBackends[3]->GetBackendId();
1193  BackendId dynamicBackendId5 = dynamicBackends[4]->GetBackendId();
1194  BackendId dynamicBackendId6 = dynamicBackends[5]->GetBackendId();
1195  BackendId dynamicBackendId7 = dynamicBackends[6]->GetBackendId();
1196  BOOST_TEST((dynamicBackendId1 == "TestValid2"));
1197  BOOST_TEST((dynamicBackendId2 == "TestValid3"));
1198  BOOST_TEST((dynamicBackendId3 == "TestValid2")); // From duplicate Arm_TestValid2_backend.so
1199  BOOST_TEST((dynamicBackendId4 == "TestValid2")); // From Arm_TestValid4_backend.so
1200  BOOST_TEST((dynamicBackendId5 == "TestValid5"));
1201  BOOST_TEST((dynamicBackendId6 == ""));
1202  BOOST_TEST((dynamicBackendId7 == "Unknown"));
1203 
1204  for (size_t i = 0; i < dynamicBackends.size(); i++)
1205  {
1206  BackendVersion dynamicBackendVersion = dynamicBackends[i]->GetBackendVersion();
1207  BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion));
1208  }
1209 
1210  // Dummy registry used for testing
1211  BackendRegistry backendRegistry;
1212  BOOST_TEST(backendRegistry.Size() == 0);
1213 
1214  std::vector<BackendId> expectedRegisteredbackendIds
1215  {
1216  "TestValid2",
1217  "TestValid3",
1218  "TestValid5"
1219  };
1220 
1221  BackendIdSet registeredBackendIds = TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry,
1222  dynamicBackends);
1223  BOOST_TEST(backendRegistry.Size() == expectedRegisteredbackendIds.size());
1224  BOOST_TEST(registeredBackendIds.size() == expectedRegisteredbackendIds.size());
1225 
1226  BackendIdSet backendIds = backendRegistry.GetBackendIds();
1227  BOOST_TEST(backendIds.size() == expectedRegisteredbackendIds.size());
1228  for (const BackendId& expectedRegisteredbackendId : expectedRegisteredbackendIds)
1229  {
1230  BOOST_TEST((backendIds.find(expectedRegisteredbackendId) != backendIds.end()));
1231  BOOST_TEST((registeredBackendIds.find(expectedRegisteredbackendId) != registeredBackendIds.end()));
1232 
1233  auto dynamicBackendFactoryFunction = backendRegistry.GetFactory(expectedRegisteredbackendId);
1234  BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
1235 
1236  IBackendInternalUniquePtr dynamicBackend = dynamicBackendFactoryFunction();
1237  BOOST_TEST((dynamicBackend != nullptr));
1238  BOOST_TEST((dynamicBackend->GetId() == expectedRegisteredbackendId));
1239  }
1240 }
1241 
1242 #if !defined(ARMNN_DYNAMIC_BACKEND_ENABLED)
1243 
1245 {
1246  using namespace armnn;
1247 
1248  // Swapping the backend registry storage for testing
1249  TestBackendRegistry testBackendRegistry;
1250 
1251  const BackendRegistry& backendRegistry = BackendRegistryInstance();
1252  BOOST_TEST(backendRegistry.Size() == 0);
1253 
1254  IRuntime::CreationOptions creationOptions;
1255  IRuntimePtr runtime = IRuntime::Create(creationOptions);
1256 
1257  const DeviceSpec& deviceSpec = *PolymorphicDowncast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1258  BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1259  BOOST_TEST(supportedBackendIds.empty());
1260 
1261  BOOST_TEST(backendRegistry.Size() == 0);
1262 }
1263 
1264 #endif
1265 
1267 {
1268  using namespace armnn;
1269  using namespace fs;
1270 
1271  // Swapping the backend registry storage for testing
1272  TestBackendRegistry testBackendRegistry;
1273 
1274  // This directory contains valid and invalid backends
1275  std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
1276  BOOST_CHECK(exists(testDynamicBackendsSubDir5));
1277 
1278  // Using the path override in CreationOptions to load some test dynamic backends
1279  IRuntime::CreationOptions creationOptions;
1280  creationOptions.m_DynamicBackendsPath = testDynamicBackendsSubDir5;
1281  IRuntimePtr runtime = IRuntime::Create(creationOptions);
1282 
1283  std::vector<BackendId> expectedRegisteredbackendIds
1284  {
1285  "TestValid2",
1286  "TestValid3"
1287  };
1288 
1289  const BackendRegistry& backendRegistry = BackendRegistryInstance();
1290  BOOST_TEST(backendRegistry.Size() == expectedRegisteredbackendIds.size());
1291 
1292  BackendIdSet backendIds = backendRegistry.GetBackendIds();
1293  for (const BackendId& expectedRegisteredbackendId : expectedRegisteredbackendIds)
1294  {
1295  BOOST_TEST((backendIds.find(expectedRegisteredbackendId) != backendIds.end()));
1296  }
1297 
1298  const DeviceSpec& deviceSpec = *PolymorphicDowncast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1299  BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1300  BOOST_TEST(supportedBackendIds.size() == expectedRegisteredbackendIds.size());
1301  for (const BackendId& expectedRegisteredbackendId : expectedRegisteredbackendIds)
1302  {
1303  BOOST_TEST((supportedBackendIds.find(expectedRegisteredbackendId) != supportedBackendIds.end()));
1304  }
1305 }
1306 
1308 {
1309  using namespace armnn;
1310  using namespace fs;
1311 
1312  // Swapping the backend registry storage for testing
1313  TestBackendRegistry testBackendRegistry;
1314 
1315  // This directory contains valid, invalid and duplicate backends
1316  std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
1317  BOOST_CHECK(exists(testDynamicBackendsSubDir6));
1318 
1319  // Using the path override in CreationOptions to load some test dynamic backends
1320  IRuntime::CreationOptions creationOptions;
1321  creationOptions.m_DynamicBackendsPath = testDynamicBackendsSubDir6;
1322  IRuntimePtr runtime = IRuntime::Create(creationOptions);
1323 
1324  std::vector<BackendId> expectedRegisteredbackendIds
1325  {
1326  "TestValid2",
1327  "TestValid5"
1328  };
1329 
1330  const BackendRegistry& backendRegistry = BackendRegistryInstance();
1331  BOOST_TEST(backendRegistry.Size() == expectedRegisteredbackendIds.size());
1332 
1333  BackendIdSet backendIds = backendRegistry.GetBackendIds();
1334  for (const BackendId& expectedRegisteredbackendId : expectedRegisteredbackendIds)
1335  {
1336  BOOST_TEST((backendIds.find(expectedRegisteredbackendId) != backendIds.end()));
1337  }
1338 
1339  const DeviceSpec& deviceSpec = *PolymorphicDowncast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1340  BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1341  BOOST_TEST(supportedBackendIds.size() == expectedRegisteredbackendIds.size());
1342  for (const BackendId& expectedRegisteredbackendId : expectedRegisteredbackendIds)
1343  {
1344  BOOST_TEST((supportedBackendIds.find(expectedRegisteredbackendId) != supportedBackendIds.end()));
1345  }
1346 }
1347 
1349 {
1350  using namespace armnn;
1351  using namespace fs;
1352 
1353  // Swapping the backend registry storage for testing
1354  TestBackendRegistry testBackendRegistry;
1355 
1356  // This directory contains only invalid backends
1357  std::string testDynamicBackendsSubDir9 = GetTestSubDirectory(g_TestDynamicBackendsSubDir9);
1358  BOOST_CHECK(exists(testDynamicBackendsSubDir9));
1359 
1360  // Using the path override in CreationOptions to load some test dynamic backends
1361  IRuntime::CreationOptions creationOptions;
1362  creationOptions.m_DynamicBackendsPath = testDynamicBackendsSubDir9;
1363  IRuntimePtr runtime = IRuntime::Create(creationOptions);
1364 
1365  const BackendRegistry& backendRegistry = BackendRegistryInstance();
1366  BOOST_TEST(backendRegistry.Size() == 0);
1367 
1368  const DeviceSpec& deviceSpec = *PolymorphicDowncast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1369  BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1370  BOOST_TEST(supportedBackendIds.empty());
1371 }
1372 
1374 {
1375  using namespace armnn;
1376 
1377  // Swapping the backend registry storage for testing
1378  TestBackendRegistry testBackendRegistry;
1379 
1380  // Using the path override in CreationOptions to load some test dynamic backends
1381  IRuntime::CreationOptions creationOptions;
1382  creationOptions.m_DynamicBackendsPath = "InvalidPath";
1383  IRuntimePtr runtime = IRuntime::Create(creationOptions);
1384 
1385  const BackendRegistry& backendRegistry = BackendRegistryInstance();
1386  BOOST_TEST(backendRegistry.Size() == 0);
1387 
1388  const DeviceSpec& deviceSpec = *PolymorphicDowncast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1389  BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1390  BOOST_TEST(supportedBackendIds.empty());
1391 }
1392 
1393 #if defined(ARMNNREF_ENABLED)
1394 
1395 // This test unit needs the reference backend, it's not available if the reference backend is not built
1396 
1397 void CreateReferenceDynamicBackendTestImpl()
1398 {
1399  using namespace armnn;
1400  using namespace fs;
1401 
1402  // Swapping the backend registry storage for testing
1403  TestBackendRegistry testBackendRegistry;
1404 
1405  // This directory contains the reference dynamic backend
1406  std::string dynamicBackendsBaseDir = GetDynamicBackendsBasePath();
1407  std::string referenceDynamicBackendSubDir = GetTestSubDirectory(dynamicBackendsBaseDir,
1408  g_ReferenceDynamicBackendSubDir);
1409  BOOST_CHECK(exists(referenceDynamicBackendSubDir));
1410 
1411  // Check that the reference dynamic backend file exists
1412  std::string referenceBackendFilePath = GetTestFilePath(referenceDynamicBackendSubDir,
1413  g_ReferenceBackendFileName);
1414  BOOST_CHECK(exists(referenceBackendFilePath));
1415 
1416  // Using the path override in CreationOptions to load the reference dynamic backend
1417  IRuntime::CreationOptions creationOptions;
1418  creationOptions.m_DynamicBackendsPath = referenceDynamicBackendSubDir;
1419  IRuntimePtr runtime = IRuntime::Create(creationOptions);
1420 
1421  const BackendRegistry& backendRegistry = BackendRegistryInstance();
1422  BOOST_TEST(backendRegistry.Size() == 1);
1423 
1424  BackendIdSet backendIds = backendRegistry.GetBackendIds();
1425  BOOST_TEST((backendIds.find("CpuRef") != backendIds.end()));
1426 
1427  const DeviceSpec& deviceSpec = *PolymorphicDowncast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1428  BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1429  BOOST_TEST(supportedBackendIds.size() == 1);
1430  BOOST_TEST((supportedBackendIds.find("CpuRef") != supportedBackendIds.end()));
1431 
1432  // Get the factory function
1433  auto referenceDynamicBackendFactoryFunction = backendRegistry.GetFactory("CpuRef");
1434  BOOST_TEST((referenceDynamicBackendFactoryFunction != nullptr));
1435 
1436  // Use the factory function to create an instance of the reference backend
1437  IBackendInternalUniquePtr referenceDynamicBackend = referenceDynamicBackendFactoryFunction();
1438  BOOST_TEST((referenceDynamicBackend != nullptr));
1439  BOOST_TEST((referenceDynamicBackend->GetId() == "CpuRef"));
1440 
1441  // Test the backend instance by querying the layer support
1442  IBackendInternal::ILayerSupportSharedPtr referenceLayerSupport = referenceDynamicBackend->GetLayerSupport();
1443  BOOST_TEST((referenceLayerSupport != nullptr));
1444 
1445  TensorShape inputShape { 1, 16, 16, 16 };
1446  TensorShape outputShape{ 1, 16, 16, 16 };
1447  TensorShape weightShape{ 16, 1, 1, 16 };
1448  TensorInfo inputInfo (inputShape, DataType::Float32);
1449  TensorInfo outputInfo(outputShape, DataType::Float32);
1450  TensorInfo weightInfo(weightShape, DataType::Float32);
1451  Convolution2dDescriptor convolution2dDescriptor;
1452  bool referenceConvolution2dSupported =
1453  referenceLayerSupport->IsConvolution2dSupported(inputInfo,
1454  outputInfo,
1455  convolution2dDescriptor,
1456  weightInfo,
1457  EmptyOptional());
1458  BOOST_TEST(referenceConvolution2dSupported);
1459 
1460  // Test the backend instance by creating a workload
1461  IBackendInternal::IWorkloadFactoryPtr referenceWorkloadFactory = referenceDynamicBackend->CreateWorkloadFactory();
1462  BOOST_TEST((referenceWorkloadFactory != nullptr));
1463 
1464  // Create dummy settings for the workload
1465  Convolution2dQueueDescriptor convolution2dQueueDescriptor;
1466  WorkloadInfo workloadInfo
1467  {
1468  { inputInfo },
1469  { outputInfo }
1470  };
1471  convolution2dQueueDescriptor.m_Inputs.push_back(nullptr);
1472  auto weights = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
1473  convolution2dQueueDescriptor.m_Weight = weights.get();
1474 
1475  // Create a convolution workload with the dummy settings
1476  auto workload = referenceWorkloadFactory->CreateConvolution2d(convolution2dQueueDescriptor, workloadInfo);
1477  BOOST_TEST((workload != nullptr));
1478  BOOST_TEST(workload.get() == PolymorphicDowncast<RefConvolution2dWorkload*>(workload.get()));
1479 }
1480 
1481 #endif
1482 
1483 #if defined(SAMPLE_DYNAMIC_BACKEND_ENABLED)
1484 
1485 void CheckSampleDynamicBackendLoaded()
1486 {
1487  using namespace armnn;
1488  // At this point we expect DYNAMIC_BACKEND_PATHS to include a path to where libArm_SampleDynamic_backend.so is.
1489  // If it hasn't been loaded there's no point continuing with the rest of the tests.
1491  if (backendIds.find("SampleDynamic") == backendIds.end())
1492  {
1493  std::string message = "The SampleDynamic backend has not been loaded. This may be a build configuration error. "
1494  "Ensure a DYNAMIC_BACKEND_PATHS was set at compile time to the location of "
1495  "libArm_SampleDynamic_backend.so. "
1496  "To disable this test recompile with: -DSAMPLE_DYNAMIC_BACKEND_ENABLED=0";
1497  BOOST_FAIL(message);
1498  }
1499 }
1500 
1501 void CreateSampleDynamicBackendTestImpl()
1502 {
1503  using namespace armnn;
1504  // Using the path override in CreationOptions to load the reference dynamic backend
1505  IRuntime::CreationOptions creationOptions;
1506  IRuntimePtr runtime = IRuntime::Create(creationOptions);
1507  const BackendRegistry& backendRegistry = BackendRegistryInstance();
1508  BOOST_TEST(backendRegistry.Size() >= 1);
1509  CheckSampleDynamicBackendLoaded();
1510  const DeviceSpec& deviceSpec = *PolymorphicDowncast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1511  BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1512  BOOST_TEST(supportedBackendIds.size()>= 1);
1513  BOOST_TEST((supportedBackendIds.find("SampleDynamic") != supportedBackendIds.end()));
1514 
1515  // Get the factory function
1516  auto sampleDynamicBackendFactoryFunction = backendRegistry.GetFactory("SampleDynamic");
1517  BOOST_TEST((sampleDynamicBackendFactoryFunction != nullptr));
1518 
1519  // Use the factory function to create an instance of the dynamic backend
1520  IBackendInternalUniquePtr sampleDynamicBackend = sampleDynamicBackendFactoryFunction();
1521  BOOST_TEST((sampleDynamicBackend != nullptr));
1522  BOOST_TEST((sampleDynamicBackend->GetId() == "SampleDynamic"));
1523 
1524  // Test the backend instance by querying the layer support
1525  IBackendInternal::ILayerSupportSharedPtr sampleLayerSupport = sampleDynamicBackend->GetLayerSupport();
1526  BOOST_TEST((sampleLayerSupport != nullptr));
1527 
1528  TensorShape inputShape { 1, 16, 16, 16 };
1529  TensorShape outputShape{ 1, 16, 16, 16 };
1530  TensorShape weightShape{ 16, 1, 1, 16 };
1531  TensorInfo inputInfo (inputShape, DataType::Float32);
1532  TensorInfo outputInfo(outputShape, DataType::Float32);
1533  TensorInfo weightInfo(weightShape, DataType::Float32);
1534  Convolution2dDescriptor convolution2dDescriptor;
1535  bool sampleConvolution2dSupported =
1536  sampleLayerSupport->IsConvolution2dSupported(inputInfo,
1537  outputInfo,
1538  convolution2dDescriptor,
1539  weightInfo,
1540  EmptyOptional());
1541  BOOST_TEST(!sampleConvolution2dSupported);
1542 
1543  // Test the backend instance by creating a workload
1544  IBackendInternal::IWorkloadFactoryPtr sampleWorkloadFactory = sampleDynamicBackend->CreateWorkloadFactory();
1545  BOOST_TEST((sampleWorkloadFactory != nullptr));
1546 
1547  // Create dummy settings for the workload
1548  AdditionQueueDescriptor additionQueueDescriptor;
1549  WorkloadInfo workloadInfo
1550  {
1551  { inputInfo, inputInfo },
1552  { outputInfo }
1553  };
1554 
1555  // Create a addition workload
1556  auto workload = sampleWorkloadFactory->CreateAddition(additionQueueDescriptor, workloadInfo);
1557  BOOST_TEST((workload != nullptr));
1558 }
1559 
1560 void SampleDynamicBackendEndToEndTestImpl()
1561 {
1562  using namespace armnn;
1563  // Create runtime in which test will run
1564  IRuntime::CreationOptions options;
1565  IRuntimePtr runtime(IRuntime::Create(options));
1566  CheckSampleDynamicBackendLoaded();
1567  // Builds up the structure of the network.
1568  INetworkPtr net(INetwork::Create());
1569 
1570  IConnectableLayer* input0 = net->AddInputLayer(0);
1571  IConnectableLayer* input1 = net->AddInputLayer(1);
1572  IConnectableLayer* add = net->AddAdditionLayer();
1573  IConnectableLayer* output = net->AddOutputLayer(0);
1574 
1575  input0->GetOutputSlot(0).Connect(add->GetInputSlot(0));
1576  input1->GetOutputSlot(0).Connect(add->GetInputSlot(1));
1577  add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1578 
1579  TensorInfo tensorInfo(TensorShape({2, 1}), DataType::Float32);
1580  input0->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1581  input1->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1582  add->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1583 
1584  // optimize the network
1585  IOptimizedNetworkPtr optNet = Optimize(*net, {"SampleDynamic"}, runtime->GetDeviceSpec());
1586 
1587  // Loads it into the runtime.
1588  NetworkId netId;
1589  runtime->LoadNetwork(netId, std::move(optNet));
1590 
1591  std::vector<float> input0Data{ 5.0f, 3.0f };
1592  std::vector<float> input1Data{ 10.0f, 8.0f };
1593  std::vector<float> expectedOutputData{ 15.0f, 11.0f };
1594  std::vector<float> outputData(2);
1595 
1596  InputTensors inputTensors
1597  {
1598  {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), input0Data.data())},
1599  {1,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), input1Data.data())}
1600  };
1601  OutputTensors outputTensors
1602  {
1603  {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
1604  };
1605 
1606  // Does the inference.
1607  runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
1608 
1609  // Checks the results.
1610  BOOST_TEST(outputData == expectedOutputData);
1611 }
1612 #endif
void GetNameMangledEntryPointTestImpl()
void GetNoExternEntryPointTestImpl()
void GetSharedObjectsTestImpl()
void CreateDynamicBackendsNoPathsTestImpl()
static armnn::BackendIdSet RegisterDynamicBackendsImplTest(armnn::BackendRegistry &backendRegistry, const std::vector< armnn::DynamicBackendPtr > &dynamicBackends)
FactoryFunction GetFactory(const BackendId &id) const
std::unique_ptr< IWorkloadFactory > IWorkloadFactoryPtr
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
Definition: INetwork.hpp:61
BackendIdSet GetBackendIds() const
void CreateDynamicBackendObjectInvalidInterface3TestImpl()
std::function< PointerType()> FactoryFunction
std::string GetTestSubDirectory(const std::string &subdir)
std::unordered_set< BackendId > BackendIdSet
Definition: BackendId.hpp:191
void CreateDynamicBackendsAllInvalidTestImpl()
static bool IsBackendCompatible(const BackendVersion &backendVersion)
void OpenNotSharedObjectTestImpl()
A Convolution2dDescriptor for the Convolution2dLayer.
std::string GetTestDirectoryBasePath()
std::unique_ptr< IRuntime, void(*)(IRuntime *runtime)> IRuntimePtr
Definition: IRuntime.hpp:25
std::unordered_map< BackendId, FactoryFunction > FactoryStorage
BackendRegistry & BackendRegistryInstance()
std::vector< std::pair< LayerBindingId, class ConstTensor > > InputTensors
Definition: Tensor.hpp:324
void BackendVersioningTestImpl()
static std::vector< DynamicBackendPtr > CreateDynamicBackends(const std::vector< std::string > &sharedObjects)
void CreateDynamicBackendObjectInvalidHandleTestImpl()
int NetworkId
Definition: IRuntime.hpp:20
std::string GetTestFilePath(const std::string &directory, const std::string &fileName)
Copyright (c) 2020 ARM Limited.
std::unique_ptr< DynamicBackend > DynamicBackendPtr
void CreateDynamicBackendObjectInvalidInterface6TestImpl()
static std::vector< std::string > GetBackendPathsImplTest(const std::string &path)
virtual void SetTensorInfo(const TensorInfo &tensorInfo)=0
void RegisterMixedDynamicBackendsTestImpl()
A tensor defined by a TensorInfo (shape and data type) and a mutable backing store.
Definition: Tensor.hpp:290
void GetValidEntryPointTestImpl()
void RuntimeDynamicBackendsTestImpl()
void GetBackendPathsOverrideTestImpl()
const char * GetBackendId()
IOptimizedNetworkPtr Optimize(const INetwork &network, const std::vector< BackendId > &backendPreferences, const IDeviceSpec &deviceSpec, const OptimizerOptions &options=OptimizerOptions(), Optional< std::vector< std::string > &> messages=EmptyOptional())
Create an optimized version of the network.
Definition: Network.cpp:1014
void CreateDynamicBackendObjectInvalidInterface5TestImpl()
const ConstCpuTensorHandle * m_Weight
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:298
#define DYNAMIC_BACKEND_BUILD_DIR
void RegisterMultipleInvalidDynamicBackendsTestImpl()
std::vector< std::pair< LayerBindingId, class Tensor > > OutputTensors
Definition: Tensor.hpp:325
void GetNotExistingEntryPointTestImpl()
void CreateDynamicBackendObjectInvalidInterface1TestImpl()
std::unique_ptr< IOptimizedNetwork, void(*)(IOptimizedNetwork *network)> IOptimizedNetworkPtr
Definition: INetwork.hpp:593
void RuntimeInvalidOverridePathTestImpl()
void CreateDynamicBackendsTestImpl()
void CreateDynamicBackendObjectInvalidInterface2TestImpl()
void RegisterMultipleDynamicBackendsTestImpl()
void CloseInvalidHandleTestImpl()
std::shared_ptr< ILayerSupport > ILayerSupportSharedPtr
void CreateDynamicBackendsMixedTypesTestImpl()
void OpenEmptyFileNameTestImpl()
std::string m_DynamicBackendsPath
Setting this value will override the paths set by the DYNAMIC_BACKEND_PATHS compiler directive Only a...
Definition: IRuntime.hpp:59
static BackendIdSet RegisterDynamicBackendsImpl(BackendRegistry &backendRegistry, const std::vector< DynamicBackendPtr > &dynamicBackends)
EmptyOptional is used to initialize the Optional class in case we want to have default value for an O...
Definition: Optional.hpp:32
static bool IsBackendCompatibleTest(const armnn::BackendVersion &backendApiVersion, const armnn::BackendVersion &backendVersion)
virtual const BackendIdSet & GetSupportedBackends() const override
Definition: DeviceSpec.hpp:25
void OpenCloseHandleTestImpl()
std::string GetDynamicBackendsBasePath()
virtual const IInputSlot & GetInputSlot(unsigned int index) const =0
Get a const input slot handle by slot index.
static bool IsBackendCompatibleImpl(const BackendVersion &backendApiVersion, const BackendVersion &backendVersion)
Protected methods for testing purposes.
void CreateDynamicBackendObjectInvalidInterface4TestImpl()
static std::vector< std::string > GetBackendPathsImpl(const std::string &backendPaths)
virtual const IOutputSlot & GetOutputSlot(unsigned int index) const =0
Get the const output slot handle by slot index.
Contains information about inputs and outputs to a layer.
void RegisterSingleDynamicBackendTestImpl()
void RuntimeEmptyTestImpl()
void RuntimeDuplicateDynamicBackendsTestImpl()
std::vector< ITensorHandle * > m_Inputs
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
Definition: INetwork.hpp:101
std::unique_ptr< IBackendInternal > IBackendInternalUniquePtr
std::string GetBasePath(const std::string &basePath)
virtual int Connect(IInputSlot &destination)=0
void RuntimeInvalidDynamicBackendsTestImpl()
void CreateValidDynamicBackendObjectTestImpl()
void OpenNotExistingFileTestImpl()
void CreateDynamicBackendObjectInvalidInterface7TestImpl()
void GetBackendPathsTestImpl()