IVGCVSW-4065 Add a RecordEvent function
authorMatteo Martincigh <matteo.martincigh@arm.com>
Mon, 4 Nov 2019 14:05:28 +0000 (14:05 +0000)
committerMatteo Martincigh <matteo.martincigh@arm.com>
Wed, 6 Nov 2019 15:50:10 +0000 (15:50 +0000)
 * Added RecordEvent utility function to the TimelineUtilityMethods
   class
 * Added new utility function to get a timestamp
 * Added unit tests

Signed-off-by: Matteo Martincigh <matteo.martincigh@arm.com>
Change-Id: Ia3f8fe7397915fa6c903ce0c0abab3047cea628c

src/profiling/PeriodicCounterCapture.cpp
src/profiling/PeriodicCounterCapture.hpp
src/profiling/ProfilingUtils.cpp
src/profiling/ProfilingUtils.hpp
src/profiling/TimelineUtilityMethods.cpp
src/profiling/TimelineUtilityMethods.hpp
src/profiling/test/TimelineUtilityMethodsTests.cpp

index f888bc0..12e58f2 100644 (file)
@@ -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<uint64_t>(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();
index 4a28711..9229a49 100644 (file)
 #include "SendCounterPacket.hpp"
 #include "ICounterValues.hpp"
 
-#include <WallClockTimer.hpp>
-
 #include <atomic>
-#include <chrono>
 #include <mutex>
 #include <thread>
 
index 4202b68..b649747 100644 (file)
@@ -8,6 +8,8 @@
 #include <armnn/Version.hpp>
 #include <armnn/Conversion.hpp>
 
+#include <WallClockTimer.hpp>
+
 #include <boost/assert.hpp>
 
 #include <fstream>
@@ -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<uint64_t>(timestamp.time_since_epoch().count());
+}
 
 } // namespace profiling
 
index fae1a83..74fc437 100644 (file)
@@ -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
 {
index 6566869..8c84aa7 100644 (file)
@@ -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
index 5f713bf..5bb4342 100644 (file)
@@ -38,6 +38,8 @@ public:
                                                      const std::string& entityName,
                                                      const std::string& entityType);
 
+    ProfilingDynamicGuid RecordEvent(ProfilingGuid entityGuid, ProfilingStaticGuid eventClassGuid);
+
 private:
     ISendTimelinePacket& m_SendTimelinePacket;
 };
index c2be6e5..3556a12 100644 (file)
@@ -262,9 +262,8 @@ void VerifyTimelineEntityBinaryPacket(Optional<ProfilingGuid> 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<ProfilingGuid> guid,
     offset += uint64_t_size;
 }
 
+void VerifyTimelineEventBinaryPacket(Optional<uint64_t> timestamp,
+                                     Optional<std::thread::id> threadId,
+                                     Optional<ProfilingGuid> 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<uint8_t> 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()