IVGCVSW-3902 Create IReadOnlyPacketBuffer, IPacketBuffer and IBufferManager interfaces

 * Create IReadOnlyPacketBuffer, IPacketBuffer and IBufferManager interfaces
 * Add Read and Write util functions that use IPacketBuffer
 * Add MockBufferManager using IBufferManager for testing
 * Modify SendCounterPacket to use IBufferManager
 * Modify MockStreamCounterBuffer to use IBufferManager
 * Remove IBufferWrapper and MockBuffer
 * Add MockPacketBuffer for testing
 * Modify unit tests to use the new interfaces

Signed-off-by: Narumol Prangnawarat <narumol.prangnawarat@arm.com>
Change-Id: Ib86768187e032f07169aa39367a418b7665c9f03
diff --git a/src/profiling/IBufferManager.hpp b/src/profiling/IBufferManager.hpp
new file mode 100644
index 0000000..190d9c4
--- /dev/null
+++ b/src/profiling/IBufferManager.hpp
@@ -0,0 +1,36 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "IPacketBuffer.hpp"
+
+#include <memory>
+
+namespace armnn
+{
+
+namespace profiling
+{
+
+class IBufferManager
+{
+public:
+    virtual ~IBufferManager() {};
+
+    virtual std::unique_ptr<IPacketBuffer> Reserve(unsigned int requestedSize, unsigned int& reservedSize) = 0;
+
+    virtual void Commit(std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int size) = 0;
+
+    virtual void Release(std::unique_ptr<IPacketBuffer>& packetBuffer) = 0;
+
+    virtual std::unique_ptr<IPacketBuffer> GetReadableBuffer() = 0;
+
+    virtual void MarkRead(std::unique_ptr<IPacketBuffer>& packetBuffer) = 0;
+};
+
+} // namespace profiling
+
+} // namespace armnn
diff --git a/src/profiling/IBufferWrapper.hpp b/src/profiling/IBufferWrapper.hpp
deleted file mode 100644
index 9c38ab1..0000000
--- a/src/profiling/IBufferWrapper.hpp
+++ /dev/null
@@ -1,30 +0,0 @@
-//
-// Copyright © 2017 Arm Ltd. All rights reserved.
-// SPDX-License-Identifier: MIT
-//
-
-#pragma once
-
-namespace armnn
-{
-
-namespace profiling
-{
-
-class IBufferWrapper
-{
-public:
-    virtual ~IBufferWrapper() {}
-
-    virtual unsigned char* Reserve(unsigned int requestedSize, unsigned int& reservedSize) = 0;
-
-    virtual void Commit(unsigned int size) = 0;
-
-    virtual const unsigned char* GetReadBuffer(unsigned int& size) = 0;
-
-    virtual void Release(unsigned int size) = 0;
-};
-
-} // namespace profiling
-
-} // namespace armnn
diff --git a/src/profiling/IPacketBuffer.hpp b/src/profiling/IPacketBuffer.hpp
new file mode 100644
index 0000000..b4bd615
--- /dev/null
+++ b/src/profiling/IPacketBuffer.hpp
@@ -0,0 +1,40 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+namespace armnn
+{
+
+namespace profiling
+{
+
+class IReadOnlyPacketBuffer // interface used by the read thread
+{
+public:
+    virtual ~IReadOnlyPacketBuffer() {}
+
+    virtual const unsigned char* const GetReadableData() const = 0;
+
+    virtual unsigned int GetSize() const = 0;
+
+    virtual void MarkRead() = 0;
+};
+
+class IPacketBuffer : public IReadOnlyPacketBuffer // interface used by code that writes binary packets
+{
+public:
+    virtual ~IPacketBuffer() {}
+
+    virtual void Commit(unsigned int size) = 0;
+
+    virtual void Release() = 0;
+
+    virtual unsigned char* GetWritableData() = 0;
+};
+
+} // namespace profiling
+
+} // namespace armnn
\ No newline at end of file
diff --git a/src/profiling/ProfilingUtils.cpp b/src/profiling/ProfilingUtils.cpp
index 7a8c678..588fcc1 100644
--- a/src/profiling/ProfilingUtils.cpp
+++ b/src/profiling/ProfilingUtils.cpp
@@ -87,6 +87,27 @@
     return counterUids;
 }
 
+void WriteUint64(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset, uint64_t value)
+{
+    BOOST_ASSERT(packetBuffer);
+
+    WriteUint64(packetBuffer->GetWritableData(), offset, value);
+}
+
+void WriteUint32(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset, uint32_t value)
+{
+    BOOST_ASSERT(packetBuffer);
+
+    WriteUint32(packetBuffer->GetWritableData(), offset, value);
+}
+
+void WriteUint16(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset, uint16_t value)
+{
+    BOOST_ASSERT(packetBuffer);
+
+    WriteUint16(packetBuffer->GetWritableData(), offset, value);
+}
+
 void WriteUint64(unsigned char* buffer, unsigned int offset, uint64_t value)
 {
     BOOST_ASSERT(buffer);
@@ -119,6 +140,34 @@
     buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
 }
 
+uint64_t ReadUint64(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset)
+{
+    BOOST_ASSERT(packetBuffer);
+
+    return ReadUint64(packetBuffer->GetReadableData(), offset);
+}
+
+uint32_t ReadUint32(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset)
+{
+    BOOST_ASSERT(packetBuffer);
+
+    return ReadUint32(packetBuffer->GetReadableData(), offset);
+}
+
+uint16_t ReadUint16(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset)
+{
+    BOOST_ASSERT(packetBuffer);
+
+    return ReadUint16(packetBuffer->GetReadableData(), offset);
+}
+
+uint8_t ReadUint8(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset)
+{
+    BOOST_ASSERT(packetBuffer);
+
+    return ReadUint8(packetBuffer->GetReadableData(), offset);
+}
+
 uint64_t ReadUint64(const unsigned char* buffer, unsigned int offset)
 {
     BOOST_ASSERT(buffer);
diff --git a/src/profiling/ProfilingUtils.hpp b/src/profiling/ProfilingUtils.hpp
index fa96eea..09b04f1 100644
--- a/src/profiling/ProfilingUtils.hpp
+++ b/src/profiling/ProfilingUtils.hpp
@@ -7,12 +7,15 @@
 
 #include <armnn/Exceptions.hpp>
 
+#include "IPacketBuffer.hpp"
+
 #include <boost/numeric/conversion/cast.hpp>
 
-#include <string>
-#include <vector>
 #include <algorithm>
 #include <cstring>
+#include <memory>
+#include <string>
+#include <vector>
 
 namespace armnn
 {
@@ -80,19 +83,33 @@
 
 std::vector<uint16_t> GetNextCounterUids(uint16_t cores);
 
+void WriteUint64(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset, uint64_t value);
+
+void WriteUint32(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset, uint32_t value);
+
+void WriteUint16(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset, uint16_t value);
+
 void WriteUint64(unsigned char* buffer, unsigned int offset, uint64_t value);
 
 void WriteUint32(unsigned char* buffer, unsigned int offset, uint32_t value);
 
 void WriteUint16(unsigned char* buffer, unsigned int offset, uint16_t value);
 
-uint64_t ReadUint64(const unsigned char* buffer, unsigned int offset);
+uint64_t ReadUint64(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset);
 
-uint32_t ReadUint32(const unsigned char* buffer, unsigned int offset);
+uint32_t ReadUint32(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset);
 
-uint16_t ReadUint16(const unsigned char* buffer, unsigned int offset);
+uint16_t ReadUint16(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset);
 
-uint8_t ReadUint8(const unsigned char* buffer, unsigned int offset);
+uint8_t ReadUint8(const std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int offset);
+
+uint64_t ReadUint64(unsigned const char* buffer, unsigned int offset);
+
+uint32_t ReadUint32(unsigned const char* buffer, unsigned int offset);
+
+uint16_t ReadUint16(unsigned const char* buffer, unsigned int offset);
+
+uint8_t ReadUint8(unsigned const char* buffer, unsigned int offset);
 
 std::string GetSoftwareInfo();
 
diff --git a/src/profiling/SendCounterPacket.cpp b/src/profiling/SendCounterPacket.cpp
index b222270..33eaeab 100644
--- a/src/profiling/SendCounterPacket.cpp
+++ b/src/profiling/SendCounterPacket.cpp
@@ -65,11 +65,12 @@
     uint32_t offset = 0;
     uint32_t reserved = 0;
 
-    unsigned char *writeBuffer = m_Buffer.Reserve(totalSize, reserved);
+    std::unique_ptr<IPacketBuffer> writeBuffer = m_BufferManager.Reserve(totalSize, reserved);
 
     if (reserved < totalSize)
     {
         CancelOperationAndThrow<BufferExhaustion>(
+                    writeBuffer,
                     boost::str(boost::format("No space left in buffer. Unable to reserve (%1%) bytes.")
                                % totalSize));
     }
@@ -120,25 +121,25 @@
 
         if (infoSize)
         {
-            memcpy(&writeBuffer[offset], info.c_str(), infoSize);
+            memcpy(&writeBuffer->GetWritableData()[offset], info.c_str(), infoSize);
             offset += infoSize;
         }
 
         if (hardwareVersionSize)
         {
-            memcpy(&writeBuffer[offset], hardwareVersion.c_str(), hardwareVersionSize);
+            memcpy(&writeBuffer->GetWritableData()[offset], hardwareVersion.c_str(), hardwareVersionSize);
             offset += hardwareVersionSize;
         }
 
         if (softwareVersionSize)
         {
-            memcpy(&writeBuffer[offset], softwareVersion.c_str(), softwareVersionSize);
+            memcpy(&writeBuffer->GetWritableData()[offset], softwareVersion.c_str(), softwareVersionSize);
             offset += softwareVersionSize;
         }
 
         if (processNameSize)
         {
-            memcpy(&writeBuffer[offset], processName.c_str(), processNameSize);
+            memcpy(&writeBuffer->GetWritableData()[offset], processName.c_str(), processNameSize);
             offset += processNameSize;
         }
 
@@ -170,10 +171,10 @@
     }
     catch(...)
     {
-        CancelOperationAndThrow<RuntimeException>("Error processing packet.");
+        CancelOperationAndThrow<RuntimeException>(writeBuffer, "Error processing packet.");
     }
 
-    m_Buffer.Commit(totalSize);
+    m_BufferManager.Commit(writeBuffer, totalSize);
 }
 
 bool SendCounterPacket::CreateCategoryRecord(const CategoryPtr& category,
@@ -792,12 +793,13 @@
 
     // Reserve space in the buffer for the packet
     uint32_t reserved = 0;
-    unsigned char* writeBuffer = m_Buffer.Reserve(totalSize, reserved);
+    std::unique_ptr<IPacketBuffer> writeBuffer = m_BufferManager.Reserve(totalSize, reserved);
 
     // Check that the reserved buffer size is enough to hold the counter directory packet
     if (reserved < totalSize)
     {
         CancelOperationAndThrow<BufferExhaustion>(
+                    writeBuffer,
                     boost::str(boost::format("No space left in buffer. Unable to reserve (%1%) bytes")
                                % totalSize));
     }
@@ -818,7 +820,7 @@
         offset += numeric_cast<uint32_t>(uint32_t_size);
     }
 
-    m_Buffer.Commit(totalSize);
+    m_BufferManager.Commit(writeBuffer, totalSize);
 }
 
 void SendCounterPacket::SendPeriodicCounterCapturePacket(uint64_t timestamp, const IndexValuePairsVector& values)
@@ -833,11 +835,12 @@
     uint32_t offset = 0;
     uint32_t reserved = 0;
 
-    unsigned char* writeBuffer = m_Buffer.Reserve(totalSize, reserved);
+    std::unique_ptr<IPacketBuffer> writeBuffer = m_BufferManager.Reserve(totalSize, reserved);
 
     if (reserved < totalSize)
     {
         CancelOperationAndThrow<BufferExhaustion>(
+                    writeBuffer,
                     boost::str(boost::format("No space left in buffer. Unable to reserve (%1%) bytes.")
                                % totalSize));
     }
@@ -868,7 +871,7 @@
         offset += numeric_cast<uint32_t>(sizeof(uint32_t));
     }
 
-    m_Buffer.Commit(totalSize);
+    m_BufferManager.Commit(writeBuffer, totalSize);
 }
 
 void SendCounterPacket::SendPeriodicCounterSelectionPacket(uint32_t capturePeriod,
@@ -883,11 +886,12 @@
     uint32_t offset = 0;
     uint32_t reserved = 0;
 
-    unsigned char* writeBuffer = m_Buffer.Reserve(totalSize, reserved);
+    std::unique_ptr<IPacketBuffer> writeBuffer = m_BufferManager.Reserve(totalSize, reserved);
 
     if (reserved < totalSize)
     {
         CancelOperationAndThrow<BufferExhaustion>(
+                    writeBuffer,
                     boost::str(boost::format("No space left in buffer. Unable to reserve (%1%) bytes.")
                                % totalSize));
     }
@@ -914,7 +918,7 @@
         offset += numeric_cast<uint32_t>(sizeof(uint16_t));
     }
 
-    m_Buffer.Commit(totalSize);
+    m_BufferManager.Commit(writeBuffer, totalSize);
 }
 
 void SendCounterPacket::SetReadyToRead()
@@ -973,9 +977,17 @@
         }
         // Wait condition lock scope - End
 
+
+
+        std::unique_ptr<IPacketBuffer> packetBuffer = m_BufferManager.GetReadableBuffer();
+        if (packetBuffer == nullptr)
+        {
+            continue;
+        }
+        const unsigned char* readBuffer = packetBuffer->GetReadableData();
         // Get the data to send from the buffer
-        unsigned int readBufferSize = 0;
-        const unsigned char* readBuffer = m_Buffer.GetReadBuffer(readBufferSize);
+        unsigned int readBufferSize = packetBuffer->GetSize();
+
         if (readBuffer == nullptr || readBufferSize == 0)
         {
             // Nothing to send, ignore and continue
@@ -988,6 +1000,8 @@
             // Write a packet to the profiling connection. Silently ignore any write error and continue
             m_ProfilingConnection.WritePacket(readBuffer, boost::numeric_cast<uint32_t>(readBufferSize));
         }
+
+        m_BufferManager.MarkRead(packetBuffer);
     }
 
     // Mark the send thread as not running
diff --git a/src/profiling/SendCounterPacket.hpp b/src/profiling/SendCounterPacket.hpp
index 8dd44ec..c57546d 100644
--- a/src/profiling/SendCounterPacket.hpp
+++ b/src/profiling/SendCounterPacket.hpp
@@ -5,7 +5,7 @@
 
 #pragma once
 
-#include "IBufferWrapper.hpp"
+#include "IBufferManager.hpp"
 #include "ISendCounterPacket.hpp"
 #include "ICounterDirectory.hpp"
 #include "IProfilingConnection.hpp"
@@ -31,9 +31,9 @@
 
     using IndexValuePairsVector = std::vector<std::pair<uint16_t, uint32_t>>;
 
-    SendCounterPacket(IProfilingConnection& profilingConnection, IBufferWrapper& buffer)
+    SendCounterPacket(IProfilingConnection& profilingConnection, IBufferManager& buffer)
         : m_ProfilingConnection(profilingConnection)
-        , m_Buffer(buffer)
+        , m_BufferManager(buffer)
         , m_IsRunning(false)
         , m_KeepRunning(false)
     {}
@@ -63,15 +63,25 @@
     template <typename ExceptionType>
     void CancelOperationAndThrow(const std::string& errorMessage)
     {
-        // Cancel the operation
-        m_Buffer.Commit(0);
+        // Throw a runtime exception with the given error message
+        throw ExceptionType(errorMessage);
+    }
+
+    template <typename ExceptionType>
+    void CancelOperationAndThrow(std::unique_ptr<IPacketBuffer>& writerBuffer, const std::string& errorMessage)
+    {
+        if (writerBuffer != nullptr)
+        {
+            // Cancel the operation
+            m_BufferManager.Release(writerBuffer);
+        }
 
         // Throw a runtime exception with the given error message
         throw ExceptionType(errorMessage);
     }
 
     IProfilingConnection& m_ProfilingConnection;
-    IBufferWrapper& m_Buffer;
+    IBufferManager& m_BufferManager;
     std::mutex m_WaitMutex;
     std::condition_variable m_WaitCondition;
     std::thread m_SendThread;
diff --git a/src/profiling/test/ProfilingTests.cpp b/src/profiling/test/ProfilingTests.cpp
index 1741160..a474c30 100644
--- a/src/profiling/test/ProfilingTests.cpp
+++ b/src/profiling/test/ProfilingTests.cpp
@@ -1756,7 +1756,7 @@
     Holder holder;
     TestCaptureThread captureThread;
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(512);
+    MockBufferManager mockBuffer(512);
     SendCounterPacket sendCounterPacket(mockProfilingConnection, mockBuffer);
 
     uint32_t sizeOfUint32 = numeric_cast<uint32_t>(sizeof(uint32_t));
@@ -1789,9 +1789,7 @@
     BOOST_TEST(counterIds[0] == 4000);
     BOOST_TEST(counterIds[1] == 5000);
 
-    unsigned int size = 0;
-
-    const unsigned char* readBuffer = mockBuffer.GetReadBuffer(size);
+    auto readBuffer = mockBuffer.GetReadableBuffer();
 
     offset = 0;
 
@@ -1814,6 +1812,8 @@
     counterId = ReadUint16(readBuffer, offset);
     BOOST_TEST(counterId == 5000);
 
+    mockBuffer.MarkRead(readBuffer);
+
     // Data with period only
     uint32_t period2 = 11;
     uint32_t dataLength2 = 4;
@@ -1831,7 +1831,7 @@
     BOOST_TEST(holder.GetCaptureData().GetCapturePeriod() == period2);
     BOOST_TEST(counterIds.size() == 0);
 
-    readBuffer = mockBuffer.GetReadBuffer(size);
+    readBuffer = mockBuffer.GetReadableBuffer();
 
     offset = 0;
 
@@ -2115,7 +2115,7 @@
     std::vector<uint16_t> captureIds2;
 
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(512);
+    MockBufferManager mockBuffer(512);
     SendCounterPacket sendCounterPacket(mockProfilingConnection, mockBuffer);
 
     std::vector<uint16_t> counterIds;
@@ -2146,9 +2146,7 @@
 
     periodicCounterCapture.Join();
 
-    unsigned int size = 0;
-
-    const unsigned char* buffer = mockBuffer.GetReadBuffer(size);
+    auto buffer = mockBuffer.GetReadableBuffer();
 
     uint32_t headerWord0 = ReadUint32(buffer, 0);
     uint32_t headerWord1 = ReadUint32(buffer, 4);
@@ -2187,7 +2185,7 @@
     Packet packetA(packetId, 0, packetData);
 
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(1024);
+    MockBufferManager mockBuffer(1024);
     SendCounterPacket sendCounterPacket(mockProfilingConnection, mockBuffer);
 
     CounterDirectory counterDirectory;
@@ -2195,8 +2193,7 @@
     RequestCounterDirectoryCommandHandler commandHandler(packetId, version, counterDirectory, sendCounterPacket);
     commandHandler(packetA);
 
-    unsigned int size = 0;
-    const unsigned char* readBuffer = mockBuffer.GetReadBuffer(size);
+    auto readBuffer = mockBuffer.GetReadableBuffer();
 
     uint32_t headerWord0 = ReadUint32(readBuffer, 0);
     uint32_t headerWord1 = ReadUint32(readBuffer, 4);
@@ -2222,7 +2219,7 @@
     Packet packetA(packetId, 0, packetData);
 
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(1024);
+    MockBufferManager mockBuffer(1024);
     SendCounterPacket sendCounterPacket(mockProfilingConnection, mockBuffer);
 
     CounterDirectory counterDirectory;
@@ -2235,8 +2232,7 @@
     RequestCounterDirectoryCommandHandler commandHandler(packetId, version, counterDirectory, sendCounterPacket);
     commandHandler(packetA);
 
-    unsigned int size = 0;
-    const unsigned char* readBuffer = mockBuffer.GetReadBuffer(size);
+    auto readBuffer = mockBuffer.GetReadableBuffer();
 
     uint32_t headerWord0 = ReadUint32(readBuffer, 0);
     uint32_t headerWord1 = ReadUint32(readBuffer, 4);
diff --git a/src/profiling/test/SendCounterPacketTests.cpp b/src/profiling/test/SendCounterPacketTests.cpp
index 3dda2e7..9659606 100644
--- a/src/profiling/test/SendCounterPacketTests.cpp
+++ b/src/profiling/test/SendCounterPacketTests.cpp
@@ -20,57 +20,61 @@
 
 using namespace armnn::profiling;
 
-size_t GetDataLength(const MockStreamCounterBuffer& mockStreamCounterBuffer, size_t packetOffset)
-{
-    // The data length is the written in the second byte
-    return ReadUint32(mockStreamCounterBuffer.GetBuffer(),
-                      boost::numeric_cast<unsigned int>(packetOffset + sizeof(uint32_t)));
-}
-
-size_t GetPacketSize(const MockStreamCounterBuffer& mockStreamCounterBuffer, size_t packetOffset)
-{
-    // The packet size is the data length plus the size of the packet header (always two words big)
-    return GetDataLength(mockStreamCounterBuffer, packetOffset) + 2 * sizeof(uint32_t);
-}
-
 BOOST_AUTO_TEST_SUITE(SendCounterPacketTests)
 
 BOOST_AUTO_TEST_CASE(MockSendCounterPacketTest)
 {
-    unsigned int size = 0;
-
-    MockBuffer mockBuffer(512);
+    MockBufferManager mockBuffer(512);
     MockSendCounterPacket sendCounterPacket(mockBuffer);
 
     sendCounterPacket.SendStreamMetaDataPacket();
-    const char* buffer = reinterpret_cast<const char*>(mockBuffer.GetReadBuffer(size));
+
+    auto packetBuffer = mockBuffer.GetReadableBuffer();
+    const char* buffer = reinterpret_cast<const char*>(packetBuffer->GetReadableData());
 
     BOOST_TEST(strcmp(buffer, "SendStreamMetaDataPacket") == 0);
 
+    mockBuffer.MarkRead(packetBuffer);
+
     CounterDirectory counterDirectory;
     sendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
 
+    packetBuffer = mockBuffer.GetReadableBuffer();
+    buffer = reinterpret_cast<const char*>(packetBuffer->GetReadableData());
+
     BOOST_TEST(strcmp(buffer, "SendCounterDirectoryPacket") == 0);
 
+    mockBuffer.MarkRead(packetBuffer);
+
     uint64_t timestamp = 0;
     std::vector<std::pair<uint16_t, uint32_t>> indexValuePairs;
 
     sendCounterPacket.SendPeriodicCounterCapturePacket(timestamp, indexValuePairs);
 
+    packetBuffer = mockBuffer.GetReadableBuffer();
+    buffer = reinterpret_cast<const char*>(packetBuffer->GetReadableData());
+
     BOOST_TEST(strcmp(buffer, "SendPeriodicCounterCapturePacket") == 0);
 
+    mockBuffer.MarkRead(packetBuffer);
+
     uint32_t capturePeriod = 0;
     std::vector<uint16_t> selectedCounterIds;
     sendCounterPacket.SendPeriodicCounterSelectionPacket(capturePeriod, selectedCounterIds);
 
+    packetBuffer = mockBuffer.GetReadableBuffer();
+    buffer = reinterpret_cast<const char*>(packetBuffer->GetReadableData());
+
     BOOST_TEST(strcmp(buffer, "SendPeriodicCounterSelectionPacket") == 0);
+
+    mockBuffer.MarkRead(packetBuffer);
 }
 
 BOOST_AUTO_TEST_CASE(SendPeriodicCounterSelectionPacketTest)
 {
     // Error no space left in buffer
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer1(10);
+    MockBufferManager mockBuffer1(10);
     SendCounterPacket sendPacket1(mockProfilingConnection, mockBuffer1);
 
     uint32_t capturePeriod = 1000;
@@ -79,12 +83,11 @@
                       BufferExhaustion);
 
     // Packet without any counters
-    MockBuffer mockBuffer2(512);
+    MockBufferManager mockBuffer2(512);
     SendCounterPacket sendPacket2(mockProfilingConnection, mockBuffer2);
 
     sendPacket2.SendPeriodicCounterSelectionPacket(capturePeriod, selectedCounterIds);
-    unsigned int sizeRead = 0;
-    const unsigned char* readBuffer2 = mockBuffer2.GetReadBuffer(sizeRead);
+    auto readBuffer2 = mockBuffer2.GetReadableBuffer();
 
     uint32_t headerWord0 = ReadUint32(readBuffer2, 0);
     uint32_t headerWord1 = ReadUint32(readBuffer2, 4);
@@ -96,7 +99,7 @@
     BOOST_TEST(period == 1000);                     // capture period
 
     // Full packet message
-    MockBuffer mockBuffer3(512);
+    MockBufferManager mockBuffer3(512);
     SendCounterPacket sendPacket3(mockProfilingConnection, mockBuffer3);
 
     selectedCounterIds.reserve(5);
@@ -106,8 +109,7 @@
     selectedCounterIds.emplace_back(400);
     selectedCounterIds.emplace_back(500);
     sendPacket3.SendPeriodicCounterSelectionPacket(capturePeriod, selectedCounterIds);
-    sizeRead = 0;
-    const unsigned char* readBuffer3 = mockBuffer3.GetReadBuffer(sizeRead);
+    auto readBuffer3 = mockBuffer3.GetReadableBuffer();
 
     headerWord0 = ReadUint32(readBuffer3, 0);
     headerWord1 = ReadUint32(readBuffer3, 4);
@@ -134,7 +136,7 @@
 {
     // Error no space left in buffer
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer1(10);
+    MockBufferManager mockBuffer1(10);
     SendCounterPacket sendPacket1(mockProfilingConnection, mockBuffer1);
 
     auto captureTimestamp = std::chrono::steady_clock::now();
@@ -145,12 +147,11 @@
                       BufferExhaustion);
 
     // Packet without any counters
-    MockBuffer mockBuffer2(512);
+    MockBufferManager mockBuffer2(512);
     SendCounterPacket sendPacket2(mockProfilingConnection, mockBuffer2);
 
     sendPacket2.SendPeriodicCounterCapturePacket(time, indexValuePairs);
-    unsigned int sizeRead = 0;
-    const unsigned char* readBuffer2 = mockBuffer2.GetReadBuffer(sizeRead);
+    auto readBuffer2 = mockBuffer2.GetReadableBuffer();
 
     uint32_t headerWord0 = ReadUint32(readBuffer2, 0);
     uint32_t headerWord1 = ReadUint32(readBuffer2, 4);
@@ -163,7 +164,7 @@
     BOOST_TEST(time == readTimestamp);               // capture period
 
     // Full packet message
-    MockBuffer mockBuffer3(512);
+    MockBufferManager mockBuffer3(512);
     SendCounterPacket sendPacket3(mockProfilingConnection, mockBuffer3);
 
     indexValuePairs.reserve(5);
@@ -173,8 +174,7 @@
     indexValuePairs.emplace_back(std::make_pair<uint16_t, uint32_t >(3, 400));
     indexValuePairs.emplace_back(std::make_pair<uint16_t, uint32_t >(4, 500));
     sendPacket3.SendPeriodicCounterCapturePacket(time, indexValuePairs);
-    sizeRead = 0;
-    const unsigned char* readBuffer3 = mockBuffer3.GetReadBuffer(sizeRead);
+    auto readBuffer3 = mockBuffer3.GetReadableBuffer();
 
     headerWord0 = ReadUint32(readBuffer3, 0);
     headerWord1 = ReadUint32(readBuffer3, 4);
@@ -216,7 +216,7 @@
 
     // Error no space left in buffer
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer1(10);
+    MockBufferManager mockBuffer1(10);
     SendCounterPacket sendPacket1(mockProfilingConnection, mockBuffer1);
     BOOST_CHECK_THROW(sendPacket1.SendStreamMetaDataPacket(), armnn::profiling::BufferExhaustion);
 
@@ -235,11 +235,10 @@
 
     uint32_t packetEntries = 6;
 
-    MockBuffer mockBuffer2(512);
+    MockBufferManager mockBuffer2(512);
     SendCounterPacket sendPacket2(mockProfilingConnection, mockBuffer2);
     sendPacket2.SendStreamMetaDataPacket();
-    unsigned int sizeRead = 0;
-    const unsigned char* readBuffer2 = mockBuffer2.GetReadBuffer(sizeRead);
+    auto readBuffer2 = mockBuffer2.GetReadableBuffer();
 
     uint32_t headerWord0 = ReadUint32(readBuffer2, 0);
     uint32_t headerWord1 = ReadUint32(readBuffer2, sizeUint32);
@@ -279,28 +278,30 @@
     offset += sizeUint32;
     BOOST_TEST(ReadUint32(readBuffer2, offset) == 0); // reserved
 
+    const unsigned char* readData2 = readBuffer2->GetReadableData();
+
     offset += sizeUint32;
     if (infoSize)
     {
-        BOOST_TEST(strcmp(reinterpret_cast<const char *>(&readBuffer2[offset]), GetSoftwareInfo().c_str()) == 0);
+        BOOST_TEST(strcmp(reinterpret_cast<const char *>(&readData2[offset]), GetSoftwareInfo().c_str()) == 0);
         offset += infoSize;
     }
 
     if (hardwareVersionSize)
     {
-        BOOST_TEST(strcmp(reinterpret_cast<const char *>(&readBuffer2[offset]), GetHardwareVersion().c_str()) == 0);
+        BOOST_TEST(strcmp(reinterpret_cast<const char *>(&readData2[offset]), GetHardwareVersion().c_str()) == 0);
         offset += hardwareVersionSize;
     }
 
     if (softwareVersionSize)
     {
-        BOOST_TEST(strcmp(reinterpret_cast<const char *>(&readBuffer2[offset]), GetSoftwareVersion().c_str()) == 0);
+        BOOST_TEST(strcmp(reinterpret_cast<const char *>(&readData2[offset]), GetSoftwareVersion().c_str()) == 0);
         offset += softwareVersionSize;
     }
 
     if (processNameSize)
     {
-        BOOST_TEST(strcmp(reinterpret_cast<const char *>(&readBuffer2[offset]), GetProcessName().c_str()) == 0);
+        BOOST_TEST(strcmp(reinterpret_cast<const char *>(&readData2[offset]), GetProcessName().c_str()) == 0);
         offset += processNameSize;
     }
 
@@ -330,7 +331,7 @@
 BOOST_AUTO_TEST_CASE(CreateDeviceRecordTest)
 {
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(0);
+    MockBufferManager mockBuffer(0);
     SendCounterPacketTest sendCounterPacketTest(mockProfilingConnection, mockBuffer);
 
     // Create a device for testing
@@ -363,7 +364,7 @@
 BOOST_AUTO_TEST_CASE(CreateInvalidDeviceRecordTest)
 {
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(0);
+    MockBufferManager mockBuffer(0);
     SendCounterPacketTest sendCounterPacketTest(mockProfilingConnection, mockBuffer);
 
     // Create a device for testing
@@ -385,7 +386,7 @@
 BOOST_AUTO_TEST_CASE(CreateCounterSetRecordTest)
 {
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(0);
+    MockBufferManager mockBuffer(0);
     SendCounterPacketTest sendCounterPacketTest(mockProfilingConnection, mockBuffer);
 
     // Create a counter set for testing
@@ -418,7 +419,7 @@
 BOOST_AUTO_TEST_CASE(CreateInvalidCounterSetRecordTest)
 {
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(0);
+    MockBufferManager mockBuffer(0);
     SendCounterPacketTest sendCounterPacketTest(mockProfilingConnection, mockBuffer);
 
     // Create a counter set for testing
@@ -440,7 +441,7 @@
 BOOST_AUTO_TEST_CASE(CreateEventRecordTest)
 {
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(0);
+    MockBufferManager mockBuffer(0);
     SendCounterPacketTest sendCounterPacketTest(mockProfilingConnection, mockBuffer);
 
     // Create a counter for testing
@@ -561,7 +562,7 @@
 BOOST_AUTO_TEST_CASE(CreateEventRecordNoUnitsTest)
 {
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(0);
+    MockBufferManager mockBuffer(0);
     SendCounterPacketTest sendCounterPacketTest(mockProfilingConnection, mockBuffer);
 
     // Create a counter for testing
@@ -665,7 +666,7 @@
 BOOST_AUTO_TEST_CASE(CreateInvalidEventRecordTest1)
 {
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(0);
+    MockBufferManager mockBuffer(0);
     SendCounterPacketTest sendCounterPacketTest(mockProfilingConnection, mockBuffer);
 
     // Create a counter for testing
@@ -704,7 +705,7 @@
 BOOST_AUTO_TEST_CASE(CreateInvalidEventRecordTest2)
 {
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(0);
+    MockBufferManager mockBuffer(0);
     SendCounterPacketTest sendCounterPacketTest(mockProfilingConnection, mockBuffer);
 
     // Create a counter for testing
@@ -743,7 +744,7 @@
 BOOST_AUTO_TEST_CASE(CreateInvalidEventRecordTest3)
 {
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(0);
+    MockBufferManager mockBuffer(0);
     SendCounterPacketTest sendCounterPacketTest(mockProfilingConnection, mockBuffer);
 
     // Create a counter for testing
@@ -782,7 +783,7 @@
 BOOST_AUTO_TEST_CASE(CreateCategoryRecordTest)
 {
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(0);
+    MockBufferManager mockBuffer(0);
     SendCounterPacketTest sendCounterPacketTest(mockProfilingConnection, mockBuffer);
 
     // Create a category for testing
@@ -984,7 +985,7 @@
 BOOST_AUTO_TEST_CASE(CreateInvalidCategoryRecordTest1)
 {
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(0);
+    MockBufferManager mockBuffer(0);
     SendCounterPacketTest sendCounterPacketTest(mockProfilingConnection, mockBuffer);
 
     // Create a category for testing
@@ -1008,7 +1009,7 @@
 BOOST_AUTO_TEST_CASE(CreateInvalidCategoryRecordTest2)
 {
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(0);
+    MockBufferManager mockBuffer(0);
     SendCounterPacketTest sendCounterPacketTest(mockProfilingConnection, mockBuffer);
 
     // Create a category for testing
@@ -1067,7 +1068,7 @@
 
     // Buffer with not enough space
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(10);
+    MockBufferManager mockBuffer(10);
     SendCounterPacket sendCounterPacket(mockProfilingConnection, mockBuffer);
     BOOST_CHECK_THROW(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory),
                       armnn::profiling::BufferExhaustion);
@@ -1160,13 +1161,12 @@
 
     // Buffer with enough space
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(1024);
+    MockBufferManager mockBuffer(1024);
     SendCounterPacket sendCounterPacket(mockProfilingConnection, mockBuffer);
     BOOST_CHECK_NO_THROW(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory));
 
-    // Get the read buffer
-    unsigned int sizeRead = 0;
-    const unsigned char* readBuffer = mockBuffer.GetReadBuffer(sizeRead);
+    // Get the readable buffer
+    auto readBuffer = mockBuffer.GetReadableBuffer();
 
     // Check the packet header
     uint32_t packetHeaderWord0 = ReadUint32(readBuffer, 0);
@@ -1229,6 +1229,9 @@
     uint32_t deviceRecordsPointerTableOffset = 2u * uint32_t_size + // packet_header
                                                6u * uint32_t_size + // body_header
                                                bodyHeaderWord1;     // device_records_pointer_table_offset
+
+    const unsigned char* readData = readBuffer->GetReadableData();
+
     for (uint32_t i = 0; i < deviceRecordCount; i++)
     {
         // Get the device record offset
@@ -1255,7 +1258,7 @@
         BOOST_CHECK(deviceRecordNameNullTerminator == '\0');
         std::vector<unsigned char> deviceRecordNameBuffer(deviceRecord.name_length - 1);
         std::memcpy(deviceRecordNameBuffer.data(),
-                    readBuffer + deviceRecordPoolOffset + uint32_t_size, deviceRecordNameBuffer.size());
+                    readData + deviceRecordPoolOffset + uint32_t_size, deviceRecordNameBuffer.size());
         deviceRecord.name.assign(deviceRecordNameBuffer.begin(), deviceRecordNameBuffer.end()); // name
 
         deviceRecords.push_back(deviceRecord);
@@ -1312,7 +1315,7 @@
         BOOST_CHECK(counterSetRecordNameNullTerminator == '\0');
         std::vector<unsigned char> counterSetRecordNameBuffer(counterSetRecord.name_length - 1);
         std::memcpy(counterSetRecordNameBuffer.data(),
-                    readBuffer + counterSetRecordPoolOffset + uint32_t_size, counterSetRecordNameBuffer.size());
+                    readData + counterSetRecordPoolOffset + uint32_t_size, counterSetRecordNameBuffer.size());
         counterSetRecord.name.assign(counterSetRecordNameBuffer.begin(), counterSetRecordNameBuffer.end()); // name
 
         counterSetRecords.push_back(counterSetRecord);
@@ -1403,7 +1406,7 @@
         BOOST_CHECK(categoryRecordNameNullTerminator == '\0');
         std::vector<unsigned char> categoryRecordNameBuffer(categoryRecord.name_length - 1);
         std::memcpy(categoryRecordNameBuffer.data(),
-                    readBuffer +
+                    readData +
                     categoryRecordPoolOffset +
                     categoryRecord.name_offset +
                     uint32_t_size,
@@ -1462,7 +1465,7 @@
             BOOST_CHECK(eventRecordNameNullTerminator == '\0');
             std::vector<unsigned char> eventRecordNameBuffer(eventRecord.name_length - 1);
             std::memcpy(eventRecordNameBuffer.data(),
-                        readBuffer +
+                        readData +
                         eventRecordPoolOffset +
                         eventRecord.name_offset +
                         uint32_t_size,
@@ -1481,7 +1484,7 @@
             BOOST_CHECK(eventRecordDescriptionNullTerminator == '\0');
             std::vector<unsigned char> eventRecordDescriptionBuffer(eventRecord.description_length - 1);
             std::memcpy(eventRecordDescriptionBuffer.data(),
-                        readBuffer +
+                        readData +
                         eventRecordPoolOffset +
                         eventRecord.description_offset +
                         uint32_t_size,
@@ -1503,7 +1506,7 @@
                 BOOST_CHECK(eventRecordUnitsNullTerminator == '\0');
                 std::vector<unsigned char> eventRecordUnitsBuffer(eventRecord.units_length - 1);
                 std::memcpy(eventRecordUnitsBuffer.data(),
-                            readBuffer +
+                            readData +
                             eventRecordPoolOffset +
                             eventRecord.units_offset +
                             uint32_t_size,
@@ -1560,7 +1563,7 @@
 
     // Buffer with enough space
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(1024);
+    MockBufferManager mockBuffer(1024);
     SendCounterPacket sendCounterPacket(mockProfilingConnection, mockBuffer);
     BOOST_CHECK_THROW(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory), armnn::RuntimeException);
 }
@@ -1579,7 +1582,7 @@
 
     // Buffer with enough space
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(1024);
+    MockBufferManager mockBuffer(1024);
     SendCounterPacket sendCounterPacket(mockProfilingConnection, mockBuffer);
     BOOST_CHECK_THROW(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory), armnn::RuntimeException);
 }
@@ -1598,7 +1601,7 @@
 
     // Buffer with enough space
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(1024);
+    MockBufferManager mockBuffer(1024);
     SendCounterPacket sendCounterPacket(mockProfilingConnection, mockBuffer);
     BOOST_CHECK_THROW(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory), armnn::RuntimeException);
 }
@@ -1633,7 +1636,7 @@
 
     // Buffer with enough space
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(1024);
+    MockBufferManager mockBuffer(1024);
     SendCounterPacket sendCounterPacket(mockProfilingConnection, mockBuffer);
     BOOST_CHECK_THROW(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory), armnn::RuntimeException);
 }
@@ -1683,7 +1686,7 @@
 
     // Buffer with enough space
     MockProfilingConnection mockProfilingConnection;
-    MockBuffer mockBuffer(1024);
+    MockBufferManager mockBuffer(1024);
     SendCounterPacket sendCounterPacket(mockProfilingConnection, mockBuffer);
     BOOST_CHECK_THROW(sendCounterPacket.SendCounterDirectoryPacket(counterDirectory), armnn::RuntimeException);
 }
@@ -1691,7 +1694,7 @@
 BOOST_AUTO_TEST_CASE(SendThreadTest0)
 {
     MockProfilingConnection mockProfilingConnection;
-    MockStreamCounterBuffer mockStreamCounterBuffer(0);
+    MockStreamCounterBuffer mockStreamCounterBuffer(1, 0);
     SendCounterPacket sendCounterPacket(mockProfilingConnection, mockStreamCounterBuffer);
 
     // Try to start the send thread many times, it must only start once
@@ -1712,10 +1715,10 @@
 
 BOOST_AUTO_TEST_CASE(SendThreadTest1)
 {
-    size_t totalWrittenSize = 0;
+    unsigned int totalWrittenSize = 0;
 
     MockProfilingConnection mockProfilingConnection;
-    MockStreamCounterBuffer mockStreamCounterBuffer(100);
+    MockStreamCounterBuffer mockStreamCounterBuffer(5,1024);
     SendCounterPacket sendCounterPacket(mockProfilingConnection, mockStreamCounterBuffer);
     sendCounterPacket.Start();
 
@@ -1728,7 +1731,10 @@
     sendCounterPacket.SendStreamMetaDataPacket();
 
     // Get the size of the Stream Metadata Packet
-    size_t streamMetadataPacketsize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    std::string processName = GetProcessName().substr(0, 60);
+    unsigned int processNameSize = boost::numeric_cast<unsigned int>(processName.size()) > 0 ?
+                                   boost::numeric_cast<unsigned int>(processName.size()) + 1 : 0;
+    unsigned int streamMetadataPacketsize = 118 + processNameSize;
     totalWrittenSize += streamMetadataPacketsize;
 
     sendCounterPacket.SetReadyToRead();
@@ -1738,7 +1744,7 @@
     sendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
 
     // Get the size of the Counter Directory Packet
-    size_t counterDirectoryPacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    unsigned int counterDirectoryPacketSize = 32;
     totalWrittenSize += counterDirectoryPacketSize;
 
     sendCounterPacket.SetReadyToRead();
@@ -1752,7 +1758,7 @@
                                                        });
 
     // Get the size of the Periodic Counter Capture Packet
-    size_t periodicCounterCapturePacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    unsigned int periodicCounterCapturePacketSize = 28;
     totalWrittenSize += periodicCounterCapturePacketSize;
 
     sendCounterPacket.SetReadyToRead();
@@ -1765,7 +1771,7 @@
                                                        });
 
     // Get the size of the Periodic Counter Capture Packet
-    periodicCounterCapturePacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    periodicCounterCapturePacketSize = 22;
     totalWrittenSize += periodicCounterCapturePacketSize;
 
     sendCounterPacket.SendPeriodicCounterCapturePacket(1234u,
@@ -1778,7 +1784,7 @@
                                                        });
 
     // Get the size of the Periodic Counter Capture Packet
-    periodicCounterCapturePacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    periodicCounterCapturePacketSize = 46;
     totalWrittenSize += periodicCounterCapturePacketSize;
 
     sendCounterPacket.SendPeriodicCounterCapturePacket(997u,
@@ -1790,7 +1796,7 @@
                                                        });
 
     // Get the size of the Periodic Counter Capture Packet
-    periodicCounterCapturePacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    periodicCounterCapturePacketSize = 40;
     totalWrittenSize += periodicCounterCapturePacketSize;
 
     sendCounterPacket.SetReadyToRead();
@@ -1800,28 +1806,28 @@
     sendCounterPacket.SendPeriodicCounterSelectionPacket(1000u, { 1345u, 254u, 4536u, 408u, 54u, 6323u, 428u, 1u, 6u });
 
     // Get the size of the Periodic Counter Capture Packet
-    periodicCounterCapturePacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    periodicCounterCapturePacketSize = 30;
     totalWrittenSize += periodicCounterCapturePacketSize;
 
     sendCounterPacket.SetReadyToRead();
 
     // To test an exact value of the "read size" in the mock buffer, wait a second to allow the send thread to
     // read all what's remaining in the buffer
-    std::this_thread::sleep_for(std::chrono::seconds(1));
+    std::this_thread::sleep_for(std::chrono::seconds(2));
 
     sendCounterPacket.Stop();
 
-    BOOST_CHECK(mockStreamCounterBuffer.GetBufferSize()    == totalWrittenSize);
+    BOOST_CHECK(mockStreamCounterBuffer.GetReadableBufferSize() == totalWrittenSize);
     BOOST_CHECK(mockStreamCounterBuffer.GetCommittedSize() == totalWrittenSize);
-    BOOST_CHECK(mockStreamCounterBuffer.GetReadSize()      == totalWrittenSize);
+    BOOST_CHECK(mockStreamCounterBuffer.GetReadSize() == totalWrittenSize);
 }
 
 BOOST_AUTO_TEST_CASE(SendThreadTest2)
 {
-    size_t totalWrittenSize = 0;
+    unsigned int totalWrittenSize = 0;
 
     MockProfilingConnection mockProfilingConnection;
-    MockStreamCounterBuffer mockStreamCounterBuffer(100);
+    MockStreamCounterBuffer mockStreamCounterBuffer(5, 1024);
     SendCounterPacket sendCounterPacket(mockProfilingConnection, mockStreamCounterBuffer);
     sendCounterPacket.Start();
 
@@ -1836,7 +1842,10 @@
     sendCounterPacket.SendStreamMetaDataPacket();
 
     // Get the size of the Stream Metadata Packet
-    size_t streamMetadataPacketsize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    std::string processName = GetProcessName().substr(0, 60);
+    unsigned int processNameSize = boost::numeric_cast<unsigned int>(processName.size()) > 0 ?
+                                   boost::numeric_cast<unsigned int>(processName.size()) + 1 : 0;
+    unsigned int streamMetadataPacketsize = 118 + processNameSize;
     totalWrittenSize += streamMetadataPacketsize;
 
     sendCounterPacket.SetReadyToRead();
@@ -1846,7 +1855,7 @@
     sendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
 
     // Get the size of the Counter Directory Packet
-    size_t counterDirectoryPacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    unsigned int counterDirectoryPacketSize = 32;
     totalWrittenSize += counterDirectoryPacketSize;
 
     sendCounterPacket.SetReadyToRead();
@@ -1861,7 +1870,7 @@
                                                        });
 
     // Get the size of the Periodic Counter Capture Packet
-    size_t periodicCounterCapturePacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    unsigned int periodicCounterCapturePacketSize = 28;
     totalWrittenSize += periodicCounterCapturePacketSize;
 
     sendCounterPacket.SetReadyToRead();
@@ -1881,7 +1890,7 @@
                                                        });
 
     // Get the size of the Periodic Counter Capture Packet
-    periodicCounterCapturePacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    periodicCounterCapturePacketSize = 22;
     totalWrittenSize += periodicCounterCapturePacketSize;
 
     sendCounterPacket.SendPeriodicCounterCapturePacket(1234u,
@@ -1894,7 +1903,7 @@
                                                        });
 
     // Get the size of the Periodic Counter Capture Packet
-    periodicCounterCapturePacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    periodicCounterCapturePacketSize = 46;
     totalWrittenSize += periodicCounterCapturePacketSize;
 
     sendCounterPacket.SetReadyToRead();
@@ -1907,7 +1916,7 @@
                                                        });
 
     // Get the size of the Periodic Counter Capture Packet
-    periodicCounterCapturePacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    periodicCounterCapturePacketSize = 40;
     totalWrittenSize += periodicCounterCapturePacketSize;
 
     sendCounterPacket.SetReadyToRead();
@@ -1918,28 +1927,28 @@
     sendCounterPacket.SendPeriodicCounterSelectionPacket(1000u, { 1345u, 254u, 4536u, 408u, 54u, 6323u, 428u, 1u, 6u });
 
     // Get the size of the Periodic Counter Capture Packet
-    periodicCounterCapturePacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    periodicCounterCapturePacketSize = 30;
     totalWrittenSize += periodicCounterCapturePacketSize;
 
     sendCounterPacket.SetReadyToRead();
 
     // To test an exact value of the "read size" in the mock buffer, wait a second to allow the send thread to
     // read all what's remaining in the buffer
-    std::this_thread::sleep_for(std::chrono::seconds(1));
+    std::this_thread::sleep_for(std::chrono::seconds(2));
 
     sendCounterPacket.Stop();
 
-    BOOST_CHECK(mockStreamCounterBuffer.GetBufferSize()    == totalWrittenSize);
+    BOOST_CHECK(mockStreamCounterBuffer.GetReadableBufferSize() == totalWrittenSize);
     BOOST_CHECK(mockStreamCounterBuffer.GetCommittedSize() == totalWrittenSize);
-    BOOST_CHECK(mockStreamCounterBuffer.GetReadSize()      == totalWrittenSize);
+    BOOST_CHECK(mockStreamCounterBuffer.GetReadSize() == totalWrittenSize);
 }
 
 BOOST_AUTO_TEST_CASE(SendThreadTest3)
 {
-    size_t totalWrittenSize = 0;
+    unsigned int totalWrittenSize = 0;
 
     MockProfilingConnection mockProfilingConnection;
-    MockStreamCounterBuffer mockStreamCounterBuffer(100);
+    MockStreamCounterBuffer mockStreamCounterBuffer(10, 1024);
     SendCounterPacket sendCounterPacket(mockProfilingConnection, mockStreamCounterBuffer);
     sendCounterPacket.Start();
 
@@ -1951,14 +1960,17 @@
     sendCounterPacket.SendStreamMetaDataPacket();
 
     // Get the size of the Stream Metadata Packet
-    size_t streamMetadataPacketsize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    std::string processName = GetProcessName().substr(0, 60);
+    unsigned int processNameSize = boost::numeric_cast<unsigned int>(processName.size()) > 0 ?
+                                   boost::numeric_cast<unsigned int>(processName.size()) + 1 : 0;
+    unsigned int streamMetadataPacketsize = 118 + processNameSize;
     totalWrittenSize += streamMetadataPacketsize;
 
     sendCounterPacket.SetReadyToRead();
     sendCounterPacket.SendCounterDirectoryPacket(counterDirectory);
 
     // Get the size of the Counter Directory Packet
-    size_t counterDirectoryPacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    unsigned int counterDirectoryPacketSize =32;
     totalWrittenSize += counterDirectoryPacketSize;
 
     sendCounterPacket.SetReadyToRead();
@@ -1970,7 +1982,7 @@
                                                        });
 
     // Get the size of the Periodic Counter Capture Packet
-    size_t periodicCounterCapturePacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    unsigned int periodicCounterCapturePacketSize = 28;
     totalWrittenSize += periodicCounterCapturePacketSize;
 
     sendCounterPacket.SetReadyToRead();
@@ -1984,7 +1996,7 @@
                                                        });
 
     // Get the size of the Periodic Counter Capture Packet
-    periodicCounterCapturePacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    periodicCounterCapturePacketSize = 22;
     totalWrittenSize += periodicCounterCapturePacketSize;
 
     sendCounterPacket.SendPeriodicCounterCapturePacket(1234u,
@@ -1997,7 +2009,7 @@
                                                        });
 
     // Get the size of the Periodic Counter Capture Packet
-    periodicCounterCapturePacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    periodicCounterCapturePacketSize = 46;
     totalWrittenSize += periodicCounterCapturePacketSize;
 
     sendCounterPacket.SetReadyToRead();
@@ -2011,7 +2023,7 @@
                                                        });
 
     // Get the size of the Periodic Counter Capture Packet
-    periodicCounterCapturePacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    periodicCounterCapturePacketSize = 40;
     totalWrittenSize += periodicCounterCapturePacketSize;
 
     sendCounterPacket.SetReadyToRead();
@@ -2019,7 +2031,7 @@
     sendCounterPacket.SendPeriodicCounterSelectionPacket(1000u, { 1345u, 254u, 4536u, 408u, 54u, 6323u, 428u, 1u, 6u });
 
     // Get the size of the Periodic Counter Capture Packet
-    periodicCounterCapturePacketSize = GetPacketSize(mockStreamCounterBuffer, totalWrittenSize);
+    periodicCounterCapturePacketSize = 30;
     totalWrittenSize += periodicCounterCapturePacketSize;
 
     sendCounterPacket.SetReadyToRead();
@@ -2028,9 +2040,10 @@
     // thread is not guaranteed to flush the buffer)
     sendCounterPacket.Stop();
 
-    BOOST_CHECK(mockStreamCounterBuffer.GetBufferSize()    == totalWrittenSize);
-    BOOST_CHECK(mockStreamCounterBuffer.GetCommittedSize() == totalWrittenSize);
-    BOOST_CHECK(mockStreamCounterBuffer.GetReadSize()      <= totalWrittenSize);
+    BOOST_CHECK(mockStreamCounterBuffer.GetReadableBufferSize() <= totalWrittenSize);
+    BOOST_CHECK(mockStreamCounterBuffer.GetCommittedSize() <= totalWrittenSize);
+    BOOST_CHECK(mockStreamCounterBuffer.GetReadSize() <= totalWrittenSize);
+    BOOST_CHECK(mockStreamCounterBuffer.GetReadSize() <= mockStreamCounterBuffer.GetCommittedSize());
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/profiling/test/SendCounterPacketTests.hpp b/src/profiling/test/SendCounterPacketTests.hpp
index 3616816..c3d4715 100644
--- a/src/profiling/test/SendCounterPacketTests.hpp
+++ b/src/profiling/test/SendCounterPacketTests.hpp
@@ -42,15 +42,46 @@
     bool m_IsOpen;
 };
 
-class MockBuffer : public IBufferWrapper
+class MockPacketBuffer : public IPacketBuffer
 {
 public:
-    MockBuffer(unsigned int size)
-        : m_BufferSize(size)
-        , m_Buffer(std::make_unique<unsigned char[]>(size))
-    {}
+    MockPacketBuffer(unsigned int maxSize)
+    : m_MaxSize(maxSize),
+      m_Size(0)
+    {
+        m_Data = std::make_unique<unsigned char[]>(m_MaxSize);
+    }
 
-    unsigned char* Reserve(unsigned int requestedSize, unsigned int& reservedSize) override
+    ~MockPacketBuffer() {}
+
+    const unsigned char* const GetReadableData() const override { return m_Data.get(); }
+
+    unsigned int GetSize() const override { return m_Size; }
+
+    void MarkRead() override { m_Size = 0;}
+
+    void Commit(unsigned int size) override { m_Size = size; }
+
+    void Release() override { m_Size = 0; }
+
+    unsigned char* GetWritableData() override { return m_Data.get(); }
+
+private:
+    unsigned int m_MaxSize;
+    unsigned int m_Size;
+    std::unique_ptr<unsigned char[]> m_Data;
+};
+
+class MockBufferManager : public IBufferManager
+{
+public:
+    MockBufferManager(unsigned int size)
+    : m_BufferSize(size),
+      m_Buffer(std::make_unique<MockPacketBuffer>(size)) {}
+
+    ~MockBufferManager() {}
+
+    std::unique_ptr<IPacketBuffer> Reserve(unsigned int requestedSize, unsigned int& reservedSize) override
     {
         if (requestedSize > m_BufferSize)
         {
@@ -61,145 +92,171 @@
             reservedSize = requestedSize;
         }
 
-        return m_Buffer.get();
+        return std::move(m_Buffer);
     }
 
-    void Commit(unsigned int size) override {}
-
-    const unsigned char* GetReadBuffer(unsigned int& size) override
+    void Commit(std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int size) override
     {
-        size = static_cast<unsigned int>(strlen(reinterpret_cast<const char*>(m_Buffer.get())) + 1);
-        return m_Buffer.get();
+        packetBuffer->Commit(size);
+        m_Buffer = std::move(packetBuffer);
     }
 
-    void Release(unsigned int size) override {}
+    std::unique_ptr<IPacketBuffer> GetReadableBuffer() override
+    {
+        return std::move(m_Buffer);
+    }
+
+    void Release(std::unique_ptr<IPacketBuffer>& packetBuffer) override
+    {
+        packetBuffer->Release();
+        m_Buffer = std::move(packetBuffer);
+    }
+
+    void MarkRead(std::unique_ptr<IPacketBuffer>& packetBuffer) override
+    {
+        packetBuffer->MarkRead();
+        m_Buffer = std::move(packetBuffer);
+    }
 
 private:
     unsigned int m_BufferSize;
-    std::unique_ptr<unsigned char[]> m_Buffer;
+    std::unique_ptr<IPacketBuffer> m_Buffer;
 };
 
-class MockStreamCounterBuffer : public IBufferWrapper
+class MockStreamCounterBuffer : public IBufferManager
 {
 public:
-    MockStreamCounterBuffer(unsigned int size)
-        : m_Buffer(size, 0)
-        , m_CommittedSize(0)
-        , m_ReadSize(0)
-    {}
-
-    unsigned char* Reserve(unsigned int requestedSize, unsigned int& reservedSize) override
+    MockStreamCounterBuffer(unsigned int numberOfBuffers = 5, unsigned int maxPacketSize = 4096)
+    : m_MaxBufferSize(maxPacketSize)
+    , m_ReadableSize(0)
+    , m_CommittedSize(0)
+    , m_ReadSize(0)
     {
-        std::unique_lock<std::mutex>(m_Mutex);
-
-        // Get the buffer size and the available size in the buffer past the committed size
-        size_t bufferSize = m_Buffer.size();
-        size_t availableSize = bufferSize - m_CommittedSize;
-
-        // Check whether the buffer needs to be resized
-        if (requestedSize > availableSize)
+        m_AvailableList.reserve(numberOfBuffers);
+        for (unsigned int i = 0; i < numberOfBuffers; ++i)
         {
-            // Resize the buffer
-            size_t newSize = m_CommittedSize + requestedSize;
-            m_Buffer.resize(newSize, 0);
+            std::unique_ptr<IPacketBuffer> buffer = std::make_unique<MockPacketBuffer>(maxPacketSize);
+            m_AvailableList.emplace_back(std::move(buffer));
         }
-
-        // Set the reserved size
-        reservedSize = requestedSize;
-
-        // Get a pointer to the beginning of the part of buffer available for writing
-        return m_Buffer.data() + m_CommittedSize;
+        m_ReadableList.reserve(numberOfBuffers);
     }
 
-    void Commit(unsigned int size) override
-    {
-        std::unique_lock<std::mutex>(m_Mutex);
+    ~MockStreamCounterBuffer() {}
 
-        // Update the committed size
+    std::unique_ptr<IPacketBuffer> Reserve(unsigned int requestedSize, unsigned int& reservedSize) override
+    {
+        std::unique_lock<std::mutex> availableListLock(m_AvailableMutex, std::defer_lock);
+        if (requestedSize > m_MaxBufferSize)
+       {
+            throw armnn::Exception("Maximum buffer size that can be requested is [" +
+                std::to_string(m_MaxBufferSize) + "] bytes");
+       }
+        availableListLock.lock();
+        if (m_AvailableList.empty())
+        {
+            throw armnn::profiling::BufferExhaustion("Buffer not available");
+        }
+        std::unique_ptr<IPacketBuffer> buffer = std::move(m_AvailableList.back());
+        m_AvailableList.pop_back();
+        availableListLock.unlock();
+        reservedSize = requestedSize;
+        return buffer;
+    }
+
+    void Commit(std::unique_ptr<IPacketBuffer>& packetBuffer, unsigned int size) override
+    {
+        std::unique_lock<std::mutex> readableListLock(m_ReadableMutex, std::defer_lock);
+        packetBuffer.get()->Commit(size);
+        readableListLock.lock();
+        m_ReadableList.push_back(std::move(packetBuffer));
+        readableListLock.unlock();
+        m_ReadDataAvailable.notify_one();
         m_CommittedSize += size;
     }
 
-    const unsigned char* GetReadBuffer(unsigned int& size) override
+    void Release(std::unique_ptr<IPacketBuffer>& packetBuffer) override
     {
-        std::unique_lock<std::mutex>(m_Mutex);
-
-        // Get the size available for reading
-        size = boost::numeric_cast<unsigned int>(m_CommittedSize - m_ReadSize);
-
-        // Get a pointer to the beginning of the part of buffer available for reading
-        const unsigned char* readBuffer = m_Buffer.data() + m_ReadSize;
-
-        // Update the read size
-        m_ReadSize = m_CommittedSize;
-
-        return readBuffer;
+        std::unique_lock<std::mutex> availableListLock(m_AvailableMutex, std::defer_lock);
+        packetBuffer.get()->Release();
+        availableListLock.lock();
+        m_AvailableList.push_back(std::move(packetBuffer));
+        availableListLock.unlock();
+        m_CommittedSize = 0;
+        m_ReadSize = 0;
+        m_ReadableSize = 0;
     }
 
-    void Release(unsigned int size) override
+    std::unique_ptr<IPacketBuffer> GetReadableBuffer() override
     {
-        std::unique_lock<std::mutex>(m_Mutex);
-
-        if (size == 0)
+        std::unique_lock<std::mutex> readableListLock(m_ReadableMutex);
+        if (!m_ReadableList.empty())
         {
-            // Nothing to release
-            return;
+            std::unique_ptr<IPacketBuffer> buffer = std::move(m_ReadableList.back());
+            m_ReadableSize+=buffer->GetSize();
+            m_ReadableList.pop_back();
+            readableListLock.unlock();
+            return buffer;
         }
-
-        // Get the buffer size
-        size_t bufferSize = m_Buffer.size();
-
-        // Remove the last "size" bytes from the buffer
-        if (size < bufferSize)
-        {
-            // Resize the buffer
-            size_t newSize = bufferSize - size;
-            m_Buffer.resize(newSize);
-        }
-        else
-        {
-            // Clear the whole buffer
-            m_Buffer.clear();
-        }
+        return nullptr;
     }
 
-    size_t GetBufferSize()           const { return m_Buffer.size(); }
-    size_t GetCommittedSize()        const { return m_CommittedSize; }
-    size_t GetReadSize()             const { return m_ReadSize;      }
-    const unsigned char* GetBuffer() const { return m_Buffer.data(); }
+    void MarkRead(std::unique_ptr<IPacketBuffer>& packetBuffer) override
+    {
+        std::unique_lock<std::mutex> availableListLock(m_AvailableMutex, std::defer_lock);
+        // increase read size
+        m_ReadSize += packetBuffer->GetSize();
+        packetBuffer->MarkRead();
+        availableListLock.lock();
+        m_AvailableList.push_back(std::move(packetBuffer));
+        availableListLock.unlock();
+    }
+
+    unsigned int GetReadableBufferSize() const
+    {
+        return m_ReadableSize;
+    }
+    unsigned int GetCommittedSize()        const { return m_CommittedSize; }
+    unsigned int GetReadSize()             const { return m_ReadSize;      }
 
 private:
-    // This mock uses an ever-expanding vector to simulate a counter stream buffer
-    std::vector<unsigned char> m_Buffer;
+    unsigned int m_MaxBufferSize;
+    std::vector<std::unique_ptr<IPacketBuffer>> m_AvailableList;
+    std::vector<std::unique_ptr<IPacketBuffer>> m_ReadableList;
+    std::mutex m_AvailableMutex;
+    std::mutex m_ReadableMutex;
+    std::condition_variable m_ReadDataAvailable;
+
+    // The size of the buffer that can be read
+    unsigned int m_ReadableSize;
 
     // The size of the buffer that has been committed for reading
-    size_t m_CommittedSize;
+    unsigned int m_CommittedSize;
 
     // The size of the buffer that has already been read
-    size_t m_ReadSize;
-
-    // This mock buffer provides basic synchronization
-    std::mutex m_Mutex;
+    unsigned int m_ReadSize;
 };
 
 class MockSendCounterPacket : public ISendCounterPacket
 {
 public:
-    MockSendCounterPacket(IBufferWrapper& sendBuffer) : m_Buffer(sendBuffer) {}
+    MockSendCounterPacket(IBufferManager& sendBuffer) : m_BufferManager(sendBuffer) {}
 
     void SendStreamMetaDataPacket() override
     {
         std::string message("SendStreamMetaDataPacket");
         unsigned int reserved = 0;
-        unsigned char* buffer = m_Buffer.Reserve(1024, reserved);
-        memcpy(buffer, message.c_str(), static_cast<unsigned int>(message.size()) + 1);
+        std::unique_ptr<IPacketBuffer> buffer = m_BufferManager.Reserve(1024, reserved);
+        memcpy(buffer->GetWritableData(), message.c_str(), static_cast<unsigned int>(message.size()) + 1);
+        m_BufferManager.Commit(buffer, reserved);
     }
 
     void SendCounterDirectoryPacket(const ICounterDirectory& counterDirectory) override
     {
         std::string message("SendCounterDirectoryPacket");
         unsigned int reserved = 0;
-        unsigned char* buffer = m_Buffer.Reserve(1024, reserved);
-        memcpy(buffer, message.c_str(), static_cast<unsigned int>(message.size()) + 1);
+        std::unique_ptr<IPacketBuffer> buffer = m_BufferManager.Reserve(1024, reserved);
+        memcpy(buffer->GetWritableData(), message.c_str(), static_cast<unsigned int>(message.size()) + 1);
+        m_BufferManager.Commit(buffer, reserved);
     }
 
     void SendPeriodicCounterCapturePacket(uint64_t timestamp,
@@ -207,8 +264,9 @@
     {
         std::string message("SendPeriodicCounterCapturePacket");
         unsigned int reserved = 0;
-        unsigned char* buffer = m_Buffer.Reserve(1024, reserved);
-        memcpy(buffer, message.c_str(), static_cast<unsigned int>(message.size()) + 1);
+        std::unique_ptr<IPacketBuffer> buffer = m_BufferManager.Reserve(1024, reserved);
+        memcpy(buffer->GetWritableData(), message.c_str(), static_cast<unsigned int>(message.size()) + 1);
+        m_BufferManager.Commit(buffer, reserved);
     }
 
     void SendPeriodicCounterSelectionPacket(uint32_t capturePeriod,
@@ -216,15 +274,15 @@
     {
         std::string message("SendPeriodicCounterSelectionPacket");
         unsigned int reserved = 0;
-        unsigned char* buffer = m_Buffer.Reserve(1024, reserved);
-        memcpy(buffer, message.c_str(), static_cast<unsigned int>(message.size()) + 1);
-        m_Buffer.Commit(reserved);
+        std::unique_ptr<IPacketBuffer> buffer = m_BufferManager.Reserve(1024, reserved);
+        memcpy(buffer->GetWritableData(), message.c_str(), static_cast<unsigned int>(message.size()) + 1);
+        m_BufferManager.Commit(buffer, reserved);
     }
 
     void SetReadyToRead() override {}
 
 private:
-    IBufferWrapper& m_Buffer;
+    IBufferManager& m_BufferManager;
 };
 
 class MockCounterDirectory : public ICounterDirectory
@@ -434,7 +492,7 @@
 class SendCounterPacketTest : public SendCounterPacket
 {
 public:
-    SendCounterPacketTest(IProfilingConnection& profilingconnection, IBufferWrapper& buffer)
+    SendCounterPacketTest(IProfilingConnection& profilingconnection, IBufferManager& buffer)
         : SendCounterPacket(profilingconnection, buffer)
     {}