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