aboutsummaryrefslogtreecommitdiff
path: root/profiling/server/src/timelineDecoder
diff options
context:
space:
mode:
Diffstat (limited to 'profiling/server/src/timelineDecoder')
-rw-r--r--profiling/server/src/timelineDecoder/CMakeLists.txt44
-rw-r--r--profiling/server/src/timelineDecoder/TimelineCaptureCommandHandler.cpp166
-rw-r--r--profiling/server/src/timelineDecoder/TimelineDecoder.cpp326
-rw-r--r--profiling/server/src/timelineDecoder/TimelineDirectoryCaptureCommandHandler.cpp117
-rw-r--r--profiling/server/src/timelineDecoder/tests/TimelineTests.cpp373
5 files changed, 1026 insertions, 0 deletions
diff --git a/profiling/server/src/timelineDecoder/CMakeLists.txt b/profiling/server/src/timelineDecoder/CMakeLists.txt
new file mode 100644
index 0000000000..7154722fa6
--- /dev/null
+++ b/profiling/server/src/timelineDecoder/CMakeLists.txt
@@ -0,0 +1,44 @@
+#
+# Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+# SPDX-License-Identifier: MIT
+#
+
+if(BUILD_TIMELINE_DECODER)
+ set(timelineDecoder_sources)
+ list(APPEND timelineDecoder_sources
+ TimelineCaptureCommandHandler.cpp
+ TimelineDecoder.cpp
+ TimelineDirectoryCaptureCommandHandler.cpp)
+
+ include_directories(${PROJECT_SOURCE_DIR}/profiling/common/include)
+
+ if(BUILD_UNIT_TESTS)
+ include_directories(${PROJECT_SOURCE_DIR}/src/profiling
+ ${PROJECT_SOURCE_DIR}/src/armnnUtils)
+ target_include_directories(UnitTests PRIVATE ${PROJECT_SOURCE_DIR}/profiling/server/include/timelineDecoder)
+ endif()
+
+
+ if (BUILD_STATIC_PIPE_LIBS)
+ add_library_ex(timelineDecoder STATIC ${timelineDecoder_sources})
+ target_link_libraries(timelineDecoder pipeCommon)
+
+ if ("${CMAKE_SYSTEM_NAME}" STREQUAL Windows)
+ target_link_libraries(timelineDecoder ws2_32.lib)
+ endif()
+ else()
+ add_library_ex(timelineDecoder SHARED ${timelineDecoder_sources})
+ target_link_libraries(timelineDecoder pipeCommon)
+
+ if ("${CMAKE_SYSTEM_NAME}" STREQUAL Windows)
+ target_link_libraries(timelineDecoder ws2_32.lib)
+ endif()
+
+ set_target_properties(timelineDecoder PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
+ set_target_properties(timelineDecoder PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} )
+
+ install(TARGETS timelineDecoder
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+ endif()
+endif()
diff --git a/profiling/server/src/timelineDecoder/TimelineCaptureCommandHandler.cpp b/profiling/server/src/timelineDecoder/TimelineCaptureCommandHandler.cpp
new file mode 100644
index 0000000000..247c9519e0
--- /dev/null
+++ b/profiling/server/src/timelineDecoder/TimelineCaptureCommandHandler.cpp
@@ -0,0 +1,166 @@
+//
+// Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <common/include/CommonProfilingUtils.hpp>
+#include <common/include/Logging.hpp>
+#include <server/include/timelineDecoder/TimelineCaptureCommandHandler.hpp>
+
+#include <string>
+
+namespace arm
+{
+
+namespace pipe
+{
+
+//Array of member functions, the array index matches the decl_id
+const TimelineCaptureCommandHandler::ReadFunction TimelineCaptureCommandHandler::m_ReadFunctions[]
+{
+ &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::SetThreadIdSize(uint32_t size)
+{
+ m_ThreadIdSize = size;
+}
+
+void TimelineCaptureCommandHandler::operator()(const arm::pipe::Packet& packet)
+{
+ ParseData(packet);
+}
+
+void TimelineCaptureCommandHandler::ParseData(const arm::pipe::Packet& packet)
+{
+ uint32_t offset = 0;
+ m_PacketLength = packet.GetLength();
+
+ // We are expecting TimelineDirectoryCaptureCommandHandler to set the thread id size
+ // if it not set in the constructor
+ if (m_ThreadIdSize == 0)
+ {
+ ARM_PIPE_LOG(error) << "TimelineCaptureCommandHandler: m_ThreadIdSize has not been set";
+ return;
+ }
+
+ if (packet.GetLength() < 8)
+ {
+ return;
+ }
+
+ const unsigned char* data = reinterpret_cast<const unsigned char*>(packet.GetData());
+
+ uint32_t declId = 0;
+
+ while ( offset < m_PacketLength )
+ {
+ declId = arm::pipe::ReadUint32(data, offset);
+ offset += uint32_t_size;
+
+ ITimelineDecoder::TimelineStatus status = (this->*m_ReadFunctions[declId])(data, offset);
+ if (status == ITimelineDecoder::TimelineStatus::TimelineStatus_Fail)
+ {
+ ARM_PIPE_LOG(error) << "Decode of timeline message type [" << declId <<
+ "] at offset [" << offset << "] failed";
+ break;
+ }
+ }
+}
+
+ITimelineDecoder::TimelineStatus TimelineCaptureCommandHandler::ReadLabel(const unsigned char* data, uint32_t& offset)
+{
+ ITimelineDecoder::Label label;
+ label.m_Guid = arm::pipe::ReadUint64(data, offset);
+ offset += uint64_t_size;
+
+ uint32_t nameLength = arm::pipe::ReadUint32(data, offset);
+ offset += uint32_t_size;
+
+ uint32_t i = 0;
+ // nameLength - 1 to account for null operator \0
+ for ( i = 0; i < nameLength - 1; ++i )
+ {
+ label.m_Name += static_cast<char>(arm::pipe::ReadUint8(data, offset + i));
+ }
+ // Shift offset past nameLength
+ uint32_t uint32WordAmount = (nameLength / uint32_t_size) + (nameLength % uint32_t_size != 0 ? 1 : 0);
+ offset += uint32WordAmount * uint32_t_size;
+
+ return m_TimelineDecoder.CreateLabel(label);
+}
+
+ITimelineDecoder::TimelineStatus TimelineCaptureCommandHandler::ReadEntity(
+ const unsigned char* data, uint32_t& offset)
+{
+ ITimelineDecoder::Entity entity;
+ entity.m_Guid = arm::pipe::ReadUint64(data, offset);
+ offset += uint64_t_size;
+ return m_TimelineDecoder.CreateEntity(entity);
+}
+
+ITimelineDecoder::TimelineStatus TimelineCaptureCommandHandler::ReadEventClass(
+ const unsigned char* data, uint32_t& offset)
+{
+ ITimelineDecoder::EventClass eventClass;
+ eventClass.m_Guid = arm::pipe::ReadUint64(data, offset);
+ offset += uint64_t_size;
+ eventClass.m_NameGuid = arm::pipe::ReadUint64(data, offset);
+ offset += uint64_t_size;
+ return m_TimelineDecoder.CreateEventClass(eventClass);
+}
+
+ITimelineDecoder::TimelineStatus TimelineCaptureCommandHandler::ReadRelationship(
+ const unsigned char* data, uint32_t& offset)
+{
+ ITimelineDecoder::Relationship relationship;
+ relationship.m_RelationshipType =
+ static_cast<ITimelineDecoder::RelationshipType>(arm::pipe::ReadUint32(data, offset));
+ offset += uint32_t_size;
+
+ relationship.m_Guid = arm::pipe::ReadUint64(data, offset);
+ offset += uint64_t_size;
+
+ relationship.m_HeadGuid = arm::pipe::ReadUint64(data, offset);
+ offset += uint64_t_size;
+
+ relationship.m_TailGuid = arm::pipe::ReadUint64(data, offset);
+ offset += uint64_t_size;
+
+ relationship.m_AttributeGuid = arm::pipe::ReadUint64(data, offset);
+ offset += uint64_t_size;
+
+ return m_TimelineDecoder.CreateRelationship(relationship);
+}
+
+ITimelineDecoder::TimelineStatus TimelineCaptureCommandHandler::ReadEvent(
+ const unsigned char* data, uint32_t& offset)
+{
+ ITimelineDecoder::Event event;
+ event.m_TimeStamp = arm::pipe::ReadUint64(data, offset);
+ offset += uint64_t_size;
+
+ if ( m_ThreadIdSize == 4 )
+ {
+ event.m_ThreadId = arm::pipe::ReadUint32(data, offset);
+ }
+ else if ( m_ThreadIdSize == 8 )
+ {
+ event.m_ThreadId = arm::pipe::ReadUint64(data, offset);
+ }
+
+ offset += m_ThreadIdSize;
+
+ event.m_Guid = arm::pipe::ReadUint64(data, offset);
+ offset += uint64_t_size;
+
+ return m_TimelineDecoder.CreateEvent(event);
+}
+
+} //namespace pipe
+
+} //namespace arm
diff --git a/profiling/server/src/timelineDecoder/TimelineDecoder.cpp b/profiling/server/src/timelineDecoder/TimelineDecoder.cpp
new file mode 100644
index 0000000000..df967de1f5
--- /dev/null
+++ b/profiling/server/src/timelineDecoder/TimelineDecoder.cpp
@@ -0,0 +1,326 @@
+//
+// Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <common/include/CommonProfilingUtils.hpp>
+#include <server/include/timelineDecoder/TimelineDecoder.hpp>
+
+#include <iostream>
+#include <sstream>
+
+namespace arm
+{
+namespace pipe
+{
+
+TimelineDecoder::TimelineStatus TimelineDecoder::CreateEntity(const Entity &entity)
+{
+ if (m_OnNewEntityCallback == nullptr)
+ {
+ return TimelineStatus::TimelineStatus_Fail;
+ }
+ m_OnNewEntityCallback(m_Model, entity);
+
+ return TimelineStatus::TimelineStatus_Success;
+}
+
+TimelineDecoder::TimelineStatus TimelineDecoder::CreateEventClass(const EventClass &eventClass)
+{
+ if (m_OnNewEventClassCallback == nullptr)
+ {
+ return TimelineStatus::TimelineStatus_Fail;
+ }
+ m_OnNewEventClassCallback(m_Model, eventClass);
+
+ return TimelineStatus::TimelineStatus_Success;
+}
+
+TimelineDecoder::TimelineStatus TimelineDecoder::CreateEvent(const Event &event)
+{
+ if (m_OnNewEventCallback == nullptr)
+ {
+ return TimelineStatus::TimelineStatus_Fail;
+ }
+ m_OnNewEventCallback(m_Model, event);
+
+ return TimelineStatus::TimelineStatus_Success;
+}
+
+TimelineDecoder::TimelineStatus TimelineDecoder::CreateLabel(const Label &label)
+{
+ if (m_OnNewLabelCallback == nullptr)
+ {
+ return TimelineStatus::TimelineStatus_Fail;
+ }
+ m_OnNewLabelCallback(m_Model, label);
+
+ return TimelineStatus::TimelineStatus_Success;
+}
+
+TimelineDecoder::TimelineStatus TimelineDecoder::CreateRelationship(const Relationship &relationship)
+{
+ if (m_OnNewRelationshipCallback == nullptr)
+ {
+ return TimelineStatus::TimelineStatus_Fail;
+ }
+ m_OnNewRelationshipCallback(m_Model, relationship);
+ return TimelineStatus::TimelineStatus_Success;
+}
+
+const TimelineDecoder::Model &TimelineDecoder::GetModel()
+{
+ return m_Model;
+}
+
+TimelineDecoder::TimelineStatus TimelineDecoder::SetEntityCallback(OnNewEntityCallback cb)
+{
+ if (cb == nullptr)
+ {
+ return TimelineStatus::TimelineStatus_Fail;
+ }
+ m_OnNewEntityCallback = cb;
+ return TimelineStatus::TimelineStatus_Success;
+}
+
+TimelineDecoder::TimelineStatus TimelineDecoder::SetEventClassCallback(OnNewEventClassCallback cb)
+{
+ if (cb == nullptr)
+ {
+ return TimelineStatus::TimelineStatus_Fail;
+ }
+ m_OnNewEventClassCallback = cb;
+ return TimelineStatus::TimelineStatus_Success;
+}
+
+TimelineDecoder::TimelineStatus TimelineDecoder::SetEventCallback(OnNewEventCallback cb)
+{
+ if (cb == nullptr)
+ {
+ return TimelineStatus::TimelineStatus_Fail;
+ }
+ m_OnNewEventCallback = cb;
+ return TimelineStatus::TimelineStatus_Success;
+}
+
+TimelineDecoder::TimelineStatus TimelineDecoder::SetLabelCallback(OnNewLabelCallback cb)
+{
+ if (cb == nullptr)
+ {
+ return TimelineStatus::TimelineStatus_Fail;
+ }
+ m_OnNewLabelCallback = cb;
+ return TimelineStatus::TimelineStatus_Success;
+}
+
+TimelineDecoder::TimelineStatus TimelineDecoder::SetRelationshipCallback(OnNewRelationshipCallback cb)
+{
+ if (cb == nullptr)
+ {
+ return TimelineStatus::TimelineStatus_Fail;
+ }
+ m_OnNewRelationshipCallback = cb;
+ return TimelineStatus::TimelineStatus_Success;
+}
+
+void TimelineDecoder::SetDefaultCallbacks()
+{
+ SetEntityCallback([](Model& model, const ITimelineDecoder::Entity entity)
+ {
+ model.m_Entities.emplace_back(entity);
+ });
+
+ SetEventClassCallback([](Model& model, const ITimelineDecoder::EventClass eventClass)
+ {
+ model.m_EventClasses.emplace_back(eventClass);
+ });
+
+ SetEventCallback([](Model& model, const ITimelineDecoder::Event event)
+ {
+ model.m_Events.emplace_back(event);
+ });
+
+ SetLabelCallback([](Model& model, const ITimelineDecoder::Label label)
+ {
+ model.m_Labels.emplace_back(label);
+ });
+
+ SetRelationshipCallback([](Model& model, const ITimelineDecoder::Relationship relationship)
+ {
+ model.m_Relationships.emplace_back(relationship);
+ });
+}
+
+void TimelineDecoder::print()
+{
+ if (m_Model.m_Labels.empty() && m_Model.m_Entities.empty() && m_Model.m_EventClasses.empty() &&
+ m_Model.m_Events.empty() && m_Model.m_Relationships.empty())
+ {
+ std::cout << "No timeline packets received" << std::endl;
+ return;
+ }
+
+ printLabels();
+ printEntities();
+ printEventClasses();
+ printEvents();
+ printRelationships();
+}
+
+void TimelineDecoder::printLabels()
+{
+ std::string header;
+
+ header.append(arm::pipe::CentreAlignFormatting("guid", 12));
+ header.append(" | ");
+ header.append(arm::pipe::CentreAlignFormatting("value", 30));
+ header.append("\n");
+
+ std::cout << "\n" << "\n";
+ std::cout << arm::pipe::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_Labels.size(); ++i)
+ {
+ std::string body;
+
+ body.append(arm::pipe::CentreAlignFormatting(std::to_string(m_Model.m_Labels[i].m_Guid), 12));
+ body.append(" | ");
+ body.append(arm::pipe::CentreAlignFormatting(m_Model.m_Labels[i].m_Name, 30));
+ body.append("\n");
+
+ std::cout << std::string(body.size(), '-') << "\n";
+ std::cout << body;
+ }
+}
+
+void TimelineDecoder::printEntities()
+{
+ std::string header;
+ header.append(arm::pipe::CentreAlignFormatting("guid", 12));
+ header.append("\n");
+
+ std::cout << "\n" << "\n";
+ std::cout << arm::pipe::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_Entities.size(); ++i)
+ {
+ std::string body;
+
+ body.append(arm::pipe::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 TimelineDecoder::printEventClasses()
+{
+ std::string header;
+ header.append(arm::pipe::CentreAlignFormatting("guid", 12));
+ header.append("\n");
+
+ std::cout << "\n" << "\n";
+ std::cout << arm::pipe::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_EventClasses.size(); ++i)
+ {
+ std::string body;
+
+ body.append(arm::pipe::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 TimelineDecoder::printEvents()
+{
+ std::string header;
+
+ header.append(arm::pipe::CentreAlignFormatting("timestamp", 12));
+ header.append(" | ");
+ header.append(arm::pipe::CentreAlignFormatting("threadId", 12));
+ header.append(" | ");
+ header.append(arm::pipe::CentreAlignFormatting("eventGuid", 12));
+ header.append("\n");
+
+ std::cout << "\n" << "\n";
+ std::cout << arm::pipe::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_Events.size(); ++i)
+ {
+ std::string body;
+
+ body.append(arm::pipe::CentreAlignFormatting(std::to_string(m_Model.m_Events[i].m_TimeStamp), 12));
+ body.append(" | ");
+
+ std::stringstream ss;
+ ss << m_Model.m_Events[i].m_ThreadId;
+ std::string threadId = ss.str();;
+
+ body.append(arm::pipe::CentreAlignFormatting(threadId, 12));
+ body.append(" | ");
+ body.append(arm::pipe::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;
+ }
+}
+
+void TimelineDecoder::printRelationships()
+{
+ std::string header;
+ header.append(arm::pipe::CentreAlignFormatting("relationshipType", 20));
+ header.append(" | ");
+ header.append(arm::pipe::CentreAlignFormatting("relationshipGuid", 20));
+ header.append(" | ");
+ header.append(arm::pipe::CentreAlignFormatting("headGuid", 12));
+ header.append(" | ");
+ header.append(arm::pipe::CentreAlignFormatting("tailGuid", 12));
+ header.append("\n");
+
+ std::cout << "\n" << "\n";
+ std::cout << arm::pipe::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_Relationships.size(); ++i)
+ {
+ std::string body;
+
+ body.append(
+ arm::pipe::CentreAlignFormatting(std::to_string(static_cast<unsigned int>
+ (m_Model.m_Relationships[i].m_RelationshipType)),
+ 20));
+ body.append(" | ");
+ body.append(arm::pipe::CentreAlignFormatting(std::to_string(m_Model.m_Relationships[i].m_Guid), 20));
+ body.append(" | ");
+ body.append(arm::pipe::CentreAlignFormatting(std::to_string(m_Model.m_Relationships[i].m_HeadGuid), 12));
+ body.append(" | ");
+ body.append(arm::pipe::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;
+ }
+}
+
+} // namespace pipe
+} // namespace arm \ No newline at end of file
diff --git a/profiling/server/src/timelineDecoder/TimelineDirectoryCaptureCommandHandler.cpp b/profiling/server/src/timelineDecoder/TimelineDirectoryCaptureCommandHandler.cpp
new file mode 100644
index 0000000000..6963dd00c7
--- /dev/null
+++ b/profiling/server/src/timelineDecoder/TimelineDirectoryCaptureCommandHandler.cpp
@@ -0,0 +1,117 @@
+//
+// Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <common/include/CommonProfilingUtils.hpp>
+#include <common/include/SwTrace.hpp>
+#include <server/include/timelineDecoder/TimelineCaptureCommandHandler.hpp>
+#include <server/include/timelineDecoder/TimelineDirectoryCaptureCommandHandler.hpp>
+
+#include <iostream>
+#include <string>
+
+namespace arm
+{
+
+namespace pipe
+{
+
+void TimelineDirectoryCaptureCommandHandler::ParseData(const arm::pipe::Packet& packet)
+{
+ uint32_t offset = 0;
+
+ if (packet.GetLength() < 8)
+ {
+ return;
+ }
+
+ const unsigned char* data = packet.GetData();
+
+ m_SwTraceHeader.m_StreamVersion = ReadUint8(data, offset);
+ offset += uint8_t_size;
+ m_SwTraceHeader.m_PointerBytes = ReadUint8(data, offset);
+ offset += uint8_t_size;
+ m_SwTraceHeader.m_ThreadIdBytes = ReadUint8(data, offset);
+ offset += uint8_t_size;
+
+ uint32_t numberOfDeclarations = arm::pipe::ReadUint32(data, offset);
+ offset += uint32_t_size;
+
+ for (uint32_t declaration = 0; declaration < numberOfDeclarations; ++declaration)
+ {
+ m_SwTraceMessages.push_back(arm::pipe::ReadSwTraceMessage(data, offset, packet.GetLength()));
+ }
+
+ m_TimelineCaptureCommandHandler.SetThreadIdSize(m_SwTraceHeader.m_ThreadIdBytes);
+}
+
+void TimelineDirectoryCaptureCommandHandler::Print()
+{
+ std::string header;
+
+ header.append(arm::pipe::CentreAlignFormatting("decl_id", 12));
+ header.append(" | ");
+ header.append(arm::pipe::CentreAlignFormatting("decl_name", 20));
+ header.append(" | ");
+ header.append(arm::pipe::CentreAlignFormatting("ui_name", 20));
+ header.append(" | ");
+ header.append(arm::pipe::CentreAlignFormatting("arg_types", 16));
+ header.append(" | ");
+ header.append(arm::pipe::CentreAlignFormatting("arg_names", 80));
+ header.append("\n");
+
+ std::cout << "\n" << "\n";
+ std::cout << arm::pipe::CentreAlignFormatting("SW DIRECTORY", static_cast<int>(header.size()));
+ std::cout << "\n";
+ std::cout << std::string(header.size(), '=') << "\n";
+
+ std::cout << header;
+
+ for (const auto& swTraceMessage : m_SwTraceMessages)
+ {
+ std::string body;
+
+ body.append(arm::pipe::CentreAlignFormatting(std::to_string(swTraceMessage.m_Id), 12));
+ body.append(" | ");
+ body.append(arm::pipe::CentreAlignFormatting(swTraceMessage.m_Name, 20));
+ body.append(" | ");
+ body.append(arm::pipe::CentreAlignFormatting(swTraceMessage.m_UiName, 20));
+ body.append(" | ");
+
+ std::string argTypes;
+ for (auto argType: swTraceMessage.m_ArgTypes)
+ {
+ argTypes += argType;
+ argTypes += " ";
+ }
+ body.append(arm::pipe::CentreAlignFormatting(argTypes, 16));
+ body.append(" | ");
+
+ std::string argNames;
+ for (auto argName: swTraceMessage.m_ArgNames)
+ {
+ argNames += argName + " ";
+ }
+ body.append(arm::pipe::CentreAlignFormatting(argNames, 80));
+
+ body.append("\n");
+
+ std::cout << std::string(body.size(), '-') << "\n";
+
+ std::cout << body;
+ }
+}
+
+void TimelineDirectoryCaptureCommandHandler::operator()(const arm::pipe::Packet& packet)
+{
+ ParseData(packet);
+
+ if (!m_QuietOperation)
+ {
+ Print();
+ }
+}
+
+} //namespace pipe
+} //namespace arm
diff --git a/profiling/server/src/timelineDecoder/tests/TimelineTests.cpp b/profiling/server/src/timelineDecoder/tests/TimelineTests.cpp
new file mode 100644
index 0000000000..e7797061c9
--- /dev/null
+++ b/profiling/server/src/timelineDecoder/tests/TimelineTests.cpp
@@ -0,0 +1,373 @@
+//
+// Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <common/include/CommandHandlerFunctor.hpp>
+#include <common/include/CommonProfilingUtils.hpp>
+#include <server/include/timelineDecoder/TimelineCaptureCommandHandler.hpp>
+#include <server/include/timelineDecoder/TimelineDirectoryCaptureCommandHandler.hpp>
+#include <server/include/timelineDecoder/TimelineDecoder.hpp>
+
+#include <BufferManager.hpp>
+#include <Threads.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)
+
+void SendTimelinePacketToCommandHandler(const unsigned char* packetBuffer,
+ arm::pipe::CommandHandlerFunctor& CommandHandler)
+{
+ uint32_t uint32_t_size = sizeof(uint32_t);
+ unsigned int offset = 0;
+
+ uint32_t header[2];
+ header[0] = arm::pipe::ReadUint32(packetBuffer, offset);
+ offset += uint32_t_size;
+ header[1] = arm::pipe::ReadUint32(packetBuffer, offset);
+ offset += uint32_t_size;
+ uint32_t PacketDataLength = header[1] & 0x00FFFFFF;
+
+ auto uniquePacketData = std::make_unique<unsigned char[]>(PacketDataLength);
+ std::memcpy(uniquePacketData.get(), packetBuffer + offset, PacketDataLength);
+
+ arm::pipe::Packet packet(header[0], PacketDataLength, uniquePacketData);
+
+ BOOST_CHECK(std::memcmp(packetBuffer + offset, packet.GetData(), packet.GetLength()) == 0);
+
+ CommandHandler(packet);
+}
+
+void PushEntity(arm::pipe::TimelineDecoder::Model& model, const arm::pipe::ITimelineDecoder::Entity entity)
+{
+ model.m_Entities.emplace_back(entity);
+}
+
+void PushEventClass(arm::pipe::TimelineDecoder::Model& model, const arm::pipe::ITimelineDecoder::EventClass eventClass)
+{
+ model.m_EventClasses.emplace_back(eventClass);
+}
+
+void PushEvent(arm::pipe::TimelineDecoder::Model& model, const arm::pipe::ITimelineDecoder::Event event)
+{
+ model.m_Events.emplace_back(event);
+}
+
+void PushLabel(arm::pipe::TimelineDecoder::Model& model, const arm::pipe::ITimelineDecoder::Label label)
+{
+ model.m_Labels.emplace_back(label);
+}
+
+void PushRelationship(arm::pipe::TimelineDecoder::Model& model,
+ const arm::pipe::ITimelineDecoder::Relationship relationship)
+{
+ model.m_Relationships.emplace_back(relationship);
+}
+
+BOOST_AUTO_TEST_CASE(TimelineDirectoryTest)
+{
+ uint32_t uint8_t_size = sizeof(uint8_t);
+ uint32_t uint32_t_size = sizeof(uint32_t);
+ uint32_t uint64_t_size = sizeof(uint64_t);
+
+ armnn::profiling::BufferManager bufferManager(5);
+ armnn::profiling::TimelinePacketWriterFactory timelinePacketWriterFactory(bufferManager);
+
+ std::unique_ptr<armnn::profiling::ISendTimelinePacket> sendTimelinePacket =
+ timelinePacketWriterFactory.GetSendTimelinePacket();
+
+ arm::pipe::PacketVersionResolver packetVersionResolver;
+
+ arm::pipe::TimelineDecoder timelineDecoder;
+ arm::pipe::TimelineCaptureCommandHandler timelineCaptureCommandHandler(
+ 1, 1, packetVersionResolver.ResolvePacketVersion(1, 1).GetEncodedValue(), timelineDecoder);
+
+ arm::pipe::TimelineDirectoryCaptureCommandHandler timelineDirectoryCaptureCommandHandler(
+ 1, 0, packetVersionResolver.ResolvePacketVersion(1, 0).GetEncodedValue(),
+ timelineCaptureCommandHandler, true);
+
+ sendTimelinePacket->SendTimelineMessageDirectoryPackage();
+ sendTimelinePacket->Commit();
+
+ std::vector<arm::pipe::SwTraceMessage> swTraceBufferMessages;
+
+ unsigned int offset = uint32_t_size * 2;
+
+ std::unique_ptr<armnn::profiling::IPacketBuffer> packetBuffer = bufferManager.GetReadableBuffer();
+
+ uint8_t readStreamVersion = ReadUint8(packetBuffer, offset);
+ BOOST_CHECK(readStreamVersion == 4);
+ offset += uint8_t_size;
+ uint8_t readPointerBytes = ReadUint8(packetBuffer, offset);
+ BOOST_CHECK(readPointerBytes == uint64_t_size);
+ offset += uint8_t_size;
+ uint8_t readThreadIdBytes = ReadUint8(packetBuffer, offset);
+ BOOST_CHECK(readThreadIdBytes == armnn::profiling::ThreadIdSize);
+ offset += uint8_t_size;
+
+ uint32_t declarationSize = arm::pipe::ReadUint32(packetBuffer->GetReadableData(), offset);
+ offset += uint32_t_size;
+ for(uint32_t i = 0; i < declarationSize; ++i)
+ {
+ swTraceBufferMessages.push_back(arm::pipe::ReadSwTraceMessage(packetBuffer->GetReadableData(),
+ offset,
+ packetBuffer->GetSize()));
+ }
+
+ SendTimelinePacketToCommandHandler(packetBuffer->GetReadableData(), timelineDirectoryCaptureCommandHandler);
+
+ for(uint32_t index = 0; index < declarationSize; ++index)
+ {
+ arm::pipe::SwTraceMessage& bufferMessage = swTraceBufferMessages[index];
+ arm::pipe::SwTraceMessage& handlerMessage = timelineDirectoryCaptureCommandHandler.m_SwTraceMessages[index];
+
+ BOOST_CHECK(bufferMessage.m_Name == handlerMessage.m_Name);
+ BOOST_CHECK(bufferMessage.m_UiName == handlerMessage.m_UiName);
+ BOOST_CHECK(bufferMessage.m_Id == handlerMessage.m_Id);
+
+ BOOST_CHECK(bufferMessage.m_ArgTypes.size() == handlerMessage.m_ArgTypes.size());
+ for(uint32_t i = 0; i < bufferMessage.m_ArgTypes.size(); ++i)
+ {
+ BOOST_CHECK(bufferMessage.m_ArgTypes[i] == handlerMessage.m_ArgTypes[i]);
+ }
+
+ BOOST_CHECK(bufferMessage.m_ArgNames.size() == handlerMessage.m_ArgNames.size());
+ for(uint32_t i = 0; i < bufferMessage.m_ArgNames.size(); ++i)
+ {
+ BOOST_CHECK(bufferMessage.m_ArgNames[i] == handlerMessage.m_ArgNames[i]);
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(TimelineCaptureTest)
+{
+ armnn::profiling::BufferManager bufferManager(50);
+ armnn::profiling::TimelinePacketWriterFactory timelinePacketWriterFactory(bufferManager);
+
+ std::unique_ptr<armnn::profiling::ISendTimelinePacket> sendTimelinePacket =
+ timelinePacketWriterFactory.GetSendTimelinePacket();
+
+ arm::pipe::PacketVersionResolver packetVersionResolver;
+
+ arm::pipe::TimelineDecoder timelineDecoder;
+ const arm::pipe::TimelineDecoder::Model& model = timelineDecoder.GetModel();
+
+
+ arm::pipe::TimelineCaptureCommandHandler timelineCaptureCommandHandler(
+ 1, 1, packetVersionResolver.ResolvePacketVersion(1, 1).GetEncodedValue(), timelineDecoder,
+ armnn::profiling::ThreadIdSize);
+
+ using Status = arm::pipe::ITimelineDecoder::TimelineStatus;
+ BOOST_CHECK(timelineDecoder.SetEntityCallback(PushEntity) == Status::TimelineStatus_Success);
+ BOOST_CHECK(timelineDecoder.SetEventClassCallback(PushEventClass) == Status::TimelineStatus_Success);
+ BOOST_CHECK(timelineDecoder.SetEventCallback(PushEvent) == Status::TimelineStatus_Success);
+ BOOST_CHECK(timelineDecoder.SetLabelCallback(PushLabel) == Status::TimelineStatus_Success);
+ BOOST_CHECK(timelineDecoder.SetRelationshipCallback(PushRelationship) == Status::TimelineStatus_Success);
+
+ const uint64_t entityGuid = 111111u;
+ const uint64_t eventClassGuid = 22222u;
+ const uint64_t eventClassNameGuid = 22322u;
+ const uint64_t timestamp = 33333u;
+ const uint64_t eventGuid = 44444u;
+
+ const int threadId = armnnUtils::Threads::GetCurrentThreadId();
+
+ // need to do a bit of work here to extract the value from threadId
+ unsigned char* uCharThreadId = new unsigned char[armnn::profiling::ThreadIdSize]();;
+ uint64_t uint64ThreadId;
+
+ arm::pipe::WriteBytes(uCharThreadId, 0, &threadId, armnn::profiling::ThreadIdSize);
+
+ if (armnn::profiling::ThreadIdSize == 4)
+ {
+ uint64ThreadId = arm::pipe::ReadUint32(uCharThreadId, 0);
+ }
+ else if (armnn::profiling::ThreadIdSize == 8)
+ {
+ uint64ThreadId = arm::pipe::ReadUint64(uCharThreadId, 0);
+ }
+ delete[] uCharThreadId;
+
+ const uint64_t labelGuid = 66666u;
+ std::string labelName = "test_label";
+
+ const uint64_t relationshipGuid = 77777u;
+ const uint64_t headGuid = 888888u;
+ const uint64_t tailGuid = 999999u;
+
+ 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, eventClassNameGuid);
+ 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
+ armnn::profiling::ProfilingRelationshipType relationshipType =
+ armnn::profiling::ProfilingRelationshipType::DataLink;
+ sendTimelinePacket->SendTimelineRelationshipBinaryPacket(relationshipType,
+ relationshipGuid,
+ headGuid,
+ tailGuid,
+ 0);
+ sendTimelinePacket->Commit();
+ SendTimelinePacketToCommandHandler(bufferManager.GetReadableBuffer()->GetReadableData(),
+ timelineCaptureCommandHandler);
+ }
+
+ for (unsigned long i = 0; i < 10; ++i)
+ {
+ BOOST_CHECK(model.m_Entities[i].m_Guid == entityGuid);
+
+ BOOST_CHECK(model.m_EventClasses[i].m_Guid == eventClassGuid);
+
+ BOOST_CHECK(model.m_Events[i].m_TimeStamp == timestamp);
+ BOOST_CHECK(model.m_Events[i].m_ThreadId == uint64ThreadId);
+ BOOST_CHECK(model.m_Events[i].m_Guid == eventGuid);
+
+ BOOST_CHECK(model.m_Labels[i].m_Guid == labelGuid);
+ BOOST_CHECK(model.m_Labels[i].m_Name == labelName);
+
+ BOOST_CHECK(model.m_Relationships[i].m_RelationshipType ==
+ arm::pipe::ITimelineDecoder::RelationshipType::DataLink);
+ BOOST_CHECK(model.m_Relationships[i].m_Guid == relationshipGuid);
+ BOOST_CHECK(model.m_Relationships[i].m_HeadGuid == headGuid);
+ BOOST_CHECK(model.m_Relationships[i].m_TailGuid == tailGuid);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(TimelineCaptureTestMultipleStringsInBuffer)
+{
+ armnn::profiling::BufferManager bufferManager(50);
+ armnn::profiling::TimelinePacketWriterFactory timelinePacketWriterFactory(bufferManager);
+
+ std::unique_ptr<armnn::profiling::ISendTimelinePacket> sendTimelinePacket =
+ timelinePacketWriterFactory.GetSendTimelinePacket();
+
+ arm::pipe::PacketVersionResolver packetVersionResolver;
+
+ arm::pipe::TimelineDecoder timelineDecoder;
+ const arm::pipe::TimelineDecoder::Model& model = timelineDecoder.GetModel();
+
+ arm::pipe::TimelineCaptureCommandHandler timelineCaptureCommandHandler(
+ 1, 1, packetVersionResolver.ResolvePacketVersion(1, 1).GetEncodedValue(), timelineDecoder,
+ armnn::profiling::ThreadIdSize);
+
+ using Status = arm::pipe::TimelineDecoder::TimelineStatus;
+ BOOST_CHECK(timelineDecoder.SetEntityCallback(PushEntity) == Status::TimelineStatus_Success);
+ BOOST_CHECK(timelineDecoder.SetEventClassCallback(PushEventClass) == Status::TimelineStatus_Success);
+ BOOST_CHECK(timelineDecoder.SetEventCallback(PushEvent) == Status::TimelineStatus_Success);
+ BOOST_CHECK(timelineDecoder.SetLabelCallback(PushLabel) == Status::TimelineStatus_Success);
+ BOOST_CHECK(timelineDecoder.SetRelationshipCallback(PushRelationship) == Status::TimelineStatus_Success);
+
+ const uint64_t entityGuid = 111111u;
+ const uint64_t eventClassGuid = 22222u;
+ const uint64_t eventClassNameGuid = 22322u;
+ const uint64_t timestamp = 33333u;
+ const uint64_t eventGuid = 44444u;
+
+ const int threadId = armnnUtils::Threads::GetCurrentThreadId();
+
+ // need to do a bit of work here to extract the value from threadId
+ unsigned char* uCharThreadId = new unsigned char[armnn::profiling::ThreadIdSize]();
+ uint64_t uint64ThreadId;
+
+ arm::pipe::WriteBytes(uCharThreadId, 0, &threadId, armnn::profiling::ThreadIdSize);
+
+ if ( armnn::profiling::ThreadIdSize == 4 )
+ {
+ uint64ThreadId = arm::pipe::ReadUint32(uCharThreadId, 0);
+ }
+ else if ( armnn::profiling::ThreadIdSize == 8 )
+ {
+ uint64ThreadId = arm::pipe::ReadUint64(uCharThreadId, 0);
+ }
+ delete[] uCharThreadId;
+
+ const uint64_t labelGuid = 66666u;
+ std::string labelName = "test_label";
+ std::string labelName2 = "test_label2";
+ std::string labelName3 = "test_label32";
+
+ const uint64_t relationshipGuid = 77777u;
+ const uint64_t headGuid = 888888u;
+ const uint64_t tailGuid = 999999u;
+
+ // Check with multiple messages in the same buffer
+ for ( int i = 0; i < 9; ++i )
+ {
+ // Send entity
+ sendTimelinePacket->SendTimelineEntityBinaryPacket(entityGuid);
+ // Send event class
+ sendTimelinePacket->SendTimelineEventClassBinaryPacket(eventClassGuid, eventClassNameGuid);
+ // Send event
+ sendTimelinePacket->SendTimelineEventBinaryPacket(timestamp, threadId, eventGuid);
+ // Send label
+ sendTimelinePacket->SendTimelineLabelBinaryPacket(labelGuid, labelName);
+ sendTimelinePacket->SendTimelineLabelBinaryPacket(labelGuid, labelName2);
+ sendTimelinePacket->SendTimelineLabelBinaryPacket(labelGuid, labelName3);
+ // Send relationship
+ armnn::profiling::ProfilingRelationshipType relationshipType =
+ armnn::profiling::ProfilingRelationshipType::DataLink;
+ sendTimelinePacket->SendTimelineRelationshipBinaryPacket(relationshipType,
+ relationshipGuid,
+ headGuid,
+ tailGuid,
+ 0);
+ }
+
+ sendTimelinePacket->Commit();
+ SendTimelinePacketToCommandHandler(bufferManager.GetReadableBuffer()->GetReadableData(),
+ timelineCaptureCommandHandler);
+
+ for ( unsigned long i = 0; i < 9; ++i )
+ {
+ BOOST_CHECK(model.m_Entities[i].m_Guid == entityGuid);
+
+ BOOST_CHECK(model.m_EventClasses[i].m_Guid == eventClassGuid);
+
+ BOOST_CHECK(model.m_Labels[i].m_Guid == labelGuid);
+
+ BOOST_CHECK(model.m_Events[i].m_TimeStamp == timestamp);
+ BOOST_CHECK(model.m_Events[i].m_ThreadId == uint64ThreadId);
+ BOOST_CHECK(model.m_Events[i].m_Guid == eventGuid);
+
+ BOOST_CHECK(model.m_Relationships[i].m_RelationshipType ==
+ arm::pipe::ITimelineDecoder::RelationshipType::DataLink);
+ BOOST_CHECK(model.m_Relationships[i].m_Guid == relationshipGuid);
+ BOOST_CHECK(model.m_Relationships[i].m_HeadGuid == headGuid);
+ BOOST_CHECK(model.m_Relationships[i].m_TailGuid == tailGuid);
+ }
+ for ( unsigned long i = 0; i < 9; i += 3 )
+ {
+ BOOST_CHECK(model.m_Labels[i].m_Name == labelName);
+ BOOST_CHECK(model.m_Labels[i+1].m_Name == labelName2);
+ BOOST_CHECK(model.m_Labels[i+2].m_Name == labelName3);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()