ArmNN
 21.02
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 
377 #if defined(ARMNNREF_ENABLED)
378 void CreateValidDynamicBackendObjectTestImpl()
379 {
380  // Valid shared object handle
381  // Correct name mangling
382  // Correct interface
383  // Correct backend implementation
384 
385  using namespace armnn;
386 
387  std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
388 
389  // We expect this path to exists so we can load a valid dynamic backend.
390  BOOST_CHECK_MESSAGE(fs::exists(testSubDirectory),
391  "Base path for shared objects does not exist: " + testSubDirectory);
392 
393  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestValidTestDynamicBackendFileName);
394 
395  void* sharedObjectHandle = nullptr;
396  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
397  BOOST_TEST((sharedObjectHandle != nullptr));
398 
399  DynamicBackendPtr dynamicBackend;
400  BOOST_CHECK_NO_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)));
401  BOOST_TEST((dynamicBackend != nullptr));
402 
403  BackendId dynamicBackendId;
404  BOOST_CHECK_NO_THROW(dynamicBackendId = dynamicBackend->GetBackendId());
405  BOOST_TEST((dynamicBackendId == "ValidTestDynamicBackend"));
406 
407  BackendVersion dynamicBackendVersion;
408  BOOST_CHECK_NO_THROW(dynamicBackendVersion = dynamicBackend->GetBackendVersion());
409  BOOST_TEST((dynamicBackendVersion == IBackendInternal::GetApiVersion()));
410 
411  IBackendInternalUniquePtr dynamicBackendInstance1;
412  BOOST_CHECK_NO_THROW(dynamicBackendInstance1 = dynamicBackend->GetBackend());
413  BOOST_TEST((dynamicBackendInstance1 != nullptr));
414 
415  BackendRegistry::FactoryFunction dynamicBackendFactoryFunction = nullptr;
416  BOOST_CHECK_NO_THROW(dynamicBackendFactoryFunction = dynamicBackend->GetFactoryFunction());
417  BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
418 
419  IBackendInternalUniquePtr dynamicBackendInstance2;
420  BOOST_CHECK_NO_THROW(dynamicBackendInstance2 = dynamicBackendFactoryFunction());
421  BOOST_TEST((dynamicBackendInstance2 != nullptr));
422 
423  BOOST_TEST((dynamicBackendInstance1->GetId() == "ValidTestDynamicBackend"));
424  BOOST_TEST((dynamicBackendInstance2->GetId() == "ValidTestDynamicBackend"));
425 }
426 #endif
427 
429 {
430  // Invalid (null) shared object handle
431 
432  using namespace armnn;
433 
434  void* sharedObjectHandle = nullptr;
435  DynamicBackendPtr dynamicBackend;
436  BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), InvalidArgumentException);
437  BOOST_TEST((dynamicBackend == nullptr));
438 }
439 
441 {
442  // Valid shared object handle
443  // Wrong (not C-style) name mangling
444 
445  using namespace armnn;
446 
447  std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
448  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend1FileName);
449 
450  void* sharedObjectHandle = nullptr;
451  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
452  BOOST_TEST((sharedObjectHandle != nullptr));
453 
454  DynamicBackendPtr dynamicBackend;
455  BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
456  BOOST_TEST((dynamicBackend == nullptr));
457 }
458 
460 {
461  // Valid shared object handle
462  // Correct name mangling
463  // Wrong interface (missing GetBackendId())
464 
465  using namespace armnn;
466 
467  std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
468  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend2FileName);
469 
470  void* sharedObjectHandle = nullptr;
471  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
472  BOOST_TEST((sharedObjectHandle != nullptr));
473 
474  DynamicBackendPtr dynamicBackend;
475  BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
476  BOOST_TEST((dynamicBackend == nullptr));
477 }
478 
480 {
481  // Valid shared object handle
482  // Correct name mangling
483  // Wrong interface (missing GetVersion())
484 
485  using namespace armnn;
486 
487  std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
488  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend3FileName);
489 
490  void* sharedObjectHandle = nullptr;
491  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
492  BOOST_TEST((sharedObjectHandle != nullptr));
493 
494  DynamicBackendPtr dynamicBackend;
495  BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
496  BOOST_TEST((dynamicBackend == nullptr));
497 }
498 
500 {
501  // Valid shared object handle
502  // Correct name mangling
503  // Wrong interface (missing BackendFactory())
504 
505  using namespace armnn;
506 
507  std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
508  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend4FileName);
509 
510  void* sharedObjectHandle = nullptr;
511  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
512  BOOST_TEST((sharedObjectHandle != nullptr));
513 
514  DynamicBackendPtr dynamicBackend;
515  BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
516  BOOST_TEST((dynamicBackend == nullptr));
517 }
518 
520 {
521  // Valid shared object handle
522  // Correct name mangling
523  // Correct interface
524  // Invalid (null) backend id returned by GetBackendId()
525 
526  using namespace armnn;
527 
528  std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
529  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend5FileName);
530 
531  void* sharedObjectHandle = nullptr;
532  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
533  BOOST_TEST((sharedObjectHandle != nullptr));
534 
535  DynamicBackendPtr dynamicBackend;
536  BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
537  BOOST_TEST((dynamicBackend == nullptr));
538 }
539 
541 {
542  // Valid shared object handle
543  // Correct name mangling
544  // Correct interface
545  // Invalid (null) backend instance returned by BackendFactory()
546 
547  using namespace armnn;
548 
549  std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
550  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend6FileName);
551 
552  void* sharedObjectHandle = nullptr;
553  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
554  BOOST_TEST((sharedObjectHandle != nullptr));
555 
556  DynamicBackendPtr dynamicBackend;
557  BOOST_CHECK_NO_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)));
558  BOOST_TEST((dynamicBackend != nullptr));
559 
560  BackendId dynamicBackendId;
561  BOOST_CHECK_NO_THROW(dynamicBackendId = dynamicBackend->GetBackendId());
562  BOOST_TEST((dynamicBackendId == "InvalidTestDynamicBackend"));
563 
564  BackendVersion dynamicBackendVersion;
565  BOOST_CHECK_NO_THROW(dynamicBackendVersion = dynamicBackend->GetBackendVersion());
566  BOOST_TEST((dynamicBackendVersion == BackendVersion({ 1, 0 })));
567 
568  IBackendInternalUniquePtr dynamicBackendInstance1;
569  BOOST_CHECK_THROW(dynamicBackendInstance1 = dynamicBackend->GetBackend(), RuntimeException);
570  BOOST_TEST((dynamicBackendInstance1 == nullptr));
571 
572  BackendRegistry::FactoryFunction dynamicBackendFactoryFunction = nullptr;
573  BOOST_CHECK_NO_THROW(dynamicBackendFactoryFunction = dynamicBackend->GetFactoryFunction());
574  BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
575 
576  IBackendInternalUniquePtr dynamicBackendInstance2;
577  BOOST_CHECK_THROW(dynamicBackendInstance2 = dynamicBackendFactoryFunction(), RuntimeException);
578  BOOST_TEST((dynamicBackendInstance2 == nullptr));
579 }
580 
582 {
583  // Valid shared object handle
584  // Correct name mangling
585  // Correct interface
586  // Invalid (incompatible backend API version) backend instance returned by BackendFactory()
587 
588  using namespace armnn;
589 
590  std::string testSubDirectory = GetTestSubDirectory(g_TestDynamicBackendSubDir);
591  std::string sharedObjectFilePath = GetTestFilePath(testSubDirectory, g_TestInvalidTestDynamicBackend7FileName);
592 
593  void* sharedObjectHandle = nullptr;
594  BOOST_CHECK_NO_THROW(sharedObjectHandle = DynamicBackendUtils::OpenHandle(sharedObjectFilePath));
595  BOOST_TEST((sharedObjectHandle != nullptr));
596 
597  DynamicBackendPtr dynamicBackend;
598  BOOST_CHECK_THROW(dynamicBackend.reset(new DynamicBackend(sharedObjectHandle)), RuntimeException);
599  BOOST_TEST((dynamicBackend == nullptr));
600 }
601 
603 {
604  using namespace armnn;
605  using namespace fs;
606 
607  // The test covers four directories:
608  // <unit test path>/src/backends/backendsCommon/test/
609  // ├─ backendsTestPath1/ -> exists, contains files
610  // ├─ backendsTestPath2/ -> exists, contains files
611  // ├─ backendsTestPath3/ -> exists, but empty
612  // └─ backendsTestPath4/ -> does not exist
613 
614  std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsSubDir1);
615  std::string subDir2 = GetTestSubDirectory(g_TestDynamicBackendsSubDir2);
616  std::string subDir3 = GetTestSubDirectory(g_TestDynamicBackendsSubDir3);
617  std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsSubDir4);
618 
619  BOOST_CHECK(exists(subDir1));
620  BOOST_CHECK(exists(subDir2));
621  BOOST_CHECK(exists(subDir3));
622  BOOST_CHECK(!exists(subDir4));
623 
624  // No path
625  BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest("").empty());
626 
627  // Malformed path
628  std::string malformedDir(subDir1 + "/" + subDir1);
629  BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(malformedDir).size()==0);
630 
631  // Single valid path
632  std::vector<std::string> DynamicBackendPaths2 = TestDynamicBackendUtils::GetBackendPathsImplTest(subDir1);
633  BOOST_TEST(DynamicBackendPaths2.size() == 1);
634  BOOST_TEST(DynamicBackendPaths2[0] == subDir1);
635 
636  // Multiple equal and valid paths
637  std::string multipleEqualDirs(subDir1 + ":" + subDir1);
638  std::vector<std::string> DynamicBackendPaths3 = TestDynamicBackendUtils::GetBackendPathsImplTest(multipleEqualDirs);
639  BOOST_TEST(DynamicBackendPaths3.size() == 1);
640  BOOST_TEST(DynamicBackendPaths3[0] == subDir1);
641 
642  // Multiple empty paths
643  BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(":::").empty());
644 
645  // Multiple valid paths
646  std::string multipleValidPaths(subDir1 + ":" + subDir2 + ":" + subDir3);
647  std::vector<std::string> DynamicBackendPaths5 =
649  BOOST_TEST(DynamicBackendPaths5.size() == 3);
650  BOOST_TEST(DynamicBackendPaths5[0] == subDir1);
651  BOOST_TEST(DynamicBackendPaths5[1] == subDir2);
652  BOOST_TEST(DynamicBackendPaths5[2] == subDir3);
653 
654  // Valid among empty paths
655  std::string validAmongEmptyDirs("::" + subDir1 + ":");
656  std::vector<std::string> DynamicBackendPaths6 =
658  BOOST_TEST(DynamicBackendPaths6.size() == 1);
659  BOOST_TEST(DynamicBackendPaths6[0] == subDir1);
660 
661  // Invalid among empty paths
662  std::string invalidAmongEmptyDirs(":" + subDir4 + "::");
663  BOOST_TEST(TestDynamicBackendUtils::GetBackendPathsImplTest(invalidAmongEmptyDirs).empty());
664 
665  // Valid, invalid and empty paths
666  std::string validInvalidEmptyDirs(subDir1 + ":" + subDir4 + ":");
667  std::vector<std::string> DynamicBackendPaths8 =
669  BOOST_TEST(DynamicBackendPaths8.size() == 1);
670  BOOST_TEST(DynamicBackendPaths8[0] == subDir1);
671 
672  // Mix of duplicates of valid, invalid and empty paths
673  std::string duplicateValidInvalidEmptyDirs(validInvalidEmptyDirs + ":" + validInvalidEmptyDirs + ":" +
674  subDir2 + ":" + subDir2);
675  std::vector<std::string> DynamicBackendPaths9 =
676  TestDynamicBackendUtils::GetBackendPathsImplTest(duplicateValidInvalidEmptyDirs);
677  BOOST_TEST(DynamicBackendPaths9.size() == 2);
678  BOOST_TEST(DynamicBackendPaths9[0] == subDir1);
679  BOOST_TEST(DynamicBackendPaths9[1] == subDir2);
680 }
681 
683 {
684  using namespace armnn;
685  using namespace fs;
686 
687  std::string subDir1 = GetTestSubDirectory(g_TestDynamicBackendsSubDir1);
688  std::string subDir4 = GetTestSubDirectory(g_TestDynamicBackendsSubDir4);
689 
690  BOOST_CHECK(exists(subDir1));
691  BOOST_CHECK(!exists(subDir4));
692 
693  // Override with valid path
694  std::vector<std::string> validResult = DynamicBackendUtils::GetBackendPaths(subDir1);
695  BOOST_TEST(validResult.size() == 1);
696  BOOST_TEST(validResult[0] == subDir1);
697 
698  // Override with invalid path
699  std::vector<std::string> invalidResult = DynamicBackendUtils::GetBackendPaths(subDir4);
700  BOOST_TEST(invalidResult.empty());
701 }
702 
704 {
705  using namespace armnn;
706  using namespace fs;
707 
708  // The test covers four directories:
709  // <unit test path>/src/backends/backendsCommon/test/
710  // ├─ backendsTestPath1/ -> exists, contains files
711  // ├─ backendsTestPath2/ -> exists, contains files
712  // ├─ backendsTestPath3/ -> exists, but empty
713  // └─ backendsTestPath4/ -> does not exist
714  //
715  // The test sub-directory backendsTestPath1/ contains the following test files:
716  //
717  // Arm_GpuAcc_backend.so -> valid (basic backend name)
718  // Arm_GpuAcc_backend.so.1 -> valid (single field version number)
719  // Arm_GpuAcc_backend.so.1.2 -> valid (multiple field version number)
720  // Arm_GpuAcc_backend.so.1.2.3 -> valid (multiple field version number)
721  // Arm_GpuAcc_backend.so.10.1.27 -> valid (Multiple digit version)
722  // Arm_GpuAcc_backend.so.10.1.33. -> not valid (dot not followed by version number)
723  // Arm_GpuAcc_backend.so.3.4..5 -> not valid (dot not followed by version number)
724  // Arm_GpuAcc_backend.so.1,1.1 -> not valid (comma instead of dot in the version)
725  //
726  // Arm123_GpuAcc_backend.so -> valid (digits in vendor name are allowed)
727  // Arm_GpuAcc456_backend.so -> valid (digits in backend id are allowed)
728  // Arm%Co_GpuAcc_backend.so -> not valid (invalid character in vendor name)
729  // Arm_Gpu.Acc_backend.so -> not valid (invalid character in backend id)
730  //
731  // GpuAcc_backend.so -> not valid (missing vendor name)
732  // _GpuAcc_backend.so -> not valid (missing vendor name)
733  // Arm__backend.so -> not valid (missing backend id)
734  // Arm_GpuAcc.so -> not valid (missing "backend" at the end)
735  // __backend.so -> not valid (missing vendor name and backend id)
736  // __.so -> not valid (missing all fields)
737  //
738  // Arm_GpuAcc_backend -> not valid (missing at least ".so" at the end)
739  // Arm_GpuAcc_backend_v1.2.so -> not valid (extra version info at the end)
740  //
741  // The test sub-directory backendsTestPath1/ contains the following test files:
742  //
743  // Arm_CpuAcc_backend.so -> valid (basic backend name)
744  // Arm_CpuAcc_backend.so.1 -> Arm_CpuAcc_backend.so -> valid (symlink to valid backend file)
745  // Arm_CpuAcc_backend.so.1.2 -> Arm_CpuAcc_backend.so.1 -> valid (symlink to valid symlink)
746  // Arm_CpuAcc_backend.so.1.2.3 -> Arm_CpuAcc_backend.so.1.2 -> valid (symlink to valid symlink)
747  //
748  // Arm_no_backend.so -> nothing -> not valid (symlink resolves to non-existent file)
749  //
750  // Arm_GpuAcc_backend.so -> valid (but duplicated from backendsTestPath1/)
751 
752  std::string testDynamicBackendsSubDir1 = GetTestSubDirectory(g_TestDynamicBackendsSubDir1);
753  std::string testDynamicBackendsSubDir2 = GetTestSubDirectory(g_TestDynamicBackendsSubDir2);
754  std::string testDynamicBackendsSubDir3 = GetTestSubDirectory(g_TestDynamicBackendsSubDir3);
755  std::string testDynamicBackendsSubDir4 = GetTestSubDirectory(g_TestDynamicBackendsSubDir4);
756  BOOST_CHECK(exists(testDynamicBackendsSubDir1));
757  BOOST_CHECK(exists(testDynamicBackendsSubDir2));
758  BOOST_CHECK(exists(testDynamicBackendsSubDir3));
759  BOOST_CHECK(!exists(testDynamicBackendsSubDir4));
760 
761  std::vector<std::string> backendPaths
762  {
763  testDynamicBackendsSubDir1,
764  testDynamicBackendsSubDir2,
765  testDynamicBackendsSubDir3,
766  testDynamicBackendsSubDir4
767  };
768  std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
769  std::vector<fs::path> expectedSharedObjects
770  {
771  path(testDynamicBackendsSubDir1 + "Arm123_GpuAcc_backend.so"), // Digits in vendor name are allowed
772  path(testDynamicBackendsSubDir1 + "Arm_GpuAcc456_backend.so"), // Digits in backend id are allowed
773  path(testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so"), // Basic backend name
774  path(testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1"), // Single field version number
775  path(testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1.2"), // Multiple field version number
776  path(testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.1.2.3"), // Multiple field version number
777  path(testDynamicBackendsSubDir1 + "Arm_GpuAcc_backend.so.10.1.27"), // Multiple digit version
778  path(testDynamicBackendsSubDir2 + "Arm_CpuAcc_backend.so"), // Duplicate symlinks removed
779  path(testDynamicBackendsSubDir2 + "Arm_GpuAcc_backend.so") // Duplicates on different paths are allowed
780  };
781 
782  BOOST_TEST(sharedObjects.size() == expectedSharedObjects.size());
783  BOOST_TEST(fs::equivalent(path(sharedObjects[0]), expectedSharedObjects[0]));
784  BOOST_TEST(fs::equivalent(path(sharedObjects[1]), expectedSharedObjects[1]));
785  BOOST_TEST(fs::equivalent(path(sharedObjects[2]), expectedSharedObjects[2]));
786  BOOST_TEST(fs::equivalent(path(sharedObjects[3]), expectedSharedObjects[3]));
787  BOOST_TEST(fs::equivalent(path(sharedObjects[4]), expectedSharedObjects[4]));
788  BOOST_TEST(fs::equivalent(path(sharedObjects[5]), expectedSharedObjects[5]));
789  BOOST_TEST(fs::equivalent(path(sharedObjects[6]), expectedSharedObjects[6]));
790  BOOST_TEST(fs::equivalent(path(sharedObjects[7]), expectedSharedObjects[7]));
791  BOOST_TEST(fs::equivalent(path(sharedObjects[8]), expectedSharedObjects[8]));
792 }
793 
795 {
796  using namespace armnn;
797  using namespace fs;
798 
799  // The test covers four directories:
800  // <unit test path>/src/backends/backendsCommon/test/
801  // ├─ backendsTestPath5/ -> exists, contains files
802  // ├─ backendsTestPath6/ -> exists, contains files
803  // ├─ backendsTestPath7/ -> exists, but empty
804  // └─ backendsTestPath8/ -> does not exist
805  //
806  // The test sub-directory backendsTestPath5/ contains the following test files:
807  //
808  // Arm_TestValid2_backend.so -> valid (basic backend name)
809  // Arm_TestValid3_backend.so -> valid (basic backend name)
810  // Arm_TestInvalid8_backend.so -> not valid (invalid backend id)
811  //
812  // The test sub-directory backendsTestPath6/ contains the following test files:
813  //
814  // Arm_TestValid2_backend.so -> valid (but duplicated from backendsTestPath5/)
815  // Arm_TestValid4_backend.so -> valid (it has a different filename,
816  // but it has the same backend id of Arm_TestValid2_backend.so
817  // and the same version)
818  // Arm_TestValid5_backend.so -> valid (basic backend name)
819  // Arm_TestInvalid9_backend.so -> not valid (it has a different filename,
820  // but it has the same backend id of Arm_TestValid2_backend.so
821  // and a version incompatible with the Backend API)
822 
823  std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
824  std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
825  std::string testDynamicBackendsSubDir7 = GetTestSubDirectory(g_TestDynamicBackendsSubDir7);
826  std::string testDynamicBackendsSubDir8 = GetTestSubDirectory(g_TestDynamicBackendsSubDir8);
827  BOOST_CHECK(exists(testDynamicBackendsSubDir5));
828  BOOST_CHECK(exists(testDynamicBackendsSubDir6));
829  BOOST_CHECK(exists(testDynamicBackendsSubDir7));
830  BOOST_CHECK(!exists(testDynamicBackendsSubDir8));
831 
832  std::vector<std::string> backendPaths
833  {
834  testDynamicBackendsSubDir5,
835  testDynamicBackendsSubDir6,
836  testDynamicBackendsSubDir7,
837  testDynamicBackendsSubDir8
838  };
839  std::vector<std::string> sharedObjects = DynamicBackendUtils::GetSharedObjects(backendPaths);
840  std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
841 
842  BOOST_TEST(dynamicBackends.size() == 5);
843  BOOST_TEST((dynamicBackends[0] != nullptr));
844  BOOST_TEST((dynamicBackends[1] != nullptr));
845  BOOST_TEST((dynamicBackends[2] != nullptr));
846  BOOST_TEST((dynamicBackends[3] != nullptr));
847  BOOST_TEST((dynamicBackends[4] != nullptr));
848 
849  // Duplicates are allowed here, they will be skipped later during the backend registration
850  BOOST_TEST((dynamicBackends[0]->GetBackendId() == "TestValid2"));
851  BOOST_TEST((dynamicBackends[1]->GetBackendId() == "TestValid3"));
852  BOOST_TEST((dynamicBackends[2]->GetBackendId() == "TestValid2")); // From duplicate Arm_TestValid2_backend.so
853  BOOST_TEST((dynamicBackends[3]->GetBackendId() == "TestValid2")); // From Arm_TestValid4_backend.so
854  BOOST_TEST((dynamicBackends[4]->GetBackendId() == "TestValid5"));
855 }
856 
858 {
859  using namespace armnn;
860 
861  std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends({});
862 
863  BOOST_TEST(dynamicBackends.empty());
864 }
865 
867 {
868  using namespace armnn;
869 
870  std::vector<std::string> sharedObjects
871  {
872  "InvalidSharedObject1",
873  "InvalidSharedObject2",
874  "InvalidSharedObject3",
875  };
876  std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
877 
878  BOOST_TEST(dynamicBackends.empty());
879 }
880 
882 {
883  using namespace armnn;
884  using namespace fs;
885 
886  std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
887  std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
888  BOOST_CHECK(exists(testDynamicBackendsSubDir5));
889  BOOST_CHECK(exists(testDynamicBackendsSubDir6));
890 
891  std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5,
892  g_TestValidBackend2FileName);
893  std::string testInvalidBackend8FilePath = GetTestFilePath(testDynamicBackendsSubDir5,
894  g_TestInvalidBackend8FileName);
895  std::string testInvalidBackend9FilePath = GetTestFilePath(testDynamicBackendsSubDir6,
896  g_TestInvalidBackend9FileName);
897  BOOST_CHECK(exists(testValidBackend2FilePath));
898  BOOST_CHECK(exists(testInvalidBackend8FilePath));
899  BOOST_CHECK(exists(testInvalidBackend9FilePath));
900 
901  std::vector<std::string> sharedObjects
902  {
903  testValidBackend2FilePath, // Arm_TestValid2_backend.so -> valid (basic backend name)
904  testInvalidBackend8FilePath, // Arm_TestInvalid8_backend.so -> not valid (invalid backend id)
905  testInvalidBackend9FilePath, // Arm_TestInvalid9_backend.so -> not valid (incompatible version)
906  "InvalidSharedObject", // The file does not exist
907  };
908  std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends(sharedObjects);
909 
910  BOOST_TEST(dynamicBackends.size() == 1);
911  BOOST_TEST((dynamicBackends[0] != nullptr));
912  BOOST_TEST((dynamicBackends[0]->GetBackendId() == "TestValid2"));
913 }
914 
915 #if defined(ARMNNREF_ENABLED)
916 void RegisterSingleDynamicBackendTestImpl()
917 {
918  using namespace armnn;
919  using namespace fs;
920 
921  // Register one valid dynamic backend
922 
923  // Dummy registry used for testing
924  BackendRegistry backendRegistry;
925  BOOST_TEST(backendRegistry.Size() == 0);
926 
927  std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
928  BOOST_CHECK(exists(testDynamicBackendsSubDir5));
929 
930  std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend2FileName);
931  BOOST_CHECK(exists(testValidBackend2FilePath));
932 
933  std::vector<std::string> sharedObjects{ testValidBackend2FilePath };
934  std::vector<DynamicBackendPtr> dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects);
935 
936  BOOST_TEST(dynamicBackends.size() == 1);
937  BOOST_TEST((dynamicBackends[0] != nullptr));
938 
939  BackendId dynamicBackendId = dynamicBackends[0]->GetBackendId();
940  BOOST_TEST((dynamicBackendId == "TestValid2"));
941 
942  BackendVersion dynamicBackendVersion = dynamicBackends[0]->GetBackendVersion();
943  BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion));
944 
945  BackendIdSet registeredBackendIds = TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry,
946  dynamicBackends);
947  BOOST_TEST(backendRegistry.Size() == 1);
948  BOOST_TEST(registeredBackendIds.size() == 1);
949 
950  BackendIdSet backendIds = backendRegistry.GetBackendIds();
951  BOOST_TEST(backendIds.size() == 1);
952  BOOST_TEST((backendIds.find(dynamicBackendId) != backendIds.end()));
953  BOOST_TEST((registeredBackendIds.find(dynamicBackendId) != registeredBackendIds.end()));
954 
955  auto dynamicBackendFactoryFunction = backendRegistry.GetFactory(dynamicBackendId);
956  BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
957 
958  IBackendInternalUniquePtr dynamicBackend = dynamicBackendFactoryFunction();
959  BOOST_TEST((dynamicBackend != nullptr));
960  BOOST_TEST((dynamicBackend->GetId() == dynamicBackendId));
961 }
962 
963 void RegisterMultipleDynamicBackendsTestImpl()
964 {
965  using namespace armnn;
966  using namespace fs;
967 
968  // Register many valid dynamic backends
969 
970  std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
971  std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
972  BOOST_CHECK(exists(testDynamicBackendsSubDir5));
973  BOOST_CHECK(exists(testDynamicBackendsSubDir6));
974 
975  std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend2FileName);
976  std::string testValidBackend3FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend3FileName);
977  std::string testValidBackend5FilePath = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend5FileName);
978  BOOST_CHECK(exists(testValidBackend2FilePath));
979  BOOST_CHECK(exists(testValidBackend3FilePath));
980  BOOST_CHECK(exists(testValidBackend5FilePath));
981 
982  std::vector<std::string> sharedObjects
983  {
984  testValidBackend2FilePath,
985  testValidBackend3FilePath,
986  testValidBackend5FilePath
987  };
988  std::vector<DynamicBackendPtr> dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects);
989 
990  BOOST_TEST(dynamicBackends.size() == 3);
991  BOOST_TEST((dynamicBackends[0] != nullptr));
992  BOOST_TEST((dynamicBackends[1] != nullptr));
993  BOOST_TEST((dynamicBackends[2] != nullptr));
994 
995  BackendId dynamicBackendId1 = dynamicBackends[0]->GetBackendId();
996  BackendId dynamicBackendId2 = dynamicBackends[1]->GetBackendId();
997  BackendId dynamicBackendId3 = dynamicBackends[2]->GetBackendId();
998  BOOST_TEST((dynamicBackendId1 == "TestValid2"));
999  BOOST_TEST((dynamicBackendId2 == "TestValid3"));
1000  BOOST_TEST((dynamicBackendId3 == "TestValid5"));
1001 
1002  for (size_t i = 0; i < dynamicBackends.size(); i++)
1003  {
1004  BackendVersion dynamicBackendVersion = dynamicBackends[i]->GetBackendVersion();
1005  BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion));
1006  }
1007 
1008  // Dummy registry used for testing
1009  BackendRegistry backendRegistry;
1010  BOOST_TEST(backendRegistry.Size() == 0);
1011 
1012  BackendIdSet registeredBackendIds = TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry,
1013  dynamicBackends);
1014  BOOST_TEST(backendRegistry.Size() == 3);
1015  BOOST_TEST(registeredBackendIds.size() == 3);
1016 
1017  BackendIdSet backendIds = backendRegistry.GetBackendIds();
1018  BOOST_TEST(backendIds.size() == 3);
1019  BOOST_TEST((backendIds.find(dynamicBackendId1) != backendIds.end()));
1020  BOOST_TEST((backendIds.find(dynamicBackendId2) != backendIds.end()));
1021  BOOST_TEST((backendIds.find(dynamicBackendId3) != backendIds.end()));
1022  BOOST_TEST((registeredBackendIds.find(dynamicBackendId1) != registeredBackendIds.end()));
1023  BOOST_TEST((registeredBackendIds.find(dynamicBackendId2) != registeredBackendIds.end()));
1024  BOOST_TEST((registeredBackendIds.find(dynamicBackendId3) != registeredBackendIds.end()));
1025 
1026  for (size_t i = 0; i < dynamicBackends.size(); i++)
1027  {
1028  BackendId dynamicBackendId = dynamicBackends[i]->GetBackendId();
1029 
1030  auto dynamicBackendFactoryFunction = backendRegistry.GetFactory(dynamicBackendId);
1031  BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
1032 
1033  IBackendInternalUniquePtr dynamicBackend = dynamicBackendFactoryFunction();
1034  BOOST_TEST((dynamicBackend != nullptr));
1035  BOOST_TEST((dynamicBackend->GetId() == dynamicBackendId));
1036  }
1037 }
1038 
1039 void RegisterMixedDynamicBackendsTestImpl()
1040 {
1041  using namespace armnn;
1042  using namespace fs;
1043 
1044  // The test covers five directories:
1045  // <unit test path>/src/backends/backendsCommon/test/
1046  // ├─ backendsTestPath5/ -> exists, contains files
1047  // ├─ backendsTestPath6/ -> exists, contains files
1048  // ├─ backendsTestPath7/ -> exists, but empty
1049  // ├─ backendsTestPath8/ -> does not exist
1050  // └─ backendsTestPath9/ -> exists, contains files
1051  //
1052  // The test sub-directory backendsTestPath5/ contains the following test files:
1053  //
1054  // Arm_TestValid2_backend.so -> valid (basic backend name)
1055  // Arm_TestValid3_backend.so -> valid (basic backend name)
1056  // Arm_TestInvalid8_backend.so -> not valid (invalid backend id)
1057  //
1058  // The test sub-directory backendsTestPath6/ contains the following test files:
1059  //
1060  // Arm_TestValid2_backend.so -> valid (but duplicated from backendsTestPath5/)
1061  // Arm_TestValid4_backend.so -> valid (it has a different filename,
1062  // but it has the same backend id of Arm_TestValid2_backend.so
1063  // and the same version)
1064  // Arm_TestValid5_backend.so -> valid (basic backend name)
1065  // Arm_TestInvalid9_backend.so -> not valid (it has a different filename,
1066  // but it has the same backend id of Arm_TestValid2_backend.so
1067  // and a version incompatible with the Backend API)
1068  //
1069  // The test sub-directory backendsTestPath9/ contains the following test files:
1070  //
1071  // Arm_TestInvalid10_backend.so -> not valid (empty backend id)
1072  // Arm_TestInvalid11_backend.so -> not valid ("Unknown" backend id)
1073 
1074  std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
1075  std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
1076  std::string testDynamicBackendsSubDir7 = GetTestSubDirectory(g_TestDynamicBackendsSubDir7);
1077  std::string testDynamicBackendsSubDir8 = GetTestSubDirectory(g_TestDynamicBackendsSubDir8);
1078  std::string testDynamicBackendsSubDir9 = GetTestSubDirectory(g_TestDynamicBackendsSubDir9);
1079  BOOST_CHECK(exists(testDynamicBackendsSubDir5));
1080  BOOST_CHECK(exists(testDynamicBackendsSubDir6));
1081  BOOST_CHECK(exists(testDynamicBackendsSubDir7));
1082  BOOST_CHECK(!exists(testDynamicBackendsSubDir8));
1083  BOOST_CHECK(exists(testDynamicBackendsSubDir9));
1084 
1085  std::string testValidBackend2FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend2FileName);
1086  std::string testValidBackend3FilePath = GetTestFilePath(testDynamicBackendsSubDir5, g_TestValidBackend3FileName);
1087  std::string testValidBackend2DupFilePath = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend2FileName);
1088  std::string testValidBackend4FilePath = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend4FileName);
1089  std::string testValidBackend5FilePath = GetTestFilePath(testDynamicBackendsSubDir6, g_TestValidBackend5FileName);
1090  std::string testInvalidBackend8FilePath = GetTestFilePath(testDynamicBackendsSubDir5,
1091  g_TestInvalidBackend8FileName);
1092  std::string testInvalidBackend9FilePath = GetTestFilePath(testDynamicBackendsSubDir6,
1093  g_TestInvalidBackend9FileName);
1094  std::string testInvalidBackend10FilePath = GetTestFilePath(testDynamicBackendsSubDir9,
1095  g_TestInvalidBackend10FileName);
1096  std::string testInvalidBackend11FilePath = GetTestFilePath(testDynamicBackendsSubDir9,
1097  g_TestInvalidBackend11FileName);
1098  BOOST_CHECK(exists(testValidBackend2FilePath));
1099  BOOST_CHECK(exists(testValidBackend3FilePath));
1100  BOOST_CHECK(exists(testValidBackend2DupFilePath));
1101  BOOST_CHECK(exists(testValidBackend4FilePath));
1102  BOOST_CHECK(exists(testValidBackend5FilePath));
1103  BOOST_CHECK(exists(testInvalidBackend8FilePath));
1104  BOOST_CHECK(exists(testInvalidBackend9FilePath));
1105  BOOST_CHECK(exists(testInvalidBackend10FilePath));
1106  BOOST_CHECK(exists(testInvalidBackend11FilePath));
1107 
1108  std::vector<std::string> sharedObjects
1109  {
1110  testValidBackend2FilePath,
1111  testValidBackend3FilePath,
1112  testValidBackend2DupFilePath,
1113  testValidBackend4FilePath,
1114  testValidBackend5FilePath,
1115  testInvalidBackend8FilePath,
1116  testInvalidBackend9FilePath,
1117  testInvalidBackend10FilePath,
1118  testInvalidBackend11FilePath,
1119  "InvalidSharedObject"
1120  };
1121  std::vector<DynamicBackendPtr> dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects);
1122 
1123  BOOST_TEST(dynamicBackends.size() == 7);
1124  BOOST_TEST((dynamicBackends[0] != nullptr));
1125  BOOST_TEST((dynamicBackends[1] != nullptr));
1126  BOOST_TEST((dynamicBackends[2] != nullptr));
1127  BOOST_TEST((dynamicBackends[3] != nullptr));
1128  BOOST_TEST((dynamicBackends[4] != nullptr));
1129  BOOST_TEST((dynamicBackends[5] != nullptr));
1130  BOOST_TEST((dynamicBackends[6] != nullptr));
1131 
1132  BackendId dynamicBackendId1 = dynamicBackends[0]->GetBackendId();
1133  BackendId dynamicBackendId2 = dynamicBackends[1]->GetBackendId();
1134  BackendId dynamicBackendId3 = dynamicBackends[2]->GetBackendId();
1135  BackendId dynamicBackendId4 = dynamicBackends[3]->GetBackendId();
1136  BackendId dynamicBackendId5 = dynamicBackends[4]->GetBackendId();
1137  BackendId dynamicBackendId6 = dynamicBackends[5]->GetBackendId();
1138  BackendId dynamicBackendId7 = dynamicBackends[6]->GetBackendId();
1139  BOOST_TEST((dynamicBackendId1 == "TestValid2"));
1140  BOOST_TEST((dynamicBackendId2 == "TestValid3"));
1141  BOOST_TEST((dynamicBackendId3 == "TestValid2")); // From duplicate Arm_TestValid2_backend.so
1142  BOOST_TEST((dynamicBackendId4 == "TestValid2")); // From Arm_TestValid4_backend.so
1143  BOOST_TEST((dynamicBackendId5 == "TestValid5"));
1144  BOOST_TEST((dynamicBackendId6 == ""));
1145  BOOST_TEST((dynamicBackendId7 == "Unknown"));
1146 
1147  for (size_t i = 0; i < dynamicBackends.size(); i++)
1148  {
1149  BackendVersion dynamicBackendVersion = dynamicBackends[i]->GetBackendVersion();
1150  BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion));
1151  }
1152 
1153  // Dummy registry used for testing
1154  BackendRegistry backendRegistry;
1155  BOOST_TEST(backendRegistry.Size() == 0);
1156 
1157  std::vector<BackendId> expectedRegisteredbackendIds
1158  {
1159  "TestValid2",
1160  "TestValid3",
1161  "TestValid5"
1162  };
1163 
1164  BackendIdSet registeredBackendIds = TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry,
1165  dynamicBackends);
1166  BOOST_TEST(backendRegistry.Size() == expectedRegisteredbackendIds.size());
1167  BOOST_TEST(registeredBackendIds.size() == expectedRegisteredbackendIds.size());
1168 
1169  BackendIdSet backendIds = backendRegistry.GetBackendIds();
1170  BOOST_TEST(backendIds.size() == expectedRegisteredbackendIds.size());
1171  for (const BackendId& expectedRegisteredbackendId : expectedRegisteredbackendIds)
1172  {
1173  BOOST_TEST((backendIds.find(expectedRegisteredbackendId) != backendIds.end()));
1174  BOOST_TEST((registeredBackendIds.find(expectedRegisteredbackendId) != registeredBackendIds.end()));
1175 
1176  auto dynamicBackendFactoryFunction = backendRegistry.GetFactory(expectedRegisteredbackendId);
1177  BOOST_TEST((dynamicBackendFactoryFunction != nullptr));
1178 
1179  IBackendInternalUniquePtr dynamicBackend = dynamicBackendFactoryFunction();
1180  BOOST_TEST((dynamicBackend != nullptr));
1181  BOOST_TEST((dynamicBackend->GetId() == expectedRegisteredbackendId));
1182  }
1183 }
1184 #endif
1185 
1187 {
1188  using namespace armnn;
1189  using namespace fs;
1190 
1191  // Try to register many invalid dynamic backends
1192 
1193  // The test covers one directory:
1194  // <unit test path>/src/backends/backendsCommon/test/
1195  // └─ backendsTestPath9/ -> exists, contains files
1196  //
1197  // The test sub-directory backendsTestPath9/ contains the following test files:
1198  //
1199  // Arm_TestInvalid10_backend.so -> not valid (invalid backend id)
1200  // Arm_TestInvalid11_backend.so -> not valid (invalid backend id)
1201 
1202  std::string testDynamicBackendsSubDir9 = GetTestSubDirectory(g_TestDynamicBackendsSubDir9);
1203  BOOST_CHECK(exists(testDynamicBackendsSubDir9));
1204 
1205  std::string testInvalidBackend10FilePath = GetTestFilePath(testDynamicBackendsSubDir9,
1206  g_TestInvalidBackend10FileName);
1207  std::string testInvalidBackend11FilePath = GetTestFilePath(testDynamicBackendsSubDir9,
1208  g_TestInvalidBackend11FileName);
1209  BOOST_CHECK(exists(testInvalidBackend10FilePath));
1210  BOOST_CHECK(exists(testInvalidBackend11FilePath));
1211 
1212  std::vector<std::string> sharedObjects
1213  {
1214  testInvalidBackend10FilePath,
1215  testInvalidBackend11FilePath,
1216  "InvalidSharedObject"
1217  };
1218  std::vector<DynamicBackendPtr> dynamicBackends = TestDynamicBackendUtils::CreateDynamicBackends(sharedObjects);
1219 
1220  BOOST_TEST(dynamicBackends.size() == 2);
1221  BOOST_TEST((dynamicBackends[0] != nullptr));
1222  BOOST_TEST((dynamicBackends[1] != nullptr));
1223 
1224  BackendId dynamicBackendId1 = dynamicBackends[0]->GetBackendId();
1225  BackendId dynamicBackendId2 = dynamicBackends[1]->GetBackendId();
1226  BOOST_TEST((dynamicBackendId1 == ""));
1227  BOOST_TEST((dynamicBackendId2 == "Unknown"));
1228 
1229  for (size_t i = 0; i < dynamicBackends.size(); i++)
1230  {
1231  BackendVersion dynamicBackendVersion = dynamicBackends[i]->GetBackendVersion();
1232  BOOST_TEST(TestDynamicBackendUtils::IsBackendCompatible(dynamicBackendVersion));
1233  }
1234 
1235  // Dummy registry used for testing
1236  BackendRegistry backendRegistry;
1237  BOOST_TEST(backendRegistry.Size() == 0);
1238 
1239  // Check that no dynamic backend got registered
1240  BackendIdSet registeredBackendIds = TestDynamicBackendUtils::RegisterDynamicBackendsImplTest(backendRegistry,
1241  dynamicBackends);
1242  BOOST_TEST(backendRegistry.Size() == 0);
1243  BOOST_TEST(registeredBackendIds.empty());
1244 }
1245 
1246 #if !defined(ARMNN_DYNAMIC_BACKEND_ENABLED)
1247 
1249 {
1250  using namespace armnn;
1251 
1252  // Swapping the backend registry storage for testing
1253  TestBackendRegistry testBackendRegistry;
1254 
1255  const BackendRegistry& backendRegistry = BackendRegistryInstance();
1256  BOOST_TEST(backendRegistry.Size() == 0);
1257 
1258  IRuntime::CreationOptions creationOptions;
1259  IRuntimePtr runtime = IRuntime::Create(creationOptions);
1260 
1261  const DeviceSpec& deviceSpec = *PolymorphicDowncast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1262  BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1263  BOOST_TEST(supportedBackendIds.empty());
1264 
1265  BOOST_TEST(backendRegistry.Size() == 0);
1266 }
1267 
1268 #endif
1269 
1271 {
1272  using namespace armnn;
1273  using namespace fs;
1274 
1275  // Swapping the backend registry storage for testing
1276  TestBackendRegistry testBackendRegistry;
1277 
1278  // This directory contains valid and invalid backends
1279  std::string testDynamicBackendsSubDir5 = GetTestSubDirectory(g_TestDynamicBackendsSubDir5);
1280  BOOST_CHECK(exists(testDynamicBackendsSubDir5));
1281 
1282  // Using the path override in CreationOptions to load some test dynamic backends
1283  IRuntime::CreationOptions creationOptions;
1284  creationOptions.m_DynamicBackendsPath = testDynamicBackendsSubDir5;
1285  IRuntimePtr runtime = IRuntime::Create(creationOptions);
1286 
1287  std::vector<BackendId> expectedRegisteredbackendIds
1288  {
1289  "TestValid2",
1290  "TestValid3"
1291  };
1292 
1293  const BackendRegistry& backendRegistry = BackendRegistryInstance();
1294  BOOST_TEST(backendRegistry.Size() == expectedRegisteredbackendIds.size());
1295 
1296  BackendIdSet backendIds = backendRegistry.GetBackendIds();
1297  for (const BackendId& expectedRegisteredbackendId : expectedRegisteredbackendIds)
1298  {
1299  BOOST_TEST((backendIds.find(expectedRegisteredbackendId) != backendIds.end()));
1300  }
1301 
1302  const DeviceSpec& deviceSpec = *PolymorphicDowncast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1303  BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1304  BOOST_TEST(supportedBackendIds.size() == expectedRegisteredbackendIds.size());
1305  for (const BackendId& expectedRegisteredbackendId : expectedRegisteredbackendIds)
1306  {
1307  BOOST_TEST((supportedBackendIds.find(expectedRegisteredbackendId) != supportedBackendIds.end()));
1308  }
1309 }
1310 
1312 {
1313  using namespace armnn;
1314  using namespace fs;
1315 
1316  // Swapping the backend registry storage for testing
1317  TestBackendRegistry testBackendRegistry;
1318 
1319  // This directory contains valid, invalid and duplicate backends
1320  std::string testDynamicBackendsSubDir6 = GetTestSubDirectory(g_TestDynamicBackendsSubDir6);
1321  BOOST_CHECK(exists(testDynamicBackendsSubDir6));
1322 
1323  // Using the path override in CreationOptions to load some test dynamic backends
1324  IRuntime::CreationOptions creationOptions;
1325  creationOptions.m_DynamicBackendsPath = testDynamicBackendsSubDir6;
1326  IRuntimePtr runtime = IRuntime::Create(creationOptions);
1327 
1328  std::vector<BackendId> expectedRegisteredbackendIds
1329  {
1330  "TestValid2",
1331  "TestValid5"
1332  };
1333 
1334  const BackendRegistry& backendRegistry = BackendRegistryInstance();
1335  BOOST_TEST(backendRegistry.Size() == expectedRegisteredbackendIds.size());
1336 
1337  BackendIdSet backendIds = backendRegistry.GetBackendIds();
1338  for (const BackendId& expectedRegisteredbackendId : expectedRegisteredbackendIds)
1339  {
1340  BOOST_TEST((backendIds.find(expectedRegisteredbackendId) != backendIds.end()));
1341  }
1342 
1343  const DeviceSpec& deviceSpec = *PolymorphicDowncast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1344  BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1345  BOOST_TEST(supportedBackendIds.size() == expectedRegisteredbackendIds.size());
1346  for (const BackendId& expectedRegisteredbackendId : expectedRegisteredbackendIds)
1347  {
1348  BOOST_TEST((supportedBackendIds.find(expectedRegisteredbackendId) != supportedBackendIds.end()));
1349  }
1350 }
1351 
1353 {
1354  using namespace armnn;
1355  using namespace fs;
1356 
1357  // Swapping the backend registry storage for testing
1358  TestBackendRegistry testBackendRegistry;
1359 
1360  // This directory contains only invalid backends
1361  std::string testDynamicBackendsSubDir9 = GetTestSubDirectory(g_TestDynamicBackendsSubDir9);
1362  BOOST_CHECK(exists(testDynamicBackendsSubDir9));
1363 
1364  // Using the path override in CreationOptions to load some test dynamic backends
1365  IRuntime::CreationOptions creationOptions;
1366  creationOptions.m_DynamicBackendsPath = testDynamicBackendsSubDir9;
1367  IRuntimePtr runtime = IRuntime::Create(creationOptions);
1368 
1369  const BackendRegistry& backendRegistry = BackendRegistryInstance();
1370  BOOST_TEST(backendRegistry.Size() == 0);
1371 
1372  const DeviceSpec& deviceSpec = *PolymorphicDowncast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1373  BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1374  BOOST_TEST(supportedBackendIds.empty());
1375 }
1376 
1378 {
1379  using namespace armnn;
1380 
1381  // Swapping the backend registry storage for testing
1382  TestBackendRegistry testBackendRegistry;
1383 
1384  // Using the path override in CreationOptions to load some test dynamic backends
1385  IRuntime::CreationOptions creationOptions;
1386  creationOptions.m_DynamicBackendsPath = "InvalidPath";
1387  IRuntimePtr runtime = IRuntime::Create(creationOptions);
1388 
1389  const BackendRegistry& backendRegistry = BackendRegistryInstance();
1390  BOOST_TEST(backendRegistry.Size() == 0);
1391 
1392  const DeviceSpec& deviceSpec = *PolymorphicDowncast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1393  BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1394  BOOST_TEST(supportedBackendIds.empty());
1395 }
1396 
1397 #if defined(ARMNNREF_ENABLED)
1398 
1399 // This test unit needs the reference backend, it's not available if the reference backend is not built
1400 
1401 void CreateReferenceDynamicBackendTestImpl()
1402 {
1403  using namespace armnn;
1404  using namespace fs;
1405 
1406  // Swapping the backend registry storage for testing
1407  TestBackendRegistry testBackendRegistry;
1408 
1409  // This directory contains the reference dynamic backend
1410  std::string dynamicBackendsBaseDir = GetDynamicBackendsBasePath();
1411  std::string referenceDynamicBackendSubDir = GetTestSubDirectory(dynamicBackendsBaseDir,
1412  g_ReferenceDynamicBackendSubDir);
1413  BOOST_CHECK(exists(referenceDynamicBackendSubDir));
1414 
1415  // Check that the reference dynamic backend file exists
1416  std::string referenceBackendFilePath = GetTestFilePath(referenceDynamicBackendSubDir,
1417  g_ReferenceBackendFileName);
1418  BOOST_CHECK(exists(referenceBackendFilePath));
1419 
1420  // Using the path override in CreationOptions to load the reference dynamic backend
1421  IRuntime::CreationOptions creationOptions;
1422  creationOptions.m_DynamicBackendsPath = referenceDynamicBackendSubDir;
1423  IRuntimePtr runtime = IRuntime::Create(creationOptions);
1424 
1425  const BackendRegistry& backendRegistry = BackendRegistryInstance();
1426  BOOST_TEST(backendRegistry.Size() == 1);
1427 
1428  BackendIdSet backendIds = backendRegistry.GetBackendIds();
1429  BOOST_TEST((backendIds.find("CpuRef") != backendIds.end()));
1430 
1431  const DeviceSpec& deviceSpec = *PolymorphicDowncast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1432  BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1433  BOOST_TEST(supportedBackendIds.size() == 1);
1434  BOOST_TEST((supportedBackendIds.find("CpuRef") != supportedBackendIds.end()));
1435 
1436  // Get the factory function
1437  auto referenceDynamicBackendFactoryFunction = backendRegistry.GetFactory("CpuRef");
1438  BOOST_TEST((referenceDynamicBackendFactoryFunction != nullptr));
1439 
1440  // Use the factory function to create an instance of the reference backend
1441  IBackendInternalUniquePtr referenceDynamicBackend = referenceDynamicBackendFactoryFunction();
1442  BOOST_TEST((referenceDynamicBackend != nullptr));
1443  BOOST_TEST((referenceDynamicBackend->GetId() == "CpuRef"));
1444 
1445  // Test the backend instance by querying the layer support
1446  IBackendInternal::ILayerSupportSharedPtr referenceLayerSupport = referenceDynamicBackend->GetLayerSupport();
1447  BOOST_TEST((referenceLayerSupport != nullptr));
1448 
1449  TensorShape inputShape { 1, 16, 16, 16 };
1450  TensorShape outputShape{ 1, 16, 16, 16 };
1451  TensorShape weightShape{ 16, 1, 1, 16 };
1452  TensorInfo inputInfo (inputShape, DataType::Float32);
1453  TensorInfo outputInfo(outputShape, DataType::Float32);
1454  TensorInfo weightInfo(weightShape, DataType::Float32);
1455  Convolution2dDescriptor convolution2dDescriptor;
1456  bool referenceConvolution2dSupported =
1457  referenceLayerSupport->IsConvolution2dSupported(inputInfo,
1458  outputInfo,
1459  convolution2dDescriptor,
1460  weightInfo,
1461  EmptyOptional());
1462  BOOST_TEST(referenceConvolution2dSupported);
1463 
1464  // Test the backend instance by creating a workload
1465  IBackendInternal::IWorkloadFactoryPtr referenceWorkloadFactory = referenceDynamicBackend->CreateWorkloadFactory();
1466  BOOST_TEST((referenceWorkloadFactory != nullptr));
1467 
1468  // Create dummy settings for the workload
1469  Convolution2dQueueDescriptor convolution2dQueueDescriptor;
1470  WorkloadInfo workloadInfo
1471  {
1472  { inputInfo },
1473  { outputInfo }
1474  };
1475  convolution2dQueueDescriptor.m_Inputs.push_back(nullptr);
1476  auto weights = std::make_unique<ScopedCpuTensorHandle>(weightInfo);
1477  convolution2dQueueDescriptor.m_Weight = weights.get();
1478 
1479  // Create a convolution workload with the dummy settings
1480  auto workload = referenceWorkloadFactory->CreateConvolution2d(convolution2dQueueDescriptor, workloadInfo);
1481  BOOST_TEST((workload != nullptr));
1482  BOOST_TEST(workload.get() == PolymorphicDowncast<RefConvolution2dWorkload*>(workload.get()));
1483 }
1484 
1485 #endif
1486 
1487 #if defined(SAMPLE_DYNAMIC_BACKEND_ENABLED)
1488 
1489 void CheckSampleDynamicBackendLoaded()
1490 {
1491  using namespace armnn;
1492  // At this point we expect DYNAMIC_BACKEND_PATHS to include a path to where libArm_SampleDynamic_backend.so is.
1493  // If it hasn't been loaded there's no point continuing with the rest of the tests.
1495  if (backendIds.find("SampleDynamic") == backendIds.end())
1496  {
1497  std::string message = "The SampleDynamic backend has not been loaded. This may be a build configuration error. "
1498  "Ensure a DYNAMIC_BACKEND_PATHS was set at compile time to the location of "
1499  "libArm_SampleDynamic_backend.so. "
1500  "To disable this test recompile with: -DSAMPLE_DYNAMIC_BACKEND_ENABLED=0";
1501  BOOST_FAIL(message);
1502  }
1503 }
1504 
1505 void CreateSampleDynamicBackendTestImpl()
1506 {
1507  using namespace armnn;
1508  // Using the path override in CreationOptions to load the reference dynamic backend
1509  IRuntime::CreationOptions creationOptions;
1510  IRuntimePtr runtime = IRuntime::Create(creationOptions);
1511  const BackendRegistry& backendRegistry = BackendRegistryInstance();
1512  BOOST_TEST(backendRegistry.Size() >= 1);
1513  CheckSampleDynamicBackendLoaded();
1514  const DeviceSpec& deviceSpec = *PolymorphicDowncast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1515  BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1516  BOOST_TEST(supportedBackendIds.size()>= 1);
1517  BOOST_TEST((supportedBackendIds.find("SampleDynamic") != supportedBackendIds.end()));
1518 
1519  // Get the factory function
1520  auto sampleDynamicBackendFactoryFunction = backendRegistry.GetFactory("SampleDynamic");
1521  BOOST_TEST((sampleDynamicBackendFactoryFunction != nullptr));
1522 
1523  // Use the factory function to create an instance of the dynamic backend
1524  IBackendInternalUniquePtr sampleDynamicBackend = sampleDynamicBackendFactoryFunction();
1525  BOOST_TEST((sampleDynamicBackend != nullptr));
1526  BOOST_TEST((sampleDynamicBackend->GetId() == "SampleDynamic"));
1527 
1528  // Test the backend instance by querying the layer support
1529  IBackendInternal::ILayerSupportSharedPtr sampleLayerSupport = sampleDynamicBackend->GetLayerSupport();
1530  BOOST_TEST((sampleLayerSupport != nullptr));
1531 
1532  TensorShape inputShape { 1, 16, 16, 16 };
1533  TensorShape outputShape{ 1, 16, 16, 16 };
1534  TensorShape weightShape{ 16, 1, 1, 16 };
1535  TensorInfo inputInfo (inputShape, DataType::Float32);
1536  TensorInfo outputInfo(outputShape, DataType::Float32);
1537  TensorInfo weightInfo(weightShape, DataType::Float32);
1538  Convolution2dDescriptor convolution2dDescriptor;
1539  bool sampleConvolution2dSupported =
1540  sampleLayerSupport->IsConvolution2dSupported(inputInfo,
1541  outputInfo,
1542  convolution2dDescriptor,
1543  weightInfo,
1544  EmptyOptional());
1545  BOOST_TEST(!sampleConvolution2dSupported);
1546 
1547  // Test the backend instance by creating a workload
1548  IBackendInternal::IWorkloadFactoryPtr sampleWorkloadFactory = sampleDynamicBackend->CreateWorkloadFactory();
1549  BOOST_TEST((sampleWorkloadFactory != nullptr));
1550 
1551  // Create dummy settings for the workload
1552  AdditionQueueDescriptor additionQueueDescriptor;
1553  WorkloadInfo workloadInfo
1554  {
1555  { inputInfo, inputInfo },
1556  { outputInfo }
1557  };
1558 
1559  // Create a addition workload
1560  auto workload = sampleWorkloadFactory->CreateAddition(additionQueueDescriptor, workloadInfo);
1561  BOOST_TEST((workload != nullptr));
1562 }
1563 
1564 void SampleDynamicBackendEndToEndTestImpl()
1565 {
1566  using namespace armnn;
1567  // Create runtime in which test will run
1568  IRuntime::CreationOptions options;
1569  IRuntimePtr runtime(IRuntime::Create(options));
1570  CheckSampleDynamicBackendLoaded();
1571  // Builds up the structure of the network.
1572  INetworkPtr net(INetwork::Create());
1573 
1574  IConnectableLayer* input0 = net->AddInputLayer(0);
1575  IConnectableLayer* input1 = net->AddInputLayer(1);
1576  IConnectableLayer* add = net->AddAdditionLayer();
1577  IConnectableLayer* output = net->AddOutputLayer(0);
1578 
1579  input0->GetOutputSlot(0).Connect(add->GetInputSlot(0));
1580  input1->GetOutputSlot(0).Connect(add->GetInputSlot(1));
1581  add->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1582 
1583  TensorInfo tensorInfo(TensorShape({2, 1}), DataType::Float32);
1584  input0->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1585  input1->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1586  add->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1587 
1588  // optimize the network
1589  IOptimizedNetworkPtr optNet = Optimize(*net, {"SampleDynamic"}, runtime->GetDeviceSpec());
1590 
1591  // Loads it into the runtime.
1592  NetworkId netId;
1593  runtime->LoadNetwork(netId, std::move(optNet));
1594 
1595  std::vector<float> input0Data{ 5.0f, 3.0f };
1596  std::vector<float> input1Data{ 10.0f, 8.0f };
1597  std::vector<float> expectedOutputData{ 15.0f, 11.0f };
1598  std::vector<float> outputData(2);
1599 
1600  InputTensors inputTensors
1601  {
1602  {0,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), input0Data.data())},
1603  {1,armnn::ConstTensor(runtime->GetInputTensorInfo(netId, 0), input1Data.data())}
1604  };
1605  OutputTensors outputTensors
1606  {
1607  {0,armnn::Tensor(runtime->GetOutputTensorInfo(netId, 0), outputData.data())}
1608  };
1609 
1610  // Does the inference.
1611  runtime->EnqueueWorkload(netId, inputTensors, outputTensors);
1612 
1613  // Checks the results.
1614  BOOST_TEST(outputData == expectedOutputData);
1615 }
1616 #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:62
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:26
std::unordered_map< BackendId, FactoryFunction > FactoryStorage
BackendRegistry & BackendRegistryInstance()
std::vector< std::pair< LayerBindingId, class ConstTensor > > InputTensors
Definition: Tensor.hpp:340
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) 2021 ARM Limited and Contributors.
std::unique_ptr< DynamicBackend > DynamicBackendPtr
void CreateDynamicBackendObjectInvalidInterface6TestImpl()
static std::vector< std::string > GetBackendPathsImplTest(const std::string &path)
virtual void SetTensorInfo(const TensorInfo &tensorInfo)=0
A tensor defined by a TensorInfo (shape and data type) and a mutable backing store.
Definition: Tensor.hpp:306
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:1502
void CreateDynamicBackendObjectInvalidInterface5TestImpl()
const ConstCpuTensorHandle * m_Weight
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:314
#define DYNAMIC_BACKEND_BUILD_DIR
void RegisterMultipleInvalidDynamicBackendsTestImpl()
std::vector< std::pair< LayerBindingId, class Tensor > > OutputTensors
Definition: Tensor.hpp:341
void GetNotExistingEntryPointTestImpl()
void CreateDynamicBackendObjectInvalidInterface1TestImpl()
std::unique_ptr< IOptimizedNetwork, void(*)(IOptimizedNetwork *network)> IOptimizedNetworkPtr
Definition: INetwork.hpp:174
void RuntimeInvalidOverridePathTestImpl()
void CreateDynamicBackendsTestImpl()
void CreateDynamicBackendObjectInvalidInterface2TestImpl()
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:60
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 RuntimeEmptyTestImpl()
void RuntimeDuplicateDynamicBackendsTestImpl()
std::vector< ITensorHandle * > m_Inputs
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
Definition: INetwork.hpp:173
std::unique_ptr< IBackendInternal > IBackendInternalUniquePtr
std::string GetBasePath(const std::string &basePath)
virtual int Connect(IInputSlot &destination)=0
void RuntimeInvalidDynamicBackendsTestImpl()
void OpenNotExistingFileTestImpl()
void CreateDynamicBackendObjectInvalidInterface7TestImpl()
void GetBackendPathsTestImpl()