IVGCVSW-3411 Add the Counter Values array and accessor methods

Signed-off-by: FinnWilliamsArm <Finn.Williams@arm.com>
Change-Id: I4fa2428a83b93cbe58b821344206e2f7ce9e37e7
diff --git a/src/profiling/CounterValues.hpp b/src/profiling/CounterValues.hpp
new file mode 100644
index 0000000..75ecad9
--- /dev/null
+++ b/src/profiling/CounterValues.hpp
@@ -0,0 +1,38 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <cstdint>
+
+namespace armnn
+{
+
+namespace profiling
+{
+
+class IReadCounterValues
+{
+public:
+    virtual uint16_t GetCounterCount() const = 0;
+    virtual void GetCounterValue(uint16_t index, uint32_t& value) const = 0;
+    virtual ~IReadCounterValues() {}
+};
+
+class IWriteCounterValues : public IReadCounterValues
+{
+public:
+    virtual void SetCounterValue(uint16_t index, uint32_t value) = 0;
+    virtual void AddCounterValue(uint16_t index, uint32_t value) = 0;
+    virtual void SubtractCounterValue(uint16_t index, uint32_t value) = 0;
+    virtual void IncrementCounterValue(uint16_t index) = 0;
+    virtual void DecrementCounterValue(uint16_t index) = 0;
+    virtual ~IWriteCounterValues() {}
+};
+
+} // namespace profiling
+
+} // namespace armnn
+
+
diff --git a/src/profiling/ProfilingService.cpp b/src/profiling/ProfilingService.cpp
index 4e61383..9f59788 100644
--- a/src/profiling/ProfilingService.cpp
+++ b/src/profiling/ProfilingService.cpp
@@ -43,6 +43,11 @@
                                            "counter name 2",
                                            "counter description");
 
+        for (unsigned short i = 0; i < m_CounterDirectory.GetCounterCount(); ++i)
+        {
+            m_CounterIdToValue[i] = 0;
+        }
+
         // For now until CounterDirectory setup is implemented, change m_State once everything initialised
         m_State.TransitionToState(ProfilingState::NotConnected);
     }
@@ -70,6 +75,47 @@
     return m_CounterDirectory;
 }
 
+void ProfilingService::SetCounterValue(uint16_t counterIndex, uint32_t value)
+{
+    CheckIndexSize(counterIndex);
+    m_CounterIdToValue.at(counterIndex).store(value, std::memory_order::memory_order_relaxed);
+}
+
+void ProfilingService::GetCounterValue(uint16_t counterIndex, uint32_t& value) const
+{
+    CheckIndexSize(counterIndex);
+    value = m_CounterIdToValue.at(counterIndex).load(std::memory_order::memory_order_relaxed);
+}
+
+void ProfilingService::AddCounterValue(uint16_t counterIndex, uint32_t value)
+{
+    CheckIndexSize(counterIndex);
+    m_CounterIdToValue.at(counterIndex).fetch_add(value, std::memory_order::memory_order_relaxed);
+}
+
+void ProfilingService::SubtractCounterValue(uint16_t counterIndex, uint32_t value)
+{
+    CheckIndexSize(counterIndex);
+    m_CounterIdToValue.at(counterIndex).fetch_sub(value, std::memory_order::memory_order_relaxed);
+}
+
+void ProfilingService::IncrementCounterValue(uint16_t counterIndex)
+{
+    CheckIndexSize(counterIndex);
+    m_CounterIdToValue.at(counterIndex).operator++(std::memory_order::memory_order_relaxed);
+}
+
+void ProfilingService::DecrementCounterValue(uint16_t counterIndex)
+{
+    CheckIndexSize(counterIndex);
+    m_CounterIdToValue.at(counterIndex).operator--(std::memory_order::memory_order_relaxed);
+}
+
+uint16_t ProfilingService::GetCounterCount() const
+{
+    return m_CounterDirectory.GetCounterCount();
+}
+
 ProfilingState ProfilingService::GetCurrentState() const
 {
     return m_State.GetCurrentState();
@@ -85,6 +131,15 @@
     }
     m_Options = options;
 }
+
+inline void ProfilingService::CheckIndexSize(uint16_t counterIndex) const
+{
+    if (counterIndex >= m_CounterDirectory.GetCounterCount())
+    {
+        throw InvalidArgumentException("Counter index is out of range");
+    }
+}
+
 } // namespace profiling
 
 } // namespace armnn
\ No newline at end of file
diff --git a/src/profiling/ProfilingService.hpp b/src/profiling/ProfilingService.hpp
index eb29c33..6d61797 100644
--- a/src/profiling/ProfilingService.hpp
+++ b/src/profiling/ProfilingService.hpp
@@ -8,6 +8,7 @@
 #include "ProfilingStateMachine.hpp"
 #include "ProfilingConnectionFactory.hpp"
 #include "CounterDirectory.hpp"
+#include "CounterValues.hpp"
 
 namespace armnn
 {
@@ -15,7 +16,7 @@
 namespace profiling
 {
 
-class ProfilingService
+class ProfilingService : IWriteCounterValues
 {
 public:
     ProfilingService(const Runtime::CreationOptions::ExternalProfilingOptions& options);
@@ -27,13 +28,24 @@
     ProfilingState GetCurrentState() const;
     void ResetExternalProfilingOptions(const Runtime::CreationOptions::ExternalProfilingOptions& options);
 
+    uint16_t GetCounterCount() const;
+    void GetCounterValue(uint16_t index, uint32_t& value) const;
+    void SetCounterValue(uint16_t index, uint32_t value);
+    void AddCounterValue(uint16_t index, uint32_t value);
+    void SubtractCounterValue(uint16_t index, uint32_t value);
+    void IncrementCounterValue(uint16_t index);
+    void DecrementCounterValue(uint16_t index);
+
 private:
     void Initialise();
+    void CheckIndexSize(uint16_t counterIndex) const;
 
     CounterDirectory m_CounterDirectory;
     ProfilingConnectionFactory m_Factory;
     Runtime::CreationOptions::ExternalProfilingOptions m_Options;
     ProfilingStateMachine m_State;
+
+    std::unordered_map<uint16_t, std::atomic<uint32_t>> m_CounterIdToValue;
 };
 
 } // namespace profiling
diff --git a/src/profiling/test/ProfilingTests.cpp b/src/profiling/test/ProfilingTests.cpp
index 48723db..b90d469 100644
--- a/src/profiling/test/ProfilingTests.cpp
+++ b/src/profiling/test/ProfilingTests.cpp
@@ -702,6 +702,38 @@
     BOOST_CHECK(counterDirectory1.GetCounterCount() != 0);
 }
 
+BOOST_AUTO_TEST_CASE(CheckProfilingServiceCounterValues)
+{
+    armnn::Runtime::CreationOptions::ExternalProfilingOptions options;
+    options.m_EnableProfiling = true;
+    ProfilingService profilingService(options);
+
+    ProfilingService* profilingServicePtr = &profilingService;
+    std::vector<std::thread> writers;
+
+    for(int i = 0; i < 100 ; ++i)
+    {
+        // Increment and decrement counter 0
+        writers.push_back(std::thread(&ProfilingService::IncrementCounterValue, profilingServicePtr, 0));
+        writers.push_back(std::thread(&ProfilingService::DecrementCounterValue, profilingServicePtr, 0));
+        // Add 10 to counter 0 and subtract 5 from counter 0
+        writers.push_back(std::thread(&ProfilingService::AddCounterValue, profilingServicePtr, 0, 10));
+        writers.push_back(std::thread(&ProfilingService::SubtractCounterValue, profilingServicePtr, 0, 5));
+    }
+
+    std::for_each(writers.begin(), writers.end(), mem_fn(&std::thread::join));
+
+    uint32_t counterValue;
+    profilingService.GetCounterValue(0, counterValue);
+    BOOST_CHECK(counterValue == 500);
+
+    profilingService.SetCounterValue(0, 0);
+    profilingService.GetCounterValue(0, counterValue);
+    BOOST_CHECK(counterValue == 0);
+
+    BOOST_CHECK_THROW(profilingService.SetCounterValue(profilingService.GetCounterCount(), 1), armnn::Exception);
+}
+
 BOOST_AUTO_TEST_CASE(CheckProfilingObjectUids)
 {
     uint16_t uid = 0;