• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright © 2019-2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #pragma once
7 
8 #include <armnn/BackendRegistry.hpp>
9 #include <armnn/backends/DynamicBackend.hpp>
10 #include <armnn/backends/ILayerSupport.hpp>
11 #include <armnn/utility/PolymorphicDowncast.hpp>
12 #include <backendsCommon/DynamicBackendUtils.hpp>
13 #include <armnn/backends/TensorHandle.hpp>
14 #include <armnnUtils/Filesystem.hpp>
15 #include <reference/workloads/RefConvolution2dWorkload.hpp>
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)
73 class TestDynamicBackendUtils : public armnn::DynamicBackendUtils
74 {
75 public:
IsBackendCompatibleTest(const armnn::BackendVersion & backendApiVersion,const armnn::BackendVersion & backendVersion)76     static bool IsBackendCompatibleTest(const armnn::BackendVersion& backendApiVersion,
77                                         const armnn::BackendVersion& backendVersion)
78     {
79         return IsBackendCompatibleImpl(backendApiVersion, backendVersion);
80     }
81 
GetBackendPathsImplTest(const std::string & path)82     static std::vector<std::string> GetBackendPathsImplTest(const std::string& path)
83     {
84         return GetBackendPathsImpl(path);
85     }
86 
RegisterDynamicBackendsImplTest(armnn::BackendRegistry & backendRegistry,const std::vector<armnn::DynamicBackendPtr> & dynamicBackends)87     static armnn::BackendIdSet RegisterDynamicBackendsImplTest(
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)
96 class TestBackendRegistry : public armnn::BackendRegistry
97 {
98 public:
TestBackendRegistry()99     TestBackendRegistry() : armnn::BackendRegistry()
100     {
101         Swap(armnn::BackendRegistryInstance(), m_TempStorage);
102     }
103 
~TestBackendRegistry()104     ~TestBackendRegistry()
105     {
106         Swap(armnn::BackendRegistryInstance(), m_TempStorage);
107     }
108 
109 private:
110     FactoryStorage m_TempStorage;
111 };
112 
113 #if defined(_MSC_VER)
GetUnitTestExecutablePath()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
GetUnitTestExecutablePath()123 std::string GetUnitTestExecutablePath()
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 
GetBasePath(const std::string & basePath)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 
GetTestDirectoryBasePath()153 std::string GetTestDirectoryBasePath()
154 {
155     return GetBasePath(g_TestBaseDir);
156 }
157 
GetDynamicBackendsBasePath()158 std::string GetDynamicBackendsBasePath()
159 {
160     return GetBasePath(g_DynamicBackendsBaseDir);
161 }
162 
GetTestSubDirectory(const std::string & subdir)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 
GetTestSubDirectory(const std::string & basePath,const std::string & subdir)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 
GetTestFilePath(const std::string & directory,const std::string & fileName)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 
OpenCloseHandleTestImpl()197 void OpenCloseHandleTestImpl()
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 
CloseInvalidHandleTestImpl()211 void CloseInvalidHandleTestImpl()
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 
OpenEmptyFileNameTestImpl()219 void OpenEmptyFileNameTestImpl()
220 {
221     using namespace armnn;
222 
223     void* sharedObjectHandle = nullptr;
224     CHECK_THROWS_AS(sharedObjectHandle = DynamicBackendUtils::OpenHandle(""), RuntimeException);
225     CHECK((sharedObjectHandle == nullptr));
226 }
227 
OpenNotExistingFileTestImpl()228 void OpenNotExistingFileTestImpl()
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 
OpenNotSharedObjectTestImpl()237 void OpenNotSharedObjectTestImpl()
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 
GetValidEntryPointTestImpl()249 void GetValidEntryPointTestImpl()
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 
GetNameMangledEntryPointTestImpl()270 void GetNameMangledEntryPointTestImpl()
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"),
285                       RuntimeException);
286     CHECK((testFunctionPointer == nullptr));
287 
288     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
289 }
290 
GetNoExternEntryPointTestImpl()291 void GetNoExternEntryPointTestImpl()
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"),
306                       RuntimeException);
307     CHECK((testFunctionPointer == nullptr));
308 
309     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
310 }
311 
GetNotExistingEntryPointTestImpl()312 void GetNotExistingEntryPointTestImpl()
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"),
327                       RuntimeException);
328     CHECK((testFunctionPointer == nullptr));
329 
330     DynamicBackendUtils::CloseHandle(sharedObjectHandle);
331 }
332 
BackendVersioningTestImpl()333 void BackendVersioningTestImpl()
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)
CreateValidDynamicBackendObjectTestImpl()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 
CreateDynamicBackendObjectInvalidHandleTestImpl()425 void CreateDynamicBackendObjectInvalidHandleTestImpl()
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 
CreateDynamicBackendObjectInvalidInterface1TestImpl()437 void CreateDynamicBackendObjectInvalidInterface1TestImpl()
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 
CreateDynamicBackendObjectInvalidInterface2TestImpl()456 void CreateDynamicBackendObjectInvalidInterface2TestImpl()
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 
CreateDynamicBackendObjectInvalidInterface3TestImpl()476 void CreateDynamicBackendObjectInvalidInterface3TestImpl()
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 
CreateDynamicBackendObjectInvalidInterface4TestImpl()496 void CreateDynamicBackendObjectInvalidInterface4TestImpl()
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 
CreateDynamicBackendObjectInvalidInterface5TestImpl()516 void CreateDynamicBackendObjectInvalidInterface5TestImpl()
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 
CreateDynamicBackendObjectInvalidInterface6TestImpl()537 void CreateDynamicBackendObjectInvalidInterface6TestImpl()
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 
CreateDynamicBackendObjectInvalidInterface7TestImpl()578 void CreateDynamicBackendObjectInvalidInterface7TestImpl()
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 
GetBackendPathsTestImpl()599 void GetBackendPathsTestImpl()
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
622     CHECK(TestDynamicBackendUtils::GetBackendPathsImplTest("").empty());
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
640     CHECK(TestDynamicBackendUtils::GetBackendPathsImplTest(":::").empty());
641 
642     // Multiple valid paths
643     std::string multipleValidPaths(subDir1 + ":" + subDir2 + ":" + subDir3);
644     std::vector<std::string> DynamicBackendPaths5 =
645         TestDynamicBackendUtils::GetBackendPathsImplTest(multipleValidPaths);
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 =
654         TestDynamicBackendUtils::GetBackendPathsImplTest(validAmongEmptyDirs);
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 =
665         TestDynamicBackendUtils::GetBackendPathsImplTest(validInvalidEmptyDirs);
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 
GetBackendPathsOverrideTestImpl()679 void GetBackendPathsOverrideTestImpl()
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 
GetSharedObjectsTestImpl()700 void GetSharedObjectsTestImpl()
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 
CreateDynamicBackendsTestImpl()791 void CreateDynamicBackendsTestImpl()
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 
CreateDynamicBackendsNoPathsTestImpl()854 void CreateDynamicBackendsNoPathsTestImpl()
855 {
856     using namespace armnn;
857 
858     std::vector<DynamicBackendPtr> dynamicBackends = DynamicBackendUtils::CreateDynamicBackends({});
859 
860     CHECK(dynamicBackends.empty());
861 }
862 
CreateDynamicBackendsAllInvalidTestImpl()863 void CreateDynamicBackendsAllInvalidTestImpl()
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 
CreateDynamicBackendsMixedTypesTestImpl()878 void CreateDynamicBackendsMixedTypesTestImpl()
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)
RegisterSingleDynamicBackendTestImpl()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 
RegisterMultipleDynamicBackendsTestImpl()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 
RegisterMixedDynamicBackendsTestImpl()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 
RegisterMultipleInvalidDynamicBackendsTestImpl()1183 void RegisterMultipleInvalidDynamicBackendsTestImpl()
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 
RuntimeEmptyTestImpl()1245 void RuntimeEmptyTestImpl()
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 
RuntimeDynamicBackendsTestImpl()1267 void RuntimeDynamicBackendsTestImpl()
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 
RuntimeDuplicateDynamicBackendsTestImpl()1308 void RuntimeDuplicateDynamicBackendsTestImpl()
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 
RuntimeInvalidDynamicBackendsTestImpl()1349 void RuntimeInvalidDynamicBackendsTestImpl()
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 
RuntimeInvalidOverridePathTestImpl()1374 void RuntimeInvalidOverridePathTestImpl()
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 
CreateReferenceDynamicBackendTestImpl()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, weightInfo },
1469         { outputInfo }
1470     };
1471     convolution2dQueueDescriptor.m_Inputs.push_back(nullptr);
1472 
1473     // Create a convolution workload with the dummy settings
1474     auto workload = referenceWorkloadFactory->CreateWorkload(LayerType::Convolution2d,
1475                                                              convolution2dQueueDescriptor,
1476                                                              workloadInfo);
1477     CHECK((workload != nullptr));
1478     CHECK(workload.get() == PolymorphicDowncast<RefConvolution2dWorkload*>(workload.get()));
1479 }
1480 
1481 #endif
1482 
1483 #if defined(SAMPLE_DYNAMIC_BACKEND_ENABLED)
1484 
CheckSampleDynamicBackendLoaded()1485 void CheckSampleDynamicBackendLoaded()
1486 {
1487     using namespace armnn;
1488     // At this point we expect DYNAMIC_BACKEND_PATHS to include a path to where libArm_SampleDynamic_backend.so is.
1489     // If it hasn't been loaded there's no point continuing with the rest of the tests.
1490     BackendIdSet backendIds = BackendRegistryInstance().GetBackendIds();
1491     if (backendIds.find("SampleDynamic") == backendIds.end())
1492     {
1493         std::string message = "The SampleDynamic backend has not been loaded. This may be a build configuration error. "
1494                               "Ensure a DYNAMIC_BACKEND_PATHS was set at compile time to the location of "
1495                               "libArm_SampleDynamic_backend.so. "
1496                               "To disable this test recompile with: -DSAMPLE_DYNAMIC_BACKEND_ENABLED=0";
1497         FAIL(message);
1498     }
1499 }
1500 
CreateSampleDynamicBackendTestImpl()1501 void CreateSampleDynamicBackendTestImpl()
1502 {
1503     using namespace armnn;
1504     // Using the path override in CreationOptions to load the reference dynamic backend
1505     IRuntime::CreationOptions creationOptions;
1506     IRuntimePtr runtime = IRuntime::Create(creationOptions);
1507     const BackendRegistry& backendRegistry = BackendRegistryInstance();
1508     CHECK(backendRegistry.Size() >= 1);
1509     CheckSampleDynamicBackendLoaded();
1510     const DeviceSpec& deviceSpec = *PolymorphicDowncast<const DeviceSpec*>(&runtime->GetDeviceSpec());
1511     BackendIdSet supportedBackendIds = deviceSpec.GetSupportedBackends();
1512     CHECK(supportedBackendIds.size()>= 1);
1513     CHECK((supportedBackendIds.find("SampleDynamic") != supportedBackendIds.end()));
1514 
1515     // Get the factory function
1516     auto sampleDynamicBackendFactoryFunction = backendRegistry.GetFactory("SampleDynamic");
1517     CHECK((sampleDynamicBackendFactoryFunction != nullptr));
1518 
1519     // Use the factory function to create an instance of the dynamic backend
1520     IBackendInternalUniquePtr sampleDynamicBackend = sampleDynamicBackendFactoryFunction();
1521     CHECK((sampleDynamicBackend != nullptr));
1522     CHECK((sampleDynamicBackend->GetId() == "SampleDynamic"));
1523 
1524     // Test the backend instance by querying the layer support
1525     IBackendInternal::ILayerSupportSharedPtr sampleLayerSupport = sampleDynamicBackend->GetLayerSupport();
1526     CHECK((sampleLayerSupport != nullptr));
1527 
1528     TensorShape inputShape {  1, 16, 16, 16 };
1529     TensorShape outputShape{  1, 16, 16, 16 };
1530     TensorShape weightShape{ 16,  1,  1, 16 };
1531     TensorInfo inputInfo (inputShape,  DataType::Float32);
1532     TensorInfo outputInfo(outputShape, DataType::Float32);
1533     TensorInfo weightInfo(weightShape, DataType::Float32);
1534     Convolution2dDescriptor convolution2dDescriptor;
1535     std::vector<TensorInfo> infos = {inputInfo, outputInfo, weightInfo, TensorInfo()};
1536     bool sampleConvolution2dSupported =
1537              sampleLayerSupport->IsLayerSupported(LayerType::Convolution2d,
1538                                                   infos,
1539                                                   convolution2dDescriptor);
1540     CHECK(!sampleConvolution2dSupported);
1541 
1542     // Test the backend instance by creating a workload
1543     IBackendInternal::IWorkloadFactoryPtr sampleWorkloadFactory = sampleDynamicBackend->CreateWorkloadFactory();
1544     CHECK((sampleWorkloadFactory != nullptr));
1545 
1546     // Create dummy settings for the workload
1547     AdditionQueueDescriptor additionQueueDescriptor;
1548     WorkloadInfo workloadInfo
1549     {
1550         { inputInfo, inputInfo },
1551         { outputInfo }
1552     };
1553 
1554     // Create a addition workload
1555     auto workload = sampleWorkloadFactory->CreateWorkload(LayerType::Addition, additionQueueDescriptor, workloadInfo);
1556     CHECK((workload != nullptr));
1557 }
1558 
SampleDynamicBackendEndToEndTestImpl()1559 void SampleDynamicBackendEndToEndTestImpl()
1560 {
1561     using namespace armnn;
1562     // Create runtime in which test will run
1563     IRuntime::CreationOptions options;
1564     IRuntimePtr runtime(IRuntime::Create(options));
1565     CheckSampleDynamicBackendLoaded();
1566     // Builds up the structure of the network.
1567     INetworkPtr net(INetwork::Create());
1568 
1569     IConnectableLayer* input0 = net->AddInputLayer(0);
1570     IConnectableLayer* input1 = net->AddInputLayer(1);
1571     ARMNN_NO_DEPRECATE_WARN_BEGIN
1572     IConnectableLayer* add = net->AddAdditionLayer();
1573     ARMNN_NO_DEPRECATE_WARN_END
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
1616