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>
diff --git a/profiling/CMakeLists.txt b/profiling/CMakeLists.txt
new file mode 100644
index 0000000..f9ffd66
--- /dev/null
+++ b/profiling/CMakeLists.txt
@@ -0,0 +1,36 @@
+#
+# Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+# SPDX-License-Identifier: MIT
+#
+cmake_minimum_required (VERSION 3.0.2) # 3.0.2 required for return() statement used in AddDllCopyCommands.cmake
+project(pipe)
+
+set(additional_cmake_files)
+list(APPEND additional_cmake_files
+    ../cmake/ArmnnVersion.cmake
+    ../cmake/Utils.cmake
+    ../cmake/GlobalConfig.cmake
+    ../cmake/AddDllCopyCommands.cmake)
+
+foreach(cmake_file ${additional_cmake_files})
+    include(${cmake_file})
+endforeach()
+
+# Include the additional cmake files in their own target so that they will appear nicely in IDEs
+add_custom_target(AdditionalCMakeFiles SOURCES ${additional_cmake_files})
+
+include(GNUInstallDirs)
+
+include_directories(SYSTEM common/include)
+include_directories(SYSTEM ${PROJECT_SOURCE_DIR})
+
+set(BUILD_UNIT_TESTS 0)
+
+if(BUILD_TIMELINE_DECODER)
+    add_subdirectory(server/src/timelineDecoder)
+    add_subdirectory(common/src)
+endif()
+
+if(BUILD_BASE_PIPE_SERVER)
+    add_subdirectory(server/src/basePipeServer)
+endif()
diff --git a/profiling/buildpipe.sh b/profiling/buildpipe.sh
new file mode 100755
index 0000000..611b7b9
--- /dev/null
+++ b/profiling/buildpipe.sh
@@ -0,0 +1,91 @@
+#!/bin/bash
+#
+# Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+# SPDX-License-Identifier: MIT
+#
+
+SOURCE="${BASH_SOURCE[0]}"
+while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
+  TARGET="$(readlink "$SOURCE")"
+  if [[ $TARGET == /* ]]; then
+    # "SOURCE '$SOURCE' is an absolute symlink to '$TARGET'"
+    SOURCE="$TARGET"
+  else
+    DIR="$( dirname "$SOURCE" )"
+    # "SOURCE '$SOURCE' is a relative symlink to '$TARGET' (relative to '$DIR')"
+    SOURCE="$DIR/$TARGET" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
+  fi
+done
+RDIR="$( dirname "$SOURCE" )"
+DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
+
+CMD=$( basename $0 )
+
+usage() {
+  echo "Usage: $CMD [options]"
+  echo "Options:        -t(type) <Debug or Release>"
+  echo "                -c(lean) build"
+  echo "                -s(tatic libraries) <1 or 0>"
+  echo "                -w(indows) build"
+  exit 1
+}
+# defaults
+TYPE=Release
+CLEAN=0
+STATIC=0
+WINDOWS=0
+
+# Parse the command line
+while getopts "whct:s:" opt; do
+  case "$opt" in
+    h|\?) usage;;
+    t) TYPE=$OPTARG;;
+    c) CLEAN=1;;
+    s) STATIC=$OPTARG;;
+    w) WINDOWS=1;;
+  esac
+done
+shift $((OPTIND - 1))
+
+if [ $CLEAN == 1 ]; then
+    echo "removing ${DIR}/build"
+    rm -rf ${DIR}/build
+fi
+
+BUILD_DIR="build"
+[ -d build ] || mkdir build
+echo $WINDOWS
+if [ "$WINDOWS" -eq "1" ]; then
+    echo "doing windows"
+    cd $BUILD_DIR
+    [ -d windows ] || mkdir windows
+    BUILD_DIR=$BUILD_DIR/windows
+    cd $DIR
+fi
+# lower case TYPE in a posix compliant manner
+LC_TYPE=$(echo "$TYPE" | tr '[:upper:]' '[:lower:]')
+if [ ${LC_TYPE} == "debug" ]; then
+    DEBUGDIR=($DIR/$BUILD_DIR/debug)
+    [ -d $DEBUGDIR ] || (cd ${BUILD_DIR} && mkdir debug && cd ..)
+    BUILD_DIR=$DEBUGDIR
+else
+    RELEASEDIR=($DIR/$BUILD_DIR/release)
+    [ -d $RELEASEDIR ] || (cd ${BUILD_DIR} && mkdir release && cd ..)
+    BUILD_DIR=$RELEASEDIR
+fi
+
+echo "Build Directory: ${BUILD_DIR}"
+
+CMAKE=cmake
+CMARGS="-DCMAKE_BUILD_TYPE=$TYPE \
+        -DBUILD_STATIC_PIPE_LIBS=$STATIC \
+        -DBUILD_PIPE_ONLY=1"
+if [ "$WINDOWS" -eq "1" ]; then
+    CMARGS="$CMARGS \
+           -DCMAKE_TOOLCHAIN_FILE=${DIR}/toolchain-x86-ubuntu-mingw64.cmake"
+fi
+MAKE=make
+
+cd ${BUILD_DIR}
+pwd
+( eval $CMAKE $CMARGS $DIR && eval ${MAKE} $MAKEFLAGS )
diff --git a/profiling/common/include/Assert.hpp b/profiling/common/include/Assert.hpp
new file mode 100644
index 0000000..c6e8bc4
--- /dev/null
+++ b/profiling/common/include/Assert.hpp
@@ -0,0 +1,24 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <cassert>
+
+namespace arm
+{
+
+namespace pipe
+{
+
+#ifndef NDEBUG
+#   define ARM_PIPE_ASSERT(COND) assert(COND)
+#   define ARM_PIPE_ASSERT_MSG(COND, MSG) assert((COND) && MSG)
+#else
+#   define ARM_PIPE_ASSERT(COND)
+#   define ARM_PIPE_ASSERT_MSG(COND, MSG)
+#endif
+} // namespace pipe
+} //namespace arm
\ No newline at end of file
diff --git a/profiling/common/include/CommandHandlerFunctor.hpp b/profiling/common/include/CommandHandlerFunctor.hpp
new file mode 100644
index 0000000..9827aa0
--- /dev/null
+++ b/profiling/common/include/CommandHandlerFunctor.hpp
@@ -0,0 +1,42 @@
+//
+// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <Packet.hpp>
+#include <cstdint>
+
+namespace arm
+{
+
+namespace pipe
+{
+
+class CommandHandlerFunctor
+{
+public:
+    CommandHandlerFunctor(uint32_t familyId, uint32_t packetId, uint32_t version)
+        : m_FamilyId(familyId),
+          m_PacketId(packetId)
+        , m_Version(version)
+    {}
+
+    uint32_t GetFamilyId() const;
+    uint32_t GetPacketId() const;
+    uint32_t GetVersion()  const;
+
+    virtual void operator()(const Packet& packet) = 0;
+
+    virtual ~CommandHandlerFunctor() {}
+
+private:
+    uint32_t m_FamilyId;
+    uint32_t m_PacketId;
+    uint32_t m_Version;
+};
+
+} // namespace pipe
+
+} // namespace arm
diff --git a/profiling/common/include/CommandHandlerKey.hpp b/profiling/common/include/CommandHandlerKey.hpp
new file mode 100644
index 0000000..f45b5be
--- /dev/null
+++ b/profiling/common/include/CommandHandlerKey.hpp
@@ -0,0 +1,41 @@
+//
+// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <cstdint>
+
+namespace arm
+{
+
+namespace pipe
+{
+
+class CommandHandlerKey
+{
+public:
+    CommandHandlerKey(uint32_t familyId, uint32_t packetId, uint32_t version)
+    : m_FamilyId(familyId), m_PacketId(packetId), m_Version(version) {};
+
+    uint32_t GetFamilyId() const;
+    uint32_t GetPacketId() const;
+    uint32_t GetVersion()  const;
+
+    bool operator< (const CommandHandlerKey& rhs) const;
+    bool operator> (const CommandHandlerKey& rhs) const;
+    bool operator<=(const CommandHandlerKey& rhs) const;
+    bool operator>=(const CommandHandlerKey& rhs) const;
+    bool operator==(const CommandHandlerKey& rhs) const;
+    bool operator!=(const CommandHandlerKey& rhs) const;
+
+private:
+    uint32_t m_FamilyId;
+    uint32_t m_PacketId;
+    uint32_t m_Version;
+};
+
+} // namespace pipe
+
+} // namespace arm
diff --git a/profiling/common/include/CommandHandlerRegistry.hpp b/profiling/common/include/CommandHandlerRegistry.hpp
new file mode 100644
index 0000000..5a5d879
--- /dev/null
+++ b/profiling/common/include/CommandHandlerRegistry.hpp
@@ -0,0 +1,49 @@
+//
+// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "CommandHandlerFunctor.hpp"
+#include "CommandHandlerKey.hpp"
+
+#include <functional>
+#include <unordered_map>
+
+namespace arm
+{
+
+namespace pipe
+{
+
+struct CommandHandlerHash
+{
+    std::size_t operator() (const CommandHandlerKey& commandHandlerKey) const
+    {
+        std::size_t seed = 0;
+        std::hash<uint32_t> hasher;
+        seed ^= hasher(commandHandlerKey.GetPacketId()) + 0x9e3779b9 + (seed<<6) + (seed>>2);
+        seed ^= hasher(commandHandlerKey.GetVersion()) + 0x9e3779b9 + (seed<<6) + (seed>>2);
+        return seed;
+    }
+};
+
+class CommandHandlerRegistry
+{
+public:
+    CommandHandlerRegistry() = default;
+
+    void RegisterFunctor(CommandHandlerFunctor* functor, uint32_t familyId, uint32_t packetId, uint32_t version);
+
+    void RegisterFunctor(CommandHandlerFunctor* functor);
+
+    CommandHandlerFunctor* GetFunctor(uint32_t familyId, uint32_t packetId, uint32_t version) const;
+
+private:
+    std::unordered_map<CommandHandlerKey, CommandHandlerFunctor*, CommandHandlerHash> registry;
+};
+
+} // namespace pipe
+
+} // namespace arm
diff --git a/profiling/common/include/CommonProfilingUtils.hpp b/profiling/common/include/CommonProfilingUtils.hpp
new file mode 100644
index 0000000..68fe6bb
--- /dev/null
+++ b/profiling/common/include/CommonProfilingUtils.hpp
@@ -0,0 +1,38 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <cstdint>
+#include <string>
+
+namespace arm
+{
+
+namespace pipe
+{
+void ReadBytes(const unsigned char* buffer, unsigned int offset, unsigned int valueSize, uint8_t outValue[]);
+
+uint64_t ReadUint64(unsigned const char* buffer, unsigned int offset);
+
+uint32_t ReadUint32(unsigned const char* buffer, unsigned int offset);
+
+uint16_t ReadUint16(unsigned const char* buffer, unsigned int offset);
+
+uint8_t ReadUint8(unsigned const char* buffer, unsigned int offset);
+
+void WriteBytes(unsigned char* buffer, unsigned int offset, const void* value, unsigned int valueSize);
+
+void WriteUint64(unsigned char* buffer, unsigned int offset, uint64_t value);
+
+void WriteUint32(unsigned char* buffer, unsigned int offset, uint32_t value);
+
+void WriteUint16(unsigned char* buffer, unsigned int offset, uint16_t value);
+
+void WriteUint8(unsigned char* buffer, unsigned int offset, uint8_t value);
+
+std::string CentreAlignFormatting(const std::string& stringToPass, const int spacingWidth);
+
+} // namespace pipe
+} // namespace arm
\ No newline at end of file
diff --git a/profiling/common/include/Constants.hpp b/profiling/common/include/Constants.hpp
index 52e0e48..01bfe79 100644
--- a/profiling/common/include/Constants.hpp
+++ b/profiling/common/include/Constants.hpp
@@ -1,10 +1,14 @@
 //
-// Copyright © 2020 Arm Ltd. All rights reserved.
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
 // SPDX-License-Identifier: MIT
 //
 #pragma once
 
-namespace armnnProfiling
+namespace arm
+{
+
+namespace pipe
 {
     static const unsigned int PIPE_MAGIC = 0x45495434;
-}
\ No newline at end of file
+} // namespace pipe
+} // namespace arm
\ No newline at end of file
diff --git a/profiling/common/include/Conversion.hpp b/profiling/common/include/Conversion.hpp
new file mode 100644
index 0000000..0a3eb0c
--- /dev/null
+++ b/profiling/common/include/Conversion.hpp
@@ -0,0 +1,43 @@
+//
+// Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#if __GNUC__
+#   define ARM_PIPE_NO_CONVERSION_WARN_BEGIN \
+    _Pragma("GCC diagnostic push")  \
+    _Pragma("GCC diagnostic ignored \"-Wconversion\"") \
+    _Pragma("GCC diagnostic ignored \"-Wsign-conversion\"")
+
+#   define ARM_PIPE_NO_CONVERSION_WARN_END \
+    _Pragma("GCC diagnostic pop")
+
+#elif __clang__
+#   define ARM_PIPE_NO_CONVERSION_WARN_BEGIN \
+    _Pragma("clang diagnostic push")  \
+    _Pragma("clang diagnostic ignored \"-Wconversion\"") \
+    _Pragma("clang diagnostic ignored \"-Wsign-conversion\"")
+
+#   define ARM_PIPE_NO_CONVERSION_WARN_END \
+    _Pragma("clang diagnostic pop")
+
+#elif defined (_MSC_VER)
+#   define ARM_PIPE_NO_CONVERSION_WARN_BEGIN \
+    __pragma(warning( push )) \
+    __pragma(warning(disable : 4101)) \
+    __pragma(warning(disable : 4267))
+
+#   define ARM_PIPE_NO_CONVERSION_WARN_END \
+    __pragma(warning( pop ))
+
+#else
+#   define ARM_PIPE_NO_CONVERSION_WARN_BEGIN
+#   define ARM_PIPE_NO_CONVERSION_WARN_END
+#endif
+
+#define ARM_PIPE_SUPRESS_CONVERSION_WARNING(func) \
+ARM_PIPE_NO_CONVERSION_WARN_BEGIN \
+func; \
+ARM_PIPE_NO_CONVERSION_WARN_END
diff --git a/profiling/common/include/EncodeVersion.hpp b/profiling/common/include/EncodeVersion.hpp
new file mode 100644
index 0000000..9257b22
--- /dev/null
+++ b/profiling/common/include/EncodeVersion.hpp
@@ -0,0 +1,83 @@
+//
+// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <cstdint>
+#include <string>
+#include <ostream>
+#include <sstream>
+
+namespace arm
+{
+
+namespace pipe
+{
+
+constexpr inline uint32_t EncodeVersion(uint32_t major, uint32_t minor, uint32_t patch)
+{
+    return (major << 22) | (minor << 12) | patch;
+}
+
+// Encodes a semantic version https://semver.org/ into a 32 bit integer in the following fashion
+//
+// bits 22:31 major: Unsigned 10-bit integer. Major component of the schema version number.
+// bits 12:21 minor: Unsigned 10-bit integer. Minor component of the schema version number.
+// bits 0:11  patch: Unsigned 12-bit integer. Patch component of the schema version number.
+//
+class Version
+{
+public:
+    Version(uint32_t encodedValue)
+    {
+        m_Major = (encodedValue >> 22) & 1023;
+        m_Minor = (encodedValue >> 12) & 1023;
+        m_Patch = encodedValue & 4095;
+    }
+
+    Version(uint32_t major, uint32_t minor, uint32_t patch) :
+        m_Major(major),
+        m_Minor(minor),
+        m_Patch(patch)
+    {}
+
+    uint32_t GetEncodedValue()
+    {
+        return EncodeVersion(m_Major, m_Minor, m_Patch);
+    }
+
+    uint32_t GetMajor() { return m_Major; }
+    uint32_t GetMinor() { return m_Minor; }
+    uint32_t GetPatch() { return m_Patch; }
+
+    bool operator==(const Version& other) const
+    {
+        return m_Major == other.m_Major && m_Minor == other.m_Minor && m_Patch == other.m_Patch;
+    }
+
+    std::string ToString() const
+    {
+        constexpr char separator = '.';
+
+        std::stringstream stringStream;
+        stringStream << m_Major << separator << m_Minor << separator << m_Patch;
+
+        return stringStream.str();
+    }
+
+private:
+    uint32_t m_Major;
+    uint32_t m_Minor;
+    uint32_t m_Patch;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const Version& version)
+{
+    os << version.ToString();
+    return os;
+}
+
+} // namespace pipe
+
+} // namespace arm
diff --git a/profiling/common/include/IgnoreUnused.hpp b/profiling/common/include/IgnoreUnused.hpp
new file mode 100644
index 0000000..fad40d3
--- /dev/null
+++ b/profiling/common/include/IgnoreUnused.hpp
@@ -0,0 +1,18 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+namespace arm
+{
+
+namespace pipe
+{
+// Utility function to selectively silence unused variable compiler warnings
+
+template<typename ... Ts>
+inline void IgnoreUnused(Ts&&...){}
+} //namespace pipe
+} //namespace arm
\ No newline at end of file
diff --git a/profiling/common/include/Logging.hpp b/profiling/common/include/Logging.hpp
new file mode 100644
index 0000000..a31c2aa
--- /dev/null
+++ b/profiling/common/include/Logging.hpp
@@ -0,0 +1,182 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <vector>
+
+namespace arm
+{
+
+namespace pipe
+{
+
+enum class LogSeverity
+{
+    Trace,
+    Debug,
+    Info,
+    Warning,
+    Error,
+    Fatal
+};
+
+inline std::string LevelToString(LogSeverity level)
+{
+    switch(level)
+    {
+        case LogSeverity::Trace:
+            return "Trace";
+        case LogSeverity::Debug:
+            return "Debug";
+        case LogSeverity::Info:
+            return "Info";
+        case LogSeverity::Warning:
+            return "Warning";
+        case LogSeverity::Error:
+            return "Error";
+        case LogSeverity::Fatal:
+            return "Fatal";
+        default:
+            return "Log";
+    }
+}
+
+class LogSink
+{
+public:
+    virtual ~LogSink(){};
+
+    virtual void Consume(const std::string&) = 0;
+private:
+
+};
+
+class StandardOutputSink : public LogSink
+{
+public:
+    void Consume(const std::string& s) override
+    {
+        std::cout << s << std::endl;
+    }
+};
+
+struct ScopedRecord
+{
+    ScopedRecord(const std::vector<std::shared_ptr<LogSink>>& sinks, LogSeverity level, bool enabled)
+    : m_LogSinks(sinks)
+    , m_Enabled(enabled)
+    {
+        if (enabled)
+        {
+            m_Os << LevelToString(level) << ": ";
+        }
+    }
+
+    ~ScopedRecord()
+    {
+        if (m_Enabled)
+        {
+            for (auto sink : m_LogSinks)
+            {
+                if (sink)
+                {
+                    sink->Consume(m_Os.str());
+                }
+            }
+        }
+    }
+
+    ScopedRecord(const ScopedRecord&) = delete;
+    ScopedRecord& operator=(const ScopedRecord&) = delete;
+    ScopedRecord& operator=(ScopedRecord&&) = delete;
+
+    ScopedRecord(ScopedRecord&& other) = default;
+
+    template<typename Streamable>
+    ScopedRecord& operator<<(const Streamable& s)
+    {
+        if (m_Enabled)
+        {
+            m_Os << s;
+        }
+        return (*this);
+    }
+
+private:
+    const std::vector<std::shared_ptr<LogSink>>& m_LogSinks;
+    std::ostringstream m_Os;
+    bool m_Enabled;
+};
+
+template<LogSeverity Level>
+class SimpleLogger
+{
+public:
+    SimpleLogger()
+        : m_Sinks{std::make_shared<StandardOutputSink>()}
+        , m_Enable(true)
+    {
+    }
+
+    static SimpleLogger& Get()
+    {
+        static SimpleLogger<Level> logger;
+        return logger;
+    }
+
+    void Enable(bool enable = true)
+    {
+        m_Enable = enable;
+    }
+
+    ScopedRecord StartNewRecord()
+    {
+        ScopedRecord record(m_Sinks, Level, m_Enable);
+        return record;
+    }
+
+    void RemoveAllSinks()
+    {
+        m_Sinks.clear();
+    }
+
+    void AddSink(std::shared_ptr<LogSink> sink)
+    {
+        m_Sinks.push_back(sink);
+    }
+private:
+    std::vector<std::shared_ptr<LogSink>> m_Sinks;
+    bool m_Enable;
+};
+
+void SetLogFilter(LogSeverity level);
+
+void SetAllLoggingSinks(bool standardOut, bool debugOut, bool coloured);
+
+enum class BoostLogSeverityMapping
+{
+    trace,
+    debug,
+    info,
+    warning,
+    error,
+    fatal
+};
+
+constexpr LogSeverity ConvertLogSeverity(BoostLogSeverityMapping severity)
+{
+    return static_cast<LogSeverity>(severity);
+}
+
+
+#define ARM_PIPE_LOG(severity) \
+    arm::pipe::SimpleLogger<ConvertLogSeverity(arm::pipe::BoostLogSeverityMapping::severity)>::Get().StartNewRecord()
+
+} // namespace pipe
+} // namespace arm
diff --git a/profiling/common/include/NetworkSockets.hpp b/profiling/common/include/NetworkSockets.hpp
index 05a45ae..29575cd 100644
--- a/profiling/common/include/NetworkSockets.hpp
+++ b/profiling/common/include/NetworkSockets.hpp
@@ -19,11 +19,14 @@
 #include <WindowsWrapper.hpp>
 #include <winsock2.h>
 #include <afunix.h>
+#elif defined(__MINGW32__)
+#include <WindowsWrapper.hpp>
+#include <winsock2.h>
 #endif
 
-namespace armnnUtils
+namespace arm
 {
-namespace Sockets
+namespace pipe
 {
 
 #if defined(__unix__)
@@ -45,6 +48,14 @@
 using socklen_t = int;
 #define SOCK_CLOEXEC 0
 
+#elif defined(__MINGW32__)
+
+using Socket = SOCKET;
+using PollFd = WSAPOLLFD;
+using nfds_t = int;
+using socklen_t = int;
+#define SOCK_CLOEXEC 0
+
 #endif
 
 /// Performs any required one-time setup.
@@ -64,5 +75,5 @@
 
 Socket Accept(Socket s, sockaddr* addr, socklen_t* addrlen, int flags);
 
-}
-}
+} // namespace arm
+} // namespace pipe
diff --git a/profiling/common/include/NumericCast.hpp b/profiling/common/include/NumericCast.hpp
new file mode 100644
index 0000000..069f951
--- /dev/null
+++ b/profiling/common/include/NumericCast.hpp
@@ -0,0 +1,128 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "Assert.hpp"
+
+#include <type_traits>
+#include <limits>
+
+namespace arm
+{
+
+namespace pipe
+{
+
+#if !defined(NDEBUG) || defined(ARM_PIPE_NUMERIC_CAST_TESTABLE)
+#define ENABLE_NUMERIC_CAST_CHECKS 1
+#else
+#define ENABLE_NUMERIC_CAST_CHECKS 0
+#endif
+
+#if defined(ARM_PIPE_NUMERIC_CAST_TESTABLE)
+#   define ARM_PIPE_NUMERIC_CAST_CHECK(cond, msg) ConditionalThrow<std::bad_cast>(cond)
+#else
+#   define ARM_PIPE_NUMERIC_CAST_CHECK(cond, msg) ARM_PIPE_ASSERT_MSG(cond, msg)
+#endif
+
+template<typename Dest, typename Source>
+typename std::enable_if_t<
+    std::is_unsigned<Source>::value &&
+    std::is_unsigned<Dest>::value
+    , Dest>
+numeric_cast(Source source)
+{
+#if ENABLE_NUMERIC_CAST_CHECKS
+    if (source > std::numeric_limits<Dest>::max())
+    {
+        ARM_PIPE_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting unsigned type to "
+                                        "narrower unsigned type. Overflow detected.");
+    }
+#endif // ENABLE_NUMERIC_CAST_CHECKS
+
+    return static_cast<Dest>(source);
+}
+
+template<typename Dest, typename Source>
+typename std::enable_if_t<
+    std::is_signed<Source>::value &&
+    std::is_signed<Dest>::value
+    , Dest>
+numeric_cast(Source source)
+{
+    static_assert(!std::is_floating_point<Source>::value && !std::is_floating_point<Dest>::value,
+        "numeric_cast doesn't cast float.");
+
+#if ENABLE_NUMERIC_CAST_CHECKS
+    if (source > std::numeric_limits<Dest>::max())
+    {
+        ARM_PIPE_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to narrower signed type. "
+                                        "Overflow detected.");
+    }
+
+    if (source < std::numeric_limits<Dest>::lowest())
+    {
+        ARM_PIPE_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to narrower signed type. "
+                                        "Underflow detected.");
+    }
+#endif // ENABLE_NUMERIC_CAST_CHECKS
+
+    return static_cast<Dest>(source);
+}
+
+// numeric cast from unsigned to signed checked for narrowing overflows
+template<typename Dest, typename Source>
+typename std::enable_if_t<
+    std::is_signed<Dest>::value &&
+    std::is_unsigned<Source>::value
+    , Dest>
+numeric_cast(Source sValue)
+{
+    static_assert(!std::is_floating_point<Dest>::value, "numeric_cast doesn't cast to float.");
+
+#if ENABLE_NUMERIC_CAST_CHECKS
+    if (sValue > static_cast< typename std::make_unsigned<Dest>::type >(std::numeric_limits<Dest>::max()))
+    {
+        ARM_PIPE_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting unsigned type to signed type. "
+                                        "Overflow detected.");
+    }
+#endif // ENABLE_NUMERIC_CAST_CHECKS
+
+    return static_cast<Dest>(sValue);
+}
+
+// numeric cast from signed to unsigned checked for underflows and narrowing overflows
+template<typename Dest, typename Source>
+typename std::enable_if_t<
+    std::is_unsigned<Dest>::value &&
+    std::is_signed<Source>::value
+    , Dest>
+numeric_cast(Source sValue)
+{
+    static_assert(!std::is_floating_point<Source>::value && !std::is_floating_point<Dest>::value,
+        "numeric_cast doesn't cast floats.");
+
+#if ENABLE_NUMERIC_CAST_CHECKS
+    if (sValue < 0)
+    {
+        ARM_PIPE_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting negative value to unsigned type. "
+                                        "Underflow detected.");
+    }
+
+    if (static_cast< typename std::make_unsigned<Source>::type >(sValue) > std::numeric_limits<Dest>::max())
+    {
+        ARM_PIPE_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to unsigned type. "
+                                        "Overflow detected.");
+    }
+
+#endif // ENABLE_NUMERIC_CAST_CHECKS
+    return static_cast<Dest>(sValue);
+}
+
+#undef ENABLE_NUMERIC_CAST_CHECKS
+
+} // namespace pipe
+} // namespace arm
diff --git a/profiling/common/include/Packet.hpp b/profiling/common/include/Packet.hpp
index 23c3124..d8fa270 100644
--- a/profiling/common/include/Packet.hpp
+++ b/profiling/common/include/Packet.hpp
@@ -1,18 +1,18 @@
 //
-// Copyright © 2017 Arm Ltd. All rights reserved.
+// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
 // SPDX-License-Identifier: MIT
 //
 
 #pragma once
 
-#include <armnn/Exceptions.hpp>
+#include "ProfilingException.hpp"
 
 #include <memory>
 
-namespace armnn
+namespace arm
 {
 
-namespace profiling
+namespace pipe
 {
 
 class Packet
@@ -45,7 +45,7 @@
 
         if (length == 0 && m_Data != nullptr)
         {
-            throw armnn::InvalidArgumentException("Data should be null when length is zero");
+            throw arm::pipe::InvalidArgumentException("Data should be null when length is zero");
         }
     }
 
@@ -86,6 +86,6 @@
     std::unique_ptr<unsigned char[]> m_Data;
 };
 
-} // namespace profiling
+} // namespace pipe
 
-} // namespace armnn
+} // namespace arm
diff --git a/profiling/common/include/PacketVersionResolver.hpp b/profiling/common/include/PacketVersionResolver.hpp
new file mode 100644
index 0000000..0ec7d2a
--- /dev/null
+++ b/profiling/common/include/PacketVersionResolver.hpp
@@ -0,0 +1,50 @@
+//
+// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "EncodeVersion.hpp"
+
+namespace arm
+{
+
+namespace pipe
+{
+
+class PacketKey final
+{
+public:
+    PacketKey(uint32_t familyId, uint32_t packetId) : m_FamilyId(familyId), m_PacketId(packetId) {}
+
+    uint32_t GetFamilyId() { return m_FamilyId; }
+    uint32_t GetPacketId() { return m_PacketId; }
+
+    bool operator< (const PacketKey& rhs) const;
+    bool operator> (const PacketKey& rhs) const;
+    bool operator<=(const PacketKey& rhs) const;
+    bool operator>=(const PacketKey& rhs) const;
+    bool operator==(const PacketKey& rhs) const;
+    bool operator!=(const PacketKey& rhs) const;
+
+private:
+    uint32_t m_FamilyId;
+    uint32_t m_PacketId;
+};
+
+static const PacketKey ActivateTimeLinePacket(0 , 6);
+static const PacketKey DeactivateTimeLinePacket(0 , 7);
+
+class PacketVersionResolver final
+{
+public:
+    PacketVersionResolver()  = default;
+    ~PacketVersionResolver() = default;
+
+    Version ResolvePacketVersion(uint32_t familyId, uint32_t packetId) const;
+};
+
+} // namespace pipe
+
+} // namespace arm
diff --git a/profiling/common/include/ProfilingException.hpp b/profiling/common/include/ProfilingException.hpp
index 532c2d4..abdc0dc 100644
--- a/profiling/common/include/ProfilingException.hpp
+++ b/profiling/common/include/ProfilingException.hpp
@@ -1,29 +1,82 @@
 //
-// Copyright © 2020 Arm Ltd. All rights reserved.
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
 // SPDX-License-Identifier: MIT
 //
 #pragma once
 
 #include <stdexcept>
 #include <string>
+#include <sstream>
 
-namespace armnnProfiling
+namespace arm
 {
 
+namespace pipe
+{
+
+struct Location
+{
+    const char* m_Function;
+    const char* m_File;
+    unsigned int m_Line;
+
+    Location(const char* func,
+             const char* file,
+             unsigned int line)
+    : m_Function{func}
+    , m_File{file}
+    , m_Line{line}
+    {
+    }
+
+    std::string AsString() const
+    {
+        std::stringstream ss;
+        ss << " at function " << m_Function
+           << " [" << m_File << ':' << m_Line << "]";
+        return ss.str();
+    }
+
+    std::string FileLine() const
+    {
+        std::stringstream ss;
+        ss << " [" << m_File << ':' << m_Line << "]";
+        return ss.str();
+    }
+};
+
 /// General Exception class for Profiling code
 class ProfilingException : public std::exception
 {
 public:
     explicit ProfilingException(const std::string& message) : m_Message(message) {};
 
+    explicit ProfilingException(const std::string& message,
+                                const Location& location) : m_Message(message + location.AsString()) {};
+
     /// @return - Error message of ProfilingException
-    virtual const char* what() const noexcept override
+    virtual const char *what() const noexcept override
     {
-        return m_Message.c_str();
+         return m_Message.c_str();
     }
 
 private:
     std::string m_Message;
 };
 
-} // namespace armnnProfiling
+class TimeoutException : public ProfilingException
+{
+public:
+    using ProfilingException::ProfilingException;
+};
+
+class InvalidArgumentException : public ProfilingException
+{
+public:
+    using ProfilingException::ProfilingException;
+};
+
+} // namespace pipe
+} // namespace arm
+
+#define LOCATION() arm::pipe::Location(__func__, __FILE__, __LINE__)
diff --git a/profiling/common/include/SocketConnectionException.hpp b/profiling/common/include/SocketConnectionException.hpp
index d18dcc3..42b8d9d 100644
--- a/profiling/common/include/SocketConnectionException.hpp
+++ b/profiling/common/include/SocketConnectionException.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
 //
 #pragma once
@@ -10,30 +10,31 @@
 
 #include "NetworkSockets.hpp"
 
-namespace armnnProfiling
+namespace arm
+{
+
+namespace pipe
 {
 
 /// Socket Connection Exception for profiling
 class SocketConnectionException : public std::exception
 {
 public:
-    explicit SocketConnectionException(const std::string& message, armnnUtils::Sockets::Socket socket)
-    : m_Message(message), m_Socket(socket), m_ErrNo(-1)
-    {};
+    explicit SocketConnectionException(const std::string &message, arm::pipe::Socket socket)
+        : m_Message(message), m_Socket(socket), m_ErrNo(-1) {};
 
-    explicit SocketConnectionException(const std::string& message, armnnUtils::Sockets::Socket socket, int errNo)
-    : m_Message(message), m_Socket(socket), m_ErrNo(errNo)
-    {};
+    explicit SocketConnectionException(const std::string &message, arm::pipe::Socket socket, int errNo)
+        : m_Message(message), m_Socket(socket), m_ErrNo(errNo) {};
 
     /// @return - Error message of  SocketProfilingConnection
-    virtual const char* what() const noexcept override
+    virtual const char *what() const noexcept override
     {
         return m_Message.c_str();
     }
 
     /// @return - Socket File Descriptor of SocketProfilingConnection
     ///           or '-1', an invalid file descriptor
-    armnnUtils::Sockets::Socket GetSocketFd() const noexcept
+    arm::pipe::Socket GetSocketFd() const noexcept
     {
         return m_Socket;
     }
@@ -46,8 +47,8 @@
 
 private:
     std::string m_Message;
-    armnnUtils::Sockets::Socket m_Socket;
+    arm::pipe::Socket m_Socket;
     int m_ErrNo;
 };
-
-} // namespace armnnProfiling
+} // namespace pipe
+} // namespace arm
diff --git a/profiling/common/include/SwTrace.hpp b/profiling/common/include/SwTrace.hpp
new file mode 100644
index 0000000..5abc59b
--- /dev/null
+++ b/profiling/common/include/SwTrace.hpp
@@ -0,0 +1,139 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "NumericCast.hpp"
+
+#include <algorithm>
+#include <cstring>
+#include <string>
+#include <vector>
+
+namespace arm
+{
+
+namespace pipe
+{
+
+struct SwTraceHeader
+{
+    uint8_t m_StreamVersion;
+    uint8_t m_PointerBytes;
+    uint8_t m_ThreadIdBytes;
+};
+
+struct SwTraceMessage
+{
+    uint32_t m_Id;
+    std::string m_Name;
+    std::string m_UiName;
+    std::vector<char> m_ArgTypes;
+    std::vector<std::string> m_ArgNames;
+};
+
+struct SwTraceCharPolicy
+{
+    static bool IsValidChar(unsigned char c)
+    {
+        // Check that the given character has ASCII 7-bit encoding
+        return c < 128;
+    }
+};
+
+struct SwTraceNameCharPolicy
+{
+    static bool IsValidChar(unsigned char c)
+    {
+        // Check that the given character has ASCII 7-bit encoding, alpha-numeric and underscore only
+        return c < 128 && (std::isalnum(c) || c == '_');
+    }
+};
+
+struct SwTraceTypeCharPolicy
+{
+    static bool IsValidChar(unsigned char c)
+    {
+        // Check that the given character is among the allowed ones
+        switch (c)
+        {
+        case '@':
+        case 't':
+        case 'i':
+        case 'I':
+        case 'l':
+        case 'L':
+        case 'F':
+        case 'p':
+        case 's':
+            return true; // Valid char
+        default:
+            return false; // Invalid char
+        }
+    }
+};
+
+template <typename SwTracePolicy>
+bool IsValidSwTraceString(const std::string& s)
+{
+    // Check that all the characters in the given string conform to the given policy
+    return std::all_of(s.begin(), s.end(), [](unsigned char c) { return SwTracePolicy::IsValidChar(c); });
+}
+
+template <typename SwTracePolicy>
+bool StringToSwTraceString(const std::string& s, std::vector<uint32_t>& outputBuffer)
+{
+    // Converts the given string to an SWTrace "string" (i.e. a string of "chars"), and writes it into
+    // the given buffer including the null-terminator. It also pads it to the next uint32_t if necessary
+
+    // Clear the output buffer
+    outputBuffer.clear();
+
+    // Check that the given string is a valid SWTrace "string" (i.e. a string of "chars")
+    if (!IsValidSwTraceString<SwTracePolicy>(s))
+    {
+        return false;
+    }
+
+    // Prepare the output buffer
+    size_t s_size        = s.size() + 1;    // The size of the string (in chars) plus the null-terminator
+    size_t uint32_t_size = sizeof(uint32_t);
+    // Output buffer size = StringLength (32 bit) + amount of complete 32bit words that fit into the string
+    //                      + an additional 32bit word if there are remaining chars to complete the string
+    //                      (The rest of the 32bit word is then filled with the NULL terminator)
+    size_t outBufferSize = 1 + (s_size / uint32_t_size) + (s_size % uint32_t_size != 0 ? 1 : 0);
+    outputBuffer.resize(outBufferSize, '\0');
+
+    // Write the SWTrace string to the output buffer
+    outputBuffer[0] = numeric_cast<uint32_t>(s_size);
+    std::memcpy(outputBuffer.data() + 1, s.data(), s_size);
+
+    return true;
+}
+
+template <typename SwTracePolicy,
+          typename SwTraceBuffer = std::vector<uint32_t>>
+bool ConvertDirectoryComponent(const std::string& directoryComponent, SwTraceBuffer& swTraceBuffer)
+{
+    // Convert the directory component using the given policy
+    SwTraceBuffer tempSwTraceBuffer;
+    bool result = StringToSwTraceString<SwTracePolicy>(directoryComponent, tempSwTraceBuffer);
+    if (!result)
+    {
+        return false;
+    }
+
+    swTraceBuffer.insert(swTraceBuffer.end(), tempSwTraceBuffer.begin(), tempSwTraceBuffer.end());
+
+    return true;
+}
+
+uint32_t CalculateSizeOfPaddedSwString(const std::string& str);
+
+SwTraceMessage ReadSwTraceMessage(const unsigned char*, unsigned int&, const unsigned int& packetLength);
+
+} // namespace pipe
+
+} // namespace arm
diff --git a/profiling/common/include/WindowsWrapper.hpp b/profiling/common/include/WindowsWrapper.hpp
new file mode 100644
index 0000000..d75fdc8
--- /dev/null
+++ b/profiling/common/include/WindowsWrapper.hpp
@@ -0,0 +1,30 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+// This header brings in the Win32 API header, with some small modifications applied to prevent clashes with our code.
+
+#if defined(_MSC_VER)
+
+#define NOMINMAX    // Prevent definition of min/max macros that interfere with std::min/max
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+// Windows.h defines some names that we don't need and interfere with some of our definition
+#undef TIME_MS      // Instrument.hpp
+#undef CreateEvent  // ITimelineDecoder.hpp
+
+#endif
+
+#if defined(__MINGW32__)
+
+#define NOMINMAX    // Prevent definition of min/max macros that interfere with std::min/max
+#define WIN32_LEAN_AND_MEAN
+#define WINVER 0x0A00
+#define _WIN32_WINNT 0x0A00
+#include <windows.h>
+// Windows.h defines some names that we don't need and interfere with some of our definition
+#undef TIME_MS      // Instrument.hpp
+#undef CreateEvent  // ITimelineDecoder.hpp
+
+#endif
diff --git a/profiling/common/src/CMakeLists.txt b/profiling/common/src/CMakeLists.txt
new file mode 100644
index 0000000..9505fb8
--- /dev/null
+++ b/profiling/common/src/CMakeLists.txt
@@ -0,0 +1,30 @@
+#
+# Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+# SPDX-License-Identifier: MIT
+#
+
+if(BUILD_TIMELINE_DECODER)
+    set(pipeCommon_sources)
+    list(APPEND pipeCommon_sources
+        CommandHandlerFunctor.cpp
+        CommandHandlerKey.cpp
+        CommandHandlerRegistry.cpp
+        CommonProfilingUtils.cpp
+        NetworkSockets.cpp
+        PacketVersionResolver.cpp
+        SwTrace.cpp)
+
+    include_directories(${PROJECT_SOURCE_DIR}/profiling/common/include)
+    include_directories(${PROJECT_SOURCE_DIR}/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/common/include)
+    endif()
+
+    # will only build a static version of this common code
+    # to simplify the build. No extra .so file to deploy to boards etc.
+    add_library_ex(pipeCommon STATIC ${pipeCommon_sources})
+
+endif()
diff --git a/profiling/common/src/CommandHandlerFunctor.cpp b/profiling/common/src/CommandHandlerFunctor.cpp
new file mode 100644
index 0000000..ea24cfb
--- /dev/null
+++ b/profiling/common/src/CommandHandlerFunctor.cpp
@@ -0,0 +1,31 @@
+//
+// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "CommandHandlerFunctor.hpp"
+
+namespace arm
+{
+
+namespace pipe
+{
+
+uint32_t CommandHandlerFunctor::GetFamilyId() const
+{
+    return m_FamilyId;
+}
+
+uint32_t CommandHandlerFunctor::GetPacketId() const
+{
+    return m_PacketId;
+}
+
+uint32_t CommandHandlerFunctor::GetVersion() const
+{
+    return m_Version;
+}
+
+} // namespace pipe
+
+} // namespace arm
diff --git a/profiling/common/src/CommandHandlerKey.cpp b/profiling/common/src/CommandHandlerKey.cpp
new file mode 100644
index 0000000..98e4567
--- /dev/null
+++ b/profiling/common/src/CommandHandlerKey.cpp
@@ -0,0 +1,77 @@
+//
+// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "CommandHandlerKey.hpp"
+
+namespace arm
+{
+
+namespace pipe
+{
+
+uint32_t CommandHandlerKey::GetFamilyId() const
+{
+    return m_FamilyId;
+}
+
+uint32_t CommandHandlerKey::GetPacketId() const
+{
+    return m_PacketId;
+}
+
+uint32_t CommandHandlerKey::GetVersion() const
+{
+    return m_Version;
+}
+
+bool CommandHandlerKey::operator<(const CommandHandlerKey& rhs) const
+{
+    bool result = true;
+    if (m_FamilyId == rhs.m_FamilyId)
+    {
+        if (m_PacketId == rhs.m_PacketId)
+        {
+            result = m_Version < rhs.m_Version;
+        }
+        else if (m_PacketId > rhs.m_PacketId)
+        {
+            result = false;
+        }
+    }
+    else if (m_FamilyId > rhs.m_FamilyId)
+    {
+        result = false;
+    }
+    return result;
+}
+
+bool CommandHandlerKey::operator>(const CommandHandlerKey& rhs) const
+{
+    return rhs < *this;
+}
+
+bool CommandHandlerKey::operator<=(const CommandHandlerKey& rhs) const
+{
+    return !(*this > rhs);
+}
+
+bool CommandHandlerKey::operator>=(const CommandHandlerKey& rhs) const
+{
+    return !(*this < rhs);
+}
+
+bool CommandHandlerKey::operator==(const CommandHandlerKey& rhs) const
+{
+    return m_FamilyId == rhs.m_FamilyId && m_PacketId == rhs.m_PacketId && m_Version == rhs.m_Version;
+}
+
+bool CommandHandlerKey::operator!=(const CommandHandlerKey& rhs) const
+{
+    return !(*this == rhs);
+}
+
+} // namespace pipe
+
+} // namespace arm
diff --git a/profiling/common/src/CommandHandlerRegistry.cpp b/profiling/common/src/CommandHandlerRegistry.cpp
new file mode 100644
index 0000000..324737e
--- /dev/null
+++ b/profiling/common/src/CommandHandlerRegistry.cpp
@@ -0,0 +1,61 @@
+//
+// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+
+#include <common/include/Assert.hpp>
+#include <common/include/CommandHandlerRegistry.hpp>
+
+#include <sstream>
+
+namespace arm
+{
+
+namespace pipe
+{
+
+void CommandHandlerRegistry::RegisterFunctor(CommandHandlerFunctor* functor,
+                                             uint32_t familyId,
+                                             uint32_t packetId,
+                                             uint32_t version)
+{
+    ARM_PIPE_ASSERT_MSG(functor, "Provided functor should not be a nullptr");
+
+    CommandHandlerKey key(familyId, packetId, version);
+    registry[key] = functor;
+}
+
+void CommandHandlerRegistry::RegisterFunctor(CommandHandlerFunctor* functor)
+{
+    ARM_PIPE_ASSERT_MSG(functor, "Provided functor should not be a nullptr");
+
+    RegisterFunctor(functor, functor->GetFamilyId(), functor->GetPacketId(), functor->GetVersion());
+}
+
+CommandHandlerFunctor* CommandHandlerRegistry::GetFunctor(uint32_t familyId,uint32_t packetId, uint32_t version) const
+{
+    CommandHandlerKey key(familyId, packetId, version);
+
+    // Check that the requested key exists
+    if (registry.find(key) == registry.end())
+    {
+        std::stringstream ss;
+        ss << "Functor with requested PacketId=" << packetId << " and Version=" << version << " does not exist";
+        throw ProfilingException(ss.str());
+    }
+
+    CommandHandlerFunctor* commandHandlerFunctor = registry.at(key);
+    if (commandHandlerFunctor == nullptr)
+    {
+        std::stringstream ss;
+        ss << "Invalid functor registered for PacketId=" << packetId << " and Version=" << version;
+        throw ProfilingException(ss.str());
+    }
+
+    return commandHandlerFunctor;
+}
+
+} // namespace pipe
+
+} // namespace arm
diff --git a/profiling/common/src/CommonProfilingUtils.cpp b/profiling/common/src/CommonProfilingUtils.cpp
new file mode 100644
index 0000000..fe98e0a
--- /dev/null
+++ b/profiling/common/src/CommonProfilingUtils.cpp
@@ -0,0 +1,145 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <common/include/Assert.hpp>
+#include <common/include/CommonProfilingUtils.hpp>
+
+#include <sstream>
+
+namespace arm
+{
+
+namespace pipe
+{
+void ReadBytes(const unsigned char* buffer, unsigned int offset, unsigned int valueSize, uint8_t outValue[])
+{
+    ARM_PIPE_ASSERT(buffer);
+    ARM_PIPE_ASSERT(outValue);
+
+    for (unsigned int i = 0; i < valueSize; i++, offset++)
+    {
+        outValue[i] = static_cast<uint8_t>(buffer[offset]);
+    }
+}
+
+uint64_t ReadUint64(const unsigned char* buffer, unsigned int offset)
+{
+    ARM_PIPE_ASSERT(buffer);
+
+    uint64_t value = 0;
+    value  = static_cast<uint64_t>(buffer[offset]);
+    value |= static_cast<uint64_t>(buffer[offset + 1]) << 8;
+    value |= static_cast<uint64_t>(buffer[offset + 2]) << 16;
+    value |= static_cast<uint64_t>(buffer[offset + 3]) << 24;
+    value |= static_cast<uint64_t>(buffer[offset + 4]) << 32;
+    value |= static_cast<uint64_t>(buffer[offset + 5]) << 40;
+    value |= static_cast<uint64_t>(buffer[offset + 6]) << 48;
+    value |= static_cast<uint64_t>(buffer[offset + 7]) << 56;
+
+    return value;
+}
+
+uint32_t ReadUint32(const unsigned char* buffer, unsigned int offset)
+{
+    ARM_PIPE_ASSERT(buffer);
+
+    uint32_t value = 0;
+    value  = static_cast<uint32_t>(buffer[offset]);
+    value |= static_cast<uint32_t>(buffer[offset + 1]) << 8;
+    value |= static_cast<uint32_t>(buffer[offset + 2]) << 16;
+    value |= static_cast<uint32_t>(buffer[offset + 3]) << 24;
+    return value;
+}
+
+uint16_t ReadUint16(const unsigned char* buffer, unsigned int offset)
+{
+    ARM_PIPE_ASSERT(buffer);
+
+    uint32_t value = 0;
+    value  = static_cast<uint32_t>(buffer[offset]);
+    value |= static_cast<uint32_t>(buffer[offset + 1]) << 8;
+    return static_cast<uint16_t>(value);
+}
+
+uint8_t ReadUint8(const unsigned char* buffer, unsigned int offset)
+{
+    ARM_PIPE_ASSERT(buffer);
+
+    return buffer[offset];
+}
+
+void WriteBytes(unsigned char* buffer, unsigned int offset, const void* value, unsigned int valueSize)
+{
+    ARM_PIPE_ASSERT(buffer);
+    ARM_PIPE_ASSERT(value);
+
+    for (unsigned int i = 0; i < valueSize; i++, offset++)
+    {
+        buffer[offset] = *(reinterpret_cast<const unsigned char*>(value) + i);
+    }
+}
+
+void WriteUint64(unsigned char* buffer, unsigned int offset, uint64_t value)
+{
+    ARM_PIPE_ASSERT(buffer);
+
+    buffer[offset]     = static_cast<unsigned char>(value & 0xFF);
+    buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
+    buffer[offset + 2] = static_cast<unsigned char>((value >> 16) & 0xFF);
+    buffer[offset + 3] = static_cast<unsigned char>((value >> 24) & 0xFF);
+    buffer[offset + 4] = static_cast<unsigned char>((value >> 32) & 0xFF);
+    buffer[offset + 5] = static_cast<unsigned char>((value >> 40) & 0xFF);
+    buffer[offset + 6] = static_cast<unsigned char>((value >> 48) & 0xFF);
+    buffer[offset + 7] = static_cast<unsigned char>((value >> 56) & 0xFF);
+}
+
+void WriteUint32(unsigned char* buffer, unsigned int offset, uint32_t value)
+{
+    ARM_PIPE_ASSERT(buffer);
+
+    buffer[offset]     = static_cast<unsigned char>(value & 0xFF);
+    buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
+    buffer[offset + 2] = static_cast<unsigned char>((value >> 16) & 0xFF);
+    buffer[offset + 3] = static_cast<unsigned char>((value >> 24) & 0xFF);
+}
+
+void WriteUint16(unsigned char* buffer, unsigned int offset, uint16_t value)
+{
+    ARM_PIPE_ASSERT(buffer);
+
+    buffer[offset]     = static_cast<unsigned char>(value & 0xFF);
+    buffer[offset + 1] = static_cast<unsigned char>((value >> 8) & 0xFF);
+}
+
+void WriteUint8(unsigned char* buffer, unsigned int offset, uint8_t value)
+{
+    ARM_PIPE_ASSERT(buffer);
+
+    buffer[offset] = static_cast<unsigned char>(value);
+}
+
+std::string CentreAlignFormatting(const std::string& stringToPass, const int spacingWidth)
+{
+    std::stringstream outputStream, centrePadding;
+    int padding = spacingWidth - static_cast<int>(stringToPass.size());
+
+    for (int i = 0; i < padding / 2; ++i)
+    {
+        centrePadding << " ";
+    }
+
+    outputStream << centrePadding.str() << stringToPass << centrePadding.str();
+
+    if (padding > 0 && padding %2 != 0)
+    {
+        outputStream << " ";
+    }
+
+    return outputStream.str();
+}
+
+
+} // namespace pipe
+} // namespace arm
\ No newline at end of file
diff --git a/profiling/common/src/NetworkSockets.cpp b/profiling/common/src/NetworkSockets.cpp
index 7f47c79..2a65655 100644
--- a/profiling/common/src/NetworkSockets.cpp
+++ b/profiling/common/src/NetworkSockets.cpp
@@ -1,27 +1,35 @@
 //
-// Copyright © 2020 Arm Ltd. All rights reserved.
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
 // SPDX-License-Identifier: MIT
 //
 
-#include "common/include/NetworkSockets.hpp"
+#include <common/include/NetworkSockets.hpp>
 
 #if defined(__unix__) || defined(__APPLE__)
 #include <unistd.h>
 #include <fcntl.h>
-#include <armnn/Conversion.hpp>
-
+#include <common/include/Conversion.hpp>
 #endif
 
-namespace armnnUtils
+#if defined(__APPLE__) || defined(_MSC_VER) || defined(__MINGW32__)
+#include <common/include/IgnoreUnused.hpp>
+#endif
+
+#if defined(__MINGW32__)
+#include <common/include/Conversion.hpp>
+#include <common/include/NumericCast.hpp>
+#endif
+
+namespace arm
 {
-namespace Sockets
+namespace pipe
 {
 
 bool Initialize()
 {
 #if defined(__unix__) || defined(__APPLE__)
     return true;
-#elif defined(_MSC_VER)
+#elif defined(_MSC_VER) || defined(__MINGW32__)
     WSADATA wsaData;
     return WSAStartup(MAKEWORD(2, 2), &wsaData) == 0;
 #endif
@@ -31,7 +39,7 @@
 {
 #if defined(__unix__) || defined(__APPLE__)
     return close(s);
-#elif defined(_MSC_VER)
+#elif defined(_MSC_VER) || defined(__MINGW32__)
     return closesocket(s);
 #endif
 }
@@ -45,6 +53,9 @@
 #elif defined(_MSC_VER)
     u_long mode = 1;
     return ioctlsocket(s, FIONBIO, &mode) == 0;
+#elif defined(__MINGW32__)
+    u_long mode = 1;
+    return ioctlsocket(s, arm::pipe::numeric_cast<long>(FIONBIO), &mode) == 0;
 #endif
 }
 
@@ -53,7 +64,7 @@
 {
 #if defined(__unix__) || defined(__APPLE__)
     return write(s, buf, len);
-#elif defined(_MSC_VER)
+#elif defined(_MSC_VER) || defined(__MINGW32__)
     return send(s, static_cast<const char*>(buf), static_cast<int>(len), 0);
 #endif
 }
@@ -63,7 +74,7 @@
 {
 #if defined(__unix__) || defined(__APPLE__)
     return read(s, buf, len);
-#elif defined(_MSC_VER)
+#elif defined(_MSC_VER) || defined(__MINGW32__)
     return recv(s, static_cast<char*>(buf), static_cast<int>(len), 0);
 #endif
 }
@@ -71,11 +82,13 @@
 int Ioctl(Socket s, unsigned long int cmd, void* arg)
 {
 #if defined(__unix__) || defined(__APPLE__)
-    ARMNN_NO_CONVERSION_WARN_BEGIN
+    ARM_PIPE_NO_CONVERSION_WARN_BEGIN
     return ioctl(s, static_cast<int>(cmd), arg);
-    ARMNN_NO_CONVERSION_WARN_END
-#elif defined(_MSC_VER)
+    ARM_PIPE_NO_CONVERSION_WARN_END
+#elif defined(_MSC_VER) || defined(__MINGW32__)
+    ARM_PIPE_NO_CONVERSION_WARN_BEGIN
     return ioctlsocket(s, cmd, static_cast<u_long*>(arg));
+    ARM_PIPE_NO_CONVERSION_WARN_END
 #endif
 }
 
@@ -84,22 +97,24 @@
 {
 #if defined(__unix__) || defined(__APPLE__)
     return poll(fds, numFds, timeout);
-#elif defined(_MSC_VER)
-    return WSAPoll(fds, numFds, timeout);
+#elif defined(_MSC_VER) || defined(__MINGW32__)
+    return WSAPoll(fds, arm::pipe::numeric_cast<unsigned long>(numFds), timeout);
 #endif
 }
 
 
-armnnUtils::Sockets::Socket Accept(Socket s, sockaddr* addr, socklen_t* addrlen, int flags)
+arm::pipe::Socket Accept(Socket s, sockaddr* addr, socklen_t* addrlen, int flags)
 {
 #if defined(__unix__)
     return accept4(s, addr, addrlen, flags);
 #elif defined(__APPLE__)
+    IgnoreUnused(flags);
     return accept(s, addr, addrlen);
-#elif defined(_MSC_VER)
+#elif defined(_MSC_VER) || defined(__MINGW32__)
+    IgnoreUnused(flags);
     return accept(s, addr, reinterpret_cast<int*>(addrlen));
 #endif
 }
 
-}
-}
+} // pipe
+} // arm
diff --git a/profiling/common/src/PacketVersionResolver.cpp b/profiling/common/src/PacketVersionResolver.cpp
new file mode 100644
index 0000000..25d92b0
--- /dev/null
+++ b/profiling/common/src/PacketVersionResolver.cpp
@@ -0,0 +1,71 @@
+//
+// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <common/include/PacketVersionResolver.hpp>
+
+namespace arm
+{
+
+namespace pipe
+{
+
+bool PacketKey::operator<(const PacketKey& rhs) const
+{
+    bool result = true;
+    if (m_FamilyId == rhs.m_FamilyId)
+    {
+            result = m_PacketId < rhs.m_PacketId;
+    }
+    else if (m_FamilyId > rhs.m_FamilyId)
+    {
+        result = false;
+    }
+    return result;
+}
+
+bool PacketKey::operator>(const PacketKey& rhs) const
+{
+    return rhs < *this;
+}
+
+bool PacketKey::operator<=(const PacketKey& rhs) const
+{
+    return !(*this > rhs);
+}
+
+bool PacketKey::operator>=(const PacketKey& rhs) const
+{
+    return !(*this < rhs);
+}
+
+bool PacketKey::operator==(const PacketKey& rhs) const
+{
+    return m_FamilyId == rhs.m_FamilyId && m_PacketId == rhs.m_PacketId;
+}
+
+bool PacketKey::operator!=(const PacketKey& rhs) const
+{
+    return !(*this == rhs);
+}
+
+Version PacketVersionResolver::ResolvePacketVersion(uint32_t familyId, uint32_t packetId) const
+{
+    const PacketKey packetKey(familyId, packetId);
+
+    if( packetKey == ActivateTimeLinePacket )
+    {
+        return Version(1, 1, 0);
+    }
+    if( packetKey == DeactivateTimeLinePacket )
+    {
+        return Version(1, 1, 0);
+    }
+
+    return Version(1, 0, 0);
+}
+
+} // namespace pipe
+
+} // namespace arm
diff --git a/profiling/common/src/SwTrace.cpp b/profiling/common/src/SwTrace.cpp
new file mode 100644
index 0000000..5860d8c
--- /dev/null
+++ b/profiling/common/src/SwTrace.cpp
@@ -0,0 +1,128 @@
+//
+// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <common/include/CommonProfilingUtils.hpp>
+#include <common/include/NumericCast.hpp>
+#include <common/include/ProfilingException.hpp>
+#include <common/include/SwTrace.hpp>
+
+#include <sstream>
+
+namespace arm
+{
+
+namespace pipe
+{
+
+// Calculate the actual length an SwString will be including the terminating null character
+// padding to bring it to the next uint32_t boundary but minus the leading uint32_t encoding
+// the size to allow the offset to be correctly updated when decoding a binary packet.
+uint32_t CalculateSizeOfPaddedSwString(const std::string& str)
+{
+    std::vector<uint32_t> swTraceString;
+    StringToSwTraceString<SwTraceCharPolicy>(str, swTraceString);
+    unsigned int uint32_t_size = sizeof(uint32_t);
+    uint32_t size = (numeric_cast<uint32_t>(swTraceString.size()) - 1) * uint32_t_size;
+    return size;
+}
+
+// Read TimelineMessageDirectoryPacket from given IPacketBuffer and offset
+SwTraceMessage ReadSwTraceMessage(const unsigned char* packetBuffer,
+                                  unsigned int& offset,
+                                  const unsigned int& packetLength)
+{
+    ARM_PIPE_ASSERT(packetBuffer);
+
+    unsigned int uint32_t_size = sizeof(uint32_t);
+
+    SwTraceMessage swTraceMessage;
+
+    // Read the decl_id
+    uint32_t readDeclId = ReadUint32(packetBuffer, offset);
+    swTraceMessage.m_Id = readDeclId;
+
+    // SWTrace "namestring" format
+    // length of the string (first 4 bytes) + string + null terminator
+
+    // Check the decl_name
+    offset += uint32_t_size;
+    uint32_t swTraceDeclNameLength = ReadUint32(packetBuffer, offset);
+
+    if (swTraceDeclNameLength == 0 || swTraceDeclNameLength > packetLength)
+    {
+        throw arm::pipe::ProfilingException("Error swTraceDeclNameLength is an invalid size", LOCATION());
+    }
+
+    offset += uint32_t_size;
+    std::vector<unsigned char> swTraceStringBuffer(swTraceDeclNameLength - 1);
+    std::memcpy(swTraceStringBuffer.data(),
+                packetBuffer + offset, swTraceStringBuffer.size());
+
+    swTraceMessage.m_Name.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // name
+
+    // Check the ui_name
+    offset += CalculateSizeOfPaddedSwString(swTraceMessage.m_Name);
+    uint32_t swTraceUINameLength = ReadUint32(packetBuffer, offset);
+
+    if (swTraceUINameLength == 0 || swTraceUINameLength > packetLength)
+    {
+        throw arm::pipe::ProfilingException("Error swTraceUINameLength is an invalid size", LOCATION());
+    }
+
+    offset += uint32_t_size;
+    swTraceStringBuffer.resize(swTraceUINameLength - 1);
+    std::memcpy(swTraceStringBuffer.data(),
+                packetBuffer  + offset, swTraceStringBuffer.size());
+
+    swTraceMessage.m_UiName.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // ui_name
+
+    // Check arg_types
+    offset += CalculateSizeOfPaddedSwString(swTraceMessage.m_UiName);
+    uint32_t swTraceArgTypesLength = ReadUint32(packetBuffer, offset);
+
+    if (swTraceArgTypesLength == 0 || swTraceArgTypesLength > packetLength)
+    {
+        throw arm::pipe::ProfilingException("Error swTraceArgTypesLength is an invalid size", LOCATION());
+    }
+
+    offset += uint32_t_size;
+    swTraceStringBuffer.resize(swTraceArgTypesLength - 1);
+    std::memcpy(swTraceStringBuffer.data(),
+                packetBuffer  + offset, swTraceStringBuffer.size());
+
+    swTraceMessage.m_ArgTypes.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end()); // arg_types
+
+    std::string swTraceString(swTraceStringBuffer.begin(), swTraceStringBuffer.end());
+
+    // Check arg_names
+    offset += CalculateSizeOfPaddedSwString(swTraceString);
+    uint32_t swTraceArgNamesLength = ReadUint32(packetBuffer, offset);
+
+    if (swTraceArgNamesLength == 0 || swTraceArgNamesLength > packetLength)
+    {
+        throw arm::pipe::ProfilingException("Error swTraceArgNamesLength is an invalid size", LOCATION());
+    }
+
+    offset += uint32_t_size;
+    swTraceStringBuffer.resize(swTraceArgNamesLength - 1);
+    std::memcpy(swTraceStringBuffer.data(),
+                packetBuffer  + offset, swTraceStringBuffer.size());
+
+    swTraceString.assign(swTraceStringBuffer.begin(), swTraceStringBuffer.end());
+    std::stringstream stringStream(swTraceString);
+    std::string argName;
+    while (std::getline(stringStream, argName, ','))
+    {
+        swTraceMessage.m_ArgNames.push_back(argName);
+    }
+
+    offset += CalculateSizeOfPaddedSwString(swTraceString);
+
+    return swTraceMessage;
+}
+
+} // namespace pipe
+
+} // namespace arm
diff --git a/profiling/server/src/basePipeServer/BasePipeServer.hpp b/profiling/server/include/basePipeServer/BasePipeServer.hpp
similarity index 78%
rename from profiling/server/src/basePipeServer/BasePipeServer.hpp
rename to profiling/server/include/basePipeServer/BasePipeServer.hpp
index bef9d29..1b6dec5 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 @@
 
 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 @@
     ~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 @@
     /// @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 @@
     /// @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 @@
     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 @@
     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
similarity index 84%
rename from profiling/server/src/basePipeServer/ConnectionHandler.hpp
rename to profiling/server/include/basePipeServer/ConnectionHandler.hpp
index 661935b..4859fce 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 @@
     ~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 @@
 
 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 0000000..18b8cc7
--- /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 0000000..c51cfd3
--- /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 0000000..ea4b144
--- /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 0000000..826ee1f
--- /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 ed5c442..81f58a5 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 @@
     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 @@
     // 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 @@
     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 @@
         // 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 @@
                 {
                     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 @@
                 {
                     // 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 @@
 
     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 @@
         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 @@
     }
 }
 
-} // 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 56ef454..b5dc68c 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})
 
-    install(TARGETS armnnBasePipeServer
-            LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
-            RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
-endif()
\ No newline at end of file
+       target_include_directories(armnnBasePipeServer PRIVATE ${PROJECT_SOURCE_DIR}/src/armnnUtils)
+
+       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 1485ab8..1c9ffa9 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 @@
 
     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 @@
     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 57fc9e9..0917927 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 @@
     // 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 0000000..7154722
--- /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 0000000..247c951
--- /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 0000000..df967de
--- /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 0000000..6963dd0
--- /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 0000000..e779706
--- /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()
diff --git a/profiling/toolchain-x86-ubuntu-mingw64.cmake b/profiling/toolchain-x86-ubuntu-mingw64.cmake
new file mode 100644
index 0000000..2d9e49f
--- /dev/null
+++ b/profiling/toolchain-x86-ubuntu-mingw64.cmake
@@ -0,0 +1,28 @@
+#
+# Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
+# SPDX-License-Identifier: MIT
+#
+
+# toolchain file for building for Windows on an Ubuntu Linux system.
+#
+# Typical usage:
+#    *) install cross compiler: `sudo apt-get install mingw-w64`
+#    *) cmake -DCMAKE_TOOLCHAIN_FILE=~/toolchain-x86-ubuntu-mingw64.cmake
+
+set(CMAKE_SYSTEM_NAME Windows)
+set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
+
+# cross compilers to use for C and C++
+set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
+set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
+
+# target environment on the build host system
+#   set 1st to dir with the cross compiler's C/C++ headers/libs
+set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
+
+# modify default behavior of FIND_XXX() commands to
+# search for headers/libs in the target environment and
+# search for programs in the build host environment
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)