IVGCVSW-4400 Backend Counter Registry Functionality

 * Adding BackendProfilingContext to the MockBackend
 * Made IBackendProfilingContext pure Virtual
 * Added UnitTest using MockBackend for testing Backend Counter Registration
 * Moved Registry of backend counters from Initialize() to AddBackendProfilingContext()
 * Added m_MaxGlobalCounterId to ProfilingService
 * Removed automatic registration of MockBack in BackendRegistry()

Signed-off-by: David Monahan <david.monahan@arm.com>
Change-Id: Ie1c6c31e56d1ac7079d6116ecad041961014aedc
diff --git a/src/backends/backendsCommon/test/BackendProfilingTests.cpp b/src/backends/backendsCommon/test/BackendProfilingTests.cpp
new file mode 100644
index 0000000..fc21730
--- /dev/null
+++ b/src/backends/backendsCommon/test/BackendProfilingTests.cpp
@@ -0,0 +1,41 @@
+//
+// Copyright © 2020 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "MockBackend.hpp"
+#include "MockBackendId.hpp"
+#include "Runtime.hpp"
+
+#include <armnn/BackendId.hpp>
+#include <boost/test/unit_test.hpp>
+#include <vector>
+
+BOOST_AUTO_TEST_SUITE(BackendProfilingTestSuite)
+
+BOOST_AUTO_TEST_CASE(BackendProfilingCounterRegisterMockBackendTest)
+{
+    // Reset the profiling service to the uninitialized state
+    armnn::IRuntime::CreationOptions options;
+    options.m_ProfilingOptions.m_EnableProfiling = true;
+    armnn::profiling::ProfilingService& profilingService = armnn::profiling::ProfilingService::Instance();
+    profilingService.ConfigureProfilingService(options.m_ProfilingOptions, true);
+
+    armnn::MockBackendInitialiser initialiser;
+    // Create a runtime
+    armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
+
+    // Check if the MockBackends 3 dummy counters {0, 1, 2-5 (four cores)} are registered
+    armnn::BackendId mockId = armnn::MockBackendId();
+    const armnn::profiling::ICounterMappings& counterMap = profilingService.GetCounterMappings();
+    BOOST_CHECK(counterMap.GetGlobalId(0, mockId) == 5);
+    BOOST_CHECK(counterMap.GetGlobalId(1, mockId) == 6);
+    BOOST_CHECK(counterMap.GetGlobalId(2, mockId) == 7);
+    BOOST_CHECK(counterMap.GetGlobalId(3, mockId) == 8);
+    BOOST_CHECK(counterMap.GetGlobalId(4, mockId) == 9);
+    BOOST_CHECK(counterMap.GetGlobalId(5, mockId) == 10);
+    options.m_ProfilingOptions.m_EnableProfiling = false;
+    profilingService.ResetExternalProfilingOptions(options.m_ProfilingOptions, true);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file
diff --git a/src/backends/backendsCommon/test/BackendRegistryTests.cpp b/src/backends/backendsCommon/test/BackendRegistryTests.cpp
index 172c0a9..213d114 100644
--- a/src/backends/backendsCommon/test/BackendRegistryTests.cpp
+++ b/src/backends/backendsCommon/test/BackendRegistryTests.cpp
@@ -72,6 +72,7 @@
 
     factoryFunction();
     BOOST_TEST(called == true);
+    BackendRegistryInstance().Deregister("HelloWorld");
 }
 
 BOOST_AUTO_TEST_CASE(TestDirectCallToRegistry)
@@ -99,6 +100,7 @@
 
     factoryFunction();
     BOOST_TEST(called == true);
+    BackendRegistryInstance().Deregister("HelloWorld");
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/backends/backendsCommon/test/CMakeLists.txt b/src/backends/backendsCommon/test/CMakeLists.txt
index 4716bd4..0376e3e 100644
--- a/src/backends/backendsCommon/test/CMakeLists.txt
+++ b/src/backends/backendsCommon/test/CMakeLists.txt
@@ -7,6 +7,7 @@
     ActivationFixture.hpp
     ArgMinMaxEndToEndTestImpl.hpp
     BackendIdTests.cpp
+    BackendProfilingTests.cpp
     BackendRegistryTests.cpp
     CommonTestUtils.cpp
     CommonTestUtils.hpp
diff --git a/src/backends/backendsCommon/test/MockBackend.cpp b/src/backends/backendsCommon/test/MockBackend.cpp
index ac99738..7ad700c 100644
--- a/src/backends/backendsCommon/test/MockBackend.cpp
+++ b/src/backends/backendsCommon/test/MockBackend.cpp
@@ -5,6 +5,7 @@
 
 #include "MockBackend.hpp"
 #include "MockBackendId.hpp"
+#include "armnn/backends/profiling/IBackendProfilingContext.hpp"
 
 #include <armnn/BackendRegistry.hpp>
 
@@ -66,19 +67,25 @@
 namespace armnn
 {
 
-namespace
+MockBackendInitialiser::MockBackendInitialiser()
 {
+    BackendRegistryInstance().Register(MockBackend::GetIdStatic(),
+                                       []()
+                                       {
+                                           return IBackendInternalUniquePtr(new MockBackend);
+                                       });
+}
 
-static BackendRegistry::StaticRegistryInitializer g_RegisterHelper
+MockBackendInitialiser::~MockBackendInitialiser()
 {
-    BackendRegistryInstance(),
-    MockBackend::GetIdStatic(),
-    []()
+    try
     {
-        return IBackendInternalUniquePtr(new MockBackend);
+        BackendRegistryInstance().Deregister(MockBackend::GetIdStatic());
     }
-};
-
+    catch (...)
+    {
+        std::cerr << "could not deregister mock backend" << std::endl;
+    }
 }
 
 const BackendId& MockBackend::GetIdStatic()
@@ -99,9 +106,13 @@
 }
 
 IBackendInternal::IBackendProfilingContextPtr MockBackend::CreateBackendProfilingContext(
-    const IRuntime::CreationOptions&, IBackendProfilingPtr&)
+    const IRuntime::CreationOptions& options, IBackendProfilingPtr& backendProfiling)
 {
-    return IBackendProfilingContextPtr{};
+    boost::ignore_unused(options);
+    IBackendInternal::IBackendProfilingContextPtr context =
+        std::make_shared<MockBackendProfilingContext>(MockBackendProfilingContext(backendProfiling));
+    MockBackendProfilingService::Instance().SetProfilingContextPtr(context);
+    return context;
 }
 
 IBackendInternal::IMemoryManagerUniquePtr MockBackend::CreateMemoryManager() const
diff --git a/src/backends/backendsCommon/test/MockBackend.hpp b/src/backends/backendsCommon/test/MockBackend.hpp
index d1a0082..21ce7ab 100644
--- a/src/backends/backendsCommon/test/MockBackend.hpp
+++ b/src/backends/backendsCommon/test/MockBackend.hpp
@@ -5,6 +5,10 @@
 
 #pragma once
 
+#include "armnn/backends/profiling/IBackendProfiling.hpp"
+#include "armnn/backends/profiling/IBackendProfilingContext.hpp"
+#include "MockBackendId.hpp"
+
 #include <LayerSupportCommon.hpp>
 #include <armnn/backends/IBackendInternal.hpp>
 #include <armnn/backends/OptimizationViews.hpp>
@@ -13,6 +17,84 @@
 namespace armnn
 {
 
+class MockBackendInitialiser
+{
+public:
+    MockBackendInitialiser();
+    ~MockBackendInitialiser();
+};
+
+class MockBackendProfilingService
+{
+public:
+    // Getter for the singleton instance
+    static MockBackendProfilingService& Instance()
+    {
+        static MockBackendProfilingService instance;
+        return instance;
+    }
+
+    armnn::profiling::IBackendProfilingContext* GetContext()
+    {
+        return m_sharedContext.get();
+    }
+
+    void SetProfilingContextPtr(IBackendInternal::IBackendProfilingContextPtr& shared)
+    {
+        m_sharedContext = shared;
+    }
+
+private:
+    IBackendInternal::IBackendProfilingContextPtr m_sharedContext;
+};
+
+class MockBackendProfilingContext : public profiling::IBackendProfilingContext
+{
+public:
+    MockBackendProfilingContext(IBackendInternal::IBackendProfilingPtr& backendProfiling)
+        : m_BackendProfiling(backendProfiling)
+    {}
+
+    ~MockBackendProfilingContext() = default;
+
+    IBackendInternal::IBackendProfilingPtr& GetBackendProfiling()
+    {
+        return m_BackendProfiling;
+    }
+
+    uint16_t RegisterCounters(uint16_t currentMaxGlobalCounterId)
+    {
+        std::unique_ptr<profiling::IRegisterBackendCounters> counterRegistrar =
+            m_BackendProfiling->GetCounterRegistrationInterface(currentMaxGlobalCounterId);
+
+            std::string categoryName("MockCounters");
+            counterRegistrar->RegisterCategory(categoryName);
+            uint16_t nextMaxGlobalCounterId = counterRegistrar->RegisterCounter(
+                0, categoryName, 0, 0, 1.f, "Mock Counter One", "Some notional counter");
+
+            nextMaxGlobalCounterId = counterRegistrar->RegisterCounter(
+                1, categoryName, 0, 0, 1.f, "Mock Counter Two", "Another notional counter");
+
+            std::string units("microseconds");
+            nextMaxGlobalCounterId = counterRegistrar->RegisterCounter(
+                2, categoryName, 0, 0, 1.f, "Mock MultiCore Counter", "A dummy four core counter", units, 4);
+            return nextMaxGlobalCounterId;
+    }
+
+    void ActivateCounters(uint32_t, const std::vector<uint16_t>&)
+    {}
+
+    std::vector<profiling::Timestamp> ReportCounterValues()
+    {
+        return std::vector<profiling::Timestamp>();
+    }
+
+    void EnableProfiling(bool)
+    {}
+
+private:
+    IBackendInternal::IBackendProfilingPtr& m_BackendProfiling;
+};
 
 class MockBackend : public IBackendInternal
 {
diff --git a/src/backends/backendsCommon/test/OptimizationViewsTests.cpp b/src/backends/backendsCommon/test/OptimizationViewsTests.cpp
index 1efc697..3aebe3e 100644
--- a/src/backends/backendsCommon/test/OptimizationViewsTests.cpp
+++ b/src/backends/backendsCommon/test/OptimizationViewsTests.cpp
@@ -199,6 +199,7 @@
     input1->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
     addition->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32));
 
+    armnn::MockBackendInitialiser initialiser;
     armnn::IRuntime::CreationOptions options;
     armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
 
diff --git a/src/backends/backendsCommon/test/OptimizeSubgraphViewTests.cpp b/src/backends/backendsCommon/test/OptimizeSubgraphViewTests.cpp
index 162cc84..f7ebf1a 100644
--- a/src/backends/backendsCommon/test/OptimizeSubgraphViewTests.cpp
+++ b/src/backends/backendsCommon/test/OptimizeSubgraphViewTests.cpp
@@ -564,6 +564,7 @@
     BOOST_TEST(Contains(layersInGraph, "pooling layer"));
 
     // Create a mock backend object
+    MockBackendInitialiser initialiser; // Register the Mock Backend
     auto backendObjPtr = CreateBackendObject(MockBackendId());
     BOOST_TEST((backendObjPtr != nullptr));
 
@@ -629,6 +630,7 @@
     BOOST_TEST(Contains(layersInGraph, "pooling3 layer"));
 
     // Create a mock backend object
+    MockBackendInitialiser initialiser; // Register the Mock Backend
     auto backendObjPtr = CreateBackendObject(MockBackendId());
     BOOST_TEST((backendObjPtr != nullptr));
 
@@ -704,6 +706,7 @@
     BOOST_TEST(Contains(layersInGraph, "conv layer"));
 
     // Create a mock backend object
+    MockBackendInitialiser initialiser; // Register the Mock Backend
     auto backendObjPtr = CreateBackendObject(MockBackendId());
     BOOST_TEST((backendObjPtr != nullptr));
 
@@ -772,6 +775,7 @@
     BOOST_TEST(Contains(layersInGraph, "conv5 layer"));
 
     // Create a mock backend object
+    MockBackendInitialiser initialiser; // Register the Mock Backend
     auto backendObjPtr = CreateBackendObject(MockBackendId());
     BOOST_TEST((backendObjPtr != nullptr));
 
@@ -857,6 +861,7 @@
     BOOST_TEST(Contains(layersInGraph, "pooling3 layer"));
 
     // Create a mock backend object
+    MockBackendInitialiser initialiser; // Register the Mock Backend
     auto backendObjPtr = CreateBackendObject(MockBackendId());
     BOOST_TEST((backendObjPtr != nullptr));
 
@@ -982,6 +987,7 @@
     BOOST_TEST(Contains(layersInGraph, "conv layer unoptimizable"));
 
     // Create a mock backend object
+    MockBackendInitialiser initialiser; // Register the Mock Backend
     auto backendObjPtr = CreateBackendObject(MockBackendId());
     BOOST_TEST((backendObjPtr != nullptr));
 
@@ -1049,6 +1055,7 @@
     BOOST_TEST(Contains(layersInGraph, "conv5 layer"));
 
     // Create a mock backend object
+    MockBackendInitialiser initialiser; // Register the Mock Backend
     auto backendObjPtr = CreateBackendObject(MockBackendId());
     BOOST_TEST((backendObjPtr != nullptr));
 
@@ -1181,6 +1188,7 @@
     BOOST_TEST(Contains(layersInGraph, "add layer"));
 
     // Create a mock backend object
+    MockBackendInitialiser initialiser; // Register the Mock Backend
     auto backendObjPtr = CreateBackendObject(MockBackendId());
     BOOST_TEST((backendObjPtr != nullptr));
 
diff --git a/src/profiling/ProfilingService.cpp b/src/profiling/ProfilingService.cpp
index c73f3b2..27b05a6 100644
--- a/src/profiling/ProfilingService.cpp
+++ b/src/profiling/ProfilingService.cpp
@@ -181,6 +181,15 @@
     }
 }
 
+// Store a profiling context returned from a backend that support profiling, and register its counters
+void ProfilingService::AddBackendProfilingContext(const BackendId backendId,
+    std::shared_ptr<armnn::profiling::IBackendProfilingContext> profilingContext)
+{
+    BOOST_ASSERT(profilingContext != nullptr);
+    // Register the backend counters
+    m_MaxGlobalCounterId = profilingContext->RegisterCounters(m_MaxGlobalCounterId);
+    m_BackendProfilingContexts.emplace(backendId, std::move(profilingContext));
+}
 const ICounterDirectory& ProfilingService::GetCounterDirectory() const
 {
     return m_CounterDirectory;
@@ -369,13 +378,6 @@
         BOOST_ASSERT(inferencesRunCounter);
         InitializeCounterValue(inferencesRunCounter->m_Uid);
     }
-    // Register the backend counters
-    uint16_t maxGlobalCounterId = armnn::profiling::INFERENCES_RUN;
-    for (auto&& profilingContext : m_BackendProfilingContexts)
-    {
-        BOOST_ASSERT(profilingContext.second != nullptr);
-        maxGlobalCounterId = profilingContext.second->RegisterCounters(maxGlobalCounterId);
-    }
 }
 
 void ProfilingService::InitializeCounterValue(uint16_t counterUid)
@@ -409,6 +411,7 @@
     // ...finally reset the profiling state machine
     m_StateMachine.Reset();
     m_BackendProfilingContexts.clear();
+    m_MaxGlobalCounterId = armnn::profiling::INFERENCES_RUN;
 }
 
 void ProfilingService::Stop()
diff --git a/src/profiling/ProfilingService.hpp b/src/profiling/ProfilingService.hpp
index 27166b3..54c6540 100644
--- a/src/profiling/ProfilingService.hpp
+++ b/src/profiling/ProfilingService.hpp
@@ -67,10 +67,7 @@
 
     // Store a profiling context returned from a backend that support profiling.
     void AddBackendProfilingContext(const BackendId backendId,
-        std::shared_ptr<armnn::profiling::IBackendProfilingContext> profilingContext)
-    {
-        m_BackendProfilingContexts.emplace(backendId, std::move(profilingContext));
-    }
+        std::shared_ptr<armnn::profiling::IBackendProfilingContext> profilingContext);
 
     const ICounterDirectory& GetCounterDirectory() const;
     ICounterRegistry& GetCounterRegistry();
@@ -147,6 +144,7 @@
     TimelinePacketWriterFactory m_TimelinePacketWriterFactory;
     std::unordered_map<BackendId,
         std::shared_ptr<armnn::profiling::IBackendProfilingContext>> m_BackendProfilingContexts;
+    uint16_t m_MaxGlobalCounterId;
 
 protected:
     // Default constructor/destructor kept protected for testing
@@ -196,6 +194,7 @@
                                                  m_PacketVersionResolver.ResolvePacketVersion(0, 5).GetEncodedValue(),
                                                  m_StateMachine)
         , m_TimelinePacketWriterFactory(m_BufferManager)
+        , m_MaxGlobalCounterId(armnn::profiling::INFERENCES_RUN)
     {
         // Register the "Connection Acknowledged" command handler
         m_CommandHandlerRegistry.RegisterFunctor(&m_ConnectionAcknowledgedCommandHandler);
diff --git a/src/profiling/test/ProfilingTestUtils.cpp b/src/profiling/test/ProfilingTestUtils.cpp
index bc8b7a7..dd54ca9 100644
--- a/src/profiling/test/ProfilingTestUtils.cpp
+++ b/src/profiling/test/ProfilingTestUtils.cpp
@@ -359,6 +359,8 @@
     // Create runtime in which test will run
     armnn::IRuntime::CreationOptions options;
     options.m_ProfilingOptions.m_EnableProfiling = true;
+    armnn::profiling::ProfilingService& profilingService = armnn::profiling::ProfilingService::Instance();
+    profilingService.ConfigureProfilingService(options.m_ProfilingOptions, true);
     armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
 
     // build up the structure of the network