IVGCVSW-3444 File Only Profiling Connection

    * Add FileOnlyProfilingConnection Decorator
    * Fix bug where Conn Ack not automatically sent back
    * Modify GatordMock to use the Counter Directory class.
    * Promote DirectoryCaptureCommandHandler from GatordMock into ArmNN.
    * Remove MockUtils as it's contents were moved or deleted.
    * Rewrite GatordMockTests to use Counter Directory class.
    * Flush streams in ProfilingConnectionDumpToFileDecorator::Close.

Signed-off-by: Keith Davis <keith.davis@arm.com>
Signed-off-by: Colm Donelan <Colm.Donelan@arm.com>
Change-Id: I77b2aedece24150dd31691b577f3b5d81b2e226f
diff --git a/src/profiling/FileOnlyProfilingConnection.cpp b/src/profiling/FileOnlyProfilingConnection.cpp
new file mode 100644
index 0000000..b32ae49
--- /dev/null
+++ b/src/profiling/FileOnlyProfilingConnection.cpp
@@ -0,0 +1,216 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "FileOnlyProfilingConnection.hpp"
+#include "PacketVersionResolver.hpp"
+
+#include <armnn/Exceptions.hpp>
+
+#include <boost/numeric/conversion/cast.hpp>
+#include <iostream>
+#include <thread>
+
+namespace armnn
+{
+
+namespace profiling
+{
+
+FileOnlyProfilingConnection::~FileOnlyProfilingConnection()
+{
+    Close();
+}
+
+bool FileOnlyProfilingConnection::IsOpen() const
+{
+    // This type of connection is always open.
+    return true;
+}
+
+void FileOnlyProfilingConnection::Close()
+{
+    // Dump any unread packets out of the queue.
+    for (unsigned int i = 0; i < m_PacketQueue.size(); i++)
+    {
+        m_PacketQueue.pop();
+    }
+}
+
+bool FileOnlyProfilingConnection::WaitForStreamMeta(const unsigned char* buffer, uint32_t length)
+{
+    // The first word, stream_metadata_identifer, should always be 0.
+    if (ToUint32(buffer, TargetEndianness::BeWire) != 0)
+    {
+        Fail("Protocol error. The stream_metadata_identifer was not 0.");
+    }
+
+    // Before we interpret the length we need to read the pipe_magic word to determine endianness.
+    if (ToUint32(buffer + 8, TargetEndianness::BeWire) == PIPE_MAGIC)
+    {
+        m_Endianness = TargetEndianness::BeWire;
+    }
+    else if (ToUint32(buffer + 8, TargetEndianness::LeWire) == PIPE_MAGIC)
+    {
+        m_Endianness = TargetEndianness::LeWire;
+    }
+    else
+    {
+        Fail("Protocol read error. Unable to read PIPE_MAGIC value.");
+    }
+    return true;
+}
+
+void FileOnlyProfilingConnection::SendConnectionAck()
+{
+    if (!m_QuietOp)
+    {
+        std::cout << "Sending connection acknowledgement." << std::endl;
+    }
+    std::unique_ptr<unsigned char[]> uniqueNullPtr = nullptr;
+    m_PacketQueue.push(Packet(0x10000, 0, uniqueNullPtr));
+}
+
+bool FileOnlyProfilingConnection::SendCounterSelectionPacket()
+{
+    uint32_t uint16_t_size = sizeof(uint16_t);
+    uint32_t uint32_t_size = sizeof(uint32_t);
+
+    uint32_t offset   = 0;
+    uint32_t bodySize = uint32_t_size + boost::numeric_cast<uint32_t>(m_IdList.size()) * uint16_t_size;
+
+    auto uniqueData     = std::make_unique<unsigned char[]>(bodySize);
+    unsigned char* data = reinterpret_cast<unsigned char*>(uniqueData.get());
+
+    // Copy capturePeriod
+    WriteUint32(data, offset, m_Options.m_CapturePeriod);
+
+    // Copy m_IdList
+    offset += uint32_t_size;
+    for (const uint16_t& id : m_IdList)
+    {
+        WriteUint16(data, offset, id);
+        offset += uint16_t_size;
+    }
+
+    m_PacketQueue.push(Packet(0x40000, bodySize, uniqueData));
+
+    return true;
+}
+
+bool FileOnlyProfilingConnection::WritePacket(const unsigned char* buffer, uint32_t length)
+{
+    BOOST_ASSERT(buffer);
+
+    // Read Header and determine case
+    uint32_t outgoingHeaderAsWords[2];
+    PackageActivity packageActivity = GetPackageActivity(buffer, outgoingHeaderAsWords);
+
+    switch (packageActivity)
+    {
+        case PackageActivity::StreamMetaData:
+        {
+            if (!WaitForStreamMeta(buffer, length))
+            {
+                return EXIT_FAILURE;
+            }
+
+            SendConnectionAck();
+            break;
+        }
+        case PackageActivity::CounterDirectory:
+        {
+            std::unique_ptr<unsigned char[]> uniqueCounterData = std::make_unique<unsigned char[]>(length - 8);
+
+            std::memcpy(uniqueCounterData.get(), buffer + 8, length - 8);
+
+            Packet directoryPacket(outgoingHeaderAsWords[0], length - 8, uniqueCounterData);
+
+            armnn::profiling::PacketVersionResolver packetVersionResolver;
+            DirectoryCaptureCommandHandler directoryCaptureCommandHandler(
+                0, 2, packetVersionResolver.ResolvePacketVersion(0, 2).GetEncodedValue());
+            directoryCaptureCommandHandler.operator()(directoryPacket);
+            const ICounterDirectory& counterDirectory = directoryCaptureCommandHandler.GetCounterDirectory();
+            for (auto& category : counterDirectory.GetCategories())
+            {
+                // Remember we need to translate the Uid's from our CounterDirectory instance to the parent one.
+                std::vector<uint16_t> translatedCounters;
+                for (auto const& copyUid : category->m_Counters)
+                {
+                    translatedCounters.emplace_back(directoryCaptureCommandHandler.TranslateUIDCopyToOriginal(copyUid));
+                }
+                m_IdList.insert(std::end(m_IdList), std::begin(translatedCounters), std::end(translatedCounters));
+            }
+            SendCounterSelectionPacket();
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+    return true;
+}
+
+Packet FileOnlyProfilingConnection::ReadPacket(uint32_t timeout)
+{
+    uint16_t loopCount       = 10;
+    uint32_t timeoutFraction = timeout / loopCount;
+    while (m_PacketQueue.empty())
+    {
+        std::this_thread::sleep_for(std::chrono::milliseconds(timeoutFraction));
+        --loopCount;
+        if ((loopCount) == 0)
+        {
+            throw armnn::TimeoutException("Thread has timed out as per requested time limit");
+        }
+    }
+    Packet returnedPacket = std::move(m_PacketQueue.front());
+    m_PacketQueue.pop();
+    return returnedPacket;
+}
+
+PackageActivity FileOnlyProfilingConnection::GetPackageActivity(const unsigned char* buffer, uint32_t headerAsWords[2])
+{
+    headerAsWords[0] = ToUint32(buffer, m_Endianness);
+    headerAsWords[1] = ToUint32(buffer + 4, m_Endianness);
+    if (headerAsWords[0] == 0x20000)    // Packet family = 0 Packet Id = 2
+    {
+        return PackageActivity::CounterDirectory;
+    }
+    else if (headerAsWords[0] == 0)    // Packet family = 0 Packet Id = 0
+    {
+        return PackageActivity::StreamMetaData;
+    }
+    else
+    {
+        return PackageActivity::Unknown;
+    }
+}
+
+uint32_t FileOnlyProfilingConnection::ToUint32(const unsigned char* data, TargetEndianness endianness)
+{
+    // Extract the first 4 bytes starting at data and push them into a 32bit integer based on the
+    // specified endianness.
+    if (endianness == TargetEndianness::BeWire)
+    {
+        return static_cast<uint32_t>(data[0]) << 24 | static_cast<uint32_t>(data[1]) << 16 |
+               static_cast<uint32_t>(data[2]) << 8 | static_cast<uint32_t>(data[3]);
+    }
+    else
+    {
+        return static_cast<uint32_t>(data[3]) << 24 | static_cast<uint32_t>(data[2]) << 16 |
+               static_cast<uint32_t>(data[1]) << 8 | static_cast<uint32_t>(data[0]);
+    }
+}
+
+void FileOnlyProfilingConnection::Fail(const std::string& errorMessage)
+{
+    Close();
+    throw RuntimeException(errorMessage);
+}
+
+}    // namespace profiling
+
+}    // namespace armnn