IVGCVSW-3931 Create the Timeline Event Binary Packet

 * Added WriteTimelineEventBinaryPacket function
 * Added unit tests
 * Code refactoring

Signed-off-by: Matteo Martincigh <matteo.martincigh@arm.com>
Change-Id: I36b6a8b26bb46eb5ea97bb711ef7e153ea6d851f
diff --git a/src/profiling/ProfilingUtils.cpp b/src/profiling/ProfilingUtils.cpp
index 798cfa4..b7def29 100644
--- a/src/profiling/ProfilingUtils.cpp
+++ b/src/profiling/ProfilingUtils.cpp
@@ -247,7 +247,7 @@
 ///   packetType        Timeline Packet Type
 ///   streamId          Stream identifier
 ///   seqeunceNumbered  When non-zero the 4 bytes following the header is a u32 sequence number
-///   dataLength        Unsigned 24-bit integer. Length of data, in bytes. Zero is permitted.
+///   dataLength        Unsigned 24-bit integer. Length of data, in bytes. Zero is permitted
 ///
 /// \returns
 ///   Pair of uint32_t containing word0 and word1 of the header
@@ -287,13 +287,18 @@
 /// * declareEvent
 ///
 /// \param
-///   Data lenght of the message body in byte
+///   dataLength The length of the message body in bytes
 ///
 /// \returns
 ///   Pair of uint32_t containing word0 and word1 of the header
 std::pair<uint32_t, uint32_t> CreateTimelineMessagePacketHeader(unsigned int dataLength)
 {
-    return CreateTimelinePacketHeader(1,0,1,0,0,dataLength);
+    return CreateTimelinePacketHeader(1,           // Packet family
+                                      0,           // Packet class
+                                      1,           // Packet type
+                                      0,           // Stream id
+                                      0,           // Sequence number
+                                      dataLength); // Data length
 }
 
 TimelinePacketStatus WriteTimelineLabelBinaryPacket(uint64_t profilingGuid,
@@ -302,7 +307,7 @@
                                                     unsigned int bufferSize,
                                                     unsigned int& numberOfBytesWritten)
 {
-    // Initialize the ouput value
+    // Initialize the output value
     numberOfBytesWritten = 0;
 
     // Check that the given buffer is valid
@@ -342,8 +347,7 @@
     }
 
     // Create packet header
-    uint32_t dataLength = boost::numeric_cast<uint32_t>(timelineLabelPacketDataLength); // decl_id + GUID + label
-    std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(dataLength);
+    std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(timelineLabelPacketDataLength);
 
     // Initialize the offset for writing in the buffer
     unsigned int offset = 0;
@@ -378,7 +382,7 @@
                                                      unsigned int bufferSize,
                                                      unsigned int& numberOfBytesWritten)
 {
-    // Initialize the ouput value
+    // Initialize the output value
     numberOfBytesWritten = 0;
 
     // Check that the given buffer is valid
@@ -407,8 +411,7 @@
     }
 
     // Create packet header
-    uint32_t dataLength = boost::numeric_cast<uint32_t>(timelineEntityPacketDataLength);
-    std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(dataLength);
+    std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(timelineEntityPacketDataLength);
 
     // Initialize the offset for writing in the buffer
     unsigned int offset = 0;
@@ -448,24 +451,25 @@
     // Utils
     unsigned int uint32_t_size = sizeof(uint32_t);
 
-    // the payload/data of the packet consists of swtrace event definitions encoded according
+    // The payload/data of the packet consists of swtrace event definitions encoded according
     // to the swtrace directory specification. The messages being the five defined below:
     // |  decl_id  |  decl_name          |    ui_name            |  arg_types  |  arg_names                          |
     // |-----------|---------------------|-----------------------|-------------|-------------------------------------|
     // |    0      |   declareLabel      |   declare label       |    ps       |  guid,value                         |
     // |    1      |   declareEntity     |   declare entity      |    p        |  guid                               |
     // |    2      | declareEventClass   |  declare event class  |    p        |  guid                               |
-    // |    3      | declareRelationship | declare relationship  |    Ippp     |  relationshipType,relationshipGuid,
-    //                                                                            headGuid,tailGuid                  |
+    // |    3      | declareRelationship | declare relationship  |    Ippp     |  relationshipType,relationshipGuid, |
+    // |           |                     |                       |             |  headGuid,tailGuid                  |
     // |    4      |   declareEvent      |   declare event       |    @tp      |  timestamp,threadId,eventGuid       |
 
-    std::vector<std::vector<std::string>> timelineDirectoryMessages =
-        { {"declareLabel", "declare label", "ps", "guid,value"},
-          {"declareEntity", "declare entity", "p", "guid"},
-          {"declareEventClass", "declare event class", "p", "guid"},
-          {"declareRelationship", "declare relationship",
-              "Ippp", "relationshipType,relationshipGuid,headGuid,tailGuid"},
-          {"declareEvent", "declare event", "@tp", "timestamp,threadId,eventGuid"} };
+    std::vector<std::vector<std::string>> timelineDirectoryMessages
+    {
+        {"declareLabel", "declare label", "ps", "guid,value"},
+        {"declareEntity", "declare entity", "p", "guid"},
+        {"declareEventClass", "declare event class", "p", "guid"},
+        {"declareRelationship", "declare relationship", "Ippp", "relationshipType,relationshipGuid,headGuid,tailGuid"},
+        {"declareEvent", "declare event", "@tp", "timestamp,threadId,eventGuid"}
+    };
 
     unsigned int messagesDataLength = 0u;
     std::vector<std::vector<std::vector<uint32_t>>> swTraceTimelineDirectoryMessages;
@@ -501,8 +505,8 @@
     }
 
     // Create packet header
-    uint32_t dataLength        = boost::numeric_cast<uint32_t>(messagesDataLength);
-    std::pair<uint32_t, uint32_t> packetHeader = CreateTimelinePacketHeader(1,0,0,0,0,dataLength);
+    uint32_t dataLength = boost::numeric_cast<uint32_t>(messagesDataLength);
+    std::pair<uint32_t, uint32_t> packetHeader = CreateTimelinePacketHeader(1, 0, 0, 0, 0, dataLength);
 
     // Initialize the offset for writing in the buffer
     unsigned int offset = 0;
@@ -540,7 +544,7 @@
                                                          unsigned int bufferSize,
                                                          unsigned int& numberOfBytesWritten)
 {
-    // Initialize the ouput value
+    // Initialize the output value
     numberOfBytesWritten = 0;
 
     // Check that the given buffer is valid
@@ -553,15 +557,15 @@
     unsigned int uint32_t_size = sizeof(uint32_t);
     unsigned int uint64_t_size = sizeof(uint64_t);
 
-    // dec_id of the timeline message
-    uint32_t decId = 2;
+    // decl_id of the timeline message
+    uint32_t declId = 2;
 
     // Calculate the length of the data (in bytes)
-    unsigned int packetBodySize = uint32_t_size + uint64_t_size;   // decl_id + Profiling GUID
+    unsigned int packetBodySize = uint32_t_size + uint64_t_size; // decl_id + Profiling GUID
 
     // Calculate the timeline binary packet size (in bytes)
-    unsigned int packetSize = 2 * uint32_t_size +   // Header (2 words)
-                              packetBodySize;       // Body
+    unsigned int packetSize = 2 * uint32_t_size + // Header (2 words)
+                              packetBodySize;     // Body
 
     // Check whether the timeline binary packet fits in the given buffer
     if (packetSize > bufferSize)
@@ -570,8 +574,7 @@
     }
 
     // Create packet header
-    uint32_t dataLength = boost::numeric_cast<uint32_t>(packetBodySize);
-    std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(dataLength);
+    std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(packetBodySize);
 
     // Initialize the offset for writing in the buffer
     unsigned int offset = 0;
@@ -583,7 +586,7 @@
     offset += uint32_t_size;
 
     // Write the timeline binary packet payload to the buffer
-    WriteUint32(buffer, offset, decId);         // dec_id
+    WriteUint32(buffer, offset, declId);        // decl_id
     offset += uint32_t_size;
     WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
 
@@ -593,6 +596,73 @@
     return TimelinePacketStatus::Ok;
 }
 
+TimelinePacketStatus WriteTimelineEventBinaryPacket(uint64_t timestamp,
+                                                    uint32_t threadId,
+                                                    uint64_t profilingGuid,
+                                                    unsigned char* buffer,
+                                                    unsigned int bufferSize,
+                                                    unsigned int& numberOfBytesWritten)
+{
+    // Initialize the output value
+    numberOfBytesWritten = 0;
+
+    // Check that the given buffer is valid
+    if (buffer == nullptr || bufferSize == 0)
+    {
+        return TimelinePacketStatus::BufferExhaustion;
+    }
+
+    // Utils
+    unsigned int uint32_t_size = sizeof(uint32_t);
+    unsigned int uint64_t_size = sizeof(uint64_t);
+
+    // decl_id of the timeline message
+    uint32_t declId = 4;
+
+    // Calculate the length of the data (in bytes)
+    unsigned int timelineEventPacketDataLength = uint32_t_size + // decl_id
+                                                 uint64_t_size + // Timestamp
+                                                 uint32_t_size + // Thread id
+                                                 uint64_t_size;  // Profiling GUID
+
+    // Calculate the timeline binary packet size (in bytes)
+    unsigned int timelineEventPacketSize = 2 * uint32_t_size +            // Header (2 words)
+                                           timelineEventPacketDataLength; // Timestamp + thread id + profiling GUID
+
+    // Check whether the timeline binary packet fits in the given buffer
+    if (timelineEventPacketSize > bufferSize)
+    {
+        return TimelinePacketStatus::BufferExhaustion;
+    }
+
+    // Create packet header
+    std::pair<uint32_t, uint32_t> packetHeader = CreateTimelineMessagePacketHeader(timelineEventPacketDataLength);
+
+    // Initialize the offset for writing in the buffer
+    unsigned int offset = 0;
+
+    // Write the timeline binary packet header to the buffer
+    WriteUint32(buffer, offset, packetHeader.first);
+    offset += uint32_t_size;
+    WriteUint32(buffer, offset, packetHeader.second);
+    offset += uint32_t_size;
+
+    // Write the timeline binary packet payload to the buffer
+    WriteUint32(buffer, offset, declId); // decl_id
+    offset += uint32_t_size;
+    WriteUint64(buffer, offset, timestamp); // Timestamp
+    offset += uint64_t_size;
+    WriteUint32(buffer, offset, threadId); // Thread id
+    offset += uint32_t_size;
+    WriteUint64(buffer, offset, profilingGuid); // Profiling GUID
+    offset += uint64_t_size;
+
+    // Update the number of bytes written
+    numberOfBytesWritten = timelineEventPacketSize;
+
+    return TimelinePacketStatus::Ok;
+}
+
 } // namespace profiling
 
 } // namespace armnn
diff --git a/src/profiling/ProfilingUtils.hpp b/src/profiling/ProfilingUtils.hpp
index 8c0251d..c8a5c7f 100644
--- a/src/profiling/ProfilingUtils.hpp
+++ b/src/profiling/ProfilingUtils.hpp
@@ -133,9 +133,9 @@
                                                     unsigned int& numberOfBytesWritten);
 
 TimelinePacketStatus WriteTimelineEntityBinaryPacket(uint64_t profilingGuid,
-                                                    unsigned char* buffer,
-                                                    unsigned int bufferSize,
-                                                    unsigned int& numberOfBytesWritten);
+                                                     unsigned char* buffer,
+                                                     unsigned int bufferSize,
+                                                     unsigned int& numberOfBytesWritten);
 
 TimelinePacketStatus WriteTimelineMessageDirectoryPackage(unsigned char* buffer,
                                                           unsigned int bufferSize,
@@ -146,6 +146,13 @@
                                                          unsigned int bufferSize,
                                                          unsigned int& numberOfBytesWritten);
 
+TimelinePacketStatus WriteTimelineEventBinaryPacket(uint64_t timestamp,
+                                                    uint32_t threadId,
+                                                    uint64_t profilingGuid,
+                                                    unsigned char* buffer,
+                                                    unsigned int bufferSize,
+                                                    unsigned int& numberOfBytesWritten);
+
 class BufferExhaustion : public armnn::Exception
 {
     using Exception::Exception;
diff --git a/src/profiling/test/TimelinePacketTests.cpp b/src/profiling/test/TimelinePacketTests.cpp
index 759d825..558af04 100644
--- a/src/profiling/test/TimelinePacketTests.cpp
+++ b/src/profiling/test/TimelinePacketTests.cpp
@@ -433,4 +433,116 @@
     BOOST_CHECK(readProfilingGuid == profilingGuid);
 }
 
-BOOST_AUTO_TEST_SUITE_END() // TimelinePacketTests
\ No newline at end of file
+BOOST_AUTO_TEST_CASE(TimelineEventPacketTest1)
+{
+    const uint64_t timestamp = 456789u;
+    const uint32_t threadId = 654321u;
+    const uint64_t profilingGuid = 123456u;
+    unsigned int numberOfBytesWritten = 789u;
+    TimelinePacketStatus result = WriteTimelineEventBinaryPacket(timestamp,
+                                                                 threadId,
+                                                                 profilingGuid,
+                                                                 nullptr,
+                                                                 512u,
+                                                                 numberOfBytesWritten);
+    BOOST_CHECK(result == TimelinePacketStatus::BufferExhaustion);
+    BOOST_CHECK(numberOfBytesWritten == 0);
+}
+
+BOOST_AUTO_TEST_CASE(TimelineEventPacketTest2)
+{
+    std::vector<unsigned char> buffer(512, 0);
+
+    const uint64_t timestamp = 456789u;
+    const uint32_t threadId = 654321u;
+    const uint64_t profilingGuid = 123456u;
+    unsigned int numberOfBytesWritten = 789u;
+    TimelinePacketStatus result = WriteTimelineEventBinaryPacket(timestamp,
+                                                                 threadId,
+                                                                 profilingGuid,
+                                                                 buffer.data(),
+                                                                 0,
+                                                                 numberOfBytesWritten);
+    BOOST_CHECK(result == TimelinePacketStatus::BufferExhaustion);
+    BOOST_CHECK(numberOfBytesWritten == 0);
+}
+
+BOOST_AUTO_TEST_CASE(TimelineEventPacketTest3)
+{
+    std::vector<unsigned char> buffer(10, 0);
+
+    const uint64_t timestamp = 456789u;
+    const uint32_t threadId = 654321u;
+    const uint64_t profilingGuid = 123456u;
+    unsigned int numberOfBytesWritten = 789u;
+    TimelinePacketStatus result = WriteTimelineEventBinaryPacket(timestamp,
+                                                                 threadId,
+                                                                 profilingGuid,
+                                                                 buffer.data(),
+                                                                 boost::numeric_cast<unsigned int>(buffer.size()),
+                                                                 numberOfBytesWritten);
+    BOOST_CHECK(result == TimelinePacketStatus::BufferExhaustion);
+    BOOST_CHECK(numberOfBytesWritten == 0);
+}
+
+BOOST_AUTO_TEST_CASE(TimelineEventPacketTest4)
+{
+    std::vector<unsigned char> buffer(512, 0);
+
+    const uint64_t timestamp = 456789u;
+    const uint32_t threadId = 654321u;
+    const uint64_t profilingGuid = 123456u;
+    unsigned int numberOfBytesWritten = 789u;
+    TimelinePacketStatus result = WriteTimelineEventBinaryPacket(timestamp,
+                                                                 threadId,
+                                                                 profilingGuid,
+                                                                 buffer.data(),
+                                                                 boost::numeric_cast<unsigned int>(buffer.size()),
+                                                                 numberOfBytesWritten);
+    BOOST_CHECK(result == TimelinePacketStatus::Ok);
+    BOOST_CHECK(numberOfBytesWritten == 32);
+
+    unsigned int uint32_t_size = sizeof(uint32_t);
+    unsigned int uint64_t_size = sizeof(uint64_t);
+
+    // Check the packet header
+    unsigned int offset = 0;
+    uint32_t packetHeaderWord0 = ReadUint32(buffer.data(), offset);
+    uint32_t packetFamily = (packetHeaderWord0 >> 26) & 0x0000003F;
+    uint32_t packetClass  = (packetHeaderWord0 >> 19) & 0x0000007F;
+    uint32_t packetType   = (packetHeaderWord0 >> 16) & 0x00000007;
+    uint32_t streamId     = (packetHeaderWord0 >>  0) & 0x00000007;
+    BOOST_CHECK(packetFamily == 1);
+    BOOST_CHECK(packetClass  == 0);
+    BOOST_CHECK(packetType   == 1);
+    BOOST_CHECK(streamId     == 0);
+
+    offset += uint32_t_size;
+    uint32_t packetHeaderWord1 = ReadUint32(buffer.data(), offset);
+    uint32_t sequenceNumbered = (packetHeaderWord1 >> 24) & 0x00000001;
+    uint32_t dataLength       = (packetHeaderWord1 >>  0) & 0x00FFFFFF;
+    BOOST_CHECK(sequenceNumbered ==  0);
+    BOOST_CHECK(dataLength       == 24);
+
+    // Check the decl_id
+    offset += uint32_t_size;
+    uint32_t readDeclId = ReadUint32(buffer.data(), offset);
+    BOOST_CHECK(readDeclId == 4);
+
+    // Check the timestamp
+    offset += uint32_t_size;
+    uint64_t readTimestamp = ReadUint64(buffer.data(), offset);
+    BOOST_CHECK(readTimestamp == timestamp);
+
+    // Check the thread id
+    offset += uint64_t_size;
+    uint32_t readThreadId = ReadUint32(buffer.data(), offset);
+    BOOST_CHECK(readThreadId == threadId);
+
+    // Check the profiling GUID
+    offset += uint32_t_size;
+    uint64_t readProfilingGuid = ReadUint64(buffer.data(), offset);
+    BOOST_CHECK(readProfilingGuid == profilingGuid);
+}
+
+BOOST_AUTO_TEST_SUITE_END()