aboutsummaryrefslogtreecommitdiff
path: root/profiling/server
diff options
context:
space:
mode:
authorJim Flynn <jim.flynn@arm.com>2020-07-20 16:57:44 +0100
committerJim Flynn <jim.flynn@arm.com>2020-07-29 15:35:15 +0100
commitbbfe603e5ae42317a2b67d713d00882bea341c88 (patch)
tree8d8a78d6836384fb92fb9741c865443624dfec68 /profiling/server
parenta9c2ce123a6a5a68728d040a0323c482bbe46903 (diff)
downloadarmnn-bbfe603e5ae42317a2b67d713d00882bea341c88.tar.gz
IVGCVSW-5166 Pull out the common and server side code into standalone libraries
Change-Id: I180f84c493a9b2be4b93b25d312ebdd9e71b1735 Signed-off-by: Jim Flynn <jim.flynn@arm.com>
Diffstat (limited to 'profiling/server')
-rw-r--r--profiling/server/include/basePipeServer/BasePipeServer.hpp (renamed from profiling/server/src/basePipeServer/BasePipeServer.hpp)30
-rw-r--r--profiling/server/include/basePipeServer/ConnectionHandler.hpp (renamed from profiling/server/src/basePipeServer/ConnectionHandler.hpp)14
-rw-r--r--profiling/server/include/timelineDecoder/ITimelineDecoder.hpp91
-rw-r--r--profiling/server/include/timelineDecoder/TimelineCaptureCommandHandler.hpp63
-rw-r--r--profiling/server/include/timelineDecoder/TimelineDecoder.hpp72
-rw-r--r--profiling/server/include/timelineDecoder/TimelineDirectoryCaptureCommandHandler.hpp50
-rw-r--r--profiling/server/src/basePipeServer/BasePipeServer.cpp63
-rw-r--r--profiling/server/src/basePipeServer/CMakeLists.txt48
-rw-r--r--profiling/server/src/basePipeServer/ConnectionHandler.cpp23
-rw-r--r--profiling/server/src/basePipeServer/tests/BasePipeServerTests.cpp8
-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
15 files changed, 1409 insertions, 79 deletions
diff --git a/profiling/server/src/basePipeServer/BasePipeServer.hpp b/profiling/server/include/basePipeServer/BasePipeServer.hpp
index bef9d29f44..1b6dec54ff 100644
--- a/profiling/server/src/basePipeServer/BasePipeServer.hpp
+++ b/profiling/server/include/basePipeServer/BasePipeServer.hpp
@@ -1,18 +1,21 @@
//
-// Copyright © 2020 Arm Ltd. All rights reserved.
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//
#pragma once
-#include <NetworkSockets.hpp>
-#include <Packet.hpp>
-#include <SocketConnectionException.hpp>
+#include <common/include/NetworkSockets.hpp>
+#include <common/include/Packet.hpp>
+#include <common/include/SocketConnectionException.hpp>
#include <string>
#include <atomic>
-namespace armnnProfiling
+namespace arm
+{
+
+namespace pipe
{
enum class TargetEndianness
@@ -34,7 +37,7 @@ class BasePipeServer
public:
- BasePipeServer(armnnUtils::Sockets::Socket clientConnection, bool echoPackets)
+ BasePipeServer(arm::pipe::Socket clientConnection, bool echoPackets)
: m_ClientConnection(clientConnection)
, m_EchoPackets(echoPackets)
{}
@@ -42,7 +45,7 @@ public:
~BasePipeServer()
{
// We have set SOCK_CLOEXEC on this socket but we'll close it to be good citizens.
- armnnUtils::Sockets::Close(m_ClientConnection);
+ arm::pipe::Close(m_ClientConnection);
}
BasePipeServer(const BasePipeServer&) = delete;
@@ -55,7 +58,7 @@ public:
/// @return 0 if successful
int Close()
{
- return armnnUtils::Sockets::Close(m_ClientConnection);
+ return arm::pipe::Close(m_ClientConnection);
}
/// Send a packet to the client
@@ -66,12 +69,12 @@ public:
/// @return true if successful.
bool SetNonBlocking()
{
- return armnnUtils::Sockets::SetNonBlocking(m_ClientConnection);
+ return arm::pipe::SetNonBlocking(m_ClientConnection);
}
/// Block on the client connection until a complete packet has been received.
/// @return true if a valid packet has been received.
- armnn::profiling::Packet WaitForPacket(uint32_t timeoutMs);
+ arm::pipe::Packet WaitForPacket(uint32_t timeoutMs);
/// Once the connection is open wait to receive the stream meta data packet from the client. Reading this
/// packet differs from others as we need to determine endianness.
@@ -99,12 +102,12 @@ private:
bool ReadFromSocket(uint8_t* packetData, uint32_t expectedLength);
bool ReadHeader(uint32_t headerAsWords[2]);
- armnn::profiling::Packet ReceivePacket();
+ arm::pipe::Packet ReceivePacket();
uint32_t ToUint32(uint8_t* data, TargetEndianness endianness);
void InsertU32(uint32_t value, uint8_t* data, TargetEndianness endianness);
- armnnUtils::Sockets::Socket m_ClientConnection;
+ arm::pipe::Socket m_ClientConnection;
bool m_EchoPackets;
TargetEndianness m_Endianness;
@@ -113,4 +116,5 @@ private:
uint32_t m_StreamMetaDataPid;
};
-} // namespace armnnProfiling \ No newline at end of file
+} // namespace pipe
+} // namespace arm
diff --git a/profiling/server/src/basePipeServer/ConnectionHandler.hpp b/profiling/server/include/basePipeServer/ConnectionHandler.hpp
index 661935b885..4859fced0d 100644
--- a/profiling/server/src/basePipeServer/ConnectionHandler.hpp
+++ b/profiling/server/include/basePipeServer/ConnectionHandler.hpp
@@ -1,5 +1,5 @@
//
-// Copyright © 2020 Arm Ltd. All rights reserved.
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//
@@ -8,7 +8,10 @@
#include "BasePipeServer.hpp"
#include <string>
-namespace armnnProfiling
+namespace arm
+{
+
+namespace pipe
{
class ConnectionHandler
@@ -22,7 +25,7 @@ public:
~ConnectionHandler()
{
// We have set SOCK_CLOEXEC on this socket but we'll close it to be good citizens.
- armnnUtils::Sockets::Close(m_ListeningSocket);
+ arm::pipe::Close(m_ListeningSocket);
}
ConnectionHandler(const ConnectionHandler&) = delete;
@@ -38,7 +41,8 @@ public:
private:
- armnnUtils::Sockets::Socket m_ListeningSocket;
+ arm::pipe::Socket m_ListeningSocket;
};
-} // namespace armnnProfiling \ No newline at end of file
+} // namespace pipe
+} // namespace arm
diff --git a/profiling/server/include/timelineDecoder/ITimelineDecoder.hpp b/profiling/server/include/timelineDecoder/ITimelineDecoder.hpp
new file mode 100644
index 0000000000..18b8cc7006
--- /dev/null
+++ b/profiling/server/include/timelineDecoder/ITimelineDecoder.hpp
@@ -0,0 +1,91 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <cstdint>
+#include <string>
+
+namespace arm
+{
+
+namespace pipe
+{
+
+class ITimelineDecoder
+{
+
+public:
+
+ enum class TimelineStatus
+ {
+ TimelineStatus_Success,
+ TimelineStatus_Fail
+ };
+
+ enum class 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).
+ };
+
+ static char const* GetRelationshipAsCString(RelationshipType rType)
+ {
+ switch (rType)
+ {
+ case RelationshipType::RetentionLink: return "RetentionLink";
+ case RelationshipType::ExecutionLink: return "ExecutionLink";
+ case RelationshipType::DataLink: return "DataLink";
+ case RelationshipType::LabelLink: return "LabelLink";
+ default: return "Unknown";
+ }
+ }
+
+ struct Entity
+ {
+ uint64_t m_Guid;
+ };
+
+ struct EventClass
+ {
+ uint64_t m_Guid;
+ uint64_t m_NameGuid;
+ };
+
+ struct Event
+ {
+ uint64_t m_Guid;
+ uint64_t m_TimeStamp;
+ uint64_t m_ThreadId;
+ };
+
+ struct Label
+ {
+ uint64_t m_Guid;
+ std::string m_Name;
+ };
+
+ struct Relationship
+ {
+ RelationshipType m_RelationshipType;
+ uint64_t m_Guid;
+ uint64_t m_HeadGuid;
+ uint64_t m_TailGuid;
+ uint64_t m_AttributeGuid;
+ };
+
+ virtual ~ITimelineDecoder() = default;
+
+ virtual TimelineStatus CreateEntity(const Entity&) = 0;
+ virtual TimelineStatus CreateEventClass(const EventClass&) = 0;
+ virtual TimelineStatus CreateEvent(const Event&) = 0;
+ virtual TimelineStatus CreateLabel(const Label&) = 0;
+ virtual TimelineStatus CreateRelationship(const Relationship&) = 0;
+};
+
+} // namespace pipe
+} // namespace arm
diff --git a/profiling/server/include/timelineDecoder/TimelineCaptureCommandHandler.hpp b/profiling/server/include/timelineDecoder/TimelineCaptureCommandHandler.hpp
new file mode 100644
index 0000000000..c51cfd32cd
--- /dev/null
+++ b/profiling/server/include/timelineDecoder/TimelineCaptureCommandHandler.hpp
@@ -0,0 +1,63 @@
+//
+// Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "ITimelineDecoder.hpp"
+
+#include <common/include/CommandHandlerFunctor.hpp>
+#include <common/include/Packet.hpp>
+
+namespace arm
+{
+
+namespace pipe
+{
+
+class TimelineCaptureCommandHandler : public arm::pipe::CommandHandlerFunctor
+{
+ // Utils
+ uint32_t uint32_t_size = sizeof(uint32_t);
+ uint32_t uint64_t_size = sizeof(uint64_t);
+
+ using ReadFunction = ITimelineDecoder::TimelineStatus (TimelineCaptureCommandHandler::*)(
+ const unsigned char*, uint32_t&);
+
+public:
+ TimelineCaptureCommandHandler(uint32_t familyId,
+ uint32_t packetId,
+ uint32_t version,
+ ITimelineDecoder& timelineDecoder,
+ uint32_t threadIdSize = 0)
+ : CommandHandlerFunctor(familyId, packetId, version)
+ , m_TimelineDecoder(timelineDecoder)
+ , m_ThreadIdSize(threadIdSize)
+ , m_PacketLength(0)
+ {}
+
+ void operator()(const arm::pipe::Packet& packet) override;
+
+
+ void SetThreadIdSize(uint32_t size);
+
+private:
+ void ParseData(const arm::pipe::Packet& packet);
+
+ ITimelineDecoder::TimelineStatus ReadLabel(const unsigned char* data, uint32_t& offset);
+ ITimelineDecoder::TimelineStatus ReadEntity(const unsigned char* data, uint32_t& offset);
+ ITimelineDecoder::TimelineStatus ReadEventClass(const unsigned char* data, uint32_t& offset);
+ ITimelineDecoder::TimelineStatus ReadRelationship(const unsigned char* data, uint32_t& offset);
+ ITimelineDecoder::TimelineStatus ReadEvent(const unsigned char* data, uint32_t& offset);
+
+ ITimelineDecoder& m_TimelineDecoder;
+ uint32_t m_ThreadIdSize;
+ unsigned int m_PacketLength;
+ static const ReadFunction m_ReadFunctions[];
+
+};
+
+} //namespace pipe
+
+} //namespace arm
diff --git a/profiling/server/include/timelineDecoder/TimelineDecoder.hpp b/profiling/server/include/timelineDecoder/TimelineDecoder.hpp
new file mode 100644
index 0000000000..ea4b144860
--- /dev/null
+++ b/profiling/server/include/timelineDecoder/TimelineDecoder.hpp
@@ -0,0 +1,72 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include "ITimelineDecoder.hpp"
+
+#include <vector>
+
+namespace arm
+{
+
+namespace pipe
+{
+
+class TimelineDecoder : public ITimelineDecoder
+{
+
+public:
+
+ struct Model
+ {
+ std::vector<Entity> m_Entities;
+ std::vector<EventClass> m_EventClasses;
+ std::vector<Event> m_Events;
+ std::vector<Label> m_Labels;
+ std::vector<Relationship> m_Relationships;
+ };
+
+ using OnNewEntityCallback = void (*)(Model &, const Entity);
+ using OnNewEventClassCallback = void (*)(Model &, const EventClass);
+ using OnNewEventCallback = void (*)(Model &, const Event);
+ using OnNewLabelCallback = void (*)(Model &, const Label);
+ using OnNewRelationshipCallback = void (*)(Model &, const Relationship);
+
+ virtual TimelineStatus CreateEntity(const Entity &) override;
+ virtual TimelineStatus CreateEventClass(const EventClass &) override;
+ virtual TimelineStatus CreateEvent(const Event &) override;
+ virtual TimelineStatus CreateLabel(const Label &) override;
+ virtual TimelineStatus CreateRelationship(const Relationship &) override;
+
+ const Model& GetModel();
+
+ TimelineStatus SetEntityCallback(const OnNewEntityCallback);
+ TimelineStatus SetEventClassCallback(const OnNewEventClassCallback);
+ TimelineStatus SetEventCallback(const OnNewEventCallback);
+ TimelineStatus SetLabelCallback(const OnNewLabelCallback);
+ TimelineStatus SetRelationshipCallback(const OnNewRelationshipCallback);
+
+ void SetDefaultCallbacks();
+
+ void print();
+
+private:
+ Model m_Model;
+
+ OnNewEntityCallback m_OnNewEntityCallback;
+ OnNewEventClassCallback m_OnNewEventClassCallback;
+ OnNewEventCallback m_OnNewEventCallback;
+ OnNewLabelCallback m_OnNewLabelCallback;
+ OnNewRelationshipCallback m_OnNewRelationshipCallback;
+
+ void printLabels();
+ void printEntities();
+ void printEventClasses();
+ void printRelationships();
+ void printEvents();
+};
+
+} // namespace pipe
+} // namespace arm \ No newline at end of file
diff --git a/profiling/server/include/timelineDecoder/TimelineDirectoryCaptureCommandHandler.hpp b/profiling/server/include/timelineDecoder/TimelineDirectoryCaptureCommandHandler.hpp
new file mode 100644
index 0000000000..826ee1f10d
--- /dev/null
+++ b/profiling/server/include/timelineDecoder/TimelineDirectoryCaptureCommandHandler.hpp
@@ -0,0 +1,50 @@
+//
+// Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "TimelineCaptureCommandHandler.hpp"
+
+#include <common/include/SwTrace.hpp>
+
+namespace arm
+{
+
+namespace pipe
+{
+
+class TimelineDirectoryCaptureCommandHandler : public arm::pipe::CommandHandlerFunctor
+{
+ // Utils
+ uint32_t uint8_t_size = sizeof(uint8_t);
+ uint32_t uint32_t_size = sizeof(uint32_t);
+
+public:
+ TimelineDirectoryCaptureCommandHandler(uint32_t familyId,
+ uint32_t packetId,
+ uint32_t version,
+ TimelineCaptureCommandHandler& timelineCaptureCommandHandler,
+ bool quietOperation = false)
+ : CommandHandlerFunctor(familyId, packetId, version)
+ , m_TimelineCaptureCommandHandler(timelineCaptureCommandHandler)
+ , m_QuietOperation(quietOperation)
+ {}
+
+ void operator()(const arm::pipe::Packet& packet) override;
+
+ arm::pipe::SwTraceHeader m_SwTraceHeader;
+ std::vector<arm::pipe::SwTraceMessage> m_SwTraceMessages;
+
+private:
+ void ParseData(const arm::pipe::Packet& packet);
+ void Print();
+
+ TimelineCaptureCommandHandler& m_TimelineCaptureCommandHandler;
+ bool m_QuietOperation;
+};
+
+} //namespace pipe
+
+} //namespace arm
diff --git a/profiling/server/src/basePipeServer/BasePipeServer.cpp b/profiling/server/src/basePipeServer/BasePipeServer.cpp
index ed5c442492..81f58a5ee9 100644
--- a/profiling/server/src/basePipeServer/BasePipeServer.cpp
+++ b/profiling/server/src/basePipeServer/BasePipeServer.cpp
@@ -1,30 +1,31 @@
//
-// Copyright © 2020 Arm Ltd. All rights reserved.
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//
-#include "BasePipeServer.hpp"
+#include <server/include/basePipeServer/BasePipeServer.hpp>
-#include "common/include/Constants.hpp"
+#include <common/include/Constants.hpp>
+#include <common/include/NumericCast.hpp>
#include <iostream>
-#include <boost/cast.hpp>
#include <vector>
#include <iomanip>
#include <string.h>
-using namespace armnnUtils;
+namespace arm
+{
-namespace armnnProfiling
+namespace pipe
{
bool BasePipeServer::ReadFromSocket(uint8_t* packetData, uint32_t expectedLength)
{
// This is a blocking read until either expectedLength has been received or an error is detected.
long totalBytesRead = 0;
- while (boost::numeric_cast<uint32_t>(totalBytesRead) < expectedLength)
+ while (arm::pipe::numeric_cast<uint32_t>(totalBytesRead) < expectedLength)
{
- long bytesRead = Sockets::Read(m_ClientConnection, packetData, expectedLength);
+ long bytesRead = arm::pipe::Read(m_ClientConnection, packetData, expectedLength);
if (bytesRead < 0)
{
std::cerr << ": Failure when reading from client socket: " << strerror(errno) << std::endl;
@@ -68,17 +69,17 @@ bool BasePipeServer::WaitForStreamMetaData()
EchoPacket(PacketDirection::ReceivedData, pipeMagic, 4);
// Before we interpret the length we need to read the pipe_magic word to determine endianness.
- if (ToUint32(&pipeMagic[0], TargetEndianness::BeWire) == armnnProfiling::PIPE_MAGIC)
+ if (ToUint32(&pipeMagic[0], TargetEndianness::BeWire) == PIPE_MAGIC)
{
m_Endianness = TargetEndianness::BeWire;
}
- else if (ToUint32(&pipeMagic[0], TargetEndianness::LeWire) == armnnProfiling::PIPE_MAGIC)
+ else if (ToUint32(&pipeMagic[0], TargetEndianness::LeWire) == PIPE_MAGIC)
{
m_Endianness = TargetEndianness::LeWire;
}
else
{
- std::cerr << ": Protocol read error. Unable to read PIPE_MAGIC value." << std::endl;
+ std::cerr << ": Protocol read error. Unable to read the PIPE_MAGIC value." << std::endl;
return false;
}
// Now we know the endianness we can get the length from the header.
@@ -87,7 +88,7 @@ bool BasePipeServer::WaitForStreamMetaData()
// Read the entire packet.
std::vector<uint8_t> packetData(metaDataLength);
if (metaDataLength !=
- boost::numeric_cast<uint32_t>(Sockets::Read(m_ClientConnection, packetData.data(), metaDataLength)))
+ arm::pipe::numeric_cast<uint32_t>(arm::pipe::Read(m_ClientConnection, packetData.data(), metaDataLength)))
{
std::cerr << ": Protocol read error. Data length mismatch." << std::endl;
return false;
@@ -100,11 +101,11 @@ bool BasePipeServer::WaitForStreamMetaData()
return true;
}
-armnn::profiling::Packet BasePipeServer::WaitForPacket(uint32_t timeoutMs)
+arm::pipe::Packet BasePipeServer::WaitForPacket(uint32_t timeoutMs)
{
// Is there currently more than a headers worth of data waiting to be read?
int bytes_available;
- Sockets::Ioctl(m_ClientConnection, FIONREAD, &bytes_available);
+ arm::pipe::Ioctl(m_ClientConnection, FIONREAD, &bytes_available);
if (bytes_available > 8)
{
// Yes there is. Read it:
@@ -115,18 +116,18 @@ armnn::profiling::Packet BasePipeServer::WaitForPacket(uint32_t timeoutMs)
// No there's not. Poll for more data.
struct pollfd pollingFd[1]{};
pollingFd[0].fd = m_ClientConnection;
- int pollResult = Sockets::Poll(pollingFd, 1, static_cast<int>(timeoutMs));
+ int pollResult = arm::pipe::Poll(pollingFd, 1, static_cast<int>(timeoutMs));
switch (pollResult)
{
// Error
case -1:
- throw armnn::RuntimeException(std::string("File descriptor reported an error during polling: ") +
- strerror(errno));
+ throw ProfilingException(std::string("File descriptor reported an error during polling: ") +
+ strerror(errno));
// Timeout
case 0:
- throw armnn::TimeoutException("Timeout while waiting to receive packet.");
+ throw arm::pipe::TimeoutException("Timeout while waiting to receive packet.");
// Normal poll return. It could still contain an error signal
default:
@@ -135,16 +136,18 @@ armnn::profiling::Packet BasePipeServer::WaitForPacket(uint32_t timeoutMs)
{
if (pollingFd[0].revents == POLLNVAL)
{
- throw armnn::RuntimeException(std::string("Error while polling receiving socket: POLLNVAL"));
+ throw arm::pipe::ProfilingException(
+ std::string("Error while polling receiving socket: POLLNVAL"));
}
if (pollingFd[0].revents == POLLERR)
{
- throw armnn::RuntimeException(std::string("Error while polling receiving socket: POLLERR: ") +
- strerror(errno));
+ throw arm::pipe::ProfilingException(
+ std::string("Error while polling receiving socket: POLLERR: ") + strerror(errno));
}
if (pollingFd[0].revents == POLLHUP)
{
- throw armnn::RuntimeException(std::string("Connection closed by remote client: POLLHUP"));
+ throw arm::pipe::ProfilingException(
+ std::string("Connection closed by remote client: POLLHUP"));
}
}
@@ -153,19 +156,20 @@ armnn::profiling::Packet BasePipeServer::WaitForPacket(uint32_t timeoutMs)
{
// This is a corner case. The socket as been woken up but not with any data.
// We'll throw a timeout exception to loop around again.
- throw armnn::TimeoutException("File descriptor was polled but no data was available to receive.");
+ throw arm::pipe::TimeoutException(
+ "File descriptor was polled but no data was available to receive.");
}
return ReceivePacket();
}
}
}
-armnn::profiling::Packet BasePipeServer::ReceivePacket()
+arm::pipe::Packet BasePipeServer::ReceivePacket()
{
uint32_t header[2];
if (!ReadHeader(header))
{
- return armnn::profiling::Packet();
+ return arm::pipe::Packet();
}
// Read data_length bytes from the socket.
std::unique_ptr<unsigned char[]> uniquePacketData = std::make_unique<unsigned char[]>(header[1]);
@@ -173,13 +177,13 @@ armnn::profiling::Packet BasePipeServer::ReceivePacket()
if (!ReadFromSocket(packetData, header[1]))
{
- return armnn::profiling::Packet();
+ return arm::pipe::Packet();
}
EchoPacket(PacketDirection::ReceivedData, packetData, header[1]);
// Construct received packet
- armnn::profiling::Packet packetRx = armnn::profiling::Packet(header[0], header[1], uniquePacketData);
+ arm::pipe::Packet packetRx = arm::pipe::Packet(header[0], header[1], uniquePacketData);
if (m_EchoPackets)
{
std::cout << "Processing packet ID= " << packetRx.GetPacketId() << " Length=" << packetRx.GetLength()
@@ -206,7 +210,7 @@ bool BasePipeServer::SendPacket(uint32_t packetFamily, uint32_t packetId, const
memcpy((packet.data() + 8), data, dataLength);
}
EchoPacket(PacketDirection::Sending, packet.data(), packet.size());
- if (-1 == armnnUtils::Sockets::Write(m_ClientConnection, packet.data(), packet.size()))
+ if (-1 == arm::pipe::Write(m_ClientConnection, packet.data(), packet.size()))
{
std::cerr << ": Failure when writing to client socket: " << strerror(errno) << std::endl;
return false;
@@ -294,4 +298,5 @@ void BasePipeServer::InsertU32(uint32_t value, uint8_t* data, TargetEndianness e
}
}
-} // namespace armnnProfiling \ No newline at end of file
+} // namespace pipe
+} // namespace arm
diff --git a/profiling/server/src/basePipeServer/CMakeLists.txt b/profiling/server/src/basePipeServer/CMakeLists.txt
index 56ef4548ec..b5dc68c2c4 100644
--- a/profiling/server/src/basePipeServer/CMakeLists.txt
+++ b/profiling/server/src/basePipeServer/CMakeLists.txt
@@ -1,37 +1,49 @@
#
-# Copyright © 2020 Arm Ltd. All rights reserved.
+# Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
# SPDX-License-Identifier: MIT
#
if(BUILD_BASE_PIPE_SERVER)
set(BasePipeServer_sources)
list(APPEND BasePipeServer_sources
- BasePipeServer.cpp
- BasePipeServer.hpp
- ConnectionHandler.cpp
- ConnectionHandler.hpp)
+ BasePipeServer.cpp)
+
+ if(NOT "${TOOLCHAIN_PREFIX}" STREQUAL x86_64-w64-mingw32)
+ list(APPEND BasePipeServer_sources
+ ConnectionHandler.cpp)
+ endif()
include_directories(${PROJECT_SOURCE_DIR}/profiling/common/include)
+ include_directories(${PROJECT_SOURCE_DIR}/profiling/server/include/basePipeServer)
if (BUILD_UNIT_TESTS)
target_include_directories(UnitTests PRIVATE ${PROJECT_SOURCE_DIR}/profiling/server/src/basePipeServer)
target_include_directories(UnitTests PUBLIC ${PROJECT_SOURCE_DIR}/profiling/common/include)
endif()
- add_library_ex(armnnBasePipeServer SHARED ${BasePipeServer_sources})
+ if (BUILD_STATIC_PIPE_LIBS)
+ add_library_ex(armnnBasePipeServer STATIC ${BasePipeServer_sources})
+ target_link_libraries(armnnBasePipeServer pipeCommon)
- set_target_properties(armnnBasePipeServer PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
- set_target_properties(armnnBasePipeServer PROPERTIES VERSION ${GENERIC_LIB_VERSION}
- SOVERSION ${GENERIC_LIB_SOVERSION})
+ if ("${CMAKE_SYSTEM_NAME}" STREQUAL Windows)
+ target_link_libraries(armnnBasePipeServer ws2_32.lib)
+ endif()
+ else()
+ add_library_ex(armnnBasePipeServer SHARED ${BasePipeServer_sources})
+ target_link_libraries(armnnBasePipeServer pipeCommon)
- target_include_directories(armnnBasePipeServer PRIVATE ${PROJECT_SOURCE_DIR}/src/armnnUtils)
+ if ("${CMAKE_SYSTEM_NAME}" STREQUAL Windows)
+ target_link_libraries(armnnBasePipeServer ws2_32.lib)
+ endif()
- target_link_libraries(armnnBasePipeServer armnn)
- if ("${CMAKE_SYSTEM_NAME}" STREQUAL Windows)
- target_link_libraries(armnnBasePipeServer Ws2_32.lib)
- endif()
+ set_target_properties(armnnBasePipeServer PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
+ set_target_properties(armnnBasePipeServer PROPERTIES VERSION ${GENERIC_LIB_VERSION}
+ SOVERSION ${GENERIC_LIB_SOVERSION})
+
+ target_include_directories(armnnBasePipeServer PRIVATE ${PROJECT_SOURCE_DIR}/src/armnnUtils)
- install(TARGETS armnnBasePipeServer
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
-endif() \ No newline at end of file
+ install(TARGETS armnnBasePipeServer
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+ endif()
+endif()
diff --git a/profiling/server/src/basePipeServer/ConnectionHandler.cpp b/profiling/server/src/basePipeServer/ConnectionHandler.cpp
index 1485ab8620..1c9ffa95c2 100644
--- a/profiling/server/src/basePipeServer/ConnectionHandler.cpp
+++ b/profiling/server/src/basePipeServer/ConnectionHandler.cpp
@@ -1,18 +1,21 @@
//
-// Copyright © 2020 Arm Ltd. All rights reserved.
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//
-#include "ConnectionHandler.hpp"
-#include <string.h>
+#include <server/include/basePipeServer/ConnectionHandler.hpp>
-using namespace armnnUtils;
+#include <string>
-namespace armnnProfiling
+namespace arm
{
+
+namespace pipe
+{
+
ConnectionHandler::ConnectionHandler(const std::string& udsNamespace, const bool setNonBlocking)
{
- Sockets::Initialize();
+ arm::pipe::Initialize();
m_ListeningSocket = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (-1 == m_ListeningSocket)
@@ -39,14 +42,13 @@ ConnectionHandler::ConnectionHandler(const std::string& udsNamespace, const bool
if (setNonBlocking)
{
- Sockets::SetNonBlocking(m_ListeningSocket);
+ arm::pipe::SetNonBlocking(m_ListeningSocket);
}
}
std::unique_ptr<BasePipeServer> ConnectionHandler::GetNewBasePipeServer(const bool echoPackets)
{
- armnnUtils::Sockets::Socket clientConnection = armnnUtils::Sockets::Accept(m_ListeningSocket, nullptr, nullptr,
- SOCK_CLOEXEC);
+ arm::pipe::Socket clientConnection = arm::pipe::Accept(m_ListeningSocket, nullptr, nullptr, SOCK_CLOEXEC);
if (clientConnection < 1)
{
return nullptr;
@@ -54,4 +56,5 @@ std::unique_ptr<BasePipeServer> ConnectionHandler::GetNewBasePipeServer(const bo
return std::make_unique<BasePipeServer>(clientConnection, echoPackets);
}
-} // namespace armnnProfiling \ No newline at end of file
+} // namespace pipe
+} // namespace arm
diff --git a/profiling/server/src/basePipeServer/tests/BasePipeServerTests.cpp b/profiling/server/src/basePipeServer/tests/BasePipeServerTests.cpp
index 57fc9e9da6..091792782f 100644
--- a/profiling/server/src/basePipeServer/tests/BasePipeServerTests.cpp
+++ b/profiling/server/src/basePipeServer/tests/BasePipeServerTests.cpp
@@ -1,9 +1,9 @@
//
-// Copyright © 2020 Arm Ltd. All rights reserved.
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//
-#include <ConnectionHandler.hpp>
+#include <server/include/basePipeServer/ConnectionHandler.hpp>
#include <SocketProfilingConnection.hpp>
#include <Processes.hpp>
@@ -15,7 +15,7 @@
BOOST_AUTO_TEST_SUITE(BasePipeServerTests)
using namespace armnn;
-using namespace armnnProfiling;
+using namespace arm::pipe;
BOOST_AUTO_TEST_CASE(BasePipeServerTest)
{
@@ -28,7 +28,7 @@ BOOST_AUTO_TEST_CASE(BasePipeServerTest)
// The socket should close once we leave the scope of BOOST_CHECK_NO_THROW
// and socketProfilingConnection should fail to connect
BOOST_CHECK_THROW(profiling::SocketProfilingConnection socketProfilingConnection,
- armnnProfiling::SocketConnectionException);
+ arm::pipe::SocketConnectionException);
// Try to initialize a listening socket through the ConnectionHandler again
ConnectionHandler connectionHandler(udsNamespace, true);
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()