IVGCVSW-4037 Add a CreateNamedTypedChildEntity method

 * Added new method to the TimelineUtilityMethods class
 * Added unit tests
 * Code refactoring
 * Skipped the 0 when generating a dynamic GUID for testing purposes

Signed-off-by: Matteo Martincigh <matteo.martincigh@arm.com>
Change-Id: Ic2c8033ad010e07b0f8b7971ce653263e21c6f97
diff --git a/src/profiling/ProfilingGuidGenerator.hpp b/src/profiling/ProfilingGuidGenerator.hpp
index 81997e1..ad3159f 100644
--- a/src/profiling/ProfilingGuidGenerator.hpp
+++ b/src/profiling/ProfilingGuidGenerator.hpp
@@ -25,8 +25,8 @@
     // NOTE: dummy implementation for the moment
     inline ProfilingDynamicGuid NextGuid() override
     {
-        ProfilingDynamicGuid guid(m_Sequence);
-        m_Sequence++;
+        // NOTE: skipping the zero for testing purposes
+        ProfilingDynamicGuid guid(++m_Sequence);
         return guid;
     }
 
diff --git a/src/profiling/TimelineUtilityMethods.cpp b/src/profiling/TimelineUtilityMethods.cpp
index 429967f..6566869 100644
--- a/src/profiling/TimelineUtilityMethods.cpp
+++ b/src/profiling/TimelineUtilityMethods.cpp
@@ -93,10 +93,10 @@
     }
 
     // Declare a label with the entity's name, this call throws in case of error
-    ProfilingGuid labelGuid = DeclareLabel(entityName);
+    ProfilingStaticGuid labelGuid = DeclareLabel(entityName);
 
     // Generate a GUID for the label relationship
-    ProfilingGuid relationshipGuid = ProfilingService::Instance().NextGuid();
+    ProfilingDynamicGuid relationshipGuid = ProfilingService::Instance().NextGuid();
 
     // Send the new label link to the external profiling service, this call throws in case of error
     m_SendTimelinePacket.SendTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
@@ -105,7 +105,7 @@
                                                               labelGuid);
 
     // Generate a GUID for the label relationship
-    ProfilingGuid relationshipLabelGuid = ProfilingService::Instance().NextGuid();
+    ProfilingDynamicGuid relationshipLabelGuid = ProfilingService::Instance().NextGuid();
 
     // Send the new label link to the external profiling service, this call throws in case of error
     m_SendTimelinePacket.SendTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
@@ -124,6 +124,39 @@
     CreateTypedLabel(entityGuid, type, LabelsAndEventClasses::TYPE_GUID);
 }
 
+ProfilingDynamicGuid TimelineUtilityMethods::CreateNamedTypedChildEntity(ProfilingGuid parentEntityGuid,
+                                                                         const std::string& entityName,
+                                                                         const std::string& entityType)
+{
+    // Check that the entity name is valid
+    if (entityName.empty())
+    {
+        // The entity name is invalid
+        throw InvalidArgumentException("Invalid entity name, the entity name cannot be empty");
+    }
+
+    // Check that the entity type is valid
+    if (entityType.empty())
+    {
+        // The entity type is invalid
+        throw InvalidArgumentException("Invalid entity type, the entity type cannot be empty");
+    }
+
+    // Create a named type entity from the given name and type, this call throws in case of error
+    ProfilingDynamicGuid childEntityGuid = CreateNamedTypedEntity(entityName, entityType);
+
+    // Generate a GUID for the retention link relationship
+    ProfilingDynamicGuid retentionLinkGuid = ProfilingService::Instance().NextGuid();
+
+    // Send the new retention link to the external profiling service, this call throws in case of error
+    m_SendTimelinePacket.SendTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                                              retentionLinkGuid,
+                                                              parentEntityGuid,
+                                                              childEntityGuid);
+
+    return childEntityGuid;
+}
+
 } // namespace profiling
 
 } // namespace armnn
diff --git a/src/profiling/TimelineUtilityMethods.hpp b/src/profiling/TimelineUtilityMethods.hpp
index 7d029e7..5f713bf 100644
--- a/src/profiling/TimelineUtilityMethods.hpp
+++ b/src/profiling/TimelineUtilityMethods.hpp
@@ -34,6 +34,10 @@
 
     void TypeEntity(ProfilingGuid entityGuid, const std::string& type);
 
+    ProfilingDynamicGuid CreateNamedTypedChildEntity(ProfilingGuid parentEntityGuid,
+                                                     const std::string& entityName,
+                                                     const std::string& entityType);
+
 private:
     ISendTimelinePacket& m_SendTimelinePacket;
 };
diff --git a/src/profiling/test/TimelineUtilityMethodsTests.cpp b/src/profiling/test/TimelineUtilityMethodsTests.cpp
index 6c5ce63..c2be6e5 100644
--- a/src/profiling/test/TimelineUtilityMethodsTests.cpp
+++ b/src/profiling/test/TimelineUtilityMethodsTests.cpp
@@ -231,9 +231,9 @@
     offset += uint64_t_size;
 }
 
-void VerifyTimelineEntityPacket(Optional<ProfilingGuid> guid,
-                                const unsigned char* readableData,
-                                unsigned int& offset)
+void VerifyTimelineEntityBinaryPacket(Optional<ProfilingGuid> guid,
+                                      const unsigned char* readableData,
+                                      unsigned int& offset)
 {
     BOOST_ASSERT(readableData);
 
@@ -380,7 +380,7 @@
                                          readableData,
                                          offset);
 
-    // First "well-known" event class: END OF LIFE
+    // Second "well-known" event class: END OF LIFE
     VerifyTimelineEventClassBinaryPacket(LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS,
                                          readableData,
                                          offset);
@@ -389,6 +389,94 @@
     mockBufferManager.MarkRead(readableBuffer);
 }
 
+BOOST_AUTO_TEST_CASE(CreateNamedTypedChildEntityTest)
+{
+    MockBufferManager mockBufferManager(1024);
+    SendTimelinePacket sendTimelinePacket(mockBufferManager);
+    TimelineUtilityMethods timelineUtilityMethods(sendTimelinePacket);
+
+    ProfilingGuid parentEntityGuid(123);
+    const std::string entityName = "some entity";
+    const std::string entityType = "some type";
+
+    BOOST_CHECK_THROW(timelineUtilityMethods.CreateNamedTypedChildEntity(parentEntityGuid, "", entityType),
+                      InvalidArgumentException);
+    BOOST_CHECK_THROW(timelineUtilityMethods.CreateNamedTypedChildEntity(parentEntityGuid, entityName, ""),
+                      InvalidArgumentException);
+
+    ProfilingGuid childEntityGuid(0);
+    BOOST_CHECK_NO_THROW(childEntityGuid = timelineUtilityMethods.CreateNamedTypedChildEntity(parentEntityGuid,
+                                                                                              entityName,
+                                                                                              entityType));
+    BOOST_CHECK(childEntityGuid != 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 == 292);
+    const unsigned char* readableData = readableBuffer->GetReadableData();
+    BOOST_CHECK(readableData != nullptr);
+
+    // Utils
+    unsigned int offset = 0;
+
+    // First packet sent: TimelineEntityBinaryPacket
+    VerifyTimelineEntityBinaryPacket(EmptyOptional(), readableData, offset);
+
+    // Second packet sent: TimelineLabelBinaryPacket
+    VerifyTimelineLabelBinaryPacket(EmptyOptional(), entityName, readableData, offset);
+
+    // Third packet sent: TimelineRelationshipBinaryPacket
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Fourth packet sent: TimelineRelationshipBinaryPacket
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::NAME_GUID,
+                                           readableData,
+                                           offset);
+
+    // Fifth packet sent: TimelineLabelBinaryPacket
+    VerifyTimelineLabelBinaryPacket(EmptyOptional(), entityType, readableData, offset);
+
+    // Sixth packet sent: TimelineRelationshipBinaryPacket
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Seventh packet sent: TimelineRelationshipBinaryPacket
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+
+    // Eighth packet sent: TimelineRelationshipBinaryPacket
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                           EmptyOptional(),
+                                           parentEntityGuid,
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Mark the buffer as read
+    mockBufferManager.MarkRead(readableBuffer);
+}
+
 BOOST_AUTO_TEST_CASE(DeclareLabelTest)
 {
     MockBufferManager mockBufferManager(1024);
@@ -439,9 +527,6 @@
     const std::string entityName = "Entity0";
     const std::string entityType = "Type0";
 
-    // Generate first guid to ensure that the named typed entity guid is not 0 on local single test.
-    ProfilingService::Instance().NextGuid();
-
     ProfilingDynamicGuid guid = timelineUtilityMethods.CreateNamedTypedEntity(entityName, entityType);
     BOOST_CHECK(guid != ProfilingGuid(0));
 
@@ -460,7 +545,7 @@
     unsigned int offset = 0;
 
     // First packet sent: TimelineEntityBinaryPacket
-    VerifyTimelineEntityPacket(guid, readableData, offset);
+    VerifyTimelineEntityBinaryPacket(guid, readableData, offset);
 
     // Packets for Name Entity
     // First packet sent: TimelineLabelBinaryPacket