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