diff options
Diffstat (limited to 'profiling')
44 files changed, 3108 insertions, 129 deletions
diff --git a/profiling/CMakeLists.txt b/profiling/CMakeLists.txt new file mode 100644 index 0000000000..f9ffd66433 --- /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 0000000000..611b7b96e0 --- /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 0000000000..c6e8bc49d4 --- /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 0000000000..9827aa05ba --- /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 0000000000..f45b5bef14 --- /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 0000000000..5a5d879996 --- /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 0000000000..68fe6bb8ca --- /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 52e0e487a8..01bfe795c2 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 0000000000..0a3eb0c0d6 --- /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 0000000000..9257b22cfc --- /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 0000000000..fad40d33d4 --- /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 0000000000..a31c2aaa7b --- /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 05a45ae90b..29575cdcd6 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 nfds_t = int; 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 @@ int Poll(PollFd* fds, nfds_t numFds, int timeout); 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 0000000000..069f9514fe --- /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 23c3124bad..d8fa2709e2 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 @@ public: 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 @@ private: 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 0000000000..0ec7d2aca4 --- /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 532c2d49f7..abdc0dc025 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 d18dcc37e4..42b8d9d67e 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 @@ public: 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 0000000000..5abc59b1a8 --- /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 0000000000..d75fdc857a --- /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 0000000000..9505fb8869 --- /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 0000000000..ea24cfb34e --- /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 0000000000..98e4567348 --- /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 0000000000..324737eda5 --- /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 0000000000..fe98e0aaa9 --- /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 7f47c79b31..2a656552f1 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 + +#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 armnnUtils +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 @@ int Close(Socket s) { #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 @@ bool SetNonBlocking(Socket s) #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 @@ long Write(Socket s, const void* buf, size_t len) { #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 @@ long Read(Socket s, void* buf, size_t len) { #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 @@ long Read(Socket s, void* buf, size_t len) 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 @@ int Poll(PollFd* fds, nfds_t numFds, int timeout) { #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 0000000000..25d92b0c5d --- /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 0000000000..5860d8cf06 --- /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 index bef9d29f44..1b6dec54ff 100644 --- a/profiling/server/src/basePipeServer/BasePipeServer.hpp +++ b/profiling/server/include/basePipeServer/BasePipeServer.hpp @@ -1,18 +1,21 @@ // -// Copyright © 2020 Arm Ltd. All rights reserved. +// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // #pragma once -#include <NetworkSockets.hpp> -#include <Packet.hpp> -#include <SocketConnectionException.hpp> +#include <common/include/NetworkSockets.hpp> +#include <common/include/Packet.hpp> +#include <common/include/SocketConnectionException.hpp> #include <string> #include <atomic> -namespace armnnProfiling +namespace arm +{ + +namespace pipe { enum class TargetEndianness @@ -34,7 +37,7 @@ class BasePipeServer public: - BasePipeServer(armnnUtils::Sockets::Socket clientConnection, bool echoPackets) + BasePipeServer(arm::pipe::Socket clientConnection, bool echoPackets) : m_ClientConnection(clientConnection) , m_EchoPackets(echoPackets) {} @@ -42,7 +45,7 @@ public: ~BasePipeServer() { // We have set SOCK_CLOEXEC on this socket but we'll close it to be good citizens. - armnnUtils::Sockets::Close(m_ClientConnection); + arm::pipe::Close(m_ClientConnection); } BasePipeServer(const BasePipeServer&) = delete; @@ -55,7 +58,7 @@ public: /// @return 0 if successful int Close() { - return armnnUtils::Sockets::Close(m_ClientConnection); + return arm::pipe::Close(m_ClientConnection); } /// Send a packet to the client @@ -66,12 +69,12 @@ public: /// @return true if successful. bool SetNonBlocking() { - return armnnUtils::Sockets::SetNonBlocking(m_ClientConnection); + return arm::pipe::SetNonBlocking(m_ClientConnection); } /// Block on the client connection until a complete packet has been received. /// @return true if a valid packet has been received. - armnn::profiling::Packet WaitForPacket(uint32_t timeoutMs); + arm::pipe::Packet WaitForPacket(uint32_t timeoutMs); /// Once the connection is open wait to receive the stream meta data packet from the client. Reading this /// packet differs from others as we need to determine endianness. @@ -99,12 +102,12 @@ private: bool ReadFromSocket(uint8_t* packetData, uint32_t expectedLength); bool ReadHeader(uint32_t headerAsWords[2]); - armnn::profiling::Packet ReceivePacket(); + arm::pipe::Packet ReceivePacket(); uint32_t ToUint32(uint8_t* data, TargetEndianness endianness); void InsertU32(uint32_t value, uint8_t* data, TargetEndianness endianness); - armnnUtils::Sockets::Socket m_ClientConnection; + arm::pipe::Socket m_ClientConnection; bool m_EchoPackets; TargetEndianness m_Endianness; @@ -113,4 +116,5 @@ private: uint32_t m_StreamMetaDataPid; }; -} // namespace armnnProfiling
\ No newline at end of file +} // namespace pipe +} // namespace arm diff --git a/profiling/server/src/basePipeServer/ConnectionHandler.hpp b/profiling/server/include/basePipeServer/ConnectionHandler.hpp index 661935b885..4859fced0d 100644 --- a/profiling/server/src/basePipeServer/ConnectionHandler.hpp +++ b/profiling/server/include/basePipeServer/ConnectionHandler.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2020 Arm Ltd. All rights reserved. +// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -8,7 +8,10 @@ #include "BasePipeServer.hpp" #include <string> -namespace armnnProfiling +namespace arm +{ + +namespace pipe { class ConnectionHandler @@ -22,7 +25,7 @@ public: ~ConnectionHandler() { // We have set SOCK_CLOEXEC on this socket but we'll close it to be good citizens. - armnnUtils::Sockets::Close(m_ListeningSocket); + arm::pipe::Close(m_ListeningSocket); } ConnectionHandler(const ConnectionHandler&) = delete; @@ -38,7 +41,8 @@ public: private: - armnnUtils::Sockets::Socket m_ListeningSocket; + arm::pipe::Socket m_ListeningSocket; }; -} // namespace armnnProfiling
\ No newline at end of file +} // namespace pipe +} // namespace arm diff --git a/profiling/server/include/timelineDecoder/ITimelineDecoder.hpp b/profiling/server/include/timelineDecoder/ITimelineDecoder.hpp new file mode 100644 index 0000000000..18b8cc7006 --- /dev/null +++ b/profiling/server/include/timelineDecoder/ITimelineDecoder.hpp @@ -0,0 +1,91 @@ +// +// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include <cstdint> +#include <string> + +namespace arm +{ + +namespace pipe +{ + +class ITimelineDecoder +{ + +public: + + enum class TimelineStatus + { + TimelineStatus_Success, + TimelineStatus_Fail + }; + + enum class RelationshipType + { + RetentionLink, /// Head retains(parents) Tail + ExecutionLink, /// Head execution start depends on Tail execution completion + DataLink, /// Head uses data of Tail + LabelLink /// Head uses label Tail (Tail MUST be a guid of a label). + }; + + static char const* GetRelationshipAsCString(RelationshipType rType) + { + switch (rType) + { + case RelationshipType::RetentionLink: return "RetentionLink"; + case RelationshipType::ExecutionLink: return "ExecutionLink"; + case RelationshipType::DataLink: return "DataLink"; + case RelationshipType::LabelLink: return "LabelLink"; + default: return "Unknown"; + } + } + + struct Entity + { + uint64_t m_Guid; + }; + + struct EventClass + { + uint64_t m_Guid; + uint64_t m_NameGuid; + }; + + struct Event + { + uint64_t m_Guid; + uint64_t m_TimeStamp; + uint64_t m_ThreadId; + }; + + struct Label + { + uint64_t m_Guid; + std::string m_Name; + }; + + struct Relationship + { + RelationshipType m_RelationshipType; + uint64_t m_Guid; + uint64_t m_HeadGuid; + uint64_t m_TailGuid; + uint64_t m_AttributeGuid; + }; + + virtual ~ITimelineDecoder() = default; + + virtual TimelineStatus CreateEntity(const Entity&) = 0; + virtual TimelineStatus CreateEventClass(const EventClass&) = 0; + virtual TimelineStatus CreateEvent(const Event&) = 0; + virtual TimelineStatus CreateLabel(const Label&) = 0; + virtual TimelineStatus CreateRelationship(const Relationship&) = 0; +}; + +} // namespace pipe +} // namespace arm diff --git a/profiling/server/include/timelineDecoder/TimelineCaptureCommandHandler.hpp b/profiling/server/include/timelineDecoder/TimelineCaptureCommandHandler.hpp new file mode 100644 index 0000000000..c51cfd32cd --- /dev/null +++ b/profiling/server/include/timelineDecoder/TimelineCaptureCommandHandler.hpp @@ -0,0 +1,63 @@ +// +// Copyright © 2019 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include "ITimelineDecoder.hpp" + +#include <common/include/CommandHandlerFunctor.hpp> +#include <common/include/Packet.hpp> + +namespace arm +{ + +namespace pipe +{ + +class TimelineCaptureCommandHandler : public arm::pipe::CommandHandlerFunctor +{ + // Utils + uint32_t uint32_t_size = sizeof(uint32_t); + uint32_t uint64_t_size = sizeof(uint64_t); + + using ReadFunction = ITimelineDecoder::TimelineStatus (TimelineCaptureCommandHandler::*)( + const unsigned char*, uint32_t&); + +public: + TimelineCaptureCommandHandler(uint32_t familyId, + uint32_t packetId, + uint32_t version, + ITimelineDecoder& timelineDecoder, + uint32_t threadIdSize = 0) + : CommandHandlerFunctor(familyId, packetId, version) + , m_TimelineDecoder(timelineDecoder) + , m_ThreadIdSize(threadIdSize) + , m_PacketLength(0) + {} + + void operator()(const arm::pipe::Packet& packet) override; + + + void SetThreadIdSize(uint32_t size); + +private: + void ParseData(const arm::pipe::Packet& packet); + + ITimelineDecoder::TimelineStatus ReadLabel(const unsigned char* data, uint32_t& offset); + ITimelineDecoder::TimelineStatus ReadEntity(const unsigned char* data, uint32_t& offset); + ITimelineDecoder::TimelineStatus ReadEventClass(const unsigned char* data, uint32_t& offset); + ITimelineDecoder::TimelineStatus ReadRelationship(const unsigned char* data, uint32_t& offset); + ITimelineDecoder::TimelineStatus ReadEvent(const unsigned char* data, uint32_t& offset); + + ITimelineDecoder& m_TimelineDecoder; + uint32_t m_ThreadIdSize; + unsigned int m_PacketLength; + static const ReadFunction m_ReadFunctions[]; + +}; + +} //namespace pipe + +} //namespace arm diff --git a/profiling/server/include/timelineDecoder/TimelineDecoder.hpp b/profiling/server/include/timelineDecoder/TimelineDecoder.hpp new file mode 100644 index 0000000000..ea4b144860 --- /dev/null +++ b/profiling/server/include/timelineDecoder/TimelineDecoder.hpp @@ -0,0 +1,72 @@ +// +// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// +#pragma once + +#include "ITimelineDecoder.hpp" + +#include <vector> + +namespace arm +{ + +namespace pipe +{ + +class TimelineDecoder : public ITimelineDecoder +{ + +public: + + struct Model + { + std::vector<Entity> m_Entities; + std::vector<EventClass> m_EventClasses; + std::vector<Event> m_Events; + std::vector<Label> m_Labels; + std::vector<Relationship> m_Relationships; + }; + + using OnNewEntityCallback = void (*)(Model &, const Entity); + using OnNewEventClassCallback = void (*)(Model &, const EventClass); + using OnNewEventCallback = void (*)(Model &, const Event); + using OnNewLabelCallback = void (*)(Model &, const Label); + using OnNewRelationshipCallback = void (*)(Model &, const Relationship); + + virtual TimelineStatus CreateEntity(const Entity &) override; + virtual TimelineStatus CreateEventClass(const EventClass &) override; + virtual TimelineStatus CreateEvent(const Event &) override; + virtual TimelineStatus CreateLabel(const Label &) override; + virtual TimelineStatus CreateRelationship(const Relationship &) override; + + const Model& GetModel(); + + TimelineStatus SetEntityCallback(const OnNewEntityCallback); + TimelineStatus SetEventClassCallback(const OnNewEventClassCallback); + TimelineStatus SetEventCallback(const OnNewEventCallback); + TimelineStatus SetLabelCallback(const OnNewLabelCallback); + TimelineStatus SetRelationshipCallback(const OnNewRelationshipCallback); + + void SetDefaultCallbacks(); + + void print(); + +private: + Model m_Model; + + OnNewEntityCallback m_OnNewEntityCallback; + OnNewEventClassCallback m_OnNewEventClassCallback; + OnNewEventCallback m_OnNewEventCallback; + OnNewLabelCallback m_OnNewLabelCallback; + OnNewRelationshipCallback m_OnNewRelationshipCallback; + + void printLabels(); + void printEntities(); + void printEventClasses(); + void printRelationships(); + void printEvents(); +}; + +} // namespace pipe +} // namespace arm
\ No newline at end of file diff --git a/profiling/server/include/timelineDecoder/TimelineDirectoryCaptureCommandHandler.hpp b/profiling/server/include/timelineDecoder/TimelineDirectoryCaptureCommandHandler.hpp new file mode 100644 index 0000000000..826ee1f10d --- /dev/null +++ b/profiling/server/include/timelineDecoder/TimelineDirectoryCaptureCommandHandler.hpp @@ -0,0 +1,50 @@ +// +// Copyright © 2019 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#pragma once + +#include "TimelineCaptureCommandHandler.hpp" + +#include <common/include/SwTrace.hpp> + +namespace arm +{ + +namespace pipe +{ + +class TimelineDirectoryCaptureCommandHandler : public arm::pipe::CommandHandlerFunctor +{ + // Utils + uint32_t uint8_t_size = sizeof(uint8_t); + uint32_t uint32_t_size = sizeof(uint32_t); + +public: + TimelineDirectoryCaptureCommandHandler(uint32_t familyId, + uint32_t packetId, + uint32_t version, + TimelineCaptureCommandHandler& timelineCaptureCommandHandler, + bool quietOperation = false) + : CommandHandlerFunctor(familyId, packetId, version) + , m_TimelineCaptureCommandHandler(timelineCaptureCommandHandler) + , m_QuietOperation(quietOperation) + {} + + void operator()(const arm::pipe::Packet& packet) override; + + arm::pipe::SwTraceHeader m_SwTraceHeader; + std::vector<arm::pipe::SwTraceMessage> m_SwTraceMessages; + +private: + void ParseData(const arm::pipe::Packet& packet); + void Print(); + + TimelineCaptureCommandHandler& m_TimelineCaptureCommandHandler; + bool m_QuietOperation; +}; + +} //namespace pipe + +} //namespace arm diff --git a/profiling/server/src/basePipeServer/BasePipeServer.cpp b/profiling/server/src/basePipeServer/BasePipeServer.cpp index ed5c442492..81f58a5ee9 100644 --- a/profiling/server/src/basePipeServer/BasePipeServer.cpp +++ b/profiling/server/src/basePipeServer/BasePipeServer.cpp @@ -1,30 +1,31 @@ // -// Copyright © 2020 Arm Ltd. All rights reserved. +// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // -#include "BasePipeServer.hpp" +#include <server/include/basePipeServer/BasePipeServer.hpp> -#include "common/include/Constants.hpp" +#include <common/include/Constants.hpp> +#include <common/include/NumericCast.hpp> #include <iostream> -#include <boost/cast.hpp> #include <vector> #include <iomanip> #include <string.h> -using namespace armnnUtils; +namespace arm +{ -namespace armnnProfiling +namespace pipe { bool BasePipeServer::ReadFromSocket(uint8_t* packetData, uint32_t expectedLength) { // This is a blocking read until either expectedLength has been received or an error is detected. long totalBytesRead = 0; - while (boost::numeric_cast<uint32_t>(totalBytesRead) < expectedLength) + while (arm::pipe::numeric_cast<uint32_t>(totalBytesRead) < expectedLength) { - long bytesRead = Sockets::Read(m_ClientConnection, packetData, expectedLength); + long bytesRead = arm::pipe::Read(m_ClientConnection, packetData, expectedLength); if (bytesRead < 0) { std::cerr << ": Failure when reading from client socket: " << strerror(errno) << std::endl; @@ -68,17 +69,17 @@ bool BasePipeServer::WaitForStreamMetaData() EchoPacket(PacketDirection::ReceivedData, pipeMagic, 4); // Before we interpret the length we need to read the pipe_magic word to determine endianness. - if (ToUint32(&pipeMagic[0], TargetEndianness::BeWire) == armnnProfiling::PIPE_MAGIC) + if (ToUint32(&pipeMagic[0], TargetEndianness::BeWire) == PIPE_MAGIC) { m_Endianness = TargetEndianness::BeWire; } - else if (ToUint32(&pipeMagic[0], TargetEndianness::LeWire) == armnnProfiling::PIPE_MAGIC) + else if (ToUint32(&pipeMagic[0], TargetEndianness::LeWire) == PIPE_MAGIC) { m_Endianness = TargetEndianness::LeWire; } else { - std::cerr << ": Protocol read error. Unable to read PIPE_MAGIC value." << std::endl; + std::cerr << ": Protocol read error. Unable to read the PIPE_MAGIC value." << std::endl; return false; } // Now we know the endianness we can get the length from the header. @@ -87,7 +88,7 @@ bool BasePipeServer::WaitForStreamMetaData() // Read the entire packet. std::vector<uint8_t> packetData(metaDataLength); if (metaDataLength != - boost::numeric_cast<uint32_t>(Sockets::Read(m_ClientConnection, packetData.data(), metaDataLength))) + arm::pipe::numeric_cast<uint32_t>(arm::pipe::Read(m_ClientConnection, packetData.data(), metaDataLength))) { std::cerr << ": Protocol read error. Data length mismatch." << std::endl; return false; @@ -100,11 +101,11 @@ bool BasePipeServer::WaitForStreamMetaData() return true; } -armnn::profiling::Packet BasePipeServer::WaitForPacket(uint32_t timeoutMs) +arm::pipe::Packet BasePipeServer::WaitForPacket(uint32_t timeoutMs) { // Is there currently more than a headers worth of data waiting to be read? int bytes_available; - Sockets::Ioctl(m_ClientConnection, FIONREAD, &bytes_available); + arm::pipe::Ioctl(m_ClientConnection, FIONREAD, &bytes_available); if (bytes_available > 8) { // Yes there is. Read it: @@ -115,18 +116,18 @@ armnn::profiling::Packet BasePipeServer::WaitForPacket(uint32_t timeoutMs) // No there's not. Poll for more data. struct pollfd pollingFd[1]{}; pollingFd[0].fd = m_ClientConnection; - int pollResult = Sockets::Poll(pollingFd, 1, static_cast<int>(timeoutMs)); + int pollResult = arm::pipe::Poll(pollingFd, 1, static_cast<int>(timeoutMs)); switch (pollResult) { // Error case -1: - throw armnn::RuntimeException(std::string("File descriptor reported an error during polling: ") + - strerror(errno)); + throw ProfilingException(std::string("File descriptor reported an error during polling: ") + + strerror(errno)); // Timeout case 0: - throw armnn::TimeoutException("Timeout while waiting to receive packet."); + throw arm::pipe::TimeoutException("Timeout while waiting to receive packet."); // Normal poll return. It could still contain an error signal default: @@ -135,16 +136,18 @@ armnn::profiling::Packet BasePipeServer::WaitForPacket(uint32_t timeoutMs) { if (pollingFd[0].revents == POLLNVAL) { - throw armnn::RuntimeException(std::string("Error while polling receiving socket: POLLNVAL")); + throw arm::pipe::ProfilingException( + std::string("Error while polling receiving socket: POLLNVAL")); } if (pollingFd[0].revents == POLLERR) { - throw armnn::RuntimeException(std::string("Error while polling receiving socket: POLLERR: ") + - strerror(errno)); + throw arm::pipe::ProfilingException( + std::string("Error while polling receiving socket: POLLERR: ") + strerror(errno)); } if (pollingFd[0].revents == POLLHUP) { - throw armnn::RuntimeException(std::string("Connection closed by remote client: POLLHUP")); + throw arm::pipe::ProfilingException( + std::string("Connection closed by remote client: POLLHUP")); } } @@ -153,19 +156,20 @@ armnn::profiling::Packet BasePipeServer::WaitForPacket(uint32_t timeoutMs) { // This is a corner case. The socket as been woken up but not with any data. // We'll throw a timeout exception to loop around again. - throw armnn::TimeoutException("File descriptor was polled but no data was available to receive."); + throw arm::pipe::TimeoutException( + "File descriptor was polled but no data was available to receive."); } return ReceivePacket(); } } } -armnn::profiling::Packet BasePipeServer::ReceivePacket() +arm::pipe::Packet BasePipeServer::ReceivePacket() { uint32_t header[2]; if (!ReadHeader(header)) { - return armnn::profiling::Packet(); + return arm::pipe::Packet(); } // Read data_length bytes from the socket. std::unique_ptr<unsigned char[]> uniquePacketData = std::make_unique<unsigned char[]>(header[1]); @@ -173,13 +177,13 @@ armnn::profiling::Packet BasePipeServer::ReceivePacket() if (!ReadFromSocket(packetData, header[1])) { - return armnn::profiling::Packet(); + return arm::pipe::Packet(); } EchoPacket(PacketDirection::ReceivedData, packetData, header[1]); // Construct received packet - armnn::profiling::Packet packetRx = armnn::profiling::Packet(header[0], header[1], uniquePacketData); + arm::pipe::Packet packetRx = arm::pipe::Packet(header[0], header[1], uniquePacketData); if (m_EchoPackets) { std::cout << "Processing packet ID= " << packetRx.GetPacketId() << " Length=" << packetRx.GetLength() @@ -206,7 +210,7 @@ bool BasePipeServer::SendPacket(uint32_t packetFamily, uint32_t packetId, const memcpy((packet.data() + 8), data, dataLength); } EchoPacket(PacketDirection::Sending, packet.data(), packet.size()); - if (-1 == armnnUtils::Sockets::Write(m_ClientConnection, packet.data(), packet.size())) + if (-1 == arm::pipe::Write(m_ClientConnection, packet.data(), packet.size())) { std::cerr << ": Failure when writing to client socket: " << strerror(errno) << std::endl; return false; @@ -294,4 +298,5 @@ void BasePipeServer::InsertU32(uint32_t value, uint8_t* data, TargetEndianness e } } -} // namespace armnnProfiling
\ No newline at end of file +} // namespace pipe +} // namespace arm diff --git a/profiling/server/src/basePipeServer/CMakeLists.txt b/profiling/server/src/basePipeServer/CMakeLists.txt index 56ef4548ec..b5dc68c2c4 100644 --- a/profiling/server/src/basePipeServer/CMakeLists.txt +++ b/profiling/server/src/basePipeServer/CMakeLists.txt @@ -1,37 +1,49 @@ # -# Copyright © 2020 Arm Ltd. All rights reserved. +# Copyright © 2020 Arm Ltd and Contributors. All rights reserved. # SPDX-License-Identifier: MIT # if(BUILD_BASE_PIPE_SERVER) set(BasePipeServer_sources) list(APPEND BasePipeServer_sources - BasePipeServer.cpp - BasePipeServer.hpp - ConnectionHandler.cpp - ConnectionHandler.hpp) + BasePipeServer.cpp) + + if(NOT "${TOOLCHAIN_PREFIX}" STREQUAL x86_64-w64-mingw32) + list(APPEND BasePipeServer_sources + ConnectionHandler.cpp) + endif() include_directories(${PROJECT_SOURCE_DIR}/profiling/common/include) + include_directories(${PROJECT_SOURCE_DIR}/profiling/server/include/basePipeServer) if (BUILD_UNIT_TESTS) target_include_directories(UnitTests PRIVATE ${PROJECT_SOURCE_DIR}/profiling/server/src/basePipeServer) target_include_directories(UnitTests PUBLIC ${PROJECT_SOURCE_DIR}/profiling/common/include) endif() - add_library_ex(armnnBasePipeServer SHARED ${BasePipeServer_sources}) + if (BUILD_STATIC_PIPE_LIBS) + add_library_ex(armnnBasePipeServer STATIC ${BasePipeServer_sources}) + target_link_libraries(armnnBasePipeServer pipeCommon) - set_target_properties(armnnBasePipeServer PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) - set_target_properties(armnnBasePipeServer PROPERTIES VERSION ${GENERIC_LIB_VERSION} - SOVERSION ${GENERIC_LIB_SOVERSION}) + if ("${CMAKE_SYSTEM_NAME}" STREQUAL Windows) + target_link_libraries(armnnBasePipeServer ws2_32.lib) + endif() + else() + add_library_ex(armnnBasePipeServer SHARED ${BasePipeServer_sources}) + target_link_libraries(armnnBasePipeServer pipeCommon) - target_include_directories(armnnBasePipeServer PRIVATE ${PROJECT_SOURCE_DIR}/src/armnnUtils) + if ("${CMAKE_SYSTEM_NAME}" STREQUAL Windows) + target_link_libraries(armnnBasePipeServer ws2_32.lib) + endif() - target_link_libraries(armnnBasePipeServer armnn) - if ("${CMAKE_SYSTEM_NAME}" STREQUAL Windows) - target_link_libraries(armnnBasePipeServer Ws2_32.lib) - endif() + set_target_properties(armnnBasePipeServer PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) + set_target_properties(armnnBasePipeServer PROPERTIES VERSION ${GENERIC_LIB_VERSION} + SOVERSION ${GENERIC_LIB_SOVERSION}) + + target_include_directories(armnnBasePipeServer PRIVATE ${PROJECT_SOURCE_DIR}/src/armnnUtils) - install(TARGETS armnnBasePipeServer - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -endif()
\ No newline at end of file + install(TARGETS armnnBasePipeServer + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + endif() +endif() diff --git a/profiling/server/src/basePipeServer/ConnectionHandler.cpp b/profiling/server/src/basePipeServer/ConnectionHandler.cpp index 1485ab8620..1c9ffa95c2 100644 --- a/profiling/server/src/basePipeServer/ConnectionHandler.cpp +++ b/profiling/server/src/basePipeServer/ConnectionHandler.cpp @@ -1,18 +1,21 @@ // -// Copyright © 2020 Arm Ltd. All rights reserved. +// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // -#include "ConnectionHandler.hpp" -#include <string.h> +#include <server/include/basePipeServer/ConnectionHandler.hpp> -using namespace armnnUtils; +#include <string> -namespace armnnProfiling +namespace arm { + +namespace pipe +{ + ConnectionHandler::ConnectionHandler(const std::string& udsNamespace, const bool setNonBlocking) { - Sockets::Initialize(); + arm::pipe::Initialize(); m_ListeningSocket = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); if (-1 == m_ListeningSocket) @@ -39,14 +42,13 @@ ConnectionHandler::ConnectionHandler(const std::string& udsNamespace, const bool if (setNonBlocking) { - Sockets::SetNonBlocking(m_ListeningSocket); + arm::pipe::SetNonBlocking(m_ListeningSocket); } } std::unique_ptr<BasePipeServer> ConnectionHandler::GetNewBasePipeServer(const bool echoPackets) { - armnnUtils::Sockets::Socket clientConnection = armnnUtils::Sockets::Accept(m_ListeningSocket, nullptr, nullptr, - SOCK_CLOEXEC); + arm::pipe::Socket clientConnection = arm::pipe::Accept(m_ListeningSocket, nullptr, nullptr, SOCK_CLOEXEC); if (clientConnection < 1) { return nullptr; @@ -54,4 +56,5 @@ std::unique_ptr<BasePipeServer> ConnectionHandler::GetNewBasePipeServer(const bo return std::make_unique<BasePipeServer>(clientConnection, echoPackets); } -} // namespace armnnProfiling
\ No newline at end of file +} // namespace pipe +} // namespace arm diff --git a/profiling/server/src/basePipeServer/tests/BasePipeServerTests.cpp b/profiling/server/src/basePipeServer/tests/BasePipeServerTests.cpp index 57fc9e9da6..091792782f 100644 --- a/profiling/server/src/basePipeServer/tests/BasePipeServerTests.cpp +++ b/profiling/server/src/basePipeServer/tests/BasePipeServerTests.cpp @@ -1,9 +1,9 @@ // -// Copyright © 2020 Arm Ltd. All rights reserved. +// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // -#include <ConnectionHandler.hpp> +#include <server/include/basePipeServer/ConnectionHandler.hpp> #include <SocketProfilingConnection.hpp> #include <Processes.hpp> @@ -15,7 +15,7 @@ BOOST_AUTO_TEST_SUITE(BasePipeServerTests) using namespace armnn; -using namespace armnnProfiling; +using namespace arm::pipe; BOOST_AUTO_TEST_CASE(BasePipeServerTest) { @@ -28,7 +28,7 @@ BOOST_AUTO_TEST_CASE(BasePipeServerTest) // The socket should close once we leave the scope of BOOST_CHECK_NO_THROW // and socketProfilingConnection should fail to connect BOOST_CHECK_THROW(profiling::SocketProfilingConnection socketProfilingConnection, - armnnProfiling::SocketConnectionException); + arm::pipe::SocketConnectionException); // Try to initialize a listening socket through the ConnectionHandler again ConnectionHandler connectionHandler(udsNamespace, true); diff --git a/profiling/server/src/timelineDecoder/CMakeLists.txt b/profiling/server/src/timelineDecoder/CMakeLists.txt new file mode 100644 index 0000000000..7154722fa6 --- /dev/null +++ b/profiling/server/src/timelineDecoder/CMakeLists.txt @@ -0,0 +1,44 @@ +# +# Copyright © 2020 Arm Ltd and Contributors. All rights reserved. +# SPDX-License-Identifier: MIT +# + +if(BUILD_TIMELINE_DECODER) + set(timelineDecoder_sources) + list(APPEND timelineDecoder_sources + TimelineCaptureCommandHandler.cpp + TimelineDecoder.cpp + TimelineDirectoryCaptureCommandHandler.cpp) + + include_directories(${PROJECT_SOURCE_DIR}/profiling/common/include) + + if(BUILD_UNIT_TESTS) + include_directories(${PROJECT_SOURCE_DIR}/src/profiling + ${PROJECT_SOURCE_DIR}/src/armnnUtils) + target_include_directories(UnitTests PRIVATE ${PROJECT_SOURCE_DIR}/profiling/server/include/timelineDecoder) + endif() + + + if (BUILD_STATIC_PIPE_LIBS) + add_library_ex(timelineDecoder STATIC ${timelineDecoder_sources}) + target_link_libraries(timelineDecoder pipeCommon) + + if ("${CMAKE_SYSTEM_NAME}" STREQUAL Windows) + target_link_libraries(timelineDecoder ws2_32.lib) + endif() + else() + add_library_ex(timelineDecoder SHARED ${timelineDecoder_sources}) + target_link_libraries(timelineDecoder pipeCommon) + + if ("${CMAKE_SYSTEM_NAME}" STREQUAL Windows) + target_link_libraries(timelineDecoder ws2_32.lib) + endif() + + set_target_properties(timelineDecoder PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) + set_target_properties(timelineDecoder PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} ) + + install(TARGETS timelineDecoder + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + endif() +endif() diff --git a/profiling/server/src/timelineDecoder/TimelineCaptureCommandHandler.cpp b/profiling/server/src/timelineDecoder/TimelineCaptureCommandHandler.cpp new file mode 100644 index 0000000000..247c9519e0 --- /dev/null +++ b/profiling/server/src/timelineDecoder/TimelineCaptureCommandHandler.cpp @@ -0,0 +1,166 @@ +// +// Copyright © 2019 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include <common/include/CommonProfilingUtils.hpp> +#include <common/include/Logging.hpp> +#include <server/include/timelineDecoder/TimelineCaptureCommandHandler.hpp> + +#include <string> + +namespace arm +{ + +namespace pipe +{ + +//Array of member functions, the array index matches the decl_id +const TimelineCaptureCommandHandler::ReadFunction TimelineCaptureCommandHandler::m_ReadFunctions[] +{ + &TimelineCaptureCommandHandler::ReadLabel, // Label decl_id = 0 + &TimelineCaptureCommandHandler::ReadEntity, // Entity decl_id = 1 + &TimelineCaptureCommandHandler::ReadEventClass, // EventClass decl_id = 2 + &TimelineCaptureCommandHandler::ReadRelationship, // Relationship decl_id = 3 + &TimelineCaptureCommandHandler::ReadEvent // Event decl_id = 4 +}; + +void TimelineCaptureCommandHandler::SetThreadIdSize(uint32_t size) +{ + m_ThreadIdSize = size; +} + +void TimelineCaptureCommandHandler::operator()(const arm::pipe::Packet& packet) +{ + ParseData(packet); +} + +void TimelineCaptureCommandHandler::ParseData(const arm::pipe::Packet& packet) +{ + uint32_t offset = 0; + m_PacketLength = packet.GetLength(); + + // We are expecting TimelineDirectoryCaptureCommandHandler to set the thread id size + // if it not set in the constructor + if (m_ThreadIdSize == 0) + { + ARM_PIPE_LOG(error) << "TimelineCaptureCommandHandler: m_ThreadIdSize has not been set"; + return; + } + + if (packet.GetLength() < 8) + { + return; + } + + const unsigned char* data = reinterpret_cast<const unsigned char*>(packet.GetData()); + + uint32_t declId = 0; + + while ( offset < m_PacketLength ) + { + declId = arm::pipe::ReadUint32(data, offset); + offset += uint32_t_size; + + ITimelineDecoder::TimelineStatus status = (this->*m_ReadFunctions[declId])(data, offset); + if (status == ITimelineDecoder::TimelineStatus::TimelineStatus_Fail) + { + ARM_PIPE_LOG(error) << "Decode of timeline message type [" << declId << + "] at offset [" << offset << "] failed"; + break; + } + } +} + +ITimelineDecoder::TimelineStatus TimelineCaptureCommandHandler::ReadLabel(const unsigned char* data, uint32_t& offset) +{ + ITimelineDecoder::Label label; + label.m_Guid = arm::pipe::ReadUint64(data, offset); + offset += uint64_t_size; + + uint32_t nameLength = arm::pipe::ReadUint32(data, offset); + offset += uint32_t_size; + + uint32_t i = 0; + // nameLength - 1 to account for null operator \0 + for ( i = 0; i < nameLength - 1; ++i ) + { + label.m_Name += static_cast<char>(arm::pipe::ReadUint8(data, offset + i)); + } + // Shift offset past nameLength + uint32_t uint32WordAmount = (nameLength / uint32_t_size) + (nameLength % uint32_t_size != 0 ? 1 : 0); + offset += uint32WordAmount * uint32_t_size; + + return m_TimelineDecoder.CreateLabel(label); +} + +ITimelineDecoder::TimelineStatus TimelineCaptureCommandHandler::ReadEntity( + const unsigned char* data, uint32_t& offset) +{ + ITimelineDecoder::Entity entity; + entity.m_Guid = arm::pipe::ReadUint64(data, offset); + offset += uint64_t_size; + return m_TimelineDecoder.CreateEntity(entity); +} + +ITimelineDecoder::TimelineStatus TimelineCaptureCommandHandler::ReadEventClass( + const unsigned char* data, uint32_t& offset) +{ + ITimelineDecoder::EventClass eventClass; + eventClass.m_Guid = arm::pipe::ReadUint64(data, offset); + offset += uint64_t_size; + eventClass.m_NameGuid = arm::pipe::ReadUint64(data, offset); + offset += uint64_t_size; + return m_TimelineDecoder.CreateEventClass(eventClass); +} + +ITimelineDecoder::TimelineStatus TimelineCaptureCommandHandler::ReadRelationship( + const unsigned char* data, uint32_t& offset) +{ + ITimelineDecoder::Relationship relationship; + relationship.m_RelationshipType = + static_cast<ITimelineDecoder::RelationshipType>(arm::pipe::ReadUint32(data, offset)); + offset += uint32_t_size; + + relationship.m_Guid = arm::pipe::ReadUint64(data, offset); + offset += uint64_t_size; + + relationship.m_HeadGuid = arm::pipe::ReadUint64(data, offset); + offset += uint64_t_size; + + relationship.m_TailGuid = arm::pipe::ReadUint64(data, offset); + offset += uint64_t_size; + + relationship.m_AttributeGuid = arm::pipe::ReadUint64(data, offset); + offset += uint64_t_size; + + return m_TimelineDecoder.CreateRelationship(relationship); +} + +ITimelineDecoder::TimelineStatus TimelineCaptureCommandHandler::ReadEvent( + const unsigned char* data, uint32_t& offset) +{ + ITimelineDecoder::Event event; + event.m_TimeStamp = arm::pipe::ReadUint64(data, offset); + offset += uint64_t_size; + + if ( m_ThreadIdSize == 4 ) + { + event.m_ThreadId = arm::pipe::ReadUint32(data, offset); + } + else if ( m_ThreadIdSize == 8 ) + { + event.m_ThreadId = arm::pipe::ReadUint64(data, offset); + } + + offset += m_ThreadIdSize; + + event.m_Guid = arm::pipe::ReadUint64(data, offset); + offset += uint64_t_size; + + return m_TimelineDecoder.CreateEvent(event); +} + +} //namespace pipe + +} //namespace arm diff --git a/profiling/server/src/timelineDecoder/TimelineDecoder.cpp b/profiling/server/src/timelineDecoder/TimelineDecoder.cpp new file mode 100644 index 0000000000..df967de1f5 --- /dev/null +++ b/profiling/server/src/timelineDecoder/TimelineDecoder.cpp @@ -0,0 +1,326 @@ +// +// Copyright © 2019 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include <common/include/CommonProfilingUtils.hpp> +#include <server/include/timelineDecoder/TimelineDecoder.hpp> + +#include <iostream> +#include <sstream> + +namespace arm +{ +namespace pipe +{ + +TimelineDecoder::TimelineStatus TimelineDecoder::CreateEntity(const Entity &entity) +{ + if (m_OnNewEntityCallback == nullptr) + { + return TimelineStatus::TimelineStatus_Fail; + } + m_OnNewEntityCallback(m_Model, entity); + + return TimelineStatus::TimelineStatus_Success; +} + +TimelineDecoder::TimelineStatus TimelineDecoder::CreateEventClass(const EventClass &eventClass) +{ + if (m_OnNewEventClassCallback == nullptr) + { + return TimelineStatus::TimelineStatus_Fail; + } + m_OnNewEventClassCallback(m_Model, eventClass); + + return TimelineStatus::TimelineStatus_Success; +} + +TimelineDecoder::TimelineStatus TimelineDecoder::CreateEvent(const Event &event) +{ + if (m_OnNewEventCallback == nullptr) + { + return TimelineStatus::TimelineStatus_Fail; + } + m_OnNewEventCallback(m_Model, event); + + return TimelineStatus::TimelineStatus_Success; +} + +TimelineDecoder::TimelineStatus TimelineDecoder::CreateLabel(const Label &label) +{ + if (m_OnNewLabelCallback == nullptr) + { + return TimelineStatus::TimelineStatus_Fail; + } + m_OnNewLabelCallback(m_Model, label); + + return TimelineStatus::TimelineStatus_Success; +} + +TimelineDecoder::TimelineStatus TimelineDecoder::CreateRelationship(const Relationship &relationship) +{ + if (m_OnNewRelationshipCallback == nullptr) + { + return TimelineStatus::TimelineStatus_Fail; + } + m_OnNewRelationshipCallback(m_Model, relationship); + return TimelineStatus::TimelineStatus_Success; +} + +const TimelineDecoder::Model &TimelineDecoder::GetModel() +{ + return m_Model; +} + +TimelineDecoder::TimelineStatus TimelineDecoder::SetEntityCallback(OnNewEntityCallback cb) +{ + if (cb == nullptr) + { + return TimelineStatus::TimelineStatus_Fail; + } + m_OnNewEntityCallback = cb; + return TimelineStatus::TimelineStatus_Success; +} + +TimelineDecoder::TimelineStatus TimelineDecoder::SetEventClassCallback(OnNewEventClassCallback cb) +{ + if (cb == nullptr) + { + return TimelineStatus::TimelineStatus_Fail; + } + m_OnNewEventClassCallback = cb; + return TimelineStatus::TimelineStatus_Success; +} + +TimelineDecoder::TimelineStatus TimelineDecoder::SetEventCallback(OnNewEventCallback cb) +{ + if (cb == nullptr) + { + return TimelineStatus::TimelineStatus_Fail; + } + m_OnNewEventCallback = cb; + return TimelineStatus::TimelineStatus_Success; +} + +TimelineDecoder::TimelineStatus TimelineDecoder::SetLabelCallback(OnNewLabelCallback cb) +{ + if (cb == nullptr) + { + return TimelineStatus::TimelineStatus_Fail; + } + m_OnNewLabelCallback = cb; + return TimelineStatus::TimelineStatus_Success; +} + +TimelineDecoder::TimelineStatus TimelineDecoder::SetRelationshipCallback(OnNewRelationshipCallback cb) +{ + if (cb == nullptr) + { + return TimelineStatus::TimelineStatus_Fail; + } + m_OnNewRelationshipCallback = cb; + return TimelineStatus::TimelineStatus_Success; +} + +void TimelineDecoder::SetDefaultCallbacks() +{ + SetEntityCallback([](Model& model, const ITimelineDecoder::Entity entity) + { + model.m_Entities.emplace_back(entity); + }); + + SetEventClassCallback([](Model& model, const ITimelineDecoder::EventClass eventClass) + { + model.m_EventClasses.emplace_back(eventClass); + }); + + SetEventCallback([](Model& model, const ITimelineDecoder::Event event) + { + model.m_Events.emplace_back(event); + }); + + SetLabelCallback([](Model& model, const ITimelineDecoder::Label label) + { + model.m_Labels.emplace_back(label); + }); + + SetRelationshipCallback([](Model& model, const ITimelineDecoder::Relationship relationship) + { + model.m_Relationships.emplace_back(relationship); + }); +} + +void TimelineDecoder::print() +{ + if (m_Model.m_Labels.empty() && m_Model.m_Entities.empty() && m_Model.m_EventClasses.empty() && + m_Model.m_Events.empty() && m_Model.m_Relationships.empty()) + { + std::cout << "No timeline packets received" << std::endl; + return; + } + + printLabels(); + printEntities(); + printEventClasses(); + printEvents(); + printRelationships(); +} + +void TimelineDecoder::printLabels() +{ + std::string header; + + header.append(arm::pipe::CentreAlignFormatting("guid", 12)); + header.append(" | "); + header.append(arm::pipe::CentreAlignFormatting("value", 30)); + header.append("\n"); + + std::cout << "\n" << "\n"; + std::cout << arm::pipe::CentreAlignFormatting("LABELS", static_cast<int>(header.size())); + std::cout << "\n"; + std::cout << std::string(header.size(), '=') << "\n"; + std::cout << header; + + for (uint32_t i = 0; i < m_Model.m_Labels.size(); ++i) + { + std::string body; + + body.append(arm::pipe::CentreAlignFormatting(std::to_string(m_Model.m_Labels[i].m_Guid), 12)); + body.append(" | "); + body.append(arm::pipe::CentreAlignFormatting(m_Model.m_Labels[i].m_Name, 30)); + body.append("\n"); + + std::cout << std::string(body.size(), '-') << "\n"; + std::cout << body; + } +} + +void TimelineDecoder::printEntities() +{ + std::string header; + header.append(arm::pipe::CentreAlignFormatting("guid", 12)); + header.append("\n"); + + std::cout << "\n" << "\n"; + std::cout << arm::pipe::CentreAlignFormatting("ENTITIES", static_cast<int>(header.size())); + std::cout << "\n"; + std::cout << std::string(header.size(), '=') << "\n"; + std::cout << header; + + for (uint32_t i = 0; i < m_Model.m_Entities.size(); ++i) + { + std::string body; + + body.append(arm::pipe::CentreAlignFormatting(std::to_string(m_Model.m_Entities[i].m_Guid), 12)); + body.append("\n"); + + std::cout << std::string(body.size(), '-') << "\n"; + std::cout << body; + } +} + +void TimelineDecoder::printEventClasses() +{ + std::string header; + header.append(arm::pipe::CentreAlignFormatting("guid", 12)); + header.append("\n"); + + std::cout << "\n" << "\n"; + std::cout << arm::pipe::CentreAlignFormatting("EVENT CLASSES", static_cast<int>(header.size())); + std::cout << "\n"; + std::cout << std::string(header.size(), '=') << "\n"; + std::cout << header; + + for (uint32_t i = 0; i < m_Model.m_EventClasses.size(); ++i) + { + std::string body; + + body.append(arm::pipe::CentreAlignFormatting(std::to_string(m_Model.m_EventClasses[i].m_Guid), 12)); + body.append("\n"); + + std::cout << std::string(body.size(), '-') << "\n"; + std::cout << body; + } +} + +void TimelineDecoder::printEvents() +{ + std::string header; + + header.append(arm::pipe::CentreAlignFormatting("timestamp", 12)); + header.append(" | "); + header.append(arm::pipe::CentreAlignFormatting("threadId", 12)); + header.append(" | "); + header.append(arm::pipe::CentreAlignFormatting("eventGuid", 12)); + header.append("\n"); + + std::cout << "\n" << "\n"; + std::cout << arm::pipe::CentreAlignFormatting("EVENTS", static_cast<int>(header.size())); + std::cout << "\n"; + std::cout << std::string(header.size(), '=') << "\n"; + std::cout << header; + + for (uint32_t i = 0; i < m_Model.m_Events.size(); ++i) + { + std::string body; + + body.append(arm::pipe::CentreAlignFormatting(std::to_string(m_Model.m_Events[i].m_TimeStamp), 12)); + body.append(" | "); + + std::stringstream ss; + ss << m_Model.m_Events[i].m_ThreadId; + std::string threadId = ss.str();; + + body.append(arm::pipe::CentreAlignFormatting(threadId, 12)); + body.append(" | "); + body.append(arm::pipe::CentreAlignFormatting(std::to_string(m_Model.m_Events[i].m_Guid), 12)); + body.append("\n"); + + std::cout << std::string(body.size(), '-') << "\n"; + std::cout << body; + } +} + +void TimelineDecoder::printRelationships() +{ + std::string header; + header.append(arm::pipe::CentreAlignFormatting("relationshipType", 20)); + header.append(" | "); + header.append(arm::pipe::CentreAlignFormatting("relationshipGuid", 20)); + header.append(" | "); + header.append(arm::pipe::CentreAlignFormatting("headGuid", 12)); + header.append(" | "); + header.append(arm::pipe::CentreAlignFormatting("tailGuid", 12)); + header.append("\n"); + + std::cout << "\n" << "\n"; + std::cout << arm::pipe::CentreAlignFormatting("RELATIONSHIPS", static_cast<int>(header.size())); + std::cout << "\n"; + std::cout << std::string(header.size(), '=') << "\n"; + std::cout << header; + + for (uint32_t i = 0; i < m_Model.m_Relationships.size(); ++i) + { + std::string body; + + body.append( + arm::pipe::CentreAlignFormatting(std::to_string(static_cast<unsigned int> + (m_Model.m_Relationships[i].m_RelationshipType)), + 20)); + body.append(" | "); + body.append(arm::pipe::CentreAlignFormatting(std::to_string(m_Model.m_Relationships[i].m_Guid), 20)); + body.append(" | "); + body.append(arm::pipe::CentreAlignFormatting(std::to_string(m_Model.m_Relationships[i].m_HeadGuid), 12)); + body.append(" | "); + body.append(arm::pipe::CentreAlignFormatting(std::to_string(m_Model.m_Relationships[i].m_TailGuid), 12)); + body.append(" | "); + body.append("\n"); + + std::cout << std::string(body.size(), '-') << "\n"; + std::cout << body; + } +} + +} // namespace pipe +} // namespace arm
\ No newline at end of file diff --git a/profiling/server/src/timelineDecoder/TimelineDirectoryCaptureCommandHandler.cpp b/profiling/server/src/timelineDecoder/TimelineDirectoryCaptureCommandHandler.cpp new file mode 100644 index 0000000000..6963dd00c7 --- /dev/null +++ b/profiling/server/src/timelineDecoder/TimelineDirectoryCaptureCommandHandler.cpp @@ -0,0 +1,117 @@ +// +// Copyright © 2019 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include <common/include/CommonProfilingUtils.hpp> +#include <common/include/SwTrace.hpp> +#include <server/include/timelineDecoder/TimelineCaptureCommandHandler.hpp> +#include <server/include/timelineDecoder/TimelineDirectoryCaptureCommandHandler.hpp> + +#include <iostream> +#include <string> + +namespace arm +{ + +namespace pipe +{ + +void TimelineDirectoryCaptureCommandHandler::ParseData(const arm::pipe::Packet& packet) +{ + uint32_t offset = 0; + + if (packet.GetLength() < 8) + { + return; + } + + const unsigned char* data = packet.GetData(); + + m_SwTraceHeader.m_StreamVersion = ReadUint8(data, offset); + offset += uint8_t_size; + m_SwTraceHeader.m_PointerBytes = ReadUint8(data, offset); + offset += uint8_t_size; + m_SwTraceHeader.m_ThreadIdBytes = ReadUint8(data, offset); + offset += uint8_t_size; + + uint32_t numberOfDeclarations = arm::pipe::ReadUint32(data, offset); + offset += uint32_t_size; + + for (uint32_t declaration = 0; declaration < numberOfDeclarations; ++declaration) + { + m_SwTraceMessages.push_back(arm::pipe::ReadSwTraceMessage(data, offset, packet.GetLength())); + } + + m_TimelineCaptureCommandHandler.SetThreadIdSize(m_SwTraceHeader.m_ThreadIdBytes); +} + +void TimelineDirectoryCaptureCommandHandler::Print() +{ + std::string header; + + header.append(arm::pipe::CentreAlignFormatting("decl_id", 12)); + header.append(" | "); + header.append(arm::pipe::CentreAlignFormatting("decl_name", 20)); + header.append(" | "); + header.append(arm::pipe::CentreAlignFormatting("ui_name", 20)); + header.append(" | "); + header.append(arm::pipe::CentreAlignFormatting("arg_types", 16)); + header.append(" | "); + header.append(arm::pipe::CentreAlignFormatting("arg_names", 80)); + header.append("\n"); + + std::cout << "\n" << "\n"; + std::cout << arm::pipe::CentreAlignFormatting("SW DIRECTORY", static_cast<int>(header.size())); + std::cout << "\n"; + std::cout << std::string(header.size(), '=') << "\n"; + + std::cout << header; + + for (const auto& swTraceMessage : m_SwTraceMessages) + { + std::string body; + + body.append(arm::pipe::CentreAlignFormatting(std::to_string(swTraceMessage.m_Id), 12)); + body.append(" | "); + body.append(arm::pipe::CentreAlignFormatting(swTraceMessage.m_Name, 20)); + body.append(" | "); + body.append(arm::pipe::CentreAlignFormatting(swTraceMessage.m_UiName, 20)); + body.append(" | "); + + std::string argTypes; + for (auto argType: swTraceMessage.m_ArgTypes) + { + argTypes += argType; + argTypes += " "; + } + body.append(arm::pipe::CentreAlignFormatting(argTypes, 16)); + body.append(" | "); + + std::string argNames; + for (auto argName: swTraceMessage.m_ArgNames) + { + argNames += argName + " "; + } + body.append(arm::pipe::CentreAlignFormatting(argNames, 80)); + + body.append("\n"); + + std::cout << std::string(body.size(), '-') << "\n"; + + std::cout << body; + } +} + +void TimelineDirectoryCaptureCommandHandler::operator()(const arm::pipe::Packet& packet) +{ + ParseData(packet); + + if (!m_QuietOperation) + { + Print(); + } +} + +} //namespace pipe +} //namespace arm diff --git a/profiling/server/src/timelineDecoder/tests/TimelineTests.cpp b/profiling/server/src/timelineDecoder/tests/TimelineTests.cpp new file mode 100644 index 0000000000..e7797061c9 --- /dev/null +++ b/profiling/server/src/timelineDecoder/tests/TimelineTests.cpp @@ -0,0 +1,373 @@ +// +// Copyright © 2019 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include <common/include/CommandHandlerFunctor.hpp> +#include <common/include/CommonProfilingUtils.hpp> +#include <server/include/timelineDecoder/TimelineCaptureCommandHandler.hpp> +#include <server/include/timelineDecoder/TimelineDirectoryCaptureCommandHandler.hpp> +#include <server/include/timelineDecoder/TimelineDecoder.hpp> + +#include <BufferManager.hpp> +#include <Threads.hpp> +#include <ProfilingService.hpp> +#include <PacketBuffer.hpp> +#include <TimelinePacketWriterFactory.hpp> + +#include <boost/test/test_tools.hpp> +#include <boost/test/unit_test_suite.hpp> + +BOOST_AUTO_TEST_SUITE(TimelineDecoderTests) + +void SendTimelinePacketToCommandHandler(const unsigned char* packetBuffer, + arm::pipe::CommandHandlerFunctor& CommandHandler) +{ + uint32_t uint32_t_size = sizeof(uint32_t); + unsigned int offset = 0; + + uint32_t header[2]; + header[0] = arm::pipe::ReadUint32(packetBuffer, offset); + offset += uint32_t_size; + header[1] = arm::pipe::ReadUint32(packetBuffer, offset); + offset += uint32_t_size; + uint32_t PacketDataLength = header[1] & 0x00FFFFFF; + + auto uniquePacketData = std::make_unique<unsigned char[]>(PacketDataLength); + std::memcpy(uniquePacketData.get(), packetBuffer + offset, PacketDataLength); + + arm::pipe::Packet packet(header[0], PacketDataLength, uniquePacketData); + + BOOST_CHECK(std::memcmp(packetBuffer + offset, packet.GetData(), packet.GetLength()) == 0); + + CommandHandler(packet); +} + +void PushEntity(arm::pipe::TimelineDecoder::Model& model, const arm::pipe::ITimelineDecoder::Entity entity) +{ + model.m_Entities.emplace_back(entity); +} + +void PushEventClass(arm::pipe::TimelineDecoder::Model& model, const arm::pipe::ITimelineDecoder::EventClass eventClass) +{ + model.m_EventClasses.emplace_back(eventClass); +} + +void PushEvent(arm::pipe::TimelineDecoder::Model& model, const arm::pipe::ITimelineDecoder::Event event) +{ + model.m_Events.emplace_back(event); +} + +void PushLabel(arm::pipe::TimelineDecoder::Model& model, const arm::pipe::ITimelineDecoder::Label label) +{ + model.m_Labels.emplace_back(label); +} + +void PushRelationship(arm::pipe::TimelineDecoder::Model& model, + const arm::pipe::ITimelineDecoder::Relationship relationship) +{ + model.m_Relationships.emplace_back(relationship); +} + +BOOST_AUTO_TEST_CASE(TimelineDirectoryTest) +{ + uint32_t uint8_t_size = sizeof(uint8_t); + uint32_t uint32_t_size = sizeof(uint32_t); + uint32_t uint64_t_size = sizeof(uint64_t); + + armnn::profiling::BufferManager bufferManager(5); + armnn::profiling::TimelinePacketWriterFactory timelinePacketWriterFactory(bufferManager); + + std::unique_ptr<armnn::profiling::ISendTimelinePacket> sendTimelinePacket = + timelinePacketWriterFactory.GetSendTimelinePacket(); + + arm::pipe::PacketVersionResolver packetVersionResolver; + + arm::pipe::TimelineDecoder timelineDecoder; + arm::pipe::TimelineCaptureCommandHandler timelineCaptureCommandHandler( + 1, 1, packetVersionResolver.ResolvePacketVersion(1, 1).GetEncodedValue(), timelineDecoder); + + arm::pipe::TimelineDirectoryCaptureCommandHandler timelineDirectoryCaptureCommandHandler( + 1, 0, packetVersionResolver.ResolvePacketVersion(1, 0).GetEncodedValue(), + timelineCaptureCommandHandler, true); + + sendTimelinePacket->SendTimelineMessageDirectoryPackage(); + sendTimelinePacket->Commit(); + + std::vector<arm::pipe::SwTraceMessage> swTraceBufferMessages; + + unsigned int offset = uint32_t_size * 2; + + std::unique_ptr<armnn::profiling::IPacketBuffer> packetBuffer = bufferManager.GetReadableBuffer(); + + uint8_t readStreamVersion = ReadUint8(packetBuffer, offset); + BOOST_CHECK(readStreamVersion == 4); + offset += uint8_t_size; + uint8_t readPointerBytes = ReadUint8(packetBuffer, offset); + BOOST_CHECK(readPointerBytes == uint64_t_size); + offset += uint8_t_size; + uint8_t readThreadIdBytes = ReadUint8(packetBuffer, offset); + BOOST_CHECK(readThreadIdBytes == armnn::profiling::ThreadIdSize); + offset += uint8_t_size; + + uint32_t declarationSize = arm::pipe::ReadUint32(packetBuffer->GetReadableData(), offset); + offset += uint32_t_size; + for(uint32_t i = 0; i < declarationSize; ++i) + { + swTraceBufferMessages.push_back(arm::pipe::ReadSwTraceMessage(packetBuffer->GetReadableData(), + offset, + packetBuffer->GetSize())); + } + + SendTimelinePacketToCommandHandler(packetBuffer->GetReadableData(), timelineDirectoryCaptureCommandHandler); + + for(uint32_t index = 0; index < declarationSize; ++index) + { + arm::pipe::SwTraceMessage& bufferMessage = swTraceBufferMessages[index]; + arm::pipe::SwTraceMessage& handlerMessage = timelineDirectoryCaptureCommandHandler.m_SwTraceMessages[index]; + + BOOST_CHECK(bufferMessage.m_Name == handlerMessage.m_Name); + BOOST_CHECK(bufferMessage.m_UiName == handlerMessage.m_UiName); + BOOST_CHECK(bufferMessage.m_Id == handlerMessage.m_Id); + + BOOST_CHECK(bufferMessage.m_ArgTypes.size() == handlerMessage.m_ArgTypes.size()); + for(uint32_t i = 0; i < bufferMessage.m_ArgTypes.size(); ++i) + { + BOOST_CHECK(bufferMessage.m_ArgTypes[i] == handlerMessage.m_ArgTypes[i]); + } + + BOOST_CHECK(bufferMessage.m_ArgNames.size() == handlerMessage.m_ArgNames.size()); + for(uint32_t i = 0; i < bufferMessage.m_ArgNames.size(); ++i) + { + BOOST_CHECK(bufferMessage.m_ArgNames[i] == handlerMessage.m_ArgNames[i]); + } + } +} + +BOOST_AUTO_TEST_CASE(TimelineCaptureTest) +{ + armnn::profiling::BufferManager bufferManager(50); + armnn::profiling::TimelinePacketWriterFactory timelinePacketWriterFactory(bufferManager); + + std::unique_ptr<armnn::profiling::ISendTimelinePacket> sendTimelinePacket = + timelinePacketWriterFactory.GetSendTimelinePacket(); + + arm::pipe::PacketVersionResolver packetVersionResolver; + + arm::pipe::TimelineDecoder timelineDecoder; + const arm::pipe::TimelineDecoder::Model& model = timelineDecoder.GetModel(); + + + arm::pipe::TimelineCaptureCommandHandler timelineCaptureCommandHandler( + 1, 1, packetVersionResolver.ResolvePacketVersion(1, 1).GetEncodedValue(), timelineDecoder, + armnn::profiling::ThreadIdSize); + + using Status = arm::pipe::ITimelineDecoder::TimelineStatus; + BOOST_CHECK(timelineDecoder.SetEntityCallback(PushEntity) == Status::TimelineStatus_Success); + BOOST_CHECK(timelineDecoder.SetEventClassCallback(PushEventClass) == Status::TimelineStatus_Success); + BOOST_CHECK(timelineDecoder.SetEventCallback(PushEvent) == Status::TimelineStatus_Success); + BOOST_CHECK(timelineDecoder.SetLabelCallback(PushLabel) == Status::TimelineStatus_Success); + BOOST_CHECK(timelineDecoder.SetRelationshipCallback(PushRelationship) == Status::TimelineStatus_Success); + + const uint64_t entityGuid = 111111u; + const uint64_t eventClassGuid = 22222u; + const uint64_t eventClassNameGuid = 22322u; + const uint64_t timestamp = 33333u; + const uint64_t eventGuid = 44444u; + + const int threadId = armnnUtils::Threads::GetCurrentThreadId(); + + // need to do a bit of work here to extract the value from threadId + unsigned char* uCharThreadId = new unsigned char[armnn::profiling::ThreadIdSize]();; + uint64_t uint64ThreadId; + + arm::pipe::WriteBytes(uCharThreadId, 0, &threadId, armnn::profiling::ThreadIdSize); + + if (armnn::profiling::ThreadIdSize == 4) + { + uint64ThreadId = arm::pipe::ReadUint32(uCharThreadId, 0); + } + else if (armnn::profiling::ThreadIdSize == 8) + { + uint64ThreadId = arm::pipe::ReadUint64(uCharThreadId, 0); + } + delete[] uCharThreadId; + + const uint64_t labelGuid = 66666u; + std::string labelName = "test_label"; + + const uint64_t relationshipGuid = 77777u; + const uint64_t headGuid = 888888u; + const uint64_t tailGuid = 999999u; + + for (int i = 0; i < 10; ++i) + { + // Send entity + sendTimelinePacket->SendTimelineEntityBinaryPacket(entityGuid); + sendTimelinePacket->Commit(); + SendTimelinePacketToCommandHandler(bufferManager.GetReadableBuffer()->GetReadableData(), + timelineCaptureCommandHandler); + + // Send event class + sendTimelinePacket->SendTimelineEventClassBinaryPacket(eventClassGuid, eventClassNameGuid); + sendTimelinePacket->Commit(); + SendTimelinePacketToCommandHandler(bufferManager.GetReadableBuffer()->GetReadableData(), + timelineCaptureCommandHandler); + + // Send event + sendTimelinePacket->SendTimelineEventBinaryPacket(timestamp, threadId, eventGuid); + sendTimelinePacket->Commit(); + SendTimelinePacketToCommandHandler(bufferManager.GetReadableBuffer()->GetReadableData(), + timelineCaptureCommandHandler); + + // Send label + sendTimelinePacket->SendTimelineLabelBinaryPacket(labelGuid, labelName); + sendTimelinePacket->Commit(); + SendTimelinePacketToCommandHandler(bufferManager.GetReadableBuffer()->GetReadableData(), + timelineCaptureCommandHandler); + + // Send relationship + armnn::profiling::ProfilingRelationshipType relationshipType = + armnn::profiling::ProfilingRelationshipType::DataLink; + sendTimelinePacket->SendTimelineRelationshipBinaryPacket(relationshipType, + relationshipGuid, + headGuid, + tailGuid, + 0); + sendTimelinePacket->Commit(); + SendTimelinePacketToCommandHandler(bufferManager.GetReadableBuffer()->GetReadableData(), + timelineCaptureCommandHandler); + } + + for (unsigned long i = 0; i < 10; ++i) + { + BOOST_CHECK(model.m_Entities[i].m_Guid == entityGuid); + + BOOST_CHECK(model.m_EventClasses[i].m_Guid == eventClassGuid); + + BOOST_CHECK(model.m_Events[i].m_TimeStamp == timestamp); + BOOST_CHECK(model.m_Events[i].m_ThreadId == uint64ThreadId); + BOOST_CHECK(model.m_Events[i].m_Guid == eventGuid); + + BOOST_CHECK(model.m_Labels[i].m_Guid == labelGuid); + BOOST_CHECK(model.m_Labels[i].m_Name == labelName); + + BOOST_CHECK(model.m_Relationships[i].m_RelationshipType == + arm::pipe::ITimelineDecoder::RelationshipType::DataLink); + BOOST_CHECK(model.m_Relationships[i].m_Guid == relationshipGuid); + BOOST_CHECK(model.m_Relationships[i].m_HeadGuid == headGuid); + BOOST_CHECK(model.m_Relationships[i].m_TailGuid == tailGuid); + } +} + +BOOST_AUTO_TEST_CASE(TimelineCaptureTestMultipleStringsInBuffer) +{ + armnn::profiling::BufferManager bufferManager(50); + armnn::profiling::TimelinePacketWriterFactory timelinePacketWriterFactory(bufferManager); + + std::unique_ptr<armnn::profiling::ISendTimelinePacket> sendTimelinePacket = + timelinePacketWriterFactory.GetSendTimelinePacket(); + + arm::pipe::PacketVersionResolver packetVersionResolver; + + arm::pipe::TimelineDecoder timelineDecoder; + const arm::pipe::TimelineDecoder::Model& model = timelineDecoder.GetModel(); + + arm::pipe::TimelineCaptureCommandHandler timelineCaptureCommandHandler( + 1, 1, packetVersionResolver.ResolvePacketVersion(1, 1).GetEncodedValue(), timelineDecoder, + armnn::profiling::ThreadIdSize); + + using Status = arm::pipe::TimelineDecoder::TimelineStatus; + BOOST_CHECK(timelineDecoder.SetEntityCallback(PushEntity) == Status::TimelineStatus_Success); + BOOST_CHECK(timelineDecoder.SetEventClassCallback(PushEventClass) == Status::TimelineStatus_Success); + BOOST_CHECK(timelineDecoder.SetEventCallback(PushEvent) == Status::TimelineStatus_Success); + BOOST_CHECK(timelineDecoder.SetLabelCallback(PushLabel) == Status::TimelineStatus_Success); + BOOST_CHECK(timelineDecoder.SetRelationshipCallback(PushRelationship) == Status::TimelineStatus_Success); + + const uint64_t entityGuid = 111111u; + const uint64_t eventClassGuid = 22222u; + const uint64_t eventClassNameGuid = 22322u; + const uint64_t timestamp = 33333u; + const uint64_t eventGuid = 44444u; + + const int threadId = armnnUtils::Threads::GetCurrentThreadId(); + + // need to do a bit of work here to extract the value from threadId + unsigned char* uCharThreadId = new unsigned char[armnn::profiling::ThreadIdSize](); + uint64_t uint64ThreadId; + + arm::pipe::WriteBytes(uCharThreadId, 0, &threadId, armnn::profiling::ThreadIdSize); + + if ( armnn::profiling::ThreadIdSize == 4 ) + { + uint64ThreadId = arm::pipe::ReadUint32(uCharThreadId, 0); + } + else if ( armnn::profiling::ThreadIdSize == 8 ) + { + uint64ThreadId = arm::pipe::ReadUint64(uCharThreadId, 0); + } + delete[] uCharThreadId; + + const uint64_t labelGuid = 66666u; + std::string labelName = "test_label"; + std::string labelName2 = "test_label2"; + std::string labelName3 = "test_label32"; + + const uint64_t relationshipGuid = 77777u; + const uint64_t headGuid = 888888u; + const uint64_t tailGuid = 999999u; + + // Check with multiple messages in the same buffer + for ( int i = 0; i < 9; ++i ) + { + // Send entity + sendTimelinePacket->SendTimelineEntityBinaryPacket(entityGuid); + // Send event class + sendTimelinePacket->SendTimelineEventClassBinaryPacket(eventClassGuid, eventClassNameGuid); + // Send event + sendTimelinePacket->SendTimelineEventBinaryPacket(timestamp, threadId, eventGuid); + // Send label + sendTimelinePacket->SendTimelineLabelBinaryPacket(labelGuid, labelName); + sendTimelinePacket->SendTimelineLabelBinaryPacket(labelGuid, labelName2); + sendTimelinePacket->SendTimelineLabelBinaryPacket(labelGuid, labelName3); + // Send relationship + armnn::profiling::ProfilingRelationshipType relationshipType = + armnn::profiling::ProfilingRelationshipType::DataLink; + sendTimelinePacket->SendTimelineRelationshipBinaryPacket(relationshipType, + relationshipGuid, + headGuid, + tailGuid, + 0); + } + + sendTimelinePacket->Commit(); + SendTimelinePacketToCommandHandler(bufferManager.GetReadableBuffer()->GetReadableData(), + timelineCaptureCommandHandler); + + for ( unsigned long i = 0; i < 9; ++i ) + { + BOOST_CHECK(model.m_Entities[i].m_Guid == entityGuid); + + BOOST_CHECK(model.m_EventClasses[i].m_Guid == eventClassGuid); + + BOOST_CHECK(model.m_Labels[i].m_Guid == labelGuid); + + BOOST_CHECK(model.m_Events[i].m_TimeStamp == timestamp); + BOOST_CHECK(model.m_Events[i].m_ThreadId == uint64ThreadId); + BOOST_CHECK(model.m_Events[i].m_Guid == eventGuid); + + BOOST_CHECK(model.m_Relationships[i].m_RelationshipType == + arm::pipe::ITimelineDecoder::RelationshipType::DataLink); + BOOST_CHECK(model.m_Relationships[i].m_Guid == relationshipGuid); + BOOST_CHECK(model.m_Relationships[i].m_HeadGuid == headGuid); + BOOST_CHECK(model.m_Relationships[i].m_TailGuid == tailGuid); + } + for ( unsigned long i = 0; i < 9; i += 3 ) + { + BOOST_CHECK(model.m_Labels[i].m_Name == labelName); + BOOST_CHECK(model.m_Labels[i+1].m_Name == labelName2); + BOOST_CHECK(model.m_Labels[i+2].m_Name == labelName3); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/profiling/toolchain-x86-ubuntu-mingw64.cmake b/profiling/toolchain-x86-ubuntu-mingw64.cmake new file mode 100644 index 0000000000..2d9e49f0c3 --- /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) |