IVGCVSW-4319 Implement Counter Status Querying

* Adds implementations for GetCounterStatus and
  GetActiveCounters.
* Adds CheckCounterStatusQuery in ProfilingTests.
* Modifies Holder and ProfilingService to open
  up access to CaptureData for use by
  BackendProfiling.

Signed-off-by: James Conroy <james.conroy@arm.com>
Signed-off-by: Colm Donelan <Colm.Donelan@arm.com>
Change-Id: Iec47952545c0072a71088b12ca3dc31673fa9c51
diff --git a/include/armnn/backends/profiling/IBackendProfiling.hpp b/include/armnn/backends/profiling/IBackendProfiling.hpp
index d3c5299..a649ece 100644
--- a/include/armnn/backends/profiling/IBackendProfiling.hpp
+++ b/include/armnn/backends/profiling/IBackendProfiling.hpp
@@ -30,6 +30,14 @@
 
 struct CounterStatus
 {
+    CounterStatus(uint16_t backendCounterId,
+                  uint16_t globalCounterId,
+                  bool enabled,
+                  uint32_t samplingRateInMicroseconds)
+                  : m_BackendCounterId(backendCounterId),
+                    m_GlobalCounterId(globalCounterId),
+                    m_Enabled(enabled),
+                    m_SamplingRateInMicroseconds(samplingRateInMicroseconds) {}
     uint16_t m_BackendCounterId;
     uint16_t m_GlobalCounterId;
     bool     m_Enabled;
@@ -73,7 +81,7 @@
     {}
 
     virtual std::unique_ptr<IRegisterBackendCounters>
-        GetCounterRegistrationInterface(uint16_t currentMaxGlobalCounterID) = 0;
+            GetCounterRegistrationInterface(uint16_t currentMaxGlobalCounterID) = 0;
 
     virtual std::unique_ptr<ISendTimelinePacket> GetSendTimelinePacket() = 0;
 
@@ -88,5 +96,7 @@
     virtual bool IsProfilingEnabled() const = 0;
 
 };
+
 }    // namespace profiling
+
 }    // namespace armnn
\ No newline at end of file
diff --git a/src/profiling/Holder.cpp b/src/profiling/Holder.cpp
index 750be7e..41c2993 100644
--- a/src/profiling/Holder.cpp
+++ b/src/profiling/Holder.cpp
@@ -46,6 +46,19 @@
     return m_CaptureData;
 }
 
+bool CaptureData::IsCounterIdInCaptureData(uint16_t counterId)
+{
+    for (auto m_CounterId : m_CounterIds) {
+        if (m_CounterId == counterId)
+        {
+            return true;
+        }
+    }
+
+    // Return false by default unless counterId is found
+    return false;
+}
+
 void Holder::SetCaptureData(uint32_t capturePeriod, const std::vector<uint16_t>& counterIds)
 {
     std::lock_guard<std::mutex> lockGuard(m_CaptureThreadMutex);
diff --git a/src/profiling/Holder.hpp b/src/profiling/Holder.hpp
index 3143105..9785b98 100644
--- a/src/profiling/Holder.hpp
+++ b/src/profiling/Holder.hpp
@@ -33,6 +33,7 @@
     void SetCounterIds(const std::vector<uint16_t>& counterIds);
     uint32_t GetCapturePeriod() const;
     const std::vector<uint16_t>& GetCounterIds() const;
+    bool IsCounterIdInCaptureData(uint16_t counterId);
 
 private:
     uint32_t m_CapturePeriod;
diff --git a/src/profiling/ProfilingService.cpp b/src/profiling/ProfilingService.cpp
index 5cee477..3540fc4 100644
--- a/src/profiling/ProfilingService.cpp
+++ b/src/profiling/ProfilingService.cpp
@@ -224,6 +224,16 @@
     return m_CounterIdMap;
 }
 
+CaptureData ProfilingService::GetCaptureData()
+{
+    return m_Holder.GetCaptureData();
+}
+
+void ProfilingService::SetCaptureData(uint32_t capturePeriod, const std::vector<uint16_t>& counterIds)
+{
+    m_Holder.SetCaptureData(capturePeriod, counterIds);
+}
+
 void ProfilingService::SetCounterValue(uint16_t counterUid, uint32_t value)
 {
     CheckCounterUid(counterUid);
diff --git a/src/profiling/ProfilingService.hpp b/src/profiling/ProfilingService.hpp
index 4438952..17099b1 100644
--- a/src/profiling/ProfilingService.hpp
+++ b/src/profiling/ProfilingService.hpp
@@ -84,6 +84,9 @@
     // Getters for the profiling service state
     bool IsProfilingEnabled();
 
+    CaptureData GetCaptureData();
+    void SetCaptureData(uint32_t capturePeriod, const std::vector<uint16_t>& counterIds);
+
     // Setters for the profiling service state
     void SetCounterValue(uint16_t counterUid, uint32_t value) override;
     uint32_t AddCounterValue(uint16_t counterUid, uint32_t value) override;
diff --git a/src/profiling/backends/BackendProfiling.cpp b/src/profiling/backends/BackendProfiling.cpp
index a49122a..884fb3f 100644
--- a/src/profiling/backends/BackendProfiling.cpp
+++ b/src/profiling/backends/BackendProfiling.cpp
@@ -15,7 +15,7 @@
 std::unique_ptr<IRegisterBackendCounters>
     BackendProfiling::GetCounterRegistrationInterface(uint16_t currentMaxGlobalCounterID)
 {
-    return std::make_unique<RegisterBackendCounters>(RegisterBackendCounters(currentMaxGlobalCounterID, m_backendId));
+    return std::make_unique<RegisterBackendCounters>(RegisterBackendCounters(currentMaxGlobalCounterID, m_BackendId));
 }
 
 std::unique_ptr<ISendTimelinePacket> BackendProfiling::GetSendTimelinePacket()
@@ -29,14 +29,43 @@
     return m_ProfilingService;
 }
 
-CounterStatus BackendProfiling::GetCounterStatus(uint16_t)
+CounterStatus BackendProfiling::GetCounterStatus(uint16_t backendCounterId)
 {
-    return CounterStatus();
+    uint16_t globalCounterId = m_ProfilingService.GetCounterMappings().GetGlobalId(backendCounterId, m_BackendId);
+    CaptureData captureData = m_ProfilingService.GetCaptureData();
+
+    CounterStatus counterStatus(backendCounterId, globalCounterId, false, 0);
+
+    if (captureData.IsCounterIdInCaptureData(globalCounterId))
+    {
+        counterStatus.m_Enabled = true;
+        counterStatus.m_SamplingRateInMicroseconds = captureData.GetCapturePeriod();
+    }
+
+    return counterStatus;
 }
 
 std::vector<CounterStatus> BackendProfiling::GetActiveCounters()
 {
-    return std::vector<CounterStatus>();
+    CaptureData captureData = m_ProfilingService.GetCaptureData();
+
+    const std::vector<uint16_t>& globalCounterIds = captureData.GetCounterIds();
+    std::vector<CounterStatus> activeCounterIds;
+
+    for (auto globalCounterId : globalCounterIds) {
+        // Get pair of local counterId and backendId using globalCounterId
+        const std::pair<uint16_t, armnn::BackendId>& backendCounterIdPair =
+                ProfilingService::Instance().GetCounterMappings().GetBackendId(globalCounterId);
+        if (backendCounterIdPair.second == m_BackendId)
+        {
+            activeCounterIds.emplace_back(backendCounterIdPair.first,
+                                          globalCounterId,
+                                          true,
+                                          captureData.GetCapturePeriod());
+        }
+    }
+
+    return activeCounterIds;
 }
 
 bool BackendProfiling::IsProfilingEnabled() const
diff --git a/src/profiling/backends/BackendProfiling.hpp b/src/profiling/backends/BackendProfiling.hpp
index 2bc365a..e0e0f58 100644
--- a/src/profiling/backends/BackendProfiling.hpp
+++ b/src/profiling/backends/BackendProfiling.hpp
@@ -3,7 +3,9 @@
 // SPDX-License-Identifier: MIT
 //
 
-#include <ProfilingService.hpp>
+#pragma once
+
+#include "ProfilingService.hpp"
 #include <armnn/backends/profiling/IBackendProfiling.hpp>
 
 namespace armnn
@@ -15,17 +17,18 @@
 class BackendProfiling : public IBackendProfiling
 {
 public:
-    BackendProfiling(const IRuntime::CreationOptions& options, ProfilingService& profilingService, const BackendId& id)
-        : m_options(options)
-        , m_ProfilingService(profilingService)
-        , m_backendId(id)
-    {}
+    BackendProfiling(const IRuntime::CreationOptions& options,
+                     ProfilingService& profilingService,
+                     const BackendId& backendId)
+            : m_Options(options),
+              m_ProfilingService(profilingService),
+              m_BackendId(backendId) {}
 
     ~BackendProfiling()
     {}
 
     std::unique_ptr<IRegisterBackendCounters>
-        GetCounterRegistrationInterface(uint16_t currentMaxGlobalCounterID) override;
+            GetCounterRegistrationInterface(uint16_t currentMaxGlobalCounterID) override;
 
     std::unique_ptr<ISendTimelinePacket> GetSendTimelinePacket() override;
 
@@ -41,9 +44,9 @@
     bool IsProfilingEnabled() const override;
 
 private:
-    IRuntime::CreationOptions m_options;
+    IRuntime::CreationOptions m_Options;
     ProfilingService& m_ProfilingService;
-    BackendId m_backendId;
+    BackendId m_BackendId;
 };
 }    // namespace profiling
 }    // namespace armnn
\ No newline at end of file
diff --git a/src/profiling/test/ProfilingTests.cpp b/src/profiling/test/ProfilingTests.cpp
index d06201d..b15ddf7 100644
--- a/src/profiling/test/ProfilingTests.cpp
+++ b/src/profiling/test/ProfilingTests.cpp
@@ -5,6 +5,7 @@
 
 #include "ProfilingTests.hpp"
 
+#include <backends/BackendProfiling.hpp>
 #include <CommandHandler.hpp>
 #include <CommandHandlerKey.hpp>
 #include <CommandHandlerRegistry.hpp>
@@ -20,6 +21,7 @@
 #include <PeriodicCounterSelectionCommandHandler.hpp>
 #include <ProfilingStateMachine.hpp>
 #include <ProfilingUtils.hpp>
+#include <RegisterBackendCounters.hpp>
 #include <RequestCounterDirectoryCommandHandler.hpp>
 #include <Runtime.hpp>
 #include <SocketProfilingConnection.hpp>
@@ -40,7 +42,7 @@
 #include <limits>
 #include <map>
 #include <random>
-#include <RegisterBackendCounters.hpp>
+
 
 using namespace armnn::profiling;
 using PacketType = MockProfilingConnection::PacketType;
@@ -3259,4 +3261,141 @@
     profilingService.ResetExternalProfilingOptions(options, true);
 }
 
+BOOST_AUTO_TEST_CASE(CheckCounterStatusQuery)
+{
+    armnn::IRuntime::CreationOptions options;
+    options.m_ProfilingOptions.m_EnableProfiling = true;
+
+    // Reset the profiling service to the uninitialized state
+    ProfilingService& profilingService = ProfilingService::Instance();
+    profilingService.ResetExternalProfilingOptions(options.m_ProfilingOptions, true);
+
+    const armnn::BackendId cpuRefId(armnn::Compute::CpuRef);
+    const armnn::BackendId cpuAccId(armnn::Compute::CpuAcc);
+
+    // Create BackendProfiling for each backend
+    BackendProfiling backendProfilingCpuRef(options, profilingService, cpuRefId);
+    BackendProfiling backendProfilingCpuAcc(options, profilingService, cpuAccId);
+
+    uint16_t initialNumGlobalCounterIds = armnn::profiling::INFERENCES_RUN;
+
+    // Create RegisterBackendCounters for CpuRef
+    RegisterBackendCounters registerBackendCountersCpuRef(initialNumGlobalCounterIds, cpuRefId);
+
+    // Create 'testCategory' in CounterDirectory (backend agnostic)
+    BOOST_CHECK(profilingService.GetCounterDirectory().GetCategories().empty());
+    registerBackendCountersCpuRef.RegisterCategory("testCategory");
+    auto categoryOnePtr = profilingService.GetCounterDirectory().GetCategory("testCategory");
+    BOOST_CHECK(categoryOnePtr);
+
+    // Counters:
+    // Global | Local | Backend
+    //    5   |   0   | CpuRef
+    //    6   |   1   | CpuRef
+    //    7   |   1   | CpuAcc
+
+    std::vector<uint16_t> cpuRefCounters = {0, 1};
+    std::vector<uint16_t> cpuAccCounters = {0};
+
+    // Register the backend counters for CpuRef and validate GetGlobalId and GetBackendId
+    uint16_t currentNumGlobalCounterIds = registerBackendCountersCpuRef.RegisterCounter(
+            0, "testCategory", 0, 0, 1.f, "CpuRefCounter0", "Zeroth CpuRef Counter");
+    BOOST_CHECK(currentNumGlobalCounterIds == initialNumGlobalCounterIds + 1);
+    uint16_t mappedGlobalId = profilingService.GetCounterMappings().GetGlobalId(0, cpuRefId);
+    BOOST_CHECK(mappedGlobalId == currentNumGlobalCounterIds);
+    auto backendMapping = profilingService.GetCounterMappings().GetBackendId(currentNumGlobalCounterIds);
+    BOOST_CHECK(backendMapping.first == 0);
+    BOOST_CHECK(backendMapping.second == cpuRefId);
+
+    currentNumGlobalCounterIds = registerBackendCountersCpuRef.RegisterCounter(
+            1, "testCategory", 0, 0, 1.f, "CpuRefCounter1", "First CpuRef Counter");
+    BOOST_CHECK(currentNumGlobalCounterIds == initialNumGlobalCounterIds + 2);
+    mappedGlobalId = profilingService.GetCounterMappings().GetGlobalId(1, cpuRefId);
+    BOOST_CHECK(mappedGlobalId == currentNumGlobalCounterIds);
+    backendMapping = profilingService.GetCounterMappings().GetBackendId(currentNumGlobalCounterIds);
+    BOOST_CHECK(backendMapping.first == 1);
+    BOOST_CHECK(backendMapping.second == cpuRefId);
+
+    // Create RegisterBackendCounters for CpuAcc
+    RegisterBackendCounters registerBackendCountersCpuAcc(currentNumGlobalCounterIds, cpuAccId);
+
+    // Register the backend counter for CpuAcc and validate GetGlobalId and GetBackendId
+    currentNumGlobalCounterIds = registerBackendCountersCpuAcc.RegisterCounter(
+            0, "testCategory", 0, 0, 1.f, "CpuAccCounter0", "Zeroth CpuAcc Counter");
+    BOOST_CHECK(currentNumGlobalCounterIds == initialNumGlobalCounterIds + 3);
+    mappedGlobalId = profilingService.GetCounterMappings().GetGlobalId(0, cpuAccId);
+    BOOST_CHECK(mappedGlobalId == currentNumGlobalCounterIds);
+    backendMapping = profilingService.GetCounterMappings().GetBackendId(currentNumGlobalCounterIds);
+    BOOST_CHECK(backendMapping.first == 0);
+    BOOST_CHECK(backendMapping.second == cpuAccId);
+
+    // Create vectors for active counters
+    const std::vector<uint16_t> activeGlobalCounterIds = {5}; // CpuRef(0) activated
+    const std::vector<uint16_t> newActiveGlobalCounterIds = {6, 7}; // CpuRef(0) and CpuAcc(1) activated
+
+    const uint32_t capturePeriod = 200;
+    const uint32_t newCapturePeriod = 100;
+
+    // Set capture period and active counters in CaptureData
+    profilingService.SetCaptureData(capturePeriod, activeGlobalCounterIds);
+
+    // Get vector of active counters for CpuRef and CpuAcc backends
+    std::vector<CounterStatus> cpuRefCounterStatus = backendProfilingCpuRef.GetActiveCounters();
+    std::vector<CounterStatus> cpuAccCounterStatus = backendProfilingCpuAcc.GetActiveCounters();
+    BOOST_CHECK_EQUAL(cpuRefCounterStatus.size(), 1);
+    BOOST_CHECK_EQUAL(cpuAccCounterStatus.size(), 0);
+
+    // Check active CpuRef counter
+    BOOST_CHECK_EQUAL(cpuRefCounterStatus[0].m_GlobalCounterId, activeGlobalCounterIds[0]);
+    BOOST_CHECK_EQUAL(cpuRefCounterStatus[0].m_BackendCounterId, cpuRefCounters[0]);
+    BOOST_CHECK_EQUAL(cpuRefCounterStatus[0].m_SamplingRateInMicroseconds, capturePeriod);
+    BOOST_CHECK_EQUAL(cpuRefCounterStatus[0].m_Enabled, true);
+
+    // Check inactive CpuRef counter
+    CounterStatus inactiveCpuRefCounter = backendProfilingCpuRef.GetCounterStatus(cpuRefCounters[1]);
+    BOOST_CHECK_EQUAL(inactiveCpuRefCounter.m_GlobalCounterId, 6);
+    BOOST_CHECK_EQUAL(inactiveCpuRefCounter.m_BackendCounterId, cpuRefCounters[1]);
+    BOOST_CHECK_EQUAL(inactiveCpuRefCounter.m_SamplingRateInMicroseconds, 0);
+    BOOST_CHECK_EQUAL(inactiveCpuRefCounter.m_Enabled, false);
+
+    // Check inactive CpuAcc counter
+    CounterStatus inactiveCpuAccCounter = backendProfilingCpuAcc.GetCounterStatus(cpuAccCounters[0]);
+    BOOST_CHECK_EQUAL(inactiveCpuAccCounter.m_GlobalCounterId, 7);
+    BOOST_CHECK_EQUAL(inactiveCpuAccCounter.m_BackendCounterId, cpuAccCounters[0]);
+    BOOST_CHECK_EQUAL(inactiveCpuAccCounter.m_SamplingRateInMicroseconds, 0);
+    BOOST_CHECK_EQUAL(inactiveCpuAccCounter.m_Enabled, false);
+
+    // Set new capture period and new active counters in CaptureData
+    profilingService.SetCaptureData(newCapturePeriod, newActiveGlobalCounterIds);
+
+    // Get vector of active counters for CpuRef and CpuAcc backends
+    cpuRefCounterStatus = backendProfilingCpuRef.GetActiveCounters();
+    cpuAccCounterStatus = backendProfilingCpuAcc.GetActiveCounters();
+    BOOST_CHECK_EQUAL(cpuRefCounterStatus.size(), 1);
+    BOOST_CHECK_EQUAL(cpuAccCounterStatus.size(), 1);
+
+    // Check active CpuRef counter
+    BOOST_CHECK_EQUAL(cpuRefCounterStatus[0].m_GlobalCounterId, newActiveGlobalCounterIds[0]);
+    BOOST_CHECK_EQUAL(cpuRefCounterStatus[0].m_BackendCounterId, cpuRefCounters[1]);
+    BOOST_CHECK_EQUAL(cpuRefCounterStatus[0].m_SamplingRateInMicroseconds, newCapturePeriod);
+    BOOST_CHECK_EQUAL(cpuRefCounterStatus[0].m_Enabled, true);
+
+    // Check active CpuAcc counter
+    BOOST_CHECK_EQUAL(cpuAccCounterStatus[0].m_GlobalCounterId, newActiveGlobalCounterIds[1]);
+    BOOST_CHECK_EQUAL(cpuAccCounterStatus[0].m_BackendCounterId, cpuAccCounters[0]);
+    BOOST_CHECK_EQUAL(cpuAccCounterStatus[0].m_SamplingRateInMicroseconds, newCapturePeriod);
+    BOOST_CHECK_EQUAL(cpuAccCounterStatus[0].m_Enabled, true);
+
+    // Check inactive CpuRef counter
+    inactiveCpuRefCounter = backendProfilingCpuRef.GetCounterStatus(cpuRefCounters[0]);
+    BOOST_CHECK_EQUAL(inactiveCpuRefCounter.m_GlobalCounterId, 5);
+    BOOST_CHECK_EQUAL(inactiveCpuRefCounter.m_BackendCounterId, cpuRefCounters[0]);
+    BOOST_CHECK_EQUAL(inactiveCpuRefCounter.m_SamplingRateInMicroseconds, 0);
+    BOOST_CHECK_EQUAL(inactiveCpuRefCounter.m_Enabled, false);
+
+    // Reset the profiling service to stop any running thread
+    options.m_ProfilingOptions.m_EnableProfiling = false;
+    profilingService.ResetExternalProfilingOptions(options.m_ProfilingOptions, true);
+}
+
 BOOST_AUTO_TEST_SUITE_END()