From 5dc816e7d027170992e45d22ae11ae3000de9244 Mon Sep 17 00:00:00 2001 From: Matteo Martincigh Date: Mon, 4 Nov 2019 14:05:28 +0000 Subject: IVGCVSW-4065 Add a RecordEvent function * Added RecordEvent utility function to the TimelineUtilityMethods class * Added new utility function to get a timestamp * Added unit tests Signed-off-by: Matteo Martincigh Change-Id: Ia3f8fe7397915fa6c903ce0c0abab3047cea628c --- src/profiling/PeriodicCounterCapture.cpp | 11 +- src/profiling/PeriodicCounterCapture.hpp | 3 - src/profiling/ProfilingUtils.cpp | 16 ++- src/profiling/ProfilingUtils.hpp | 6 +- src/profiling/TimelineUtilityMethods.cpp | 35 ++++++ src/profiling/TimelineUtilityMethods.hpp | 2 + src/profiling/test/TimelineUtilityMethodsTests.cpp | 133 ++++++++++++++++++++- 7 files changed, 187 insertions(+), 19 deletions(-) diff --git a/src/profiling/PeriodicCounterCapture.cpp b/src/profiling/PeriodicCounterCapture.cpp index f888bc045e..12e58f2800 100644 --- a/src/profiling/PeriodicCounterCapture.cpp +++ b/src/profiling/PeriodicCounterCapture.cpp @@ -92,18 +92,11 @@ void PeriodicCounterCapture::Capture(const IReadCounterValues& readCounterValues values.emplace_back(std::make_pair(requestedId, counterValue)); } - #if USE_CLOCK_MONOTONIC_RAW - using clock = MonotonicClockRaw; - #else - using clock = std::chrono::steady_clock; - #endif - // Take a timestamp - auto timestamp = clock::now(); + uint64_t timestamp = GetTimestamp(); // Write a Periodic Counter Capture packet to the Counter Stream Buffer - m_SendCounterPacket.SendPeriodicCounterCapturePacket( - static_cast(timestamp.time_since_epoch().count()), values); + m_SendCounterPacket.SendPeriodicCounterCapturePacket(timestamp, values); // Notify the Send Thread that new data is available in the Counter Stream Buffer m_SendCounterPacket.SetReadyToRead(); diff --git a/src/profiling/PeriodicCounterCapture.hpp b/src/profiling/PeriodicCounterCapture.hpp index 4a28711d6b..9229a49d85 100644 --- a/src/profiling/PeriodicCounterCapture.hpp +++ b/src/profiling/PeriodicCounterCapture.hpp @@ -11,10 +11,7 @@ #include "SendCounterPacket.hpp" #include "ICounterValues.hpp" -#include - #include -#include #include #include diff --git a/src/profiling/ProfilingUtils.cpp b/src/profiling/ProfilingUtils.cpp index 4202b68662..b649747df1 100644 --- a/src/profiling/ProfilingUtils.cpp +++ b/src/profiling/ProfilingUtils.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include @@ -889,7 +891,6 @@ TimelinePacketStatus WriteTimelineEventBinaryPacket(uint64_t timestamp, return TimelinePacketStatus::Ok; } - std::string CentreAlignFormatting(const std::string& stringToPass, const int spacingWidth) { std::stringstream outputStream, centrePadding; @@ -1090,6 +1091,19 @@ void PrintCounterDirectory(ICounterDirectory& counterDirectory) std::cout << "\n"; } +uint64_t GetTimestamp() +{ +#if USE_CLOCK_MONOTONIC_RAW + using clock = MonotonicClockRaw; +#else + using clock = std::chrono::steady_clock; +#endif + + // Take a timestamp + auto timestamp = clock::now(); + + return static_cast(timestamp.time_since_epoch().count()); +} } // namespace profiling diff --git a/src/profiling/ProfilingUtils.hpp b/src/profiling/ProfilingUtils.hpp index fae1a83024..74fc437333 100644 --- a/src/profiling/ProfilingUtils.hpp +++ b/src/profiling/ProfilingUtils.hpp @@ -202,9 +202,11 @@ class BufferExhaustion : public armnn::Exception using Exception::Exception; }; -} // namespace profiling +uint64_t GetTimestamp(); -} // namespace armnn +} // namespace profiling + +} // namespace armnn namespace std { diff --git a/src/profiling/TimelineUtilityMethods.cpp b/src/profiling/TimelineUtilityMethods.cpp index 65668697f7..8c84aa73e9 100644 --- a/src/profiling/TimelineUtilityMethods.cpp +++ b/src/profiling/TimelineUtilityMethods.cpp @@ -157,6 +157,41 @@ ProfilingDynamicGuid TimelineUtilityMethods::CreateNamedTypedChildEntity(Profili return childEntityGuid; } +ProfilingDynamicGuid TimelineUtilityMethods::RecordEvent(ProfilingGuid entityGuid, ProfilingStaticGuid eventClassGuid) +{ + // Take a timestamp + uint64_t timestamp = GetTimestamp(); + + // Get the thread id + std::thread::id threadId = std::this_thread::get_id(); + + // Generate a GUID for the event + ProfilingDynamicGuid eventGuid = ProfilingService::Instance().NextGuid(); + + // Send the new timeline event to the external profiling service, this call throws in case of error + m_SendTimelinePacket.SendTimelineEventBinaryPacket(timestamp, threadId, eventGuid); + + // Generate a GUID for the execution link + ProfilingDynamicGuid executionLinkId = ProfilingService::Instance().NextGuid(); + + // Send the new execution link to the external profiling service, this call throws in case of error + m_SendTimelinePacket.SendTimelineRelationshipBinaryPacket(ProfilingRelationshipType::ExecutionLink, + executionLinkId, + entityGuid, + eventGuid); + + // Generate a GUID for the data relationship link + ProfilingDynamicGuid eventClassLinkId = ProfilingService::Instance().NextGuid(); + + // Send the new data relationship link to the external profiling service, this call throws in case of error + m_SendTimelinePacket.SendTimelineRelationshipBinaryPacket(ProfilingRelationshipType::DataLink, + eventClassLinkId, + entityGuid, + eventClassGuid); + + return eventGuid; +} + } // namespace profiling } // namespace armnn diff --git a/src/profiling/TimelineUtilityMethods.hpp b/src/profiling/TimelineUtilityMethods.hpp index 5f713bf6d4..5bb4342197 100644 --- a/src/profiling/TimelineUtilityMethods.hpp +++ b/src/profiling/TimelineUtilityMethods.hpp @@ -38,6 +38,8 @@ public: const std::string& entityName, const std::string& entityType); + ProfilingDynamicGuid RecordEvent(ProfilingGuid entityGuid, ProfilingStaticGuid eventClassGuid); + private: ISendTimelinePacket& m_SendTimelinePacket; }; diff --git a/src/profiling/test/TimelineUtilityMethodsTests.cpp b/src/profiling/test/TimelineUtilityMethodsTests.cpp index c2be6e5c46..3556a12a7b 100644 --- a/src/profiling/test/TimelineUtilityMethodsTests.cpp +++ b/src/profiling/test/TimelineUtilityMethodsTests.cpp @@ -262,9 +262,8 @@ void VerifyTimelineEntityBinaryPacket(Optional guid, // Check the decl_id offset += uint32_t_size; - uint32_t entitytDecId = ReadUint32(readableData, offset); - - BOOST_CHECK(entitytDecId == uint32_t(1)); + uint32_t entityDeclId = ReadUint32(readableData, offset); + BOOST_CHECK(entityDeclId == 1); // Check the profiling GUID offset += uint32_t_size; @@ -282,6 +281,83 @@ void VerifyTimelineEntityBinaryPacket(Optional guid, offset += uint64_t_size; } +void VerifyTimelineEventBinaryPacket(Optional timestamp, + Optional threadId, + Optional eventGuid, + const unsigned char* readableData, + unsigned int& offset) +{ + BOOST_ASSERT(readableData); + + // Utils + unsigned int uint32_t_size = sizeof(uint32_t); + unsigned int uint64_t_size = sizeof(uint64_t); + unsigned int threadId_size = sizeof(std::thread::id); + + // Reading TimelineEventBinaryPacket + uint32_t entityBinaryPacketHeaderWord0 = ReadUint32(readableData, offset); + uint32_t entityBinaryPacketFamily = (entityBinaryPacketHeaderWord0 >> 26) & 0x0000003F; + uint32_t entityBinaryPacketClass = (entityBinaryPacketHeaderWord0 >> 19) & 0x0000007F; + uint32_t entityBinaryPacketType = (entityBinaryPacketHeaderWord0 >> 16) & 0x00000007; + uint32_t entityBinaryPacketStreamId = (entityBinaryPacketHeaderWord0 >> 0) & 0x00000007; + + BOOST_CHECK(entityBinaryPacketFamily == 1); + BOOST_CHECK(entityBinaryPacketClass == 0); + BOOST_CHECK(entityBinaryPacketType == 1); + BOOST_CHECK(entityBinaryPacketStreamId == 0); + + offset += uint32_t_size; + uint32_t entityBinaryPacketHeaderWord1 = ReadUint32(readableData, offset); + uint32_t entityBinaryPacketSequenceNumbered = (entityBinaryPacketHeaderWord1 >> 24) & 0x00000001; + uint32_t entityBinaryPacketDataLength = (entityBinaryPacketHeaderWord1 >> 0) & 0x00FFFFFF; + BOOST_CHECK(entityBinaryPacketSequenceNumbered == 0); + BOOST_CHECK(entityBinaryPacketDataLength == 20 + threadId_size); + + // Check the decl_id + offset += uint32_t_size; + uint32_t entityDeclId = ReadUint32(readableData, offset); + BOOST_CHECK(entityDeclId == 4); + + // Check the timestamp + offset += uint32_t_size; + uint64_t readTimestamp = ReadUint64(readableData, offset); + if (timestamp.has_value()) + { + BOOST_CHECK(readTimestamp == timestamp.value()); + } + else + { + BOOST_CHECK(readTimestamp != 0); + } + + // Check the thread id + offset += uint64_t_size; + std::vector readThreadId(threadId_size, 0); + ReadBytes(readableData, offset, threadId_size, readThreadId.data()); + if (threadId.has_value()) + { + BOOST_CHECK(readThreadId == threadId.value()); + } + else + { + BOOST_CHECK(readThreadId == std::this_thread::get_id()); + } + + // Check the event GUID + offset += threadId_size; + uint64_t readEventGuid = ReadUint64(readableData, offset); + if (eventGuid.has_value()) + { + BOOST_CHECK(readEventGuid == eventGuid.value()); + } + else + { + BOOST_CHECK(readEventGuid != ProfilingGuid(0)); + } + + offset += uint64_t_size; +} + } // Anonymous namespace BOOST_AUTO_TEST_SUITE(TimelineUtilityMethodsTests) @@ -518,7 +594,7 @@ BOOST_AUTO_TEST_CASE(CreateNameTypeEntityInvalidTest) } -BOOST_AUTO_TEST_CASE(CreateNameTypeEntitylTest) +BOOST_AUTO_TEST_CASE(CreateNameTypeEntityTest) { MockBufferManager mockBufferManager(1024); SendTimelinePacket sendTimelinePacket(mockBufferManager); @@ -591,4 +667,53 @@ BOOST_AUTO_TEST_CASE(CreateNameTypeEntitylTest) mockBufferManager.MarkRead(readableBuffer); } +BOOST_AUTO_TEST_CASE(RecordEventTest) +{ + MockBufferManager mockBufferManager(1024); + SendTimelinePacket sendTimelinePacket(mockBufferManager); + TimelineUtilityMethods timelineUtilityMethods(sendTimelinePacket); + + ProfilingGuid entityGuid(123); + ProfilingStaticGuid eventClassGuid(456); + ProfilingDynamicGuid eventGuid(0); + BOOST_CHECK_NO_THROW(eventGuid = timelineUtilityMethods.RecordEvent(entityGuid, eventClassGuid)); + BOOST_CHECK(eventGuid != ProfilingGuid(0)); + + // Commit all packets at once + sendTimelinePacket.Commit(); + + // Get the readable buffer + auto readableBuffer = mockBufferManager.GetReadableBuffer(); + BOOST_CHECK(readableBuffer != nullptr); + unsigned int size = readableBuffer->GetSize(); + BOOST_CHECK(size == 116); + const unsigned char* readableData = readableBuffer->GetReadableData(); + BOOST_CHECK(readableData != nullptr); + + // Utils + unsigned int offset = 0; + + // First packet sent: TimelineEntityBinaryPacket + VerifyTimelineEventBinaryPacket(EmptyOptional(), EmptyOptional(), EmptyOptional(), readableData, offset); + + // Second packet sent: TimelineRelationshipBinaryPacket + VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::ExecutionLink, + EmptyOptional(), + entityGuid, + EmptyOptional(), + readableData, + offset); + + // Third packet sent: TimelineRelationshipBinaryPacket + VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::DataLink, + EmptyOptional(), + entityGuid, + eventClassGuid, + readableData, + offset); + + // Mark the buffer as read + mockBufferManager.MarkRead(readableBuffer); +} + BOOST_AUTO_TEST_SUITE_END() -- cgit v1.2.1