IVGCVSW-3721 Add support for startup sequence (Mock Gatord service).

* Receive and process the stream metadata from the client.
* Send the connection ack packet.
* Wait in a receiving thread and print the packets.
* GatordMockTest and Impl for PeriodicCounterCapture CommandHandler
* CaptureData class to retain packet data
* MockUtils
* Update SocketProfilingConnection to fix non blocking receipt of packets.
* Restructure directory layout following review comments.
* Extract the mock service into a static library in the cmake files.

Signed-off-by: Colm Donelan <Colm.Donelan@arm.com>
Signed-off-by: Keith Davis <keith.davis@arm.com>
Signed-off-by: Mike Kelly <mike.kelly@arm.com>
Signed-off-by: Finn Williams <Finn.Williams@arm.com>
Signed-off-by: Kevin May <kevin.may@arm.com>
Change-Id: I33c1c9f93976708c9315f71290d42cff53b8c075
diff --git a/src/profiling/SocketProfilingConnection.cpp b/src/profiling/SocketProfilingConnection.cpp
index ad62992..6f7101b 100644
--- a/src/profiling/SocketProfilingConnection.cpp
+++ b/src/profiling/SocketProfilingConnection.cpp
@@ -5,10 +5,11 @@
 
 #include "SocketProfilingConnection.hpp"
 
+#include <cerrno>
 #include <fcntl.h>
+#include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/un.h>
-#include <cerrno>
 #include <string>
 
 namespace armnn
@@ -23,7 +24,7 @@
     m_Socket[0].fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
     if (m_Socket[0].fd == -1)
     {
-        throw RuntimeException(std::string("Socket construction failed: ") + strerror(errno));
+        throw armnn::RuntimeException(std::string("Socket construction failed: ") + strerror(errno));
     }
 
     // Connect to the named unix domain socket.
@@ -35,7 +36,7 @@
     if (0 != connect(m_Socket[0].fd, reinterpret_cast<const sockaddr*>(&server), sizeof(sockaddr_un)))
     {
         close(m_Socket[0].fd);
-        throw RuntimeException(std::string("Cannot connect to stream socket: ") + strerror(errno));
+        throw armnn::RuntimeException(std::string("Cannot connect to stream socket: ") + strerror(errno));
     }
 
     // Our socket will only be interested in polling reads.
@@ -46,7 +47,7 @@
     if (0 != fcntl(m_Socket[0].fd, F_SETFL, currentFlags | O_NONBLOCK))
     {
         close(m_Socket[0].fd);
-        throw RuntimeException(std::string("Failed to set socket as non blocking: ") + strerror(errno));
+        throw armnn::RuntimeException(std::string("Failed to set socket as non blocking: ") + strerror(errno));
     }
 }
 
@@ -59,7 +60,7 @@
 {
     if (close(m_Socket[0].fd) != 0)
     {
-        throw RuntimeException(std::string("Cannot close stream socket: ") + strerror(errno));
+        throw armnn::RuntimeException(std::string("Cannot close stream socket: ") + strerror(errno));
     }
 
     memset(m_Socket, 0, sizeof(m_Socket));
@@ -77,54 +78,67 @@
 
 Packet SocketProfilingConnection::ReadPacket(uint32_t timeout)
 {
-    // Poll for data on the socket or until timeout occurs
-    int pollResult = poll(m_Socket, 1, static_cast<int>(timeout));
-
-    switch (pollResult)
+    // Is there currently at least a headers worth of data waiting to be read?
+    int bytes_available;
+    ioctl(m_Socket[0].fd, FIONREAD, &bytes_available);
+    if (bytes_available >= 8)
     {
-    case -1: // Error
-        throw RuntimeException(std::string("Read failure from socket: ") + strerror(errno));
+        // Yes there is. Read it:
+        return ReceivePacket();
+    }
+    else
+    {
+        // Poll for data on the socket or until timeout occurs
+        int pollResult = poll(m_Socket, 1, static_cast<int>(timeout));
 
-    case 0: // Timeout
-        throw RuntimeException("Timeout while reading from socket");
-
-    default: // Normal poll return but it could still contain an error signal
-
-        // Check if the socket reported an error
-        if (m_Socket[0].revents & (POLLNVAL | POLLERR | POLLHUP))
+        switch (pollResult)
         {
-            throw Exception(std::string("Socket 0 reported an error: ") + strerror(errno));
+            case -1: // Error
+                throw armnn::RuntimeException(std::string("Read failure from socket: ") + strerror(errno));
+
+            case 0: // Timeout
+                throw TimeoutException("Timeout while reading from socket");
+
+            default: // Normal poll return but it could still contain an error signal
+
+                // Check if the socket reported an error
+                if (m_Socket[0].revents & (POLLNVAL | POLLERR | POLLHUP))
+                {
+                    throw armnn::RuntimeException(std::string("Socket reported an error: ") + strerror(errno));
+                }
+
+                // Check if there is data to read
+                if (!(m_Socket[0].revents & (POLLIN)))
+                {
+                    // This is a very odd case. The file descriptor was woken up but no data was written.
+                    throw armnn::RuntimeException("Poll resulted in : no data to read");
+                }
+
+                return ReceivePacket();
         }
+    }
+}
 
-        // Check if there is data to read
-        if (!(m_Socket[0].revents & (POLLIN)))
-        {
-            // No data to read from the socket. Silently ignore and continue
-            return Packet();
-        }
+Packet SocketProfilingConnection::ReceivePacket()
+{
+    char header[8] = {};
+    if (8 != recv(m_Socket[0].fd, &header, sizeof(header), 0))
+    {
+        // What do we do here if there's not a valid 8 byte header to read?
+        throw armnn::RuntimeException("The received packet did not contains a valid MIPE header");
+    }
+    // stream_metadata_identifier is the first 4 bytes
+    uint32_t metadataIdentifier = 0;
+    std::memcpy(&metadataIdentifier, header, sizeof(metadataIdentifier));
 
-        // There is data to read, read the header first
-        char header[8] = {};
-        if (8 != recv(m_Socket[0].fd, &header, sizeof(header), 0))
-        {
-            // What do we do here if there's not a valid 8 byte header to read?
-            throw RuntimeException("The received packet did not contains a valid MIPE header");
-        }
-
-        // stream_metadata_identifier is the first 4 bytes
-        uint32_t metadataIdentifier = 0;
-        std::memcpy(&metadataIdentifier, header, sizeof(metadataIdentifier));
-
-        // data_length is the next 4 bytes
-        uint32_t dataLength = 0;
-        std::memcpy(&dataLength, header + 4u, sizeof(dataLength));
+    // data_length is the next 4 bytes
+    uint32_t dataLength = 0;
+    std::memcpy(&dataLength, header + 4u, sizeof(dataLength));
 
         std::unique_ptr<unsigned char[]> packetData;
-        if (dataLength > 0)
-        {
+    if (dataLength > 0)
+    {
             packetData = std::make_unique<unsigned char[]>(dataLength);
-        }
-
         ssize_t receivedLength = recv(m_Socket[0].fd, packetData.get(), dataLength, 0);
         if (receivedLength < 0)
         {
@@ -133,11 +147,11 @@
         if (dataLength != static_cast<uint32_t>(receivedLength))
         {
             // What do we do here if we can't read in a full packet?
-            throw RuntimeException("Invalid MIPE packet");
+            throw armnn::RuntimeException("Invalid MIPE packet");
         }
-
-        return Packet(metadataIdentifier, dataLength, packetData);
     }
+
+    return Packet(metadataIdentifier, dataLength, packetData);
 }
 
 } // namespace profiling
diff --git a/src/profiling/SocketProfilingConnection.hpp b/src/profiling/SocketProfilingConnection.hpp
index 7c77a8b..5fb02bb 100644
--- a/src/profiling/SocketProfilingConnection.hpp
+++ b/src/profiling/SocketProfilingConnection.hpp
@@ -25,6 +25,10 @@
     Packet ReadPacket(uint32_t timeout) final;
 
 private:
+
+    // Read a full packet from the socket.
+    Packet ReceivePacket();
+
     // To indicate we want to use an abstract UDS ensure the first character of the address is 0.
     const char* m_GatorNamespace = "\0gatord_namespace";
     struct pollfd m_Socket[1]{};