IVGCVSW-3951 Create the timeline decoder
authorFinn Williams <Finn.Williams@arm.com>
Tue, 22 Oct 2019 09:30:49 +0000 (10:30 +0100)
committerDavid Monahan <david.monahan@arm.com>
Thu, 7 Nov 2019 12:20:47 +0000 (12:20 +0000)
 * Added ITimelineDecoder.h C interface
 * Added an example implementation of ITimelineDecoder.h
 * Added command handlers for the timeline directory and objects
 * Added tests for the decoder implementation
 * Changed ReadSwTraceMessage to take a const unsigned char*
   so it can be used by the directory command handler
 * Fixed some bugs in ProfilingUtils.cpp and related tests

Change-Id: If06faf1fe0274a8f022f194a6d3527f5ce5374c6
Signed-off-by: Finn Williams <Finn.Williams@arm.com>
16 files changed:
CMakeLists.txt
src/profiling/DirectoryCaptureCommandHandler.cpp
src/profiling/ProfilingUtils.cpp
src/profiling/ProfilingUtils.hpp
src/profiling/test/SendTimelinePacketTests.cpp
src/profiling/test/TimelinePacketTests.cpp
src/profiling/test/TimelineUtilityMethodsTests.cpp
tests/profiling/timelineDecoder/ITimelineDecoder.h [new file with mode: 0644]
tests/profiling/timelineDecoder/TimelineCaptureCommandHandler.cpp [new file with mode: 0644]
tests/profiling/timelineDecoder/TimelineCaptureCommandHandler.hpp [new file with mode: 0644]
tests/profiling/timelineDecoder/TimelineDecoder.cpp [new file with mode: 0644]
tests/profiling/timelineDecoder/TimelineDirectoryCaptureCommandHandler.cpp [new file with mode: 0644]
tests/profiling/timelineDecoder/TimelineDirectoryCaptureCommandHandler.hpp [new file with mode: 0644]
tests/profiling/timelineDecoder/TimelineModel.h [new file with mode: 0644]
tests/profiling/timelineDecoder/tests/TimelineTestFunctions.hpp [new file with mode: 0644]
tests/profiling/timelineDecoder/tests/TimelineTests.cpp [new file with mode: 0644]

index 867fb34..5b80430 100644 (file)
@@ -822,6 +822,7 @@ if(BUILD_UNIT_TESTS)
     if(BUILD_GATORD_MOCK)
         list(APPEND unittest_sources
             tests/profiling/gatordmock/tests/GatordMockTests.cpp
+            tests/profiling/timelineDecoder/tests/TimelineTests.cpp
             )
     endif()
 
@@ -936,6 +937,13 @@ if(BUILD_GATORD_MOCK)
         tests/profiling/gatordmock/PeriodicCounterCaptureCommandHandler.hpp
         tests/profiling/gatordmock/PeriodicCounterSelectionResponseHandler.cpp
         tests/profiling/gatordmock/PeriodicCounterSelectionResponseHandler.hpp
+        tests/profiling/timelineDecoder/ITimelineDecoder.h
+        tests/profiling/timelineDecoder/TimelineCaptureCommandHandler.cpp
+        tests/profiling/timelineDecoder/TimelineCaptureCommandHandler.hpp
+        tests/profiling/timelineDecoder/TimelineDecoder.cpp
+        tests/profiling/timelineDecoder/TimelineDirectoryCaptureCommandHandler.cpp
+        tests/profiling/timelineDecoder/TimelineDirectoryCaptureCommandHandler.hpp
+        tests/profiling/timelineDecoder/tests/TimelineTestFunctions.hpp
         )
 
     include_directories(${Boost_INCLUDE_DIRS} src/profiling)
index 22d1e6d..c5a2d97 100644 (file)
@@ -3,6 +3,7 @@
 // SPDX-License-Identifier: MIT
 //
 
+#include <atomic>
 #include "DirectoryCaptureCommandHandler.hpp"
 #include "SendCounterPacket.hpp"
 
index b649747..4dde235 100644 (file)
@@ -347,7 +347,7 @@ uint32_t CalculateSizeOfPaddedSwString(const std::string& str)
 }
 
 // Read TimelineMessageDirectoryPacket from given IPacketBuffer and offset
-SwTraceMessage ReadSwTraceMessage(const IPacketBufferPtr& packetBuffer, unsigned int& offset)
+SwTraceMessage ReadSwTraceMessage(const unsigned char* packetBuffer, unsigned int& offset)
 {
     BOOST_ASSERT(packetBuffer);
 
@@ -369,7 +369,7 @@ SwTraceMessage ReadSwTraceMessage(const IPacketBufferPtr& packetBuffer, unsigned
     offset += uint32_t_size;
     std::vector<unsigned char> swTraceStringBuffer(swTraceDeclNameLength - 1);
     std::memcpy(swTraceStringBuffer.data(),
-                packetBuffer->GetReadableData()  + offset, swTraceStringBuffer.size());
+                packetBuffer + offset, swTraceStringBuffer.size());
 
     swTraceMessage.name.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // name
 
@@ -380,7 +380,7 @@ SwTraceMessage ReadSwTraceMessage(const IPacketBufferPtr& packetBuffer, unsigned
     offset += uint32_t_size;
     swTraceStringBuffer.resize(swTraceUINameLength - 1);
     std::memcpy(swTraceStringBuffer.data(),
-                packetBuffer->GetReadableData()  + offset, swTraceStringBuffer.size());
+                packetBuffer  + offset, swTraceStringBuffer.size());
 
     swTraceMessage.uiName.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // ui_name
 
@@ -391,7 +391,7 @@ SwTraceMessage ReadSwTraceMessage(const IPacketBufferPtr& packetBuffer, unsigned
     offset += uint32_t_size;
     swTraceStringBuffer.resize(swTraceArgTypesLength - 1);
     std::memcpy(swTraceStringBuffer.data(),
-                packetBuffer->GetReadableData()  + offset, swTraceStringBuffer.size());
+                packetBuffer  + offset, swTraceStringBuffer.size());
 
     swTraceMessage.argTypes.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // arg_types
 
@@ -404,7 +404,7 @@ SwTraceMessage ReadSwTraceMessage(const IPacketBufferPtr& packetBuffer, unsigned
     offset += uint32_t_size;
     swTraceStringBuffer.resize(swTraceArgNamesLength - 1);
     std::memcpy(swTraceStringBuffer.data(),
-                packetBuffer->GetReadableData()  + offset, swTraceStringBuffer.size());
+                packetBuffer  + offset, swTraceStringBuffer.size());
 
     swTraceString.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end());
     std::stringstream stringStream(swTraceString);
@@ -536,12 +536,11 @@ TimelinePacketStatus WriteTimelineEntityBinaryPacket(uint64_t profilingGuid,
     unsigned int uint64_t_size = sizeof(uint64_t);
 
     // Calculate the length of the data (in bytes)
-    unsigned int timelineEntityPacketDataLength = uint64_t_size;   // Profiling GUID
+    unsigned int timelineEntityPacketDataLength = uint32_t_size + uint64_t_size;  // decl_id + Profiling GUID
 
 
     // Calculate the timeline binary packet size (in bytes)
     unsigned int timelineEntityPacketSize = 2 * uint32_t_size +             // Header (2 words)
-                                            uint32_t_size +                 // decl_Id
                                             timelineEntityPacketDataLength; // Profiling GUID
 
     // Check whether the timeline binary packet fits in the given buffer
@@ -744,6 +743,9 @@ TimelinePacketStatus WriteTimelineMessageDirectoryPackage(unsigned char* buffer,
     WriteUint32(buffer, offset, packetHeader.second);
     offset += uint32_t_size;
 
+    WriteUint32(buffer, offset, static_cast<uint32_t >(swTraceTimelineDirectoryMessages.size()));
+    offset += uint32_t_size;
+
     for (unsigned int i = 0u; i < swTraceTimelineDirectoryMessages.size(); ++i)
     {
         // Write the timeline binary packet payload to the buffer
index 74fc437..f7b46be 100644 (file)
@@ -156,7 +156,7 @@ enum class ProfilingRelationshipType
 
 uint32_t CalculateSizeOfPaddedSwString(const std::string& str);
 
-SwTraceMessage ReadSwTraceMessage(const IPacketBufferPtr& packetBuffer, unsigned int& offset);
+SwTraceMessage ReadSwTraceMessage(const unsigned char*, unsigned int& offset);
 
 TimelinePacketStatus WriteTimelineLabelBinaryPacket(uint64_t profilingGuid,
                                                     const std::string& label,
index 60cda9a..7f30949 100644 (file)
@@ -53,7 +53,11 @@ BOOST_AUTO_TEST_CASE(SendTimelineMessageDirectoryPackageTest)
     BOOST_CHECK(dataLength       == 416);
 
     offset += uint32_t_size;
-    SwTraceMessage swTraceMessage = ReadSwTraceMessage(packetBuffer, offset);
+    uint32_t DeclCount = ReadUint32(packetBuffer, offset);
+    BOOST_CHECK(DeclCount == 5);
+
+    offset += uint32_t_size;
+    SwTraceMessage swTraceMessage = ReadSwTraceMessage(packetBuffer->GetReadableData(), offset);
 
     BOOST_CHECK(swTraceMessage.id == 0);
     BOOST_CHECK(swTraceMessage.name == "declareLabel");
@@ -65,7 +69,7 @@ BOOST_AUTO_TEST_CASE(SendTimelineMessageDirectoryPackageTest)
     BOOST_CHECK(swTraceMessage.argNames[0] == "guid");
     BOOST_CHECK(swTraceMessage.argNames[1] == "value");
 
-    swTraceMessage = ReadSwTraceMessage(packetBuffer, offset);
+    swTraceMessage = ReadSwTraceMessage(packetBuffer->GetReadableData(), offset);
 
     BOOST_CHECK(swTraceMessage.id == 1);
     BOOST_CHECK(swTraceMessage.name == "declareEntity");
@@ -75,7 +79,7 @@ BOOST_AUTO_TEST_CASE(SendTimelineMessageDirectoryPackageTest)
     BOOST_CHECK(swTraceMessage.argNames.size() == 1);
     BOOST_CHECK(swTraceMessage.argNames[0] == "guid");
 
-    swTraceMessage = ReadSwTraceMessage(packetBuffer, offset);
+    swTraceMessage = ReadSwTraceMessage(packetBuffer->GetReadableData(), offset);
 
     BOOST_CHECK(swTraceMessage.id == 2);
     BOOST_CHECK(swTraceMessage.name == "declareEventClass");
@@ -85,7 +89,7 @@ BOOST_AUTO_TEST_CASE(SendTimelineMessageDirectoryPackageTest)
     BOOST_CHECK(swTraceMessage.argNames.size() == 1);
     BOOST_CHECK(swTraceMessage.argNames[0] == "guid");
 
-    swTraceMessage = ReadSwTraceMessage(packetBuffer, offset);
+    swTraceMessage = ReadSwTraceMessage(packetBuffer->GetReadableData(), offset);
 
     BOOST_CHECK(swTraceMessage.id == 3);
     BOOST_CHECK(swTraceMessage.name == "declareRelationship");
@@ -101,7 +105,7 @@ BOOST_AUTO_TEST_CASE(SendTimelineMessageDirectoryPackageTest)
     BOOST_CHECK(swTraceMessage.argNames[2] == "headGuid");
     BOOST_CHECK(swTraceMessage.argNames[3] == "tailGuid");
 
-    swTraceMessage = ReadSwTraceMessage(packetBuffer, offset);
+    swTraceMessage = ReadSwTraceMessage(packetBuffer->GetReadableData(), offset);
 
     BOOST_CHECK(swTraceMessage.id == 4);
     BOOST_CHECK(swTraceMessage.name == "declareEvent");
@@ -157,7 +161,7 @@ BOOST_AUTO_TEST_CASE(SendTimelineEntityPlusEventClassBinaryPacketTest)
     uint32_t entityBinaryPacketSequenceNumbered = (entityBinaryPacketHeaderWord1 >> 24) & 0x00000001;
     uint32_t entityBinaryPacketDataLength       = (entityBinaryPacketHeaderWord1 >>  0) & 0x00FFFFFF;
     BOOST_CHECK(entityBinaryPacketSequenceNumbered == 0);
-    BOOST_CHECK(entityBinaryPacketDataLength       == 8);
+    BOOST_CHECK(entityBinaryPacketDataLength       == 12);
 
     // Check the decl_id
     offset += uint32_t_size;
@@ -243,7 +247,7 @@ BOOST_AUTO_TEST_CASE(SendTimelinePacketTests1)
     uint32_t entityBinaryPacketSequenceNumbered = (entityBinaryPacketHeaderWord1 >> 24) & 0x00000001;
     uint32_t entityBinaryPacketDataLength       = (entityBinaryPacketHeaderWord1 >>  0) & 0x00FFFFFF;
     BOOST_CHECK(entityBinaryPacketSequenceNumbered == 0);
-    BOOST_CHECK(entityBinaryPacketDataLength       == 8);
+    BOOST_CHECK(entityBinaryPacketDataLength       == 12);
 
     // Check the decl_id
     offset += uint32_t_size;
index 6a8aa85..68cd948 100644 (file)
@@ -543,6 +543,11 @@ BOOST_AUTO_TEST_CASE(TimelineMessageDirectoryPacketTest3)
     BOOST_CHECK(sequenceNumbered ==  0);
     BOOST_CHECK(dataLength       == 416);
 
+    // Check the number of declarations
+    offset += uint32_t_size;
+    uint32_t declCount = ReadUint32(buffer.data(), offset);
+    BOOST_CHECK(declCount == 5);
+
     // Check the decl_id
     offset += uint32_t_size;
     uint32_t readDeclId = ReadUint32(buffer.data(), offset);
@@ -689,7 +694,7 @@ BOOST_AUTO_TEST_CASE(TimelineEntityPacketTest4)
     uint32_t sequenceNumbered = (packetHeaderWord1 >> 24) & 0x00000001;
     uint32_t dataLength       = (packetHeaderWord1 >>  0) & 0x00FFFFFF;
     BOOST_CHECK(sequenceNumbered ==  0);
-    BOOST_CHECK(dataLength       == 8);
+    BOOST_CHECK(dataLength       == 12);
 
     // Check decl_Id
     offset += uint32_t_size;
index 3556a12..f784afc 100644 (file)
@@ -258,7 +258,7 @@ void VerifyTimelineEntityBinaryPacket(Optional<ProfilingGuid> guid,
     uint32_t entityBinaryPacketSequenceNumbered = (entityBinaryPacketHeaderWord1 >> 24) & 0x00000001;
     uint32_t entityBinaryPacketDataLength       = (entityBinaryPacketHeaderWord1 >>  0) & 0x00FFFFFF;
     BOOST_CHECK(entityBinaryPacketSequenceNumbered == 0);
-    BOOST_CHECK(entityBinaryPacketDataLength       == 8);
+    BOOST_CHECK(entityBinaryPacketDataLength       == 12);
 
     // Check the decl_id
     offset += uint32_t_size;
diff --git a/tests/profiling/timelineDecoder/ITimelineDecoder.h b/tests/profiling/timelineDecoder/ITimelineDecoder.h
new file mode 100644 (file)
index 0000000..65ec8bf
--- /dev/null
@@ -0,0 +1,41 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#ifndef ARMNN_ITIMELINEDECODER_H
+#define ARMNN_ITIMELINEDECODER_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "TimelineModel.h"
+
+typedef enum ErrorCode
+{
+    ErrorCode_Success,
+    ErrorCode_Fail
+} ErrorCode;
+
+ErrorCode CreateModel(Model** model);
+ErrorCode DestroyModel(Model** model);
+
+ErrorCode SetEntityCallback(OnNewEntityCallback cb, Model* model);
+ErrorCode SetEventClassCallback(OnNewEventClassCallback cb, Model* model);
+ErrorCode SetEventCallback(OnNewEventCallback cb, Model* model);
+ErrorCode SetLabelCallback(OnNewLabelCallback cb, Model* model);
+ErrorCode SetRelationshipCallback(OnNewRelationshipCallback cb, Model* model);
+
+ErrorCode CreateEntity(const Entity entity, Model* model);
+ErrorCode CreateEventClass(const EventClass eventClass, Model* model);
+ErrorCode CreateEvent(const Event event, Model* model);
+ErrorCode CreateLabel(const Label label, Model* model);
+ErrorCode CreateRelationship(const Relationship relationship, Model* model);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //ARMNN_ITIMELINEDECODER_H
\ No newline at end of file
diff --git a/tests/profiling/timelineDecoder/TimelineCaptureCommandHandler.cpp b/tests/profiling/timelineDecoder/TimelineCaptureCommandHandler.cpp
new file mode 100644 (file)
index 0000000..bdceca6
--- /dev/null
@@ -0,0 +1,300 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "TimelineCaptureCommandHandler.hpp"
+
+#include <iostream>
+#include <string>
+
+namespace armnn
+{
+
+namespace gatordmock
+{
+
+//Array of member functions, the array index matches the decl_id
+const TimelineCaptureCommandHandler::ReadFunction TimelineCaptureCommandHandler::m_ReadFunctions[5]
+{
+    &TimelineCaptureCommandHandler::ReadLabel,              // Label decl_id = 0
+    &TimelineCaptureCommandHandler::ReadEntity,             // Entity decl_id = 1
+    &TimelineCaptureCommandHandler::ReadEventClass,         // EventClass decl_id = 2
+    &TimelineCaptureCommandHandler::ReadRelationship,       // Relationship decl_id = 3
+    &TimelineCaptureCommandHandler::ReadEvent               // Event decl_id = 4
+};
+
+void TimelineCaptureCommandHandler::ParseData(const armnn::profiling::Packet& packet)
+{
+    uint32_t offset = 0;
+
+    if (packet.GetLength() < 8)
+    {
+        return;
+    }
+
+    const unsigned char* data = reinterpret_cast<const unsigned char*>(packet.GetData());
+
+    uint32_t declId = 0;
+
+    declId = profiling::ReadUint32(data, offset);
+    offset += uint32_t_size;
+
+    (this->*m_ReadFunctions[declId])(data, offset);
+}
+
+void TimelineCaptureCommandHandler::ReadLabel(const unsigned char* data, uint32_t offset)
+{
+    Label label;
+    label.m_Guid = profiling::ReadUint64(data, offset);
+    offset += uint64_t_size;
+
+    uint32_t nameLength = profiling::ReadUint32(data, offset);
+    offset += uint32_t_size;
+
+    label.m_Name = new char[nameLength];
+    for (uint32_t i = 0; i< nameLength; ++i)
+    {
+        label.m_Name[i] = static_cast<char>(profiling::ReadUint8(data, offset + i));
+    }
+
+    CreateLabel(label, m_Model);
+
+    if (!m_QuietOperation)
+    {
+        printLabels();
+    }
+}
+
+void TimelineCaptureCommandHandler::ReadEntity(const unsigned char* data, uint32_t offset)
+{
+    Entity entity;
+    entity.m_Guid = profiling::ReadUint64(data, offset);
+
+    CreateEntity(entity, m_Model);
+
+    if (!m_QuietOperation)
+    {
+        printEntities();
+    }
+}
+
+void TimelineCaptureCommandHandler::ReadEventClass(const unsigned char* data, uint32_t offset)
+{
+    EventClass eventClass;
+    eventClass.m_Guid = profiling::ReadUint64(data, offset);
+
+    CreateEventClass(eventClass, m_Model);
+
+    if (!m_QuietOperation)
+    {
+        printEventClasses();
+    }
+}
+
+void TimelineCaptureCommandHandler::ReadRelationship(const unsigned char* data, uint32_t offset)
+{
+    Relationship relationship;
+    relationship.m_RelationshipType = static_cast<RelationshipType>(profiling::ReadUint32(data, offset));
+    offset += uint32_t_size;
+
+    relationship.m_Guid = profiling::ReadUint64(data, offset);
+    offset += uint64_t_size;
+
+    relationship.m_HeadGuid  = profiling::ReadUint64(data, offset);
+    offset += uint64_t_size;
+
+    relationship.m_TailGuid = profiling::ReadUint64(data, offset);
+
+    CreateRelationship(relationship, m_Model);
+
+    if (!m_QuietOperation)
+    {
+        printRelationships();
+    }
+}
+
+
+
+void TimelineCaptureCommandHandler::ReadEvent(const unsigned char* data, uint32_t offset)
+{
+    Event event;
+    event.m_TimeStamp = profiling::ReadUint64(data, offset);
+    offset += uint64_t_size;
+
+    event.m_ThreadId = new u_int8_t[threadId_size];
+    profiling::ReadBytes(data, offset, threadId_size, event.m_ThreadId);
+    offset += threadId_size;
+
+    event.m_Guid = profiling::ReadUint64(data, offset);
+
+    CreateEvent(event, m_Model);
+
+    if (!m_QuietOperation)
+    {
+        printEvents();
+    }
+}
+
+void TimelineCaptureCommandHandler::operator()(const profiling::Packet& packet)
+{
+    ParseData(packet);
+}
+
+void TimelineCaptureCommandHandler::printLabels()
+{
+    std::string header;
+
+    header.append(profiling::CentreAlignFormatting("guid", 12));
+    header.append(" | ");
+    header.append(profiling::CentreAlignFormatting("value", 30));
+    header.append("\n");
+
+    std::cout << "\n" << "\n";
+    std::cout << profiling::CentreAlignFormatting("LABELS", static_cast<int>(header.size()));
+    std::cout << "\n";
+    std::cout << std::string(header.size(), '=') << "\n";
+    std::cout << header;
+
+    for (uint32_t i = 0; i < m_Model->m_LabelCount; ++i)
+    {
+        std::string body;
+
+        body.append(profiling::CentreAlignFormatting(std::to_string(m_Model->m_Labels[i]->m_Guid), 12));
+        body.append(" | ");
+        body.append(profiling::CentreAlignFormatting(m_Model->m_Labels[i]->m_Name, 30));
+        body.append("\n");
+
+        std::cout << std::string(body.size(), '-') << "\n";
+        std::cout<< body;
+    }
+}
+
+void TimelineCaptureCommandHandler::printEntities()
+{
+    std::string header;
+    header.append(profiling::CentreAlignFormatting("guid", 12));
+    header.append("\n");
+
+    std::cout << "\n" << "\n";
+    std::cout << profiling::CentreAlignFormatting("ENTITIES", static_cast<int>(header.size()));
+    std::cout << "\n";
+    std::cout << std::string(header.size(), '=') << "\n";
+    std::cout << header;
+
+    for (uint32_t i = 0; i < m_Model->m_EntityCount; ++i)
+    {
+        std::string body;
+
+        body.append(profiling::CentreAlignFormatting(std::to_string(m_Model->m_Entities[i]->m_Guid), 12));
+        body.append("\n");
+
+        std::cout << std::string(body.size(), '-') << "\n";
+        std::cout<< body;
+    }
+}
+
+void TimelineCaptureCommandHandler::printEventClasses()
+{
+    std::string header;
+    header.append(profiling::CentreAlignFormatting("guid", 12));
+    header.append("\n");
+
+    std::cout << "\n" << "\n";
+    std::cout << profiling::CentreAlignFormatting("EVENT CLASSES", static_cast<int>(header.size()));
+    std::cout << "\n";
+    std::cout << std::string(header.size(), '=') << "\n";
+    std::cout << header;
+
+    for (uint32_t i = 0; i < m_Model->m_EventClassCount; ++i)
+    {
+        std::string body;
+
+        body.append(profiling::CentreAlignFormatting(std::to_string(m_Model->m_EventClasses[i]->m_Guid), 12));
+        body.append("\n");
+
+        std::cout << std::string(body.size(), '-') << "\n";
+        std::cout<< body;
+    }
+}
+
+void TimelineCaptureCommandHandler::printRelationships()
+{
+    std::string header;
+    header.append(profiling::CentreAlignFormatting("relationshipType", 20));
+    header.append(" | ");
+    header.append(profiling::CentreAlignFormatting("relationshipGuid", 20));
+    header.append(" | ");
+    header.append(profiling::CentreAlignFormatting("headGuid", 12));
+    header.append(" | ");
+    header.append(profiling::CentreAlignFormatting("tailGuid", 12));
+    header.append("\n");
+
+    std::cout << "\n" << "\n";
+    std::cout << profiling::CentreAlignFormatting("RELATIONSHIPS", static_cast<int>(header.size()));
+    std::cout << "\n";
+    std::cout << std::string(header.size(), '=') << "\n";
+    std::cout << header;
+
+    for (uint32_t i = 0; i < m_Model->m_RelationshipCount; ++i)
+    {
+        std::string body;
+
+        body.append(
+                profiling::CentreAlignFormatting(std::to_string(m_Model->m_Relationships[i]->m_RelationshipType), 20));
+        body.append(" | ");
+        body.append(profiling::CentreAlignFormatting(std::to_string(m_Model->m_Relationships[i]->m_Guid), 20));
+        body.append(" | ");
+        body.append(profiling::CentreAlignFormatting(std::to_string(m_Model->m_Relationships[i]->m_HeadGuid), 12));
+        body.append(" | ");
+        body.append(profiling::CentreAlignFormatting(std::to_string(m_Model->m_Relationships[i]->m_TailGuid), 12));
+        body.append(" | ");
+        body.append("\n");
+
+        std::cout << std::string(body.size(), '-') << "\n";
+        std::cout<< body;
+    }
+}
+
+void TimelineCaptureCommandHandler::printEvents()
+{
+    std::string header;
+
+    header.append(profiling::CentreAlignFormatting("timestamp", 12));
+    header.append(" | ");
+    header.append(profiling::CentreAlignFormatting("threadId", 12));
+    header.append(" | ");
+    header.append(profiling::CentreAlignFormatting("eventGuid", 12));
+    header.append("\n");
+
+    std::cout << "\n" << "\n";
+    std::cout << profiling::CentreAlignFormatting("EVENTS", static_cast<int>(header.size()));
+    std::cout << "\n";
+    std::cout << std::string(header.size(), '=') << "\n";
+    std::cout << header;
+
+    for (uint32_t i = 0; i < m_Model->m_EventCount; ++i)
+    {
+        std::string body;
+
+        body.append(profiling::CentreAlignFormatting(std::to_string(m_Model->m_Events[i]->m_TimeStamp), 12));
+        body.append(" | ");
+
+        std::string threadId;
+        for(uint32_t j =0; j< threadId_size; j++)
+        {
+            threadId += static_cast<char>(m_Model->m_Events[i]->m_ThreadId[j]);
+        }
+        body.append(profiling::CentreAlignFormatting(threadId, 12));
+        body.append(" | ");
+        body.append(profiling::CentreAlignFormatting(std::to_string(m_Model->m_Events[i]->m_Guid), 12));
+        body.append("\n");
+
+        std::cout << std::string(body.size(), '-') << "\n";
+        std::cout<< body;
+    }
+}
+
+} //namespace gatordmock
+
+} //namespace armnn
diff --git a/tests/profiling/timelineDecoder/TimelineCaptureCommandHandler.hpp b/tests/profiling/timelineDecoder/TimelineCaptureCommandHandler.hpp
new file mode 100644 (file)
index 0000000..3f32404
--- /dev/null
@@ -0,0 +1,66 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "ITimelineDecoder.h"
+
+#include <CommandHandlerFunctor.hpp>
+#include <Packet.hpp>
+#include <ProfilingUtils.hpp>
+
+namespace armnn
+{
+
+namespace gatordmock
+{
+
+class TimelineCaptureCommandHandler : public profiling::CommandHandlerFunctor
+{
+    // Utils
+    uint32_t uint32_t_size = sizeof(uint32_t);
+    uint32_t uint64_t_size = sizeof(uint64_t);
+    uint32_t threadId_size = sizeof(std::thread::id);
+
+    using ReadFunction = void (TimelineCaptureCommandHandler::*)(const unsigned char*, uint32_t);
+
+public:
+    TimelineCaptureCommandHandler(uint32_t familyId,
+                                  uint32_t packetId,
+                                  uint32_t version,
+                                  Model* model,
+                                  bool quietOperation = false)
+            : CommandHandlerFunctor(familyId, packetId, version)
+            , m_Model(model)
+            , m_QuietOperation(quietOperation)
+    {}
+
+    void operator()(const armnn::profiling::Packet& packet) override;
+
+    void ReadLabel(const unsigned char* data, uint32_t offset);
+    void ReadEntity(const unsigned char* data, uint32_t offset);
+    void ReadEventClass(const unsigned char* data, uint32_t offset);
+    void ReadRelationship(const unsigned char* data, uint32_t offset);
+    void ReadEvent(const unsigned char* data, uint32_t offset);
+
+    void print();
+
+private:
+    void ParseData(const armnn::profiling::Packet& packet);
+
+    Model* m_Model;
+    bool m_QuietOperation;
+    static const ReadFunction m_ReadFunctions[];
+
+    void printLabels();
+    void printEntities();
+    void printEventClasses();
+    void printRelationships();
+    void printEvents();
+};
+
+} //namespace gatordmock
+
+} //namespace armnn
diff --git a/tests/profiling/timelineDecoder/TimelineDecoder.cpp b/tests/profiling/timelineDecoder/TimelineDecoder.cpp
new file mode 100644 (file)
index 0000000..b6f051b
--- /dev/null
@@ -0,0 +1,166 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "ITimelineDecoder.h"
+
+ErrorCode CreateEntity(const Entity entity, Model* model)
+{
+    if (model == nullptr || model->m_EntityCb == nullptr)
+    {
+        return ErrorCode::ErrorCode_Fail;
+    }
+    model->m_EntityCb(entity, model);
+    return ErrorCode::ErrorCode_Success;
+}
+
+ErrorCode CreateEventClass(const EventClass eventClass, Model* model)
+{
+    if (model == nullptr || model->m_EventClassCb == nullptr)
+    {
+        return ErrorCode::ErrorCode_Fail;
+    }
+    model->m_EventClassCb(eventClass, model);
+    return ErrorCode::ErrorCode_Success;
+}
+
+ErrorCode CreateEvent(const Event event, Model* model)
+{
+    if (model == nullptr || model->m_EventCb == nullptr)
+    {
+        return ErrorCode::ErrorCode_Fail;
+    }
+    model->m_EventCb(event, model);
+    return ErrorCode::ErrorCode_Success;
+}
+
+ErrorCode CreateLabel(const Label label, Model* model)
+{
+    if (model == nullptr || model->m_LabelCb == nullptr)
+    {
+        return ErrorCode::ErrorCode_Fail;
+    }
+    model->m_LabelCb(label, model);
+    return ErrorCode::ErrorCode_Success;
+}
+
+ErrorCode CreateRelationship(Relationship relationship, Model* model)
+{
+    if (model == nullptr || model->m_RelationshipCb == nullptr)
+    {
+        return ErrorCode::ErrorCode_Fail;
+    }
+    model->m_RelationshipCb(relationship, model);
+    return ErrorCode::ErrorCode_Success;
+}
+
+ErrorCode SetEntityCallback(OnNewEntityCallback cb, Model* model)
+{
+    if (cb == nullptr || model == nullptr)
+    {
+        return ErrorCode::ErrorCode_Fail;
+    }
+    model->m_EntityCb = cb;
+    return ErrorCode::ErrorCode_Success;
+}
+
+ErrorCode SetEventClassCallback(OnNewEventClassCallback cb, Model* model)
+{
+    if (cb == nullptr || model == nullptr)
+    {
+        return ErrorCode::ErrorCode_Fail;
+    }
+    model->m_EventClassCb = cb;
+    return ErrorCode::ErrorCode_Success;
+}
+
+ErrorCode SetEventCallback(OnNewEventCallback cb, Model* model)
+{
+    if (cb == nullptr || model == nullptr)
+    {
+        return ErrorCode::ErrorCode_Fail;
+    }
+    model->m_EventCb = cb;
+    return ErrorCode::ErrorCode_Success;
+}
+
+ErrorCode SetLabelCallback(OnNewLabelCallback cb, Model* model)
+{
+    if (cb == nullptr || model == nullptr)
+    {
+        return ErrorCode::ErrorCode_Fail;
+    }
+    model->m_LabelCb = cb;
+    return ErrorCode::ErrorCode_Success;
+}
+
+ErrorCode SetRelationshipCallback(OnNewRelationshipCallback cb, Model* model)
+{
+    if (cb == nullptr || model == nullptr)
+    {
+        return ErrorCode::ErrorCode_Fail;
+    }
+    model->m_RelationshipCb = cb;
+    return ErrorCode::ErrorCode_Success;
+}
+
+ErrorCode CreateModel(Model** model)
+{
+    Model* modelPtr = new Model;
+
+    modelPtr->m_EntityCount = 0;
+    modelPtr->m_EventClassCount = 0;
+    modelPtr->m_EventCount = 0;
+    modelPtr->m_LabelCount = 0;
+    modelPtr->m_RelationshipCount = 0;
+
+    *model = modelPtr;
+    return ErrorCode::ErrorCode_Success;
+}
+
+ErrorCode DestroyModel(Model** model)
+{
+    if (*model == nullptr)
+    {
+        return ErrorCode::ErrorCode_Fail;
+    }
+
+    Model* modelPtr = *model;
+
+    for (uint32_t i = 0; i < modelPtr->m_EntityCount; ++i)
+    {
+        delete modelPtr->m_Entities[i];
+    }
+
+    for (uint32_t i = 0; i < modelPtr->m_EventClassCount; ++i)
+    {
+        delete modelPtr->m_EventClasses[i];
+    }
+
+    for (uint32_t i = 0; i < modelPtr->m_EventCount; ++i)
+    {
+        delete[] modelPtr->m_Events[i]->m_ThreadId;
+        delete modelPtr->m_Events[i];
+    }
+
+    for (uint32_t i = 0; i < modelPtr->m_LabelCount; ++i)
+    {
+        delete[] modelPtr->m_Labels[i]->m_Name;
+        delete modelPtr->m_Labels[i];
+    }
+
+    for (uint32_t i = 0; i < modelPtr->m_RelationshipCount; ++i)
+    {
+        delete modelPtr->m_Relationships[i];
+    }
+
+    delete[] modelPtr->m_Entities;
+    delete[] modelPtr->m_EventClasses;
+    delete[] modelPtr->m_Events;
+    delete[] modelPtr->m_Labels;
+    delete[] modelPtr->m_Relationships;
+
+    delete modelPtr;
+    return ErrorCode::ErrorCode_Success;
+}
\ No newline at end of file
diff --git a/tests/profiling/timelineDecoder/TimelineDirectoryCaptureCommandHandler.cpp b/tests/profiling/timelineDecoder/TimelineDirectoryCaptureCommandHandler.cpp
new file mode 100644 (file)
index 0000000..cb860a9
--- /dev/null
@@ -0,0 +1,106 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "TimelineDirectoryCaptureCommandHandler.hpp"
+
+#include <iostream>
+#include <string>
+
+namespace armnn
+{
+
+namespace gatordmock
+{
+
+void TimelineDirectoryCaptureCommandHandler::ParseData(const armnn::profiling::Packet& packet)
+{
+    uint32_t offset = 0;
+
+    if (packet.GetLength() < 8)
+    {
+        return;
+    }
+
+    const unsigned char* data = packet.GetData();
+
+    uint32_t numberOfDeclarations = profiling::ReadUint32(data, offset);
+    offset += uint32_t_size;
+
+    for (uint32_t declaration = 0; declaration <  numberOfDeclarations; ++declaration)
+    {
+        m_SwTraceMessages.push_back(profiling::ReadSwTraceMessage(data, offset));
+    }
+}
+
+void TimelineDirectoryCaptureCommandHandler::Print()
+{
+    std::string header;
+
+    header.append(profiling::CentreAlignFormatting("decl_id", 12));
+    header.append(" | ");
+    header.append(profiling::CentreAlignFormatting("decl_name", 20));
+    header.append(" | ");
+    header.append(profiling::CentreAlignFormatting("ui_name", 20));
+    header.append(" | ");
+    header.append(profiling::CentreAlignFormatting("arg_types", 16));
+    header.append(" | ");
+    header.append(profiling::CentreAlignFormatting("arg_names", 80));
+    header.append("\n");
+
+    std::cout << "\n" << "\n";
+    std::cout << profiling::CentreAlignFormatting("SW DIRECTORY", static_cast<int>(header.size()));
+    std::cout << "\n";
+    std::cout << std::string(header.size(), '=') << "\n";
+
+    std::cout<< header;
+
+    for (auto swTraceMessage : m_SwTraceMessages)
+    {
+        std::string body;
+
+        body.append(profiling::CentreAlignFormatting(std::to_string(swTraceMessage.id), 12));
+        body.append(" | ");
+        body.append(profiling::CentreAlignFormatting(swTraceMessage.name, 20));
+        body.append(" | ");
+        body.append(profiling::CentreAlignFormatting(swTraceMessage.uiName, 20));
+        body.append(" | ");
+
+        std::string argTypes;
+        for(auto argType: swTraceMessage.argTypes)
+        {
+            argTypes += argType;
+            argTypes += " ";
+        }
+        body.append(profiling::CentreAlignFormatting(argTypes, 16));
+        body.append(" | ");
+
+        std::string argNames;
+        for(auto argName: swTraceMessage.argNames)
+        {
+            argNames += argName + " ";
+        }
+        body.append(profiling::CentreAlignFormatting(argNames, 80));
+
+        body.append("\n");
+
+        std::cout << std::string(body.size(), '-') << "\n";
+
+        std::cout<< body;
+    }
+}
+
+void TimelineDirectoryCaptureCommandHandler::operator()(const profiling::Packet& packet)
+{
+    ParseData(packet);
+
+    if(!m_QuietOperation)
+    {
+        Print();
+    }
+}
+
+} //namespace gatordmock
+
+} //namespace armnn
\ No newline at end of file
diff --git a/tests/profiling/timelineDecoder/TimelineDirectoryCaptureCommandHandler.hpp b/tests/profiling/timelineDecoder/TimelineDirectoryCaptureCommandHandler.hpp
new file mode 100644 (file)
index 0000000..3a575d7
--- /dev/null
@@ -0,0 +1,47 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+
+#include <CommandHandlerFunctor.hpp>
+#include <Packet.hpp>
+#include <PacketBuffer.hpp>
+#include <ProfilingUtils.hpp>
+
+namespace armnn
+{
+
+namespace gatordmock
+{
+
+class TimelineDirectoryCaptureCommandHandler : public profiling::CommandHandlerFunctor
+{
+    // Utils
+    uint32_t uint32_t_size = sizeof(uint32_t);
+
+public:
+    TimelineDirectoryCaptureCommandHandler(uint32_t familyId,
+                                           uint32_t packetId,
+                                           uint32_t version,
+                                           bool quietOperation = false)
+            : CommandHandlerFunctor(familyId, packetId, version)
+            , m_QuietOperation(quietOperation)
+    {}
+
+    void operator()(const armnn::profiling::Packet& packet) override;
+
+    std::vector<profiling::SwTraceMessage> m_SwTraceMessages;
+
+private:
+    void ParseData(const armnn::profiling::Packet& packet);
+    void Print();
+
+    bool m_QuietOperation;
+};
+
+} //namespace gatordmock
+
+} //namespace armnn
\ No newline at end of file
diff --git a/tests/profiling/timelineDecoder/TimelineModel.h b/tests/profiling/timelineDecoder/TimelineModel.h
new file mode 100644 (file)
index 0000000..a4fbd0d
--- /dev/null
@@ -0,0 +1,96 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#ifndef ARMNN_ITIMELINEMODEL_H
+#define ARMNN_ITIMELINEMODEL_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdint.h>
+
+struct Model;
+
+typedef enum RelationshipType
+{
+    RetentionLink, /// Head retains(parents) Tail
+    ExecutionLink, /// Head execution start depends on Tail execution completion
+    DataLink,      /// Head uses data of Tail
+    LabelLink      /// Head uses label Tail (Tail MUST be a guid of a label).
+} RelationshipType;
+
+typedef struct Entity
+{
+    uint64_t m_Guid;
+} Entity;
+
+typedef struct EventClass
+{
+    uint64_t m_Guid;
+} EventClass;
+
+typedef struct Event
+{
+    uint64_t m_Guid;
+    uint64_t m_TimeStamp;
+    unsigned char* m_ThreadId;
+} ProfilingEvent;
+
+typedef struct Label
+{
+    uint64_t m_Guid;
+    char* m_Name;
+} Label;
+
+typedef struct Relationship
+{
+    RelationshipType m_RelationshipType;
+    uint64_t m_Guid;
+    uint64_t m_HeadGuid;
+    uint64_t m_TailGuid;
+} Relationship;
+
+typedef void (*OnNewEntityCallback)(const Entity, struct Model* model);
+typedef void (*OnNewEventClassCallback)(const EventClass, struct Model* model);
+typedef void (*OnNewEventCallback)(const Event, struct Model* model);
+typedef void (*OnNewLabelCallback)(const Label, struct Model* model);
+typedef void (*OnNewRelationshipCallback)(const Relationship, struct Model* model) ;
+
+typedef struct Model
+{
+    OnNewEntityCallback m_EntityCb;
+    OnNewEventClassCallback m_EventClassCb;
+    OnNewEventCallback m_EventCb;
+    OnNewLabelCallback m_LabelCb;
+    OnNewRelationshipCallback m_RelationshipCb;
+
+    Entity** m_Entities;
+    EventClass** m_EventClasses;
+    Event** m_Events;
+    Label** m_Labels;
+    Relationship** m_Relationships;
+
+    uint32_t m_EntityCount;
+    uint32_t m_EntityCapacity;
+
+    uint32_t m_EventClassCount;
+    uint32_t m_EventClassCapacity;
+
+    uint32_t m_EventCount;
+    uint32_t m_EventCapacity;
+
+    uint32_t m_LabelCount;
+    uint32_t m_LabelCapacity;
+
+    uint32_t m_RelationshipCount;
+    uint32_t m_RelationshipCapacity;
+} Model;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //ARMNN_ITIMELINEMODEL_H
\ No newline at end of file
diff --git a/tests/profiling/timelineDecoder/tests/TimelineTestFunctions.hpp b/tests/profiling/timelineDecoder/tests/TimelineTestFunctions.hpp
new file mode 100644 (file)
index 0000000..3fd9d04
--- /dev/null
@@ -0,0 +1,143 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <algorithm>
+#include "../TimelineModel.h"
+
+void PushEntity(const Entity entity, Model* model)
+{
+    if(model->m_EntityCount == 0)
+    {
+        model->m_EntityCapacity = 1;
+        model->m_Entities = new Entity*[model->m_EntityCapacity];
+    }
+    else if(model->m_EntityCount >= model->m_EntityCapacity)
+    {
+        Entity** newEntityArray = new Entity*[model->m_EntityCapacity*2];
+
+        std::copy(model->m_Entities, model->m_Entities + model->m_EntityCapacity, newEntityArray);
+        delete[] model->m_Entities;
+        model->m_Entities = newEntityArray;
+
+        model->m_EntityCapacity = model->m_EntityCapacity *2;
+    }
+
+    Entity* newEntity = new Entity;
+
+    newEntity->m_Guid = entity.m_Guid;
+
+    model->m_Entities[model->m_EntityCount] = newEntity;
+    model->m_EntityCount++;
+};
+
+void PushEventClass(const EventClass eventClass, Model* model)
+{
+    if(model->m_EventClassCount == 0)
+    {
+        model->m_EventClassCapacity = 1;
+        model->m_EventClasses = new EventClass*[model->m_EventClassCapacity];
+    }
+    else if(model->m_EventClassCount >= model->m_EventClassCapacity)
+    {
+        EventClass** newEventClassArray = new EventClass*[model->m_EventClassCapacity *2];
+
+        std::copy(model->m_EventClasses, model->m_EventClasses + model->m_EventClassCapacity, newEventClassArray);
+        delete[] model->m_EventClasses;
+        model->m_EventClasses = newEventClassArray;
+
+        model->m_EventClassCapacity = model->m_EventClassCapacity *2;
+    }
+
+    EventClass* newEventClass = new EventClass;
+
+    newEventClass->m_Guid = eventClass.m_Guid;
+
+    model->m_EventClasses[model->m_EventClassCount] = newEventClass;
+    model->m_EventClassCount++;
+};
+
+void PushEvent(const Event event, Model* model)
+{
+    if(model->m_EventCount == 0)
+    {
+        model->m_EventCapacity = 1;
+        model->m_Events = new Event*[model->m_EventCapacity];
+    }
+    else if(model->m_EventCount >= model->m_EventCapacity)
+    {
+        Event** newEventArray = new Event*[model->m_EventCapacity * 2];
+
+        std::copy(model->m_Events, model->m_Events + model->m_EventCapacity, newEventArray);
+        delete[] model->m_Events;
+        model->m_Events = newEventArray;
+
+        model->m_EventCapacity = model->m_EventCapacity *2;
+    }
+
+    Event* newEvent = new Event;
+
+    newEvent->m_TimeStamp = event.m_TimeStamp;
+    newEvent->m_ThreadId = event.m_ThreadId;
+    newEvent->m_Guid = event.m_Guid;
+
+    model->m_Events[model->m_EventCount] = newEvent;
+    model->m_EventCount++;
+};
+
+void PushLabel(const Label label, Model* model)
+{
+    if(model->m_LabelCount == 0)
+    {
+        model->m_LabelCapacity = 1;
+        model->m_Labels = new Label*[model->m_LabelCapacity];
+    }
+    else if(model->m_LabelCount >= model->m_LabelCapacity)
+    {
+        Label** newLabelArray = new Label*[model->m_LabelCapacity *2];
+
+        std::copy(model->m_Labels, model->m_Labels + model->m_LabelCapacity, newLabelArray);
+        delete[] model->m_Labels;
+        model->m_Labels = newLabelArray;
+
+        model->m_LabelCapacity = model->m_LabelCapacity *2;
+    }
+
+    Label* newLabel = new Label;
+
+    newLabel->m_Guid = label.m_Guid;
+    newLabel->m_Name = label.m_Name;
+
+    model->m_Labels[model->m_LabelCount] = newLabel;
+    model->m_LabelCount++;
+};
+
+void PushRelationship(const Relationship relationship, Model* model)
+{
+    if(model->m_RelationshipCount == 0)
+    {
+        model->m_RelationshipCapacity = 1;
+        model->m_Relationships = new Relationship*[model->m_RelationshipCapacity];
+    }
+    else if(model->m_RelationshipCount >= model->m_RelationshipCapacity)
+    {
+        Relationship** newRelationshipArray = new Relationship*[model->m_RelationshipCapacity *2];
+
+        std::copy(model->m_Relationships, model->m_Relationships + model->m_RelationshipCapacity, newRelationshipArray);
+        delete[] model->m_Relationships;
+        model->m_Relationships = newRelationshipArray;
+
+        model->m_RelationshipCapacity = model->m_RelationshipCapacity *2;
+    }
+
+    Relationship* newRelationship = new Relationship;
+
+    newRelationship->m_Guid = relationship.m_Guid;
+    newRelationship->m_RelationshipType = relationship.m_RelationshipType;
+    newRelationship->m_HeadGuid = relationship.m_HeadGuid;
+    newRelationship->m_TailGuid = relationship.m_TailGuid;
+
+    model->m_Relationships[model->m_RelationshipCount] = newRelationship;
+    model->m_RelationshipCount++;
+};
diff --git a/tests/profiling/timelineDecoder/tests/TimelineTests.cpp b/tests/profiling/timelineDecoder/tests/TimelineTests.cpp
new file mode 100644 (file)
index 0000000..a9c352b
--- /dev/null
@@ -0,0 +1,206 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "../TimelineCaptureCommandHandler.hpp"
+#include "../TimelineDirectoryCaptureCommandHandler.hpp"
+#include "../ITimelineDecoder.h"
+#include "../TimelineModel.h"
+#include "TimelineTestFunctions.hpp"
+
+#include <CommandHandlerFunctor.hpp>
+#include <ProfilingService.hpp>
+#include <PacketBuffer.hpp>
+#include <TimelinePacketWriterFactory.hpp>
+
+#include <boost/test/test_tools.hpp>
+#include <boost/test/unit_test_suite.hpp>
+
+BOOST_AUTO_TEST_SUITE(TimelineDecoderTests)
+
+using namespace armnn;
+
+void SendTimelinePacketToCommandHandler(const unsigned char* packetBuffer,
+                                        profiling::CommandHandlerFunctor &CommandHandler)
+{
+    uint32_t uint32_t_size = sizeof(uint32_t);
+    unsigned int offset = 0;
+
+    uint32_t header[2];
+    header[0] = profiling::ReadUint32(packetBuffer, offset);
+    offset += uint32_t_size;
+    header[1] = profiling::ReadUint32(packetBuffer, offset);
+    offset += uint32_t_size;
+
+    uint32_t PacketDataLength  = header[1] & 0x00FFFFFF;
+
+    std::unique_ptr<unsigned char[]> uniquePacketData = std::make_unique<unsigned char[]>(PacketDataLength);
+
+    std::memcpy(uniquePacketData.get(), packetBuffer + offset, PacketDataLength);
+
+    armnn::profiling::Packet packet = armnn::profiling::Packet(header[0], PacketDataLength, uniquePacketData);
+
+    CommandHandler(packet);
+}
+
+BOOST_AUTO_TEST_CASE(TimelineDirecotryTest)
+{
+    uint32_t uint32_t_size = sizeof(uint32_t);
+
+    profiling::BufferManager bufferManager(5);
+    profiling::TimelinePacketWriterFactory timelinePacketWriterFactory(bufferManager);
+
+    std::unique_ptr<profiling::ISendTimelinePacket> sendTimelinePacket =
+            timelinePacketWriterFactory.GetSendTimelinePacket();
+
+    profiling::PacketVersionResolver packetVersionResolver;
+
+    gatordmock::TimelineDirectoryCaptureCommandHandler timelineDirectoryCaptureCommandHandler(
+            1, 0, packetVersionResolver.ResolvePacketVersion(1, 0).GetEncodedValue(), true);
+
+    sendTimelinePacket->SendTimelineMessageDirectoryPackage();
+    sendTimelinePacket->Commit();
+
+    std::vector<profiling::SwTraceMessage> swTraceBufferMessages;
+
+    unsigned int offset = uint32_t_size * 2;
+
+    std::unique_ptr<profiling::IPacketBuffer> packetBuffer = bufferManager.GetReadableBuffer();
+
+    uint32_t declarationSize = profiling::ReadUint32(packetBuffer, offset);
+    offset += uint32_t_size;
+    for(uint32_t i = 0; i < declarationSize; ++i)
+    {
+        swTraceBufferMessages.push_back(profiling::ReadSwTraceMessage(packetBuffer->GetReadableData(), offset));
+    }
+
+    SendTimelinePacketToCommandHandler(packetBuffer->GetReadableData(), timelineDirectoryCaptureCommandHandler);
+
+    for(uint32_t index = 0; index < declarationSize; ++index)
+    {
+        profiling::SwTraceMessage& bufferMessage = swTraceBufferMessages[index];
+        profiling::SwTraceMessage& handlerMessage = timelineDirectoryCaptureCommandHandler.m_SwTraceMessages[index];
+
+        BOOST_CHECK(bufferMessage.name == handlerMessage.name);
+        BOOST_CHECK(bufferMessage.uiName == handlerMessage.uiName);
+        BOOST_CHECK(bufferMessage.id == handlerMessage.id);
+
+        BOOST_CHECK(bufferMessage.argTypes.size() == handlerMessage.argTypes.size());
+        for(uint32_t i = 0; i < bufferMessage.argTypes.size(); ++i)
+        {
+            BOOST_CHECK(bufferMessage.argTypes[i] == handlerMessage.argTypes[i]);
+        }
+
+        BOOST_CHECK(bufferMessage.argNames.size() == handlerMessage.argNames.size());
+        for(uint32_t i = 0; i < bufferMessage.argNames.size(); ++i)
+        {
+            BOOST_CHECK(bufferMessage.argNames[i] == handlerMessage.argNames[i]);
+        }
+    }
+}
+
+BOOST_AUTO_TEST_CASE(TimelineCaptureTest)
+{
+    uint32_t threadId_size = sizeof(std::thread::id);
+
+    profiling::BufferManager bufferManager(50);
+    profiling::TimelinePacketWriterFactory timelinePacketWriterFactory(bufferManager);
+
+    std::unique_ptr<profiling::ISendTimelinePacket> sendTimelinePacket =
+        timelinePacketWriterFactory.GetSendTimelinePacket();
+
+    profiling::PacketVersionResolver packetVersionResolver;
+
+    Model* modelPtr;
+    CreateModel(&modelPtr);
+
+    gatordmock::TimelineCaptureCommandHandler timelineCaptureCommandHandler(
+        1, 1, packetVersionResolver.ResolvePacketVersion(1, 1).GetEncodedValue(), modelPtr, true);
+
+    BOOST_CHECK(SetEntityCallback(PushEntity, modelPtr)             == ErrorCode_Success);
+    BOOST_CHECK(SetEventClassCallback(PushEventClass, modelPtr)     == ErrorCode_Success);
+    BOOST_CHECK(SetEventCallback(PushEvent, modelPtr)               == ErrorCode_Success);
+    BOOST_CHECK(SetLabelCallback(PushLabel, modelPtr)               == ErrorCode_Success);
+    BOOST_CHECK(SetRelationshipCallback(PushRelationship, modelPtr) == ErrorCode_Success);
+
+    const uint64_t entityGuid = 22222u;
+
+    const uint64_t eventClassGuid = 33333u;
+
+    const uint64_t timestamp = 111111u;
+    const uint64_t eventGuid = 55555u;
+
+    const std::thread::id threadId = std::this_thread::get_id();;
+
+    const uint64_t labelGuid = 11111u;
+    std::string labelName = "test_label";
+
+    const uint64_t relationshipGuid = 44444u;
+    const uint64_t headGuid = 111111u;
+    const uint64_t tailGuid = 222222u;
+
+    for (int i = 0; i < 10; ++i)
+    {
+        // Send entity
+        sendTimelinePacket->SendTimelineEntityBinaryPacket(entityGuid);
+        sendTimelinePacket->Commit();
+        SendTimelinePacketToCommandHandler(bufferManager.GetReadableBuffer()->GetReadableData(),
+                                           timelineCaptureCommandHandler);
+
+        // Send event class
+        sendTimelinePacket->SendTimelineEventClassBinaryPacket(eventClassGuid);
+        sendTimelinePacket->Commit();
+        SendTimelinePacketToCommandHandler(bufferManager.GetReadableBuffer()->GetReadableData(),
+                                           timelineCaptureCommandHandler);
+
+        // Send event
+        sendTimelinePacket->SendTimelineEventBinaryPacket(timestamp, threadId, eventGuid);
+        sendTimelinePacket->Commit();
+        SendTimelinePacketToCommandHandler(bufferManager.GetReadableBuffer()->GetReadableData(),
+                                           timelineCaptureCommandHandler);
+
+        // Send label
+        sendTimelinePacket->SendTimelineLabelBinaryPacket(labelGuid, labelName);
+        sendTimelinePacket->Commit();
+        SendTimelinePacketToCommandHandler(bufferManager.GetReadableBuffer()->GetReadableData(),
+                                           timelineCaptureCommandHandler);
+
+        // Send relationship
+        profiling::ProfilingRelationshipType relationshipType = profiling::ProfilingRelationshipType::DataLink;
+        sendTimelinePacket->SendTimelineRelationshipBinaryPacket(relationshipType,
+                                                                 relationshipGuid,
+                                                                 headGuid,
+                                                                 tailGuid);
+        sendTimelinePacket->Commit();
+        SendTimelinePacketToCommandHandler(bufferManager.GetReadableBuffer()->GetReadableData(),
+                                           timelineCaptureCommandHandler);
+    }
+
+    for (int i = 0; i < 10; ++i)
+    {
+        BOOST_CHECK(modelPtr->m_Entities[i]->m_Guid == entityGuid);
+
+        BOOST_CHECK(modelPtr->m_EventClasses[i]->m_Guid == eventClassGuid);
+
+        BOOST_CHECK(modelPtr->m_Events[i]->m_TimeStamp == timestamp);
+
+        std::vector<uint8_t> readThreadId(threadId_size, 0);
+        profiling::ReadBytes(modelPtr->m_Events[i]->m_ThreadId, 0, threadId_size, readThreadId.data());
+        BOOST_CHECK(readThreadId == threadId);
+
+        BOOST_CHECK(modelPtr->m_Events[i]->m_Guid == eventGuid);
+
+        BOOST_CHECK(modelPtr->m_Labels[i]->m_Guid == labelGuid);
+        BOOST_CHECK(std::string(modelPtr->m_Labels[i]->m_Name) == labelName);
+
+        BOOST_CHECK(modelPtr->m_Relationships[i]->m_RelationshipType == RelationshipType::DataLink);
+        BOOST_CHECK(modelPtr->m_Relationships[i]->m_Guid == relationshipGuid);
+        BOOST_CHECK(modelPtr->m_Relationships[i]->m_HeadGuid == headGuid);
+        BOOST_CHECK(modelPtr->m_Relationships[i]->m_TailGuid == tailGuid);
+    }
+
+    DestroyModel(&modelPtr);
+}
+
+BOOST_AUTO_TEST_SUITE_END()