IVGCVSW-5101 Add a SOL/EOL and a process ID label to Network

Change-Id: I6261f46404a3aab5c069bca40586994d31d26fe8
Signed-off-by: Jim Flynn <jim.flynn@arm.com>
diff --git a/src/armnn/LoadedNetwork.cpp b/src/armnn/LoadedNetwork.cpp
index 0dd75aa..593539d 100644
--- a/src/armnn/LoadedNetwork.cpp
+++ b/src/armnn/LoadedNetwork.cpp
@@ -7,6 +7,7 @@
 #include "Layer.hpp"
 #include "Graph.hpp"
 #include "Network.hpp"
+#include <Processes.hpp>
 #include "Runtime.hpp"
 #include "Profiling.hpp"
 #include "HeapProfiling.hpp"
@@ -196,6 +197,13 @@
     if (timelineUtils)
     {
         timelineUtils->CreateTypedEntity(networkGuid, LabelsAndEventClasses::NETWORK_GUID);
+        // Mark the network with a start of life event
+        timelineUtils->RecordEvent(networkGuid, LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS);
+        // and with the process ID
+        int processID = armnnUtils::Processes::GetCurrentId();
+        std::stringstream ss;
+        ss << processID;
+        timelineUtils->MarkEntityWithLabel(networkGuid, ss.str(), LabelsAndEventClasses::PROCESS_ID_GUID);
     }
 
     //Then create workloads.
@@ -298,6 +306,11 @@
     timelineUtils->Commit();
 }
 
+profiling::ProfilingGuid LoadedNetwork::GetNetworkGuid()
+{
+    return m_OptimizedNetwork->GetGuid();
+}
+
 TensorInfo LoadedNetwork::GetInputTensorInfo(LayerBindingId layerId) const
 {
     for (auto&& inputLayer : m_OptimizedNetwork->GetGraph().GetInputLayers())
diff --git a/src/armnn/LoadedNetwork.hpp b/src/armnn/LoadedNetwork.hpp
index 8c21030..39b6089 100644
--- a/src/armnn/LoadedNetwork.hpp
+++ b/src/armnn/LoadedNetwork.hpp
@@ -58,6 +58,8 @@
 
     void SendNetworkStructure();
 
+    profiling::ProfilingGuid GetNetworkGuid();
+
 private:
     void AllocateWorkingMemory(std::lock_guard<std::mutex>& lock);
 
diff --git a/src/armnn/Runtime.cpp b/src/armnn/Runtime.cpp
index 28e2df2..63f39c6 100644
--- a/src/armnn/Runtime.cpp
+++ b/src/armnn/Runtime.cpp
@@ -6,6 +6,7 @@
 
 #include <armnn/Version.hpp>
 #include <armnn/BackendRegistry.hpp>
+#include <LabelsAndEventClasses.hpp>
 #include <armnn/Logging.hpp>
 #include <armnn/utility/Timer.hpp>
 
@@ -117,9 +118,22 @@
         return Status::Failure;
     }
 
+    std::unique_ptr<profiling::TimelineUtilityMethods> timelineUtils =
+            profiling::TimelineUtilityMethods::GetTimelineUtils(m_ProfilingService);
     {
         std::lock_guard<std::mutex> lockGuard(m_Mutex);
 
+        // If timeline recording is on mark the Network end of life
+        if (timelineUtils)
+        {
+            auto search = m_LoadedNetworks.find(networkId);
+            if (search != m_LoadedNetworks.end())
+            {
+                profiling::ProfilingGuid networkGuid = search->second->GetNetworkGuid();
+                timelineUtils->RecordEvent(networkGuid,
+                                           profiling::LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS);
+            }
+        }
         if (m_LoadedNetworks.erase(networkId) == 0)
         {
             ARMNN_LOG(warning) << "WARNING: Runtime::UnloadNetwork(): " << networkId << " not found!";
diff --git a/src/armnn/test/RuntimeTests.cpp b/src/armnn/test/RuntimeTests.cpp
index 7e9acb7..12ec8b1 100644
--- a/src/armnn/test/RuntimeTests.cpp
+++ b/src/armnn/test/RuntimeTests.cpp
@@ -6,6 +6,7 @@
 #include <armnn/Descriptors.hpp>
 #include <armnn/IRuntime.hpp>
 #include <armnn/INetwork.hpp>
+#include <Processes.hpp>
 #include <Runtime.hpp>
 #include <armnn/TypesUtils.hpp>
 
@@ -414,7 +415,6 @@
     BOOST_CHECK(readableBuffer != nullptr);
 
     unsigned int size = readableBuffer->GetSize();
-    BOOST_CHECK(size == 772);
 
     const unsigned char* readableData = readableBuffer->GetReadableData();
     BOOST_CHECK(readableData != nullptr);
@@ -422,7 +422,7 @@
     unsigned int offset = 0;
 
     // Verify Header
-    VerifyTimelineHeaderBinary(readableData, offset, 764);
+    VerifyTimelineHeaderBinary(readableData, offset, size - 8);
     BOOST_TEST_MESSAGE("HEADER OK");
 
     // Post-optimisation network
@@ -440,6 +440,42 @@
                                                offset);
     BOOST_TEST_MESSAGE("NETWORK TYPE RELATIONSHIP OK");
 
+    // Network - START OF LIFE
+    ProfilingGuid networkSolEventGuid = VerifyTimelineEventBinaryPacket(EmptyOptional(),
+                                                                        EmptyOptional(),
+                                                                        EmptyOptional(),
+                                                                        readableData,
+                                                                        offset);
+    BOOST_TEST_MESSAGE("NETWORK START OF LIFE EVENT OK");
+
+    // Network - START OF LIFE event relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::ExecutionLink,
+                                               EmptyOptional(),
+                                               optNetGuid,
+                                               networkSolEventGuid,
+                                               LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS,
+                                               readableData,
+                                               offset);
+    BOOST_TEST_MESSAGE("NETWORK START OF LIFE RELATIONSHIP OK");
+
+    // Process ID Label
+    int processID = armnnUtils::Processes::GetCurrentId();
+    std::stringstream ss;
+    ss << processID;
+    std::string processIdLabel = ss.str();
+    VerifyTimelineLabelBinaryPacketData(EmptyOptional(), processIdLabel, readableData, offset);
+    BOOST_TEST_MESSAGE("PROCESS ID LABEL OK");
+
+    // Entity - Process ID relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::LabelLink,
+                                               EmptyOptional(),
+                                               optNetGuid,
+                                               EmptyOptional(),
+                                               LabelsAndEventClasses::PROCESS_ID_GUID,
+                                               readableData,
+                                               offset);
+    BOOST_TEST_MESSAGE("NETWORK PROCESS ID RELATIONSHIP OK");
+
     // Input layer
     // Input layer entity
     VerifyTimelineEntityBinaryPacketData(input->GetGuid(), readableData, offset);
diff --git a/src/profiling/LabelsAndEventClasses.cpp b/src/profiling/LabelsAndEventClasses.cpp
index 6b6a190..fe6d119 100644
--- a/src/profiling/LabelsAndEventClasses.cpp
+++ b/src/profiling/LabelsAndEventClasses.cpp
@@ -21,6 +21,7 @@
 std::string LabelsAndEventClasses::BACKENDID_LABEL("backendId");
 std::string LabelsAndEventClasses::CHILD_LABEL("child");
 std::string LabelsAndEventClasses::EXECUTION_OF_LABEL("execution_of");
+std::string LabelsAndEventClasses::PROCESS_ID_LABEL("processId");
 
 ProfilingStaticGuid LabelsAndEventClasses::EMPTY_GUID(0);
 ProfilingStaticGuid LabelsAndEventClasses::NAME_GUID(
@@ -35,6 +36,8 @@
     m_GuidGenerator.GenerateStaticId(LabelsAndEventClasses::CHILD_LABEL));
 ProfilingStaticGuid LabelsAndEventClasses::EXECUTION_OF_GUID(
     m_GuidGenerator.GenerateStaticId(LabelsAndEventClasses::EXECUTION_OF_LABEL));
+ProfilingStaticGuid LabelsAndEventClasses::PROCESS_ID_GUID(
+    m_GuidGenerator.GenerateStaticId(LabelsAndEventClasses::PROCESS_ID_LABEL));
 
 // Common types
 std::string LabelsAndEventClasses::LAYER("layer");
diff --git a/src/profiling/LabelsAndEventClasses.hpp b/src/profiling/LabelsAndEventClasses.hpp
index 835fc79..b06b9a1 100644
--- a/src/profiling/LabelsAndEventClasses.hpp
+++ b/src/profiling/LabelsAndEventClasses.hpp
@@ -27,6 +27,7 @@
     ARMNN_DLLEXPORT static std::string BACKENDID_LABEL;
     ARMNN_DLLEXPORT static std::string CHILD_LABEL;
     ARMNN_DLLEXPORT static std::string EXECUTION_OF_LABEL;
+    ARMNN_DLLEXPORT static std::string PROCESS_ID_LABEL;
     ARMNN_DLLEXPORT static ProfilingStaticGuid EMPTY_GUID;
     ARMNN_DLLEXPORT static ProfilingStaticGuid NAME_GUID;
     ARMNN_DLLEXPORT static ProfilingStaticGuid TYPE_GUID;
@@ -34,6 +35,7 @@
     ARMNN_DLLEXPORT static ProfilingStaticGuid BACKENDID_GUID;
     ARMNN_DLLEXPORT static ProfilingStaticGuid CHILD_GUID;
     ARMNN_DLLEXPORT static ProfilingStaticGuid EXECUTION_OF_GUID;
+    ARMNN_DLLEXPORT static ProfilingStaticGuid PROCESS_ID_GUID;
 
     // Common types
     ARMNN_DLLEXPORT static std::string LAYER;
diff --git a/src/profiling/TimelineUtilityMethods.cpp b/src/profiling/TimelineUtilityMethods.cpp
index fe5c6b1..e72894a 100644
--- a/src/profiling/TimelineUtilityMethods.cpp
+++ b/src/profiling/TimelineUtilityMethods.cpp
@@ -53,6 +53,10 @@
     timelinePacket.SendTimelineLabelBinaryPacket(LabelsAndEventClasses::EXECUTION_OF_GUID,
                                                  LabelsAndEventClasses::EXECUTION_OF_LABEL);
 
+    // Send the "process_id" label, this call throws in case of error
+    timelinePacket.SendTimelineLabelBinaryPacket(LabelsAndEventClasses::PROCESS_ID_GUID,
+                                                 LabelsAndEventClasses::PROCESS_ID_LABEL);
+
     // Send the "layer" label, this call throws in case of error
     timelinePacket.SendTimelineLabelBinaryPacket(LabelsAndEventClasses::LAYER_GUID,
                                                  LabelsAndEventClasses::LAYER);
diff --git a/src/profiling/TimelineUtilityMethods.hpp b/src/profiling/TimelineUtilityMethods.hpp
index 857d82f..80d5e8d 100644
--- a/src/profiling/TimelineUtilityMethods.hpp
+++ b/src/profiling/TimelineUtilityMethods.hpp
@@ -47,7 +47,7 @@
 
     void CreateNamedTypedEntity(ProfilingGuid entityGuid, const std::string& name, ProfilingStaticGuid typeGuid);
 
-    void MarkEntityWithLabel(ProfilingGuid entityGuid, const std::string &labelName, ProfilingStaticGuid labelLinkGuid);
+    void MarkEntityWithLabel(ProfilingGuid entityGuid, const std::string& labelName, ProfilingStaticGuid labelLinkGuid);
 
     ProfilingStaticGuid DeclareLabel(const std::string& labelName);
 
diff --git a/src/profiling/test/FileOnlyProfilingDecoratorTests.cpp b/src/profiling/test/FileOnlyProfilingDecoratorTests.cpp
index 69ebe33..f9df633 100644
--- a/src/profiling/test/FileOnlyProfilingDecoratorTests.cpp
+++ b/src/profiling/test/FileOnlyProfilingDecoratorTests.cpp
@@ -114,39 +114,40 @@
         std::vector<std::string> desc = GetModelDescription(model);
         std::vector<std::string> expectedOutput;
         expectedOutput.push_back("Entity [0] name = input type = layer");
-        expectedOutput.push_back("   connection [14] from entity [0] to entity [1]");
-        expectedOutput.push_back("   child: Entity [23] backendId = " + backend.Get() + " type = workload");
+        expectedOutput.push_back("   connection [17] from entity [0] to entity [1]");
+        expectedOutput.push_back("   child: Entity [26] backendId = " + backend.Get() + " type = workload");
         expectedOutput.push_back("Entity [1] name = Rsqrt type = layer");
-        expectedOutput.push_back("   connection [22] from entity [1] to entity [2]");
-        expectedOutput.push_back("   child: Entity [15] backendId = " + backend.Get() + " type = workload");
+        expectedOutput.push_back("   connection [25] from entity [1] to entity [2]");
+        expectedOutput.push_back("   child: Entity [18] backendId = " + backend.Get() + " type = workload");
         expectedOutput.push_back("Entity [2] name = output type = layer");
-        expectedOutput.push_back("   child: Entity [27] backendId = " + backend.Get() + " type = workload");
-        expectedOutput.push_back("Entity [6] type = network");
+        expectedOutput.push_back("   child: Entity [30] backendId = " + backend.Get() + " type = workload");
+        expectedOutput.push_back("Entity [6] processId = [processId] type = network");
         expectedOutput.push_back("   child: Entity [0] name = input type = layer");
         expectedOutput.push_back("   child: Entity [1] name = Rsqrt type = layer");
         expectedOutput.push_back("   child: Entity [2] name = output type = layer");
-        expectedOutput.push_back("   execution: Entity [31] type = inference");
-        expectedOutput.push_back("Entity [15] backendId = " + backend.Get() + " type = workload");
-        expectedOutput.push_back("   execution: Entity [44] type = workload_execution");
-        expectedOutput.push_back("Entity [23] backendId = " + backend.Get() + " type = workload");
-        expectedOutput.push_back("   execution: Entity [36] type = workload_execution");
-        expectedOutput.push_back("Entity [27] backendId = " + backend.Get() + " type = workload");
-        expectedOutput.push_back("   execution: Entity [52] type = workload_execution");
-        expectedOutput.push_back("Entity [31] type = inference");
-        expectedOutput.push_back("   child: Entity [36] type = workload_execution");
-        expectedOutput.push_back("   child: Entity [44] type = workload_execution");
-        expectedOutput.push_back("   child: Entity [52] type = workload_execution");
-        expectedOutput.push_back("   event: [34] class [start_of_life]");
-        expectedOutput.push_back("   event: [60] class [end_of_life]");
-        expectedOutput.push_back("Entity [36] type = workload_execution");
-        expectedOutput.push_back("   event: [40] class [start_of_life]");
-        expectedOutput.push_back("   event: [42] class [end_of_life]");
-        expectedOutput.push_back("Entity [44] type = workload_execution");
-        expectedOutput.push_back("   event: [48] class [start_of_life]");
-        expectedOutput.push_back("   event: [50] class [end_of_life]");
-        expectedOutput.push_back("Entity [52] type = workload_execution");
-        expectedOutput.push_back("   event: [56] class [start_of_life]");
-        expectedOutput.push_back("   event: [58] class [end_of_life]");
+        expectedOutput.push_back("   execution: Entity [34] type = inference");
+        expectedOutput.push_back("   event: [8] class [start_of_life]");
+        expectedOutput.push_back("Entity [18] backendId = " + backend.Get() + " type = workload");
+        expectedOutput.push_back("   execution: Entity [47] type = workload_execution");
+        expectedOutput.push_back("Entity [26] backendId = " + backend.Get() + " type = workload");
+        expectedOutput.push_back("   execution: Entity [39] type = workload_execution");
+        expectedOutput.push_back("Entity [30] backendId = " + backend.Get() + " type = workload");
+        expectedOutput.push_back("   execution: Entity [55] type = workload_execution");
+        expectedOutput.push_back("Entity [34] type = inference");
+        expectedOutput.push_back("   child: Entity [39] type = workload_execution");
+        expectedOutput.push_back("   child: Entity [47] type = workload_execution");
+        expectedOutput.push_back("   child: Entity [55] type = workload_execution");
+        expectedOutput.push_back("   event: [37] class [start_of_life]");
+        expectedOutput.push_back("   event: [63] class [end_of_life]");
+        expectedOutput.push_back("Entity [39] type = workload_execution");
+        expectedOutput.push_back("   event: [43] class [start_of_life]");
+        expectedOutput.push_back("   event: [45] class [end_of_life]");
+        expectedOutput.push_back("Entity [47] type = workload_execution");
+        expectedOutput.push_back("   event: [51] class [start_of_life]");
+        expectedOutput.push_back("   event: [53] class [end_of_life]");
+        expectedOutput.push_back("Entity [55] type = workload_execution");
+        expectedOutput.push_back("   event: [59] class [start_of_life]");
+        expectedOutput.push_back("   event: [61] class [end_of_life]");
         BOOST_TEST(CompareOutput(desc, expectedOutput));
     }
 }
diff --git a/src/profiling/test/ProfilingTestUtils.cpp b/src/profiling/test/ProfilingTestUtils.cpp
index 2dae5cf..8050eaa 100644
--- a/src/profiling/test/ProfilingTestUtils.cpp
+++ b/src/profiling/test/ProfilingTestUtils.cpp
@@ -8,8 +8,9 @@
 
 #include <armnn/Descriptors.hpp>
 #include <LabelsAndEventClasses.hpp>
-#include <Threads.hpp>
+#include <Processes.hpp>
 #include <ProfilingService.hpp>
+#include <Threads.hpp>
 
 #include <test/TestUtils.hpp>
 
@@ -438,11 +439,9 @@
     profiling::BufferManager& bufferManager = profilingServiceHelper.GetProfilingBufferManager();
     auto readableBuffer = bufferManager.GetReadableBuffer();
 
-    // Profiling is enable, the post-optimisation structure should be created
+    // Profiling is enabled, the post-optimisation structure should be created
     BOOST_CHECK(readableBuffer != nullptr);
-
     unsigned int size = readableBuffer->GetSize();
-    BOOST_CHECK(size == 1124);
 
     const unsigned char* readableData = readableBuffer->GetReadableData();
     BOOST_CHECK(readableData != nullptr);
@@ -450,7 +449,7 @@
     unsigned int offset = 0;
 
     // Verify Header
-    VerifyTimelineHeaderBinary(readableData, offset, 1116);
+    VerifyTimelineHeaderBinary(readableData, offset, size - 8);
     BOOST_TEST_MESSAGE("HEADER OK");
 
     // Post-optimisation network
@@ -468,6 +467,42 @@
                                                offset);
     BOOST_TEST_MESSAGE("NETWORK TYPE RELATIONSHIP OK");
 
+    // Network - START OF LIFE
+    ProfilingGuid networkSolEventGuid = VerifyTimelineEventBinaryPacket(EmptyOptional(),
+                                                                        EmptyOptional(),
+                                                                        EmptyOptional(),
+                                                                        readableData,
+                                                                        offset);
+    BOOST_TEST_MESSAGE("NETWORK START OF LIFE EVENT OK");
+
+    // Network - START OF LIFE event relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::ExecutionLink,
+                                               EmptyOptional(),
+                                               optNetGuid,
+                                               networkSolEventGuid,
+                                               LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS,
+                                               readableData,
+                                               offset);
+    BOOST_TEST_MESSAGE("NETWORK START OF LIFE RELATIONSHIP OK");
+
+    // Process ID Label
+    int processID = armnnUtils::Processes::GetCurrentId();
+    std::stringstream ss;
+    ss << processID;
+    std::string processIdLabel = ss.str();
+    VerifyTimelineLabelBinaryPacketData(EmptyOptional(), processIdLabel, readableData, offset);
+    BOOST_TEST_MESSAGE("PROCESS ID LABEL OK");
+
+    // Entity - Process ID relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::LabelLink,
+                                               EmptyOptional(),
+                                               optNetGuid,
+                                               EmptyOptional(),
+                                               LabelsAndEventClasses::PROCESS_ID_GUID,
+                                               readableData,
+                                               offset);
+    BOOST_TEST_MESSAGE("NETWORK PROCESS ID RELATIONSHIP OK");
+
     // Input layer
     // Input layer entity
     VerifyTimelineEntityBinaryPacketData(input->GetGuid(), readableData, offset);
diff --git a/src/profiling/test/TimelineModel.cpp b/src/profiling/test/TimelineModel.cpp
index d16a300..2e4fd06 100644
--- a/src/profiling/test/TimelineModel.cpp
+++ b/src/profiling/test/TimelineModel.cpp
@@ -359,7 +359,13 @@
     ss << "Entity [" << entity.GetGuid() << "]";
     for (auto& attributeEntry : entity.GetAttributes())
     {
-        ss << " " << attributeEntry.second.first << " = " << attributeEntry.second.second;
+        if (profiling::LabelsAndEventClasses::PROCESS_ID_LABEL == attributeEntry.second.first)
+        {
+            ss << " " << attributeEntry.second.first << " = [processId]";
+        }
+        else {
+            ss << " " << attributeEntry.second.first << " = " << attributeEntry.second.second;
+        }
     }
     return ss.str();
 }
diff --git a/src/profiling/test/TimelineUtilityMethodsTests.cpp b/src/profiling/test/TimelineUtilityMethodsTests.cpp
index 720b8b4..cbe3b79 100644
--- a/src/profiling/test/TimelineUtilityMethodsTests.cpp
+++ b/src/profiling/test/TimelineUtilityMethodsTests.cpp
@@ -82,7 +82,7 @@
     auto readableBuffer = mockBufferManager.GetReadableBuffer();
     BOOST_CHECK(readableBuffer != nullptr);
     unsigned int size = readableBuffer->GetSize();
-    BOOST_TEST(size == 432);
+    BOOST_TEST(size == 460);
     const unsigned char* readableData = readableBuffer->GetReadableData();
     BOOST_CHECK(readableData != nullptr);
 
@@ -90,7 +90,7 @@
     unsigned int offset = 0;
 
     // Verify Header
-    VerifyTimelineHeaderBinary(readableData, offset, 424);
+    VerifyTimelineHeaderBinary(readableData, offset, 452);
 
     // First "well-known" label: NAME
     VerifyTimelineLabelBinaryPacketData(LabelsAndEventClasses::NAME_GUID,
@@ -128,6 +128,12 @@
                                         readableData,
                                         offset);
 
+    // Seventh "well-known" label: PROCESS_ID_LABEL
+    VerifyTimelineLabelBinaryPacketData(LabelsAndEventClasses::PROCESS_ID_GUID,
+                                        LabelsAndEventClasses::PROCESS_ID_LABEL,
+                                        readableData,
+                                        offset);
+
     // Well-known types
     // Layer
     VerifyTimelineLabelBinaryPacketData(LabelsAndEventClasses::LAYER_GUID,