IVGCVSW-4070 Implement "send post-optimized network structure"
authorNarumol Prangnawarat <narumol.prangnawarat@arm.com>
Fri, 22 Nov 2019 11:26:06 +0000 (11:26 +0000)
committerJim Flynn Arm <jim.flynn@arm.com>
Fri, 29 Nov 2019 17:01:45 +0000 (17:01 +0000)
 * Send post-optimisation network structure if profiling service is enabled
 * Refactor TimelineUtilityMethods
 * Fix RecordEvent to link eventGuid with eventClassGuid
 * Add common types and guid to LabelsAndEventClasses
 * Add CreateRelationship to TimelineUtilityMethods
 * Add CreateTypedEntity to TimelineUtilityMethods
 * Add MarkEntityWithType to TimelineUtilityMethods
 * Move VerifyTimeline functions to ProfilingTestUtils
 * Post-optimisation network structure unit tests to Ref, Cl, Neon

Signed-off-by: Narumol Prangnawarat <narumol.prangnawarat@arm.com>
Change-Id: I0194f2037c236450c912f4c3cb11e46b80c0f512

14 files changed:
Android.mk
CMakeLists.txt
src/armnn/LoadedNetwork.cpp
src/armnn/test/RuntimeTests.cpp
src/backends/cl/test/ClRuntimeTests.cpp
src/backends/neon/test/NeonRuntimeTests.cpp
src/profiling/LabelsAndEventClasses.cpp
src/profiling/LabelsAndEventClasses.hpp
src/profiling/ProfilingService.hpp
src/profiling/TimelineUtilityMethods.cpp
src/profiling/TimelineUtilityMethods.hpp
src/profiling/test/ProfilingTestUtils.cpp [new file with mode: 0644]
src/profiling/test/ProfilingTestUtils.hpp [new file with mode: 0644]
src/profiling/test/TimelineUtilityMethodsTests.cpp

index d755d20..4dc023e 100644 (file)
@@ -199,6 +199,7 @@ LOCAL_SRC_FILES := \
         src/profiling/SendCounterPacket.cpp \
         src/profiling/SendTimelinePacket.cpp \
         src/profiling/SocketProfilingConnection.cpp \
+        src/profiling/TimelinePacketWriterFactory.cpp \
         src/profiling/TimelineUtilityMethods.cpp
 
 LOCAL_STATIC_LIBRARIES := \
@@ -330,7 +331,8 @@ LOCAL_SRC_FILES := \
         src/armnn/test/TensorTest.cpp \
         src/armnn/test/TestUtils.cpp \
         src/armnn/test/UnitTests.cpp \
-        src/armnn/test/UtilsTests.cpp
+        src/armnn/test/UtilsTests.cpp \
+        src/profiling/test/ProfilingTestUtils.cpp
 
 ifeq ($(ARMNN_REF_ENABLED),1)
 LOCAL_SRC_FILES += \
index ad9e9ee..7b6e1ab 100644 (file)
@@ -632,6 +632,8 @@ if(BUILD_UNIT_TESTS)
         src/profiling/test/ProfilingGuidTest.cpp
         src/profiling/test/ProfilingTests.cpp
         src/profiling/test/ProfilingTests.hpp
+        src/profiling/test/ProfilingTestUtils.cpp
+        src/profiling/test/ProfilingTestUtils.hpp
         src/profiling/test/SendCounterPacketTests.cpp
         src/profiling/test/SendCounterPacketTests.hpp
         src/profiling/test/SendTimelinePacketTests.cpp
index e9a3545..36a56b0 100644 (file)
@@ -17,6 +17,9 @@
 #include <backendsCommon/IMemoryManager.hpp>
 #include <backendsCommon/MemCopyWorkload.hpp>
 #include <backendsCommon/MemSyncWorkload.hpp>
+#include <LabelsAndEventClasses.hpp>
+#include <ProfilingService.hpp>
+#include <TimelineUtilityMethods.hpp>
 
 #include <boost/polymorphic_cast.hpp>
 #include <boost/assert.hpp>
@@ -27,6 +30,7 @@ namespace armnn
 {
 
 using namespace std;
+using namespace armnn::profiling;
 
 namespace
 {
@@ -39,6 +43,43 @@ std::string ToErrorMessage(const char * prefix, const ExceptionType & error)
     return ss.str();
 }
 
+void AddLayerStructure(std::unique_ptr<TimelineUtilityMethods>& timelineUtils,
+                       const Layer& layer,
+                       ProfilingGuid networkGuid)
+{
+    // Add layer to the post-optimisation network structure
+    std::string layerName = layer.GetNameStr().empty() ? "<Unnamed>" : layer.GetNameStr();
+    timelineUtils->CreateNamedTypedChildEntity(layer.GetGuid(),
+                                               networkGuid,
+                                               layerName,
+                                               LabelsAndEventClasses::LAYER_GUID);
+    for (auto&& input : layer.GetInputSlots())
+    {
+        const IOutputSlot* source = input.GetConnectedOutputSlot();
+        BOOST_ASSERT(source != NULL);
+        timelineUtils->CreateConnectionRelationship(ProfilingRelationshipType::RetentionLink,
+                                                    source->GetOwningLayerGuid(),
+                                                    layer.GetGuid());
+    }
+}
+
+void AddWorkloadStructure(std::unique_ptr<TimelineUtilityMethods>& timelineUtils,
+                          std::unique_ptr<IWorkload>& workload,
+                          const Layer& layer)
+{
+    // Add workload to the post-optimisation network structure
+    timelineUtils->CreateTypedEntity(workload->GetGuid(), LabelsAndEventClasses::WORKLOAD_GUID);
+    timelineUtils->MarkEntityWithLabel(workload->GetGuid(),
+                                       layer.GetBackendId().Get(),
+                                       LabelsAndEventClasses::BACKENDID_GUID);
+
+    // Link the workload to the layer
+    timelineUtils->CreateRelationship(ProfilingRelationshipType::RetentionLink,
+                                      layer.GetGuid(),
+                                      workload->GetGuid());
+
+}
+
 } // anonymous
 
 std::unique_ptr<LoadedNetwork> LoadedNetwork::MakeLoadedNetwork(std::unique_ptr<OptimizedNetwork> net,
@@ -149,9 +190,22 @@ LoadedNetwork::LoadedNetwork(std::unique_ptr<OptimizedNetwork> net,
         }
     }
 
+    ProfilingGuid networkGuid = m_OptimizedNetwork->GetGuid();
+    std::unique_ptr<TimelineUtilityMethods> timelineUtils = TimelineUtilityMethods::GetTimelineUtils();
+    if (timelineUtils)
+    {
+        timelineUtils->CreateTypedEntity(networkGuid, LabelsAndEventClasses::NETWORK_GUID);
+    }
+
     //Then create workloads.
     for (auto&& layer : order)
     {
+        if (timelineUtils)
+        {
+            // Add layer to the post-optimisation network structure
+            AddLayerStructure(timelineUtils, *layer, networkGuid);
+        }
+
         const IWorkloadFactory& workloadFactory = GetWorkloadFactory(*layer);
 
         switch (layer->GetType())
@@ -168,13 +222,20 @@ LoadedNetwork::LoadedNetwork(std::unique_ptr<OptimizedNetwork> net,
 
                 if (!workload)
                 {
-                    const char* const layerName = layer->GetNameStr().length() != 0 ? layer->GetName() : "<Unnamed>";
+                    const char* const layerName =
+                        layer->GetNameStr().length() != 0 ? layer->GetName() : "<Unnamed>";
                     throw InvalidArgumentException(boost::str(
                         boost::format("No workload created for layer (name: '%1%' type: '%2%') (compute '%3%')")
                         % layerName % static_cast<int>(layer->GetType()) % layer->GetBackendId().Get()
                     ));
                 }
 
+                if (timelineUtils)
+                {
+                    // Add workload to the post-optimisation network structure
+                    AddWorkloadStructure(timelineUtils, workload, *layer);
+                }
+
                 m_WorkloadQueue.push_back(move(workload));
                 // release the constant data in the layer..
                 layer->ReleaseConstantData();
@@ -183,6 +244,12 @@ LoadedNetwork::LoadedNetwork(std::unique_ptr<OptimizedNetwork> net,
         }
     }
 
+    if (timelineUtils)
+    {
+        // Commit to send the post-optimisation network structure
+        timelineUtils->Commit();
+    }
+
     // Set up memory.
     m_OptimizedNetwork->GetGraph().AllocateDynamicBuffers();
 
index 998808c..f84f73d 100644 (file)
@@ -9,6 +9,9 @@
 #include <Runtime.hpp>
 #include <armnn/TypesUtils.hpp>
 
+#include <LabelsAndEventClasses.hpp>
+#include <test/ProfilingTestUtils.hpp>
+
 #include <HeapProfiling.hpp>
 #include <LeakChecking.hpp>
 
@@ -17,6 +20,7 @@
 #endif
 
 #include <boost/test/unit_test.hpp>
+#include "RuntimeTests.hpp"
 
 namespace armnn
 {
@@ -284,4 +288,360 @@ BOOST_AUTO_TEST_CASE(IVGCVSW_1929_QuantizedSoftmaxIssue)
     BOOST_TEST(!optNet);
 }
 
+BOOST_AUTO_TEST_CASE(ProfilingDisable)
+{
+    using namespace armnn;
+
+    // Create runtime in which the test will run
+    armnn::IRuntime::CreationOptions options;
+    armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
+
+    // build up the structure of the network
+    INetworkPtr net(INetwork::Create());
+
+    IConnectableLayer* input = net->AddInputLayer(0);
+
+    // This layer configuration isn't supported by CpuAcc, should fall back to CpuRef.
+    NormalizationDescriptor descriptor;
+    IConnectableLayer* normalize = net->AddNormalizationLayer(descriptor);
+
+    IConnectableLayer* output = net->AddOutputLayer(0);
+
+    input->GetOutputSlot(0).Connect(normalize->GetInputSlot(0));
+    normalize->GetOutputSlot(0).Connect(output->GetInputSlot(0));
+
+    input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 4 }, DataType::Float32));
+    normalize->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 4 }, DataType::Float32));
+
+    // optimize the network
+    std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
+    IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
+
+    // Load it into the runtime. It should succeed.
+    armnn::NetworkId netId;
+    BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet)) == Status::Success);
+
+    profiling::ProfilingServiceRuntimeHelper profilingServiceHelper;
+    profiling::BufferManager& bufferManager = profilingServiceHelper.GetProfilingBufferManager();
+    auto readableBuffer = bufferManager.GetReadableBuffer();
+
+    // Profiling is not enabled, the post-optimisation structure should not be created
+    BOOST_TEST(!readableBuffer);
+}
+
+BOOST_AUTO_TEST_CASE(ProfilingEnableCpuRef)
+{
+    using namespace armnn;
+    using namespace armnn::profiling;
+
+    // Create runtime in which the test will run
+    armnn::IRuntime::CreationOptions options;
+    options.m_ProfilingOptions.m_EnableProfiling = true;
+    armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
+
+    // build up the structure of the network
+    INetworkPtr net(INetwork::Create());
+
+    IConnectableLayer* input = net->AddInputLayer(0, "input");
+
+    NormalizationDescriptor descriptor;
+    IConnectableLayer* normalize = net->AddNormalizationLayer(descriptor, "normalization");
+
+    IConnectableLayer* output = net->AddOutputLayer(0, "output");
+
+    input->GetOutputSlot(0).Connect(normalize->GetInputSlot(0));
+    normalize->GetOutputSlot(0).Connect(output->GetInputSlot(0));
+
+    input->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 4 }, DataType::Float32));
+    normalize->GetOutputSlot(0).SetTensorInfo(TensorInfo({ 1, 1, 4, 4 }, DataType::Float32));
+
+    // optimize the network
+    std::vector<armnn::BackendId> backends = { armnn::Compute::CpuRef };
+    IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
+
+    ProfilingGuid optNetGuid = optNet->GetGuid();
+
+    // Load it into the runtime. It should succeed.
+    armnn::NetworkId netId;
+    BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet)) == Status::Success);
+
+    profiling::ProfilingServiceRuntimeHelper profilingServiceHelper;
+    profiling::BufferManager& bufferManager = profilingServiceHelper.GetProfilingBufferManager();
+    auto readableBuffer = bufferManager.GetReadableBuffer();
+
+    // Profiling is enabled, the post-optimisation structure should be created
+    BOOST_CHECK(readableBuffer != nullptr);
+
+    unsigned int size = readableBuffer->GetSize();
+    BOOST_CHECK(size == 1356);
+
+    const unsigned char* readableData = readableBuffer->GetReadableData();
+    BOOST_CHECK(readableData != nullptr);
+
+    unsigned int offset = 0;
+
+    // Post-optimisation network
+    // Network entity
+    VerifyTimelineEntityBinaryPacket(optNetGuid, readableData, offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           optNetGuid,
+                                           LabelsAndEventClasses::NETWORK_GUID,
+                                           readableData,
+                                           offset);
+
+    // Type label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+
+    // Input layer
+    // Input layer entity
+    VerifyTimelineEntityBinaryPacket(input->GetGuid(), readableData, offset);
+
+    // Name Entity
+    VerifyTimelineLabelBinaryPacket(EmptyOptional(), "input", readableData, offset);
+
+    // Entity - Name relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           input->GetGuid(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Name label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::NAME_GUID,
+                                           readableData,
+                                           offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           input->GetGuid(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Type label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+
+    // Network - Input layer relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                           EmptyOptional(),
+                                           optNetGuid,
+                                           input->GetGuid(),
+                                           readableData,
+                                           offset);
+
+    // Normalization layer
+    // Normalization layer entity
+    VerifyTimelineEntityBinaryPacket(normalize->GetGuid(), readableData, offset);
+
+    // Name entity
+    VerifyTimelineLabelBinaryPacket(EmptyOptional(), "normalization", readableData, offset);
+
+    // Entity - Name relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           normalize->GetGuid(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Name label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::NAME_GUID,
+                                           readableData,
+                                           offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           normalize->GetGuid(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Type label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+
+    // Network - Normalize layer relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                           EmptyOptional(),
+                                           optNetGuid,
+                                           normalize->GetGuid(),
+                                           readableData,
+                                           offset);
+
+    // Input layer - Normalize layer relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                           EmptyOptional(),
+                                           input->GetGuid(),
+                                           normalize->GetGuid(),
+                                           readableData,
+                                           offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::CONNECTION_GUID,
+                                           readableData,
+                                           offset);
+
+    // Type label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+
+    // Normalization workload
+    // Normalization workload entity
+    VerifyTimelineEntityBinaryPacket(EmptyOptional(), readableData, offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Type label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+
+    // BackendId entity
+    VerifyTimelineLabelBinaryPacket(EmptyOptional(), "CpuRef", readableData, offset);
+
+    // Entity - BackendId relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // BackendId label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::BACKENDID_GUID,
+                                           readableData,
+                                           offset);
+
+    // Normalize layer - Normalize workload relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                           EmptyOptional(),
+                                           normalize->GetGuid(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Output layer
+    // Output layer entity
+    VerifyTimelineEntityBinaryPacket(output->GetGuid(), readableData, offset);
+
+    // Name entity
+    VerifyTimelineLabelBinaryPacket(EmptyOptional(), "output", readableData, offset);
+
+    // Entity - Name relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           output->GetGuid(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Name label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::NAME_GUID,
+                                           readableData,
+                                           offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           output->GetGuid(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Type label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+
+    // Network - Output layer relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                           EmptyOptional(),
+                                           optNetGuid,
+                                           output->GetGuid(),
+                                           readableData,
+                                           offset);
+
+    // Normalize layer - Output layer relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                           EmptyOptional(),
+                                           normalize->GetGuid(),
+                                           output->GetGuid(),
+                                           readableData,
+                                           offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::CONNECTION_GUID,
+                                           readableData,
+                                           offset);
+
+    // Type label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+    
+    bufferManager.MarkRead(readableBuffer);
+}
+
+BOOST_AUTO_TEST_CASE(ProfilingPostOptimisationStructureCpuRef)
+{
+    VerifyPostOptimisationStructureTestImpl(armnn::Compute::CpuRef);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
index c6da261..9aa3617 100644 (file)
@@ -8,6 +8,7 @@
 #include <LeakChecking.hpp>
 
 #include <backendsCommon/test/RuntimeTestImpl.hpp>
+#include <test/ProfilingTestUtils.hpp>
 
 #include <boost/core/ignore_unused.hpp>
 #include <boost/test/unit_test.hpp>
@@ -148,4 +149,9 @@ BOOST_AUTO_TEST_CASE(RuntimeMemoryUsage)
 }
 #endif
 
+BOOST_AUTO_TEST_CASE(ProfilingPostOptimisationStructureGpuAcc)
+{
+    VerifyPostOptimisationStructureTestImpl(armnn::Compute::GpuAcc);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
index 129cd1a..2aaf422 100644 (file)
@@ -8,6 +8,7 @@
 #include <LeakChecking.hpp>
 
 #include <backendsCommon/test/RuntimeTestImpl.hpp>
+#include <test/ProfilingTestUtils.hpp>
 
 #include <boost/test/unit_test.hpp>
 
@@ -65,4 +66,9 @@ BOOST_AUTO_TEST_CASE(RuntimeMemoryLeaksCpuAcc)
 }
 #endif
 
+BOOST_AUTO_TEST_CASE(ProfilingPostOptimisationStructureCpuAcc)
+{
+    VerifyPostOptimisationStructureTestImpl(armnn::Compute::CpuAcc);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file
index a00562d..2424104 100644 (file)
@@ -17,6 +17,7 @@ ProfilingGuidGenerator LabelsAndEventClasses::m_GuidGenerator;
 std::string LabelsAndEventClasses::NAME_LABEL("name");
 std::string LabelsAndEventClasses::TYPE_LABEL("type");
 std::string LabelsAndEventClasses::INDEX_LABEL("index");
+std::string LabelsAndEventClasses::BACKENDID_LABEL("backendId");
 
 ProfilingStaticGuid LabelsAndEventClasses::NAME_GUID(
     m_GuidGenerator.GenerateStaticId(LabelsAndEventClasses::NAME_LABEL));
@@ -24,6 +25,23 @@ ProfilingStaticGuid LabelsAndEventClasses::TYPE_GUID(
     m_GuidGenerator.GenerateStaticId(LabelsAndEventClasses::TYPE_LABEL));
 ProfilingStaticGuid LabelsAndEventClasses::INDEX_GUID(
     m_GuidGenerator.GenerateStaticId(LabelsAndEventClasses::INDEX_LABEL));
+ProfilingStaticGuid LabelsAndEventClasses::BACKENDID_GUID(
+    m_GuidGenerator.GenerateStaticId(LabelsAndEventClasses::BACKENDID_LABEL));
+
+// Common types
+std::string LabelsAndEventClasses::LAYER("layer");
+std::string LabelsAndEventClasses::WORKLOAD("workload");
+std::string LabelsAndEventClasses::NETWORK("network");
+std::string LabelsAndEventClasses::CONNECTION("connection");
+
+ProfilingStaticGuid LabelsAndEventClasses::LAYER_GUID(
+    m_GuidGenerator.GenerateStaticId(LabelsAndEventClasses::LAYER));
+ProfilingStaticGuid LabelsAndEventClasses::WORKLOAD_GUID(
+    m_GuidGenerator.GenerateStaticId(LabelsAndEventClasses::WORKLOAD));
+ProfilingStaticGuid LabelsAndEventClasses::NETWORK_GUID(
+    m_GuidGenerator.GenerateStaticId(LabelsAndEventClasses::NETWORK));
+ProfilingStaticGuid LabelsAndEventClasses::CONNECTION_GUID(
+    m_GuidGenerator.GenerateStaticId(LabelsAndEventClasses::CONNECTION));
 
 // Event Class GUIDs
 ProfilingStaticGuid LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS(
index daa33ad..c2082dd 100644 (file)
@@ -22,9 +22,21 @@ public:
     static std::string NAME_LABEL;
     static std::string TYPE_LABEL;
     static std::string INDEX_LABEL;
+    static std::string BACKENDID_LABEL;
     static ProfilingStaticGuid NAME_GUID;
     static ProfilingStaticGuid TYPE_GUID;
     static ProfilingStaticGuid INDEX_GUID;
+    static ProfilingStaticGuid BACKENDID_GUID;
+
+    // Common types
+    static std::string LAYER;
+    static std::string WORKLOAD;
+    static std::string NETWORK;
+    static std::string CONNECTION;
+    static ProfilingStaticGuid LAYER_GUID;
+    static ProfilingStaticGuid WORKLOAD_GUID;
+    static ProfilingStaticGuid NETWORK_GUID;
+    static ProfilingStaticGuid CONNECTION_GUID;
 
     // Event Class GUIDs
     static ProfilingStaticGuid ARMNN_PROFILING_SOL_EVENT_CLASS;
index 9fc642f..f9b057c 100644 (file)
@@ -77,6 +77,9 @@ public:
 
     std::unique_ptr<ISendTimelinePacket> GetSendTimelinePacket() const;
 
+    /// Check if the profiling is enabled
+    bool IsEnabled() { return m_Options.m_EnableProfiling; }
+
 private:
     // Copy/move constructors/destructors and copy/move assignment operators are deleted
     ProfilingService(const ProfilingService&) = delete;
@@ -201,6 +204,11 @@ protected:
     {
         return instance.m_SendCounterPacket.WaitForPacketSent(timeout);
     }
+
+    BufferManager& GetBufferManager(ProfilingService& instance)
+    {
+        return instance.m_BufferManager;
+    }
 };
 
 } // namespace profiling
index c1ae610..d540c59 100644 (file)
@@ -13,25 +13,60 @@ namespace armnn
 namespace profiling
 {
 
+std::unique_ptr<TimelineUtilityMethods> TimelineUtilityMethods::GetTimelineUtils()
+{
+    if (ProfilingService::Instance().IsEnabled())
+    {
+        std::unique_ptr<ISendTimelinePacket> sendTimelinepacket = ProfilingService::Instance().GetSendTimelinePacket();
+        return std::make_unique<TimelineUtilityMethods>(sendTimelinepacket);
+    }
+    else
+    {
+        std::unique_ptr<TimelineUtilityMethods> empty;
+        return empty;
+    }
+}
+
+
 void TimelineUtilityMethods::SendWellKnownLabelsAndEventClasses()
 {
     // Send the "name" label, this call throws in case of error
-    m_SendTimelinePacket.SendTimelineLabelBinaryPacket(LabelsAndEventClasses::NAME_GUID,
-                                                       LabelsAndEventClasses::NAME_LABEL);
+    m_SendTimelinePacket->SendTimelineLabelBinaryPacket(LabelsAndEventClasses::NAME_GUID,
+                                                        LabelsAndEventClasses::NAME_LABEL);
 
     // Send the "type" label, this call throws in case of error
-    m_SendTimelinePacket.SendTimelineLabelBinaryPacket(LabelsAndEventClasses::TYPE_GUID,
-                                                       LabelsAndEventClasses::TYPE_LABEL);
+    m_SendTimelinePacket->SendTimelineLabelBinaryPacket(LabelsAndEventClasses::TYPE_GUID,
+                                                        LabelsAndEventClasses::TYPE_LABEL);
 
     // Send the "index" label, this call throws in case of error
-    m_SendTimelinePacket.SendTimelineLabelBinaryPacket(LabelsAndEventClasses::INDEX_GUID,
-                                                       LabelsAndEventClasses::INDEX_LABEL);
+    m_SendTimelinePacket->SendTimelineLabelBinaryPacket(LabelsAndEventClasses::INDEX_GUID,
+                                                        LabelsAndEventClasses::INDEX_LABEL);
+
+    // Send the "backendId" label, this call throws in case of error
+    m_SendTimelinePacket->SendTimelineLabelBinaryPacket(LabelsAndEventClasses::BACKENDID_GUID,
+                                                        LabelsAndEventClasses::BACKENDID_LABEL);
+
+    // Send the "layer" label, this call throws in case of error
+    m_SendTimelinePacket->SendTimelineLabelBinaryPacket(LabelsAndEventClasses::LAYER_GUID,
+                                                        LabelsAndEventClasses::LAYER);
+
+    // Send the "workload" label, this call throws in case of error
+    m_SendTimelinePacket->SendTimelineLabelBinaryPacket(LabelsAndEventClasses::WORKLOAD_GUID,
+                                                        LabelsAndEventClasses::WORKLOAD);
+
+    // Send the "network" label, this call throws in case of error
+    m_SendTimelinePacket->SendTimelineLabelBinaryPacket(LabelsAndEventClasses::NETWORK_GUID,
+                                                        LabelsAndEventClasses::NETWORK);
+
+    // Send the "connection" label, this call throws in case of error
+    m_SendTimelinePacket->SendTimelineLabelBinaryPacket(LabelsAndEventClasses::CONNECTION_GUID,
+                                                        LabelsAndEventClasses::CONNECTION);
 
     // Send the "start of life" event class, this call throws in case of error
-    m_SendTimelinePacket.SendTimelineEventClassBinaryPacket(LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS);
+    m_SendTimelinePacket->SendTimelineEventClassBinaryPacket(LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS);
 
     // Send the "end of life" event class, this call throws in case of error
-    m_SendTimelinePacket.SendTimelineEventClassBinaryPacket(LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS);
+    m_SendTimelinePacket->SendTimelineEventClassBinaryPacket(LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS);
 }
 
 ProfilingDynamicGuid TimelineUtilityMethods::CreateNamedTypedEntity(const std::string& name, const std::string& type)
@@ -56,7 +91,7 @@ ProfilingDynamicGuid TimelineUtilityMethods::CreateNamedTypedEntity(const std::s
     return entityGuid;
 }
 
-void TimelineUtilityMethods::CreateNamedTypedEntity(ProfilingDynamicGuid entityGuid,
+void TimelineUtilityMethods::CreateNamedTypedEntity(ProfilingGuid entityGuid,
                                                     const std::string& name,
                                                     const std::string& type)
 {
@@ -73,7 +108,7 @@ void TimelineUtilityMethods::CreateNamedTypedEntity(ProfilingDynamicGuid entityG
     }
 
     // Send Entity Binary Packet of the entity to the external profiling service
-    m_SendTimelinePacket.SendTimelineEntityBinaryPacket(entityGuid);
+    m_SendTimelinePacket->SendTimelineEntityBinaryPacket(entityGuid);
 
     // Create name entity and send the relationship of the entity with the given name
     NameEntity(entityGuid, name);
@@ -82,6 +117,26 @@ void TimelineUtilityMethods::CreateNamedTypedEntity(ProfilingDynamicGuid entityG
     TypeEntity(entityGuid, type);
 }
 
+void TimelineUtilityMethods::CreateNamedTypedEntity(ProfilingGuid entityGuid,
+                                                    const std::string& name,
+                                                    ProfilingStaticGuid typeGuid)
+{
+    // Check that the entity name is valid
+    if (name.empty())
+    {
+        throw InvalidArgumentException("Invalid entity name, the entity name cannot be empty");
+    }
+
+    // Send Entity Binary Packet of the entity to the external profiling service
+    m_SendTimelinePacket->SendTimelineEntityBinaryPacket(entityGuid);
+
+    // Create name entity and send the relationship of the entity with the given name
+    NameEntity(entityGuid, name);
+
+    // Create type entity and send the relationship of the entity with the given type
+    MarkEntityWithType(entityGuid, typeGuid);
+}
+
 ProfilingStaticGuid TimelineUtilityMethods::DeclareLabel(const std::string& labelName)
 {
     // Check that the label name is valid
@@ -95,52 +150,74 @@ ProfilingStaticGuid TimelineUtilityMethods::DeclareLabel(const std::string& labe
     ProfilingStaticGuid labelGuid = ProfilingService::Instance().GenerateStaticId(labelName);
 
     // Send the new label to the external profiling service, this call throws in case of error
-    m_SendTimelinePacket.SendTimelineLabelBinaryPacket(labelGuid, labelName);
+    m_SendTimelinePacket->SendTimelineLabelBinaryPacket(labelGuid, labelName);
 
     return labelGuid;
 }
 
-void TimelineUtilityMethods::CreateTypedLabel(ProfilingGuid entityGuid,
-                                              const std::string& entityName,
-                                              ProfilingStaticGuid labelTypeGuid)
+void TimelineUtilityMethods::MarkEntityWithLabel(ProfilingGuid entityGuid,
+                                                 const std::string& labelName,
+                                                 ProfilingStaticGuid labelTypeGuid)
 {
-    // Check that the entity name is valid
-    if (entityName.empty())
+    // Check that the label name is valid
+    if (labelName.empty())
     {
-        // The entity name is invalid
+        // The label name is invalid
         throw InvalidArgumentException("Invalid entity name, the entity name cannot be empty");
     }
 
-    // Declare a label with the entity's name, this call throws in case of error
-    ProfilingStaticGuid labelGuid = DeclareLabel(entityName);
+    // Declare a label with the label's name, this call throws in case of error
+    ProfilingStaticGuid labelGuid = DeclareLabel(labelName);
+
+    // Generate a GUID for the label relationship
+    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,
+                                                               relationshipGuid,
+                                                               entityGuid,
+                                                               labelGuid);
+
+    // Generate a GUID for the label relationship
+    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,
+                                                               relationshipLabelGuid,
+                                                               relationshipGuid,
+                                                               labelTypeGuid);
+}
 
+void TimelineUtilityMethods::MarkEntityWithType(ProfilingGuid entityGuid,
+                                                ProfilingStaticGuid typeNameGuid)
+{
     // Generate a GUID for the label relationship
     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,
-                                                              relationshipGuid,
-                                                              entityGuid,
-                                                              labelGuid);
+    m_SendTimelinePacket->SendTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                                               relationshipGuid,
+                                                               entityGuid,
+                                                               typeNameGuid);
 
     // Generate a GUID for the label relationship
     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,
-                                                              relationshipLabelGuid,
-                                                              relationshipGuid,
-                                                              labelTypeGuid);
+    m_SendTimelinePacket->SendTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                                               relationshipLabelGuid,
+                                                               relationshipGuid,
+                                                               LabelsAndEventClasses::TYPE_GUID);
 }
 
 void TimelineUtilityMethods::NameEntity(ProfilingGuid entityGuid, const std::string& name)
 {
-    CreateTypedLabel(entityGuid, name, LabelsAndEventClasses::NAME_GUID);
+    MarkEntityWithLabel(entityGuid, name, LabelsAndEventClasses::NAME_GUID);
 }
 
 void TimelineUtilityMethods::TypeEntity(ProfilingGuid entityGuid, const std::string& type)
 {
-    CreateTypedLabel(entityGuid, type, LabelsAndEventClasses::TYPE_GUID);
+    MarkEntityWithLabel(entityGuid, type, LabelsAndEventClasses::TYPE_GUID);
 }
 
 ProfilingDynamicGuid TimelineUtilityMethods::CreateNamedTypedChildEntity(ProfilingGuid parentEntityGuid,
@@ -168,15 +245,15 @@ ProfilingDynamicGuid TimelineUtilityMethods::CreateNamedTypedChildEntity(Profili
     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);
+    m_SendTimelinePacket->SendTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                                               retentionLinkGuid,
+                                                               parentEntityGuid,
+                                                               childEntityGuid);
 
     return childEntityGuid;
 }
 
-void TimelineUtilityMethods::CreateNamedTypedChildEntity(ProfilingDynamicGuid childEntityGuid,
+void TimelineUtilityMethods::CreateNamedTypedChildEntity(ProfilingGuid childEntityGuid,
                                                          ProfilingGuid parentEntityGuid,
                                                          const std::string& entityName,
                                                          const std::string& entityType)
@@ -202,10 +279,76 @@ void TimelineUtilityMethods::CreateNamedTypedChildEntity(ProfilingDynamicGuid ch
     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);
+    m_SendTimelinePacket->SendTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                                               retentionLinkGuid,
+                                                               parentEntityGuid,
+                                                               childEntityGuid);
+}
+
+void TimelineUtilityMethods::CreateNamedTypedChildEntity(ProfilingGuid childEntityGuid,
+                                                         ProfilingGuid parentEntityGuid,
+                                                         const std::string& entityName,
+                                                         ProfilingStaticGuid typeGuid)
+{
+    // 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");
+    }
+
+    // Create a named type entity from the given guid, name and type, this call throws in case of error
+    CreateNamedTypedEntity(childEntityGuid, entityName, typeGuid);
+
+    // 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);
+}
+
+ProfilingDynamicGuid TimelineUtilityMethods::CreateRelationship(ProfilingRelationshipType relationshipType,
+                                                                ProfilingGuid headGuid,
+                                                                ProfilingGuid tailGuid)
+{
+    // Generate a GUID for the relationship
+    ProfilingDynamicGuid relationshipGuid = ProfilingService::Instance().NextGuid();
+
+    // Send the new retention link to the external profiling service, this call throws in case of error
+    m_SendTimelinePacket->SendTimelineRelationshipBinaryPacket(relationshipType,
+                                                               relationshipGuid,
+                                                               headGuid,
+                                                               tailGuid);
+    return relationshipGuid;
+}
+
+ProfilingDynamicGuid TimelineUtilityMethods::CreateConnectionRelationship(ProfilingRelationshipType relationshipType,
+                                                                          ProfilingGuid headGuid,
+                                                                          ProfilingGuid tailGuid)
+{
+    // Generate a GUID for the relationship
+    ProfilingDynamicGuid relationshipGuid = ProfilingService::Instance().NextGuid();
+
+    // Send the new retention link to the external profiling service, this call throws in case of error
+    m_SendTimelinePacket->SendTimelineRelationshipBinaryPacket(relationshipType,
+                                                               relationshipGuid,
+                                                               headGuid,
+                                                               tailGuid);
+
+    MarkEntityWithType(relationshipGuid, LabelsAndEventClasses::CONNECTION_GUID);
+    return relationshipGuid;
+}
+
+void TimelineUtilityMethods::CreateTypedEntity(ProfilingGuid entityGuid, ProfilingStaticGuid entityTypeGuid)
+{
+    // Send Entity Binary Packet of the entity to the external profiling service
+    m_SendTimelinePacket->SendTimelineEntityBinaryPacket(entityGuid);
+
+    // Create type entity and send the relationship of the entity with the given type
+    MarkEntityWithType(entityGuid, entityTypeGuid);
 }
 
 ProfilingDynamicGuid TimelineUtilityMethods::RecordEvent(ProfilingGuid entityGuid, ProfilingStaticGuid eventClassGuid)
@@ -220,25 +363,25 @@ ProfilingDynamicGuid TimelineUtilityMethods::RecordEvent(ProfilingGuid entityGui
     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);
+    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);
+    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);
+    m_SendTimelinePacket->SendTimelineRelationshipBinaryPacket(ProfilingRelationshipType::DataLink,
+                                                               eventClassLinkId,
+                                                               eventGuid,
+                                                               eventClassGuid);
 
     return eventGuid;
 }
index 3683ed3..8e07161 100644 (file)
@@ -17,18 +17,34 @@ namespace profiling
 class TimelineUtilityMethods
 {
 public:
-    TimelineUtilityMethods(ISendTimelinePacket& sendTimelinePacket)
-        : m_SendTimelinePacket(sendTimelinePacket)
-    {}
+
+    // static factory method which will return a pointer to a timelie utility methods
+    // object if profiling is enabled. Otherwise will return a null unique_ptr
+    static std::unique_ptr<TimelineUtilityMethods> GetTimelineUtils();
+
+    TimelineUtilityMethods(std::unique_ptr<ISendTimelinePacket>& sendTimelinePacket)
+        : m_SendTimelinePacket(std::move(sendTimelinePacket)) {}
+
+    TimelineUtilityMethods(TimelineUtilityMethods&& other)
+        : m_SendTimelinePacket(std::move(other.m_SendTimelinePacket)) {}
+
+    TimelineUtilityMethods(const TimelineUtilityMethods& other) = delete;
+
+    TimelineUtilityMethods& operator=(const TimelineUtilityMethods& other) = delete;
+
+    TimelineUtilityMethods& operator=(TimelineUtilityMethods&& other) = default;
+
     ~TimelineUtilityMethods() = default;
 
     void SendWellKnownLabelsAndEventClasses();
 
     ProfilingDynamicGuid CreateNamedTypedEntity(const std::string& name, const std::string& type);
 
-    void CreateNamedTypedEntity(ProfilingDynamicGuid entityGuid, const std::string& name, const std::string& type);
+    void CreateNamedTypedEntity(ProfilingGuid entityGuid, const std::string& name, const std::string& type);
+
+    void CreateNamedTypedEntity(ProfilingGuid entityGuid, const std::string& name, ProfilingStaticGuid typeGuid);
 
-    void CreateTypedLabel(ProfilingGuid entityGuid, const std::string& entityName, ProfilingStaticGuid labelTypeGuid);
+    void MarkEntityWithLabel(ProfilingGuid entityGuid, const std::string &labelName, ProfilingStaticGuid labelLinkGuid);
 
     ProfilingStaticGuid DeclareLabel(const std::string& labelName);
 
@@ -40,15 +56,34 @@ public:
                                                      const std::string& entityName,
                                                      const std::string& entityType);
 
-    void CreateNamedTypedChildEntity(ProfilingDynamicGuid entityGuid,
+    void CreateNamedTypedChildEntity(ProfilingGuid entityGuid,
                                      ProfilingGuid parentEntityGuid,
                                      const std::string& entityName,
                                      const std::string& entityType);
 
+    void CreateNamedTypedChildEntity(ProfilingGuid entityGuid,
+                                     ProfilingGuid parentEntityGuid,
+                                     const std::string& entityName,
+                                     ProfilingStaticGuid typeGuid);
+
+    ProfilingDynamicGuid CreateRelationship(ProfilingRelationshipType relationshipType,
+                                            ProfilingGuid headGuid,
+                                            ProfilingGuid tailGuid);
+
+    ProfilingDynamicGuid CreateConnectionRelationship(ProfilingRelationshipType relationshipType,
+                                                      ProfilingGuid headGuid,
+                                                      ProfilingGuid tailGuid);
+
+    void CreateTypedEntity(ProfilingGuid entityGuid, ProfilingStaticGuid typeGuid);
+
+    void MarkEntityWithType(ProfilingGuid entityGuid, ProfilingStaticGuid typeNameGuid);
+
     ProfilingDynamicGuid RecordEvent(ProfilingGuid entityGuid, ProfilingStaticGuid eventClassGuid);
 
+    void Commit() { m_SendTimelinePacket->Commit(); }
+
 private:
-    ISendTimelinePacket& m_SendTimelinePacket;
+    std::unique_ptr<ISendTimelinePacket> m_SendTimelinePacket;
 };
 
 } // namespace profiling
diff --git a/src/profiling/test/ProfilingTestUtils.cpp b/src/profiling/test/ProfilingTestUtils.cpp
new file mode 100644 (file)
index 0000000..7f18ef3
--- /dev/null
@@ -0,0 +1,818 @@
+//
+// Copyright Â© 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "ProfilingTestUtils.hpp"
+#include "ProfilingUtils.hpp"
+
+#include <armnn/Descriptors.hpp>
+#include <LabelsAndEventClasses.hpp>
+#include <ProfilingService.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+inline unsigned int OffsetToNextWord(unsigned int numberOfBytes)
+{
+    unsigned int uint32_t_size = sizeof(uint32_t);
+
+    unsigned int remainder = numberOfBytes % uint32_t_size;
+    if (remainder == 0)
+    {
+        return numberOfBytes;
+    }
+
+    return numberOfBytes + uint32_t_size - remainder;
+}
+
+void VerifyTimelineLabelBinaryPacket(Optional<ProfilingGuid> guid,
+                                     const std::string& label,
+                                     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 label_size    = boost::numeric_cast<unsigned int>(label.size());
+
+    // Check the TimelineLabelBinaryPacket header
+    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 eventBinaryPacketSequenceNumber = (entityBinaryPacketHeaderWord1 >> 24) & 0x00000001;
+    uint32_t eventBinaryPacketDataLength     = (entityBinaryPacketHeaderWord1 >>  0) & 0x00FFFFFF;
+    BOOST_CHECK(eventBinaryPacketSequenceNumber == 0);
+    BOOST_CHECK(eventBinaryPacketDataLength     == 16 + OffsetToNextWord(label_size + 1));
+
+    // Check the decl id
+    offset += uint32_t_size;
+    uint32_t eventClassDeclId = ReadUint32(readableData, offset);
+    BOOST_CHECK(eventClassDeclId == 0);
+
+    // Check the profiling GUID
+    offset += uint32_t_size;
+    uint64_t readProfilingGuid = ReadUint64(readableData, offset);
+    if (guid.has_value())
+    {
+        BOOST_CHECK(readProfilingGuid == guid.value());
+    }
+    else
+    {
+        BOOST_CHECK(readProfilingGuid == ProfilingService::Instance().GenerateStaticId(label));
+    }
+
+    // Check the SWTrace label
+    offset += uint64_t_size;
+    uint32_t swTraceLabelLength = ReadUint32(readableData, offset);
+    BOOST_CHECK(swTraceLabelLength == label_size + 1); // Label length including the null-terminator
+    offset += uint32_t_size;
+    BOOST_CHECK(std::memcmp(readableData + offset,                  // Offset to the label in the buffer
+                            label.data(),                           // The original label
+                            swTraceLabelLength - 1) == 0);          // The length of the label
+    BOOST_CHECK(readableData[offset + swTraceLabelLength] == '\0'); // The null-terminator
+
+    // SWTrace strings are written in blocks of words, so the offset has to be updated to the next whole word
+    offset += OffsetToNextWord(swTraceLabelLength);
+}
+
+void VerifyTimelineEventClassBinaryPacket(ProfilingGuid guid,
+                                          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);
+
+    // Check the TimelineEventClassBinaryPacket header
+    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 eventBinaryPacketSequenceNumber = (entityBinaryPacketHeaderWord1 >> 24) & 0x00000001;
+    uint32_t eventBinaryPacketDataLength     = (entityBinaryPacketHeaderWord1 >>  0) & 0x00FFFFFF;
+    BOOST_CHECK(eventBinaryPacketSequenceNumber == 0);
+    BOOST_CHECK(eventBinaryPacketDataLength     == 12);
+
+    // Check the decl id
+    offset += uint32_t_size;
+    uint32_t eventClassDeclId = ReadUint32(readableData, offset);
+    BOOST_CHECK(eventClassDeclId == 2);
+
+    // Check the profiling GUID
+    offset += uint32_t_size;
+    uint64_t readProfilingGuid = ReadUint64(readableData, offset);
+    BOOST_CHECK(readProfilingGuid == guid);
+
+    // Update the offset to allow parsing to be continued after this function returns
+    offset += uint64_t_size;
+}
+
+void VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType relationshipType,
+                                            Optional<ProfilingGuid> relationshipGuid,
+                                            Optional<ProfilingGuid> headGuid,
+                                            Optional<ProfilingGuid> tailGuid,
+                                            const unsigned char* readableData,
+                                            unsigned int& offset)
+{
+    BOOST_ASSERT(readableData);
+
+    uint32_t relationshipTypeUint = 0;
+    switch (relationshipType)
+    {
+        case ProfilingRelationshipType::RetentionLink:
+            relationshipTypeUint = 0;
+            break;
+        case ProfilingRelationshipType::ExecutionLink:
+            relationshipTypeUint = 1;
+            break;
+        case ProfilingRelationshipType::DataLink:
+            relationshipTypeUint = 2;
+            break;
+        case ProfilingRelationshipType::LabelLink:
+            relationshipTypeUint = 3;
+            break;
+        default:
+            BOOST_ERROR("Unknown relationship type");
+    }
+
+    // Utils
+    unsigned int uint32_t_size = sizeof(uint32_t);
+    unsigned int uint64_t_size = sizeof(uint64_t);
+
+    // Check the TimelineLabelBinaryPacket header
+    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 eventBinaryPacketSequenceNumber = (entityBinaryPacketHeaderWord1 >> 24) & 0x00000001;
+    uint32_t eventBinaryPacketDataLength     = (entityBinaryPacketHeaderWord1 >>  0) & 0x00FFFFFF;
+    BOOST_CHECK(eventBinaryPacketSequenceNumber == 0);
+    BOOST_CHECK(eventBinaryPacketDataLength     == 32);
+
+    // Check the decl id
+    offset += uint32_t_size;
+    uint32_t eventClassDeclId = ReadUint32(readableData, offset);
+    BOOST_CHECK(eventClassDeclId == 3);
+
+    // Check the relationship type
+    offset += uint32_t_size;
+    uint32_t readRelationshipTypeUint = ReadUint32(readableData, offset);
+    BOOST_CHECK(readRelationshipTypeUint == relationshipTypeUint);
+
+    // Check the relationship GUID
+    offset += uint32_t_size;
+    uint64_t readRelationshipGuid = ReadUint64(readableData, offset);
+    if (relationshipGuid.has_value())
+    {
+        BOOST_CHECK(readRelationshipGuid == relationshipGuid.value());
+    }
+    else
+    {
+        BOOST_CHECK(readRelationshipGuid != ProfilingGuid(0));
+    }
+
+    // Check the head of relationship GUID
+    offset += uint64_t_size;
+    uint64_t readHeadRelationshipGuid = ReadUint64(readableData, offset);
+    if (headGuid.has_value())
+    {
+        BOOST_CHECK(readHeadRelationshipGuid == headGuid.value());
+    }
+    else
+    {
+        BOOST_CHECK(readHeadRelationshipGuid != ProfilingGuid(0));
+    }
+
+    // Check the tail of relationship GUID
+    offset += uint64_t_size;
+    uint64_t readTailRelationshipGuid = ReadUint64(readableData, offset);
+    if (tailGuid.has_value())
+    {
+        BOOST_CHECK(readTailRelationshipGuid == tailGuid.value());
+    }
+    else
+    {
+        BOOST_CHECK(readTailRelationshipGuid != ProfilingGuid(0));
+    }
+
+    // Update the offset to allow parsing to be continued after this function returns
+    offset += uint64_t_size;
+}
+
+void VerifyTimelineEntityBinaryPacket(Optional<ProfilingGuid> guid,
+                                      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);
+
+    // Reading TimelineEntityClassBinaryPacket
+    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       == 12);
+
+    // Check the decl_id
+    offset += uint32_t_size;
+    uint32_t entityDeclId = ReadUint32(readableData, offset);
+    BOOST_CHECK(entityDeclId == 1);
+
+    // Check the profiling GUID
+    offset += uint32_t_size;
+    uint64_t readProfilingGuid = ReadUint64(readableData, offset);
+
+    if (guid.has_value())
+    {
+        BOOST_CHECK(readProfilingGuid == guid.value());
+    }
+    else
+    {
+        BOOST_CHECK(readProfilingGuid != ProfilingGuid(0));
+    }
+
+    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;
+}
+
+void VerifyPostOptimisationStructureTestImpl(armnn::BackendId backendId)
+{
+    using namespace armnn;
+
+    // Create runtime in which test will run
+    armnn::IRuntime::CreationOptions options;
+    options.m_ProfilingOptions.m_EnableProfiling = true;
+    armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options));
+
+    // build up the structure of the network
+    INetworkPtr net(INetwork::Create());
+
+    // Convolution details
+    TensorInfo inputInfo({ 1, 2, 5, 1 }, DataType::Float32);
+    TensorInfo weightInfo({ 3, 2, 3, 1}, DataType::Float32);
+    TensorInfo biasInfo({ 3 }, DataType::Float32);
+    TensorInfo outputInfo({ 1, 3, 7, 1}, DataType::Float32);
+    std::vector<float> weightsData{
+            1.0f,  0.0f,  0.0f,
+            0.0f,  2.0f, -1.5f,
+
+            0.0f,  0.0f,  0.0f,
+            0.2f,  0.2f,  0.2f,
+
+            0.5f,  0.0f,  0.5f,
+            0.0f, -1.0f,  0.0f
+    };
+    ConstTensor weights(weightInfo, weightsData);
+
+    Optional<ConstTensor> optionalBiases;
+    std::vector<float> biasesData{ 1.0f, 0.0f, 0.0f };
+    ConstTensor biases(biasInfo, biasesData);
+    optionalBiases = Optional<ConstTensor>(biases);
+
+    // Input layer
+    IConnectableLayer* input = net->AddInputLayer(0, "input");
+
+    // Convolution2d layer
+    Convolution2dDescriptor conv2dDesc;
+    conv2dDesc.m_StrideX  = 1;
+    conv2dDesc.m_StrideY  = 1;
+    conv2dDesc.m_PadLeft = 0;
+    conv2dDesc.m_PadRight = 0;
+    conv2dDesc.m_PadTop = 2;
+    conv2dDesc.m_PadBottom = 2;
+    conv2dDesc.m_BiasEnabled = true;
+    IConnectableLayer* conv2d = net->AddConvolution2dLayer(conv2dDesc, weights, optionalBiases);
+
+    // Activation layer
+    armnn::ActivationDescriptor activationDesc;
+    armnn::IConnectableLayer* const activation = net->AddActivationLayer(activationDesc, "activation");
+
+    // Output layer
+    IConnectableLayer* output = net->AddOutputLayer(0, "output");
+
+    input->GetOutputSlot(0).Connect(conv2d->GetInputSlot(0));
+    conv2d->GetOutputSlot(0).Connect(activation->GetInputSlot(0));
+    activation->GetOutputSlot(0).Connect(output->GetInputSlot(0));
+
+    input->GetOutputSlot(0).SetTensorInfo(inputInfo);
+    conv2d->GetOutputSlot(0).SetTensorInfo(outputInfo);
+    activation->GetOutputSlot(0).SetTensorInfo(outputInfo);
+
+    // optimize the network
+    std::vector<armnn::BackendId> backends = { backendId };
+    IOptimizedNetworkPtr optNet = Optimize(*net, backends, runtime->GetDeviceSpec());
+
+    ProfilingGuid optNetGuid = optNet->GetGuid();
+
+    // Load it into the runtime. It should success.
+    armnn::NetworkId netId;
+    BOOST_TEST(runtime->LoadNetwork(netId, std::move(optNet)) == Status::Success);
+
+    profiling::ProfilingServiceRuntimeHelper profilingServiceHelper;
+    profiling::BufferManager& bufferManager = profilingServiceHelper.GetProfilingBufferManager();
+    auto readableBuffer = bufferManager.GetReadableBuffer();
+
+    // Profiling is enable, the post-optimisation structure should be created
+    BOOST_CHECK(readableBuffer != nullptr);
+
+    unsigned int size = readableBuffer->GetSize();
+    BOOST_CHECK(size == 1980);
+
+    const unsigned char* readableData = readableBuffer->GetReadableData();
+    BOOST_CHECK(readableData != nullptr);
+
+    unsigned int offset = 0;
+
+    // Post-optimisation network
+    // Network entity
+    VerifyTimelineEntityBinaryPacket(optNetGuid, readableData, offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           optNetGuid,
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Type label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+
+    // Input layer
+    // Input layer entity
+    VerifyTimelineEntityBinaryPacket(input->GetGuid(), readableData, offset);
+
+    // Name Entity
+    VerifyTimelineLabelBinaryPacket(EmptyOptional(), "input", readableData, offset);
+
+    // Entity - Name relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           input->GetGuid(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Name label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::NAME_GUID,
+                                           readableData,
+                                           offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           input->GetGuid(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Type label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+
+    // Network - Input layer relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                           EmptyOptional(),
+                                           optNetGuid,
+                                           input->GetGuid(),
+                                           readableData,
+                                           offset);
+
+    // Conv2d layer
+    // Conv2d layer entity
+    VerifyTimelineEntityBinaryPacket(conv2d->GetGuid(), readableData, offset);
+
+    // Name entity
+    VerifyTimelineLabelBinaryPacket(EmptyOptional(), "<Unnamed>", readableData, offset);
+
+    // Entity - Name relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           conv2d->GetGuid(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Name label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::NAME_GUID,
+                                           readableData,
+                                           offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           conv2d->GetGuid(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Type label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+
+    // Network - Conv2d layer relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                           EmptyOptional(),
+                                           optNetGuid,
+                                           conv2d->GetGuid(),
+                                           readableData,
+                                           offset);
+
+    // Input layer - Conv2d layer relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                           EmptyOptional(),
+                                           input->GetGuid(),
+                                           conv2d->GetGuid(),
+                                           readableData,
+                                           offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::CONNECTION_GUID,
+                                           readableData,
+                                           offset);
+
+    // Type label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+
+    // Conv2d workload
+    // Conv2d workload entity
+    VerifyTimelineEntityBinaryPacket(EmptyOptional(), readableData, offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Type label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+
+    // BackendId entity
+    VerifyTimelineLabelBinaryPacket(EmptyOptional(), backendId.Get(), readableData, offset);
+
+    // Entity - BackendId relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // BackendId label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::BACKENDID_GUID,
+                                           readableData,
+                                           offset);
+
+    // Conv2d layer - Conv2d workload relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                           EmptyOptional(),
+                                           conv2d->GetGuid(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Activation layer
+    // Activation layer entity
+    VerifyTimelineEntityBinaryPacket(activation->GetGuid(), readableData, offset);
+
+    // Name entity
+    VerifyTimelineLabelBinaryPacket(EmptyOptional(), "activation", readableData, offset);
+
+    // Entity - Name relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           activation->GetGuid(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Name label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::NAME_GUID,
+                                           readableData,
+                                           offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           activation->GetGuid(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Type label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+
+    // Network - Activation layer relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                           EmptyOptional(),
+                                           optNetGuid,
+                                           activation->GetGuid(),
+                                           readableData,
+                                           offset);
+
+    // Conv2d layer - Activation layer relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                           EmptyOptional(),
+                                           conv2d->GetGuid(),
+                                           activation->GetGuid(),
+                                           readableData,
+                                           offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::CONNECTION_GUID,
+                                           readableData,
+                                           offset);
+
+    // Type label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+
+    // Activation workload
+    // Activation workload entity
+    VerifyTimelineEntityBinaryPacket(EmptyOptional(), readableData, offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Type label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+
+    // BackendId entity
+    VerifyTimelineLabelBinaryPacket(EmptyOptional(), backendId.Get(), readableData, offset);
+
+    // Entity - BackendId relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // BackendId label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::BACKENDID_GUID,
+                                           readableData,
+                                           offset);
+
+    // Activation layer - Activation workload relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                           EmptyOptional(),
+                                           activation->GetGuid(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Output layer
+    // Output layer entity
+    VerifyTimelineEntityBinaryPacket(output->GetGuid(), readableData, offset);
+
+    // Name entity
+    VerifyTimelineLabelBinaryPacket(EmptyOptional(), "output", readableData, offset);
+
+    // Entity - Name relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           output->GetGuid(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Name label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::NAME_GUID,
+                                           readableData,
+                                           offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           output->GetGuid(),
+                                           EmptyOptional(),
+                                           readableData,
+                                           offset);
+
+    // Type label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+
+    // Network - Output layer relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                           EmptyOptional(),
+                                           optNetGuid,
+                                           output->GetGuid(),
+                                           readableData,
+                                           offset);
+
+    // Activation layer - Output layer relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::RetentionLink,
+                                           EmptyOptional(),
+                                           activation->GetGuid(),
+                                           output->GetGuid(),
+                                           readableData,
+                                           offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::CONNECTION_GUID,
+                                           readableData,
+                                           offset);
+
+    // Type label relationship
+    VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::LabelLink,
+                                           EmptyOptional(),
+                                           EmptyOptional(),
+                                           LabelsAndEventClasses::TYPE_GUID,
+                                           readableData,
+                                           offset);
+
+    bufferManager.MarkRead(readableBuffer);
+}
diff --git a/src/profiling/test/ProfilingTestUtils.hpp b/src/profiling/test/ProfilingTestUtils.hpp
new file mode 100644 (file)
index 0000000..7fb5d62
--- /dev/null
@@ -0,0 +1,70 @@
+//
+// Copyright Â© 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "ProfilingUtils.hpp"
+
+#include <armnn/BackendId.hpp>
+#include <armnn/Optional.hpp>
+#include <armnn/Types.hpp>
+#include <BufferManager.hpp>
+#include <ProfilingService.hpp>
+
+using namespace armnn;
+using namespace armnn::profiling;
+
+inline unsigned int OffsetToNextWord(unsigned int numberOfBytes);
+
+void VerifyTimelineLabelBinaryPacket(Optional<ProfilingGuid> guid,
+                                     const std::string& label,
+                                     const unsigned char* readableData,
+                                     unsigned int& offset);
+
+void VerifyTimelineEventClassBinaryPacket(ProfilingGuid guid,
+                                          const unsigned char* readableData,
+                                          unsigned int& offset);
+
+void VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType relationshipType,
+                                            Optional<ProfilingGuid> relationshipGuid,
+                                            Optional<ProfilingGuid> headGuid,
+                                            Optional<ProfilingGuid> tailGuid,
+                                            const unsigned char* readableData,
+                                            unsigned int& offset);
+
+void VerifyTimelineEntityBinaryPacket(Optional<ProfilingGuid> guid,
+                                      const unsigned char* readableData,
+                                      unsigned int& offset);
+
+void VerifyTimelineEventBinaryPacket(Optional<uint64_t> timestamp,
+                                     Optional<std::thread::id> threadId,
+                                     Optional<ProfilingGuid> eventGuid,
+                                     const unsigned char* readableData,
+                                     unsigned int& offset);
+
+void VerifyPostOptimisationStructureTestImpl(armnn::BackendId backendId);
+
+namespace armnn
+{
+
+namespace profiling
+{
+
+class ProfilingServiceRuntimeHelper : public ProfilingService
+{
+public:
+    ProfilingServiceRuntimeHelper() = default;
+    ~ProfilingServiceRuntimeHelper() = default;
+
+    BufferManager& GetProfilingBufferManager()
+    {
+        return GetBufferManager(ProfilingService::Instance());
+    }
+};
+
+} // namespace profiling
+
+} // namespace armnn
+
index 7d1a7c1..ae1ee55 100644 (file)
 //
 
 #include "SendCounterPacketTests.hpp"
+#include "ProfilingTestUtils.hpp"
 
 #include <SendTimelinePacket.hpp>
 #include <TimelineUtilityMethods.hpp>
 #include <LabelsAndEventClasses.hpp>
 #include <ProfilingService.hpp>
 
+#include <memory>
+
 #include <boost/test/unit_test.hpp>
 
 using namespace armnn;
 using namespace armnn::profiling;
 
-namespace
-{
-
-inline unsigned int OffsetToNextWord(unsigned int numberOfBytes)
-{
-    unsigned int uint32_t_size = sizeof(uint32_t);
-
-    unsigned int remainder = numberOfBytes % uint32_t_size;
-    if (remainder == 0)
-    {
-        return numberOfBytes;
-    }
-
-    return numberOfBytes + uint32_t_size - remainder;
-}
-
-void VerifyTimelineLabelBinaryPacket(Optional<ProfilingGuid> guid,
-                                     const std::string& label,
-                                     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 label_size    = boost::numeric_cast<unsigned int>(label.size());
-
-    // Check the TimelineLabelBinaryPacket header
-    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 eventBinaryPacketSequenceNumber = (entityBinaryPacketHeaderWord1 >> 24) & 0x00000001;
-    uint32_t eventBinaryPacketDataLength     = (entityBinaryPacketHeaderWord1 >>  0) & 0x00FFFFFF;
-    BOOST_CHECK(eventBinaryPacketSequenceNumber == 0);
-    BOOST_CHECK(eventBinaryPacketDataLength     == 16 + OffsetToNextWord(label_size + 1));
-
-    // Check the decl id
-    offset += uint32_t_size;
-    uint32_t eventClassDeclId = ReadUint32(readableData, offset);
-    BOOST_CHECK(eventClassDeclId == 0);
-
-    // Check the profiling GUID
-    offset += uint32_t_size;
-    uint64_t readProfilingGuid = ReadUint64(readableData, offset);
-    if (guid.has_value())
-    {
-        BOOST_CHECK(readProfilingGuid == guid.value());
-    }
-    else
-    {
-        BOOST_CHECK(readProfilingGuid == ProfilingService::Instance().GenerateStaticId(label));
-    }
-
-    // Check the SWTrace label
-    offset += uint64_t_size;
-    uint32_t swTraceLabelLength = ReadUint32(readableData, offset);
-    BOOST_CHECK(swTraceLabelLength == label_size + 1); // Label length including the null-terminator
-    offset += uint32_t_size;
-    BOOST_CHECK(std::memcmp(readableData + offset,                  // Offset to the label in the buffer
-                            label.data(),                           // The original label
-                            swTraceLabelLength - 1) == 0);          // The length of the label
-    BOOST_CHECK(readableData[offset + swTraceLabelLength] == '\0'); // The null-terminator
-
-    // SWTrace strings are written in blocks of words, so the offset has to be updated to the next whole word
-    offset += OffsetToNextWord(swTraceLabelLength);
-}
-
-void VerifyTimelineEventClassBinaryPacket(ProfilingGuid guid,
-                                          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);
-
-    // Check the TimelineEventClassBinaryPacket header
-    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 eventBinaryPacketSequenceNumber = (entityBinaryPacketHeaderWord1 >> 24) & 0x00000001;
-    uint32_t eventBinaryPacketDataLength     = (entityBinaryPacketHeaderWord1 >>  0) & 0x00FFFFFF;
-    BOOST_CHECK(eventBinaryPacketSequenceNumber == 0);
-    BOOST_CHECK(eventBinaryPacketDataLength     == 12);
-
-    // Check the decl id
-    offset += uint32_t_size;
-    uint32_t eventClassDeclId = ReadUint32(readableData, offset);
-    BOOST_CHECK(eventClassDeclId == 2);
-
-    // Check the profiling GUID
-    offset += uint32_t_size;
-    uint64_t readProfilingGuid = ReadUint64(readableData, offset);
-    BOOST_CHECK(readProfilingGuid == guid);
-
-    // Update the offset to allow parsing to be continued after this function returns
-    offset += uint64_t_size;
-}
-
-void VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType relationshipType,
-                                            Optional<ProfilingGuid> relationshipGuid,
-                                            Optional<ProfilingGuid> headGuid,
-                                            Optional<ProfilingGuid> tailGuid,
-                                            const unsigned char* readableData,
-                                            unsigned int& offset)
-{
-    BOOST_ASSERT(readableData);
-
-    uint32_t relationshipTypeUint = 0;
-    switch (relationshipType)
-    {
-        case ProfilingRelationshipType::RetentionLink:
-            relationshipTypeUint = 0;
-            break;
-        case ProfilingRelationshipType::ExecutionLink:
-            relationshipTypeUint = 1;
-            break;
-        case ProfilingRelationshipType::DataLink:
-            relationshipTypeUint = 2;
-            break;
-        case ProfilingRelationshipType::LabelLink:
-            relationshipTypeUint = 3;
-            break;
-        default:
-            BOOST_ERROR("Unknown relationship type");
-    }
-
-    // Utils
-    unsigned int uint32_t_size = sizeof(uint32_t);
-    unsigned int uint64_t_size = sizeof(uint64_t);
-
-    // Check the TimelineLabelBinaryPacket header
-    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 eventBinaryPacketSequenceNumber = (entityBinaryPacketHeaderWord1 >> 24) & 0x00000001;
-    uint32_t eventBinaryPacketDataLength     = (entityBinaryPacketHeaderWord1 >>  0) & 0x00FFFFFF;
-    BOOST_CHECK(eventBinaryPacketSequenceNumber == 0);
-    BOOST_CHECK(eventBinaryPacketDataLength     == 32);
-
-    // Check the decl id
-    offset += uint32_t_size;
-    uint32_t eventClassDeclId = ReadUint32(readableData, offset);
-    BOOST_CHECK(eventClassDeclId == 3);
-
-    // Check the relationship type
-    offset += uint32_t_size;
-    uint32_t readRelationshipTypeUint = ReadUint32(readableData, offset);
-    BOOST_CHECK(readRelationshipTypeUint == relationshipTypeUint);
-
-    // Check the relationship GUID
-    offset += uint32_t_size;
-    uint64_t readRelationshipGuid = ReadUint64(readableData, offset);
-    if (relationshipGuid.has_value())
-    {
-        BOOST_CHECK(readRelationshipGuid == relationshipGuid.value());
-    }
-    else
-    {
-        BOOST_CHECK(readRelationshipGuid != ProfilingGuid(0));
-    }
-
-    // Check the head of relationship GUID
-    offset += uint64_t_size;
-    uint64_t readHeadRelationshipGuid = ReadUint64(readableData, offset);
-    if (headGuid.has_value())
-    {
-        BOOST_CHECK(readHeadRelationshipGuid == headGuid.value());
-    }
-    else
-    {
-        BOOST_CHECK(readHeadRelationshipGuid != ProfilingGuid(0));
-    }
-
-    // Check the tail of relationship GUID
-    offset += uint64_t_size;
-    uint64_t readTailRelationshipGuid = ReadUint64(readableData, offset);
-    if (tailGuid.has_value())
-    {
-        BOOST_CHECK(readTailRelationshipGuid == tailGuid.value());
-    }
-    else
-    {
-        BOOST_CHECK(readTailRelationshipGuid != ProfilingGuid(0));
-    }
-
-    // Update the offset to allow parsing to be continued after this function returns
-    offset += uint64_t_size;
-}
-
-void VerifyTimelineEntityBinaryPacket(Optional<ProfilingGuid> guid,
-                                      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);
-
-    // Reading TimelineEntityClassBinaryPacket
-    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       == 12);
-
-    // Check the decl_id
-    offset += uint32_t_size;
-    uint32_t entityDeclId = ReadUint32(readableData, offset);
-    BOOST_CHECK(entityDeclId == 1);
-
-    // Check the profiling GUID
-    offset += uint32_t_size;
-    uint64_t readProfilingGuid = ReadUint64(readableData, offset);
-
-    if (guid.has_value())
-    {
-        BOOST_CHECK(readProfilingGuid == guid.value());
-    }
-    else
-    {
-        BOOST_CHECK(readProfilingGuid != ProfilingGuid(0));
-    }
-
-    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)
 
 BOOST_AUTO_TEST_CASE(CreateTypedLabelTest)
 {
     MockBufferManager mockBufferManager(1024);
-    SendTimelinePacket sendTimelinePacket(mockBufferManager);
+    std::unique_ptr<ISendTimelinePacket> sendTimelinePacket = std::make_unique<SendTimelinePacket>(mockBufferManager);
     TimelineUtilityMethods timelineUtilityMethods(sendTimelinePacket);
 
     // Generate first guid to ensure that the named typed entity guid is not 0 on local single test.
@@ -375,10 +33,10 @@ BOOST_AUTO_TEST_CASE(CreateTypedLabelTest)
     const std::string entityName = "some entity";
     ProfilingStaticGuid labelTypeGuid(456);
 
-    BOOST_CHECK_NO_THROW(timelineUtilityMethods.CreateTypedLabel(entityGuid, entityName, labelTypeGuid));
+    BOOST_CHECK_NO_THROW(timelineUtilityMethods.MarkEntityWithLabel(entityGuid, entityName, labelTypeGuid));
 
     // Commit all packets at once
-    sendTimelinePacket.Commit();
+    timelineUtilityMethods.Commit();
 
     // Get the readable buffer
     auto readableBuffer = mockBufferManager.GetReadableBuffer();
@@ -417,19 +75,19 @@ BOOST_AUTO_TEST_CASE(CreateTypedLabelTest)
 BOOST_AUTO_TEST_CASE(SendWellKnownLabelsAndEventClassesTest)
 {
     MockBufferManager mockBufferManager(1024);
-    SendTimelinePacket sendTimelinePacket(mockBufferManager);
+    std::unique_ptr<ISendTimelinePacket> sendTimelinePacket = std::make_unique<SendTimelinePacket>(mockBufferManager);
     TimelineUtilityMethods timelineUtilityMethods(sendTimelinePacket);
 
     BOOST_CHECK_NO_THROW(timelineUtilityMethods.SendWellKnownLabelsAndEventClasses());
 
     // Commit all packets at once
-    sendTimelinePacket.Commit();
+    timelineUtilityMethods.Commit();
 
     // Get the readable buffer
     auto readableBuffer = mockBufferManager.GetReadableBuffer();
     BOOST_CHECK(readableBuffer != nullptr);
     unsigned int size = readableBuffer->GetSize();
-    BOOST_CHECK(size == 136);
+    BOOST_TEST(size == 308);
     const unsigned char* readableData = readableBuffer->GetReadableData();
     BOOST_CHECK(readableData != nullptr);
 
@@ -454,6 +112,37 @@ BOOST_AUTO_TEST_CASE(SendWellKnownLabelsAndEventClassesTest)
                                     readableData,
                                     offset);
 
+    // Forth "well-known" label: BACKENDID
+    VerifyTimelineLabelBinaryPacket(LabelsAndEventClasses::BACKENDID_GUID,
+                                    LabelsAndEventClasses::BACKENDID_LABEL,
+                                    readableData,
+                                    offset);
+
+    // Well-known types
+    // Layer
+    VerifyTimelineLabelBinaryPacket(LabelsAndEventClasses::LAYER_GUID,
+                                    LabelsAndEventClasses::LAYER,
+                                    readableData,
+                                    offset);
+
+    // Workload
+    VerifyTimelineLabelBinaryPacket(LabelsAndEventClasses::WORKLOAD_GUID,
+                                    LabelsAndEventClasses::WORKLOAD,
+                                    readableData,
+                                    offset);
+
+    // Network
+    VerifyTimelineLabelBinaryPacket(LabelsAndEventClasses::NETWORK_GUID,
+                                    LabelsAndEventClasses::NETWORK,
+                                    readableData,
+                                    offset);
+
+    // Connection
+    VerifyTimelineLabelBinaryPacket(LabelsAndEventClasses::CONNECTION_GUID,
+                                    LabelsAndEventClasses::CONNECTION,
+                                    readableData,
+                                    offset);
+
     // First "well-known" event class: START OF LIFE
     VerifyTimelineEventClassBinaryPacket(LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS,
                                          readableData,
@@ -471,7 +160,7 @@ BOOST_AUTO_TEST_CASE(SendWellKnownLabelsAndEventClassesTest)
 BOOST_AUTO_TEST_CASE(CreateNamedTypedChildEntityTest)
 {
     MockBufferManager mockBufferManager(1024);
-    SendTimelinePacket sendTimelinePacket(mockBufferManager);
+    std::unique_ptr<ISendTimelinePacket> sendTimelinePacket = std::make_unique<SendTimelinePacket>(mockBufferManager);
     TimelineUtilityMethods timelineUtilityMethods(sendTimelinePacket);
 
     ProfilingDynamicGuid childEntityGuid(0);
@@ -497,7 +186,7 @@ BOOST_AUTO_TEST_CASE(CreateNamedTypedChildEntityTest)
     BOOST_CHECK(childEntityGuid != ProfilingGuid(0));
 
     // Commit all packets at once
-    sendTimelinePacket.Commit();
+    timelineUtilityMethods.Commit();
 
     // Get the readable buffer
     auto readableBuffer = mockBufferManager.GetReadableBuffer();
@@ -566,7 +255,7 @@ BOOST_AUTO_TEST_CASE(CreateNamedTypedChildEntityTest)
 BOOST_AUTO_TEST_CASE(DeclareLabelTest)
 {
     MockBufferManager mockBufferManager(1024);
-    SendTimelinePacket sendTimelinePacket(mockBufferManager);
+    std::unique_ptr<ISendTimelinePacket> sendTimelinePacket = std::make_unique<SendTimelinePacket>(mockBufferManager);
     TimelineUtilityMethods timelineUtilityMethods(sendTimelinePacket);
 
     // Generate first guid to ensure that the named typed entity guid is not 0 on local single test.
@@ -594,7 +283,7 @@ BOOST_AUTO_TEST_CASE(DeclareLabelTest)
 BOOST_AUTO_TEST_CASE(CreateNameTypeEntityInvalidTest)
 {
     MockBufferManager mockBufferManager(1024);
-    SendTimelinePacket sendTimelinePacket(mockBufferManager);
+    std::unique_ptr<ISendTimelinePacket> sendTimelinePacket = std::make_unique<SendTimelinePacket>(mockBufferManager);
     TimelineUtilityMethods timelineUtilityMethods(sendTimelinePacket);
 
     // Invalid name
@@ -618,7 +307,7 @@ BOOST_AUTO_TEST_CASE(CreateNameTypeEntityInvalidTest)
 BOOST_AUTO_TEST_CASE(CreateNameTypeEntityTest)
 {
     MockBufferManager mockBufferManager(1024);
-    SendTimelinePacket sendTimelinePacket(mockBufferManager);
+    std::unique_ptr<ISendTimelinePacket> sendTimelinePacket = std::make_unique<SendTimelinePacket>(mockBufferManager);
     TimelineUtilityMethods timelineUtilityMethods(sendTimelinePacket);
 
     const std::string entityName = "Entity0";
@@ -631,7 +320,7 @@ BOOST_AUTO_TEST_CASE(CreateNameTypeEntityTest)
     BOOST_CHECK(guid != ProfilingGuid(0));
 
     // Commit all packets at once
-    sendTimelinePacket.Commit();
+    timelineUtilityMethods.Commit();
 
     // Get the readable buffer
     auto readableBuffer = mockBufferManager.GetReadableBuffer();
@@ -694,9 +383,8 @@ BOOST_AUTO_TEST_CASE(CreateNameTypeEntityTest)
 BOOST_AUTO_TEST_CASE(RecordEventTest)
 {
     MockBufferManager mockBufferManager(1024);
-    SendTimelinePacket sendTimelinePacket(mockBufferManager);
+    std::unique_ptr<ISendTimelinePacket> sendTimelinePacket = std::make_unique<SendTimelinePacket>(mockBufferManager);
     TimelineUtilityMethods timelineUtilityMethods(sendTimelinePacket);
-
     // Generate first guid to ensure that the named typed entity guid is not 0 on local single test.
     ProfilingService::Instance().NextGuid();
 
@@ -707,7 +395,7 @@ BOOST_AUTO_TEST_CASE(RecordEventTest)
     BOOST_CHECK(eventGuid != ProfilingGuid(0));
 
     // Commit all packets at once
-    sendTimelinePacket.Commit();
+    timelineUtilityMethods.Commit();
 
     // Get the readable buffer
     auto readableBuffer = mockBufferManager.GetReadableBuffer();
@@ -734,7 +422,7 @@ BOOST_AUTO_TEST_CASE(RecordEventTest)
     // Third packet sent: TimelineRelationshipBinaryPacket
     VerifyTimelineRelationshipBinaryPacket(ProfilingRelationshipType::DataLink,
                                            EmptyOptional(),
-                                           entityGuid,
+                                           eventGuid,
                                            eventClassGuid,
                                            readableData,
                                            offset);