IVGCVSW-3980 Implementation of Guid generator

 * Improve implementation of Guid Generator to separate the range of
Static Guid and Dynamic Guid
 * Unit tests to ensure non-collision

Signed-off-by: Narumol Prangnawarat <narumol.prangnawarat@arm.com>
Change-Id: I4ad1a75ea0b1f37155da0decafb51fc5a61e4187
diff --git a/include/armnn/Types.hpp b/include/armnn/Types.hpp
index 94f4530..4e80c3c 100644
--- a/include/armnn/Types.hpp
+++ b/include/armnn/Types.hpp
@@ -229,6 +229,8 @@
 namespace profiling
 {
 
+static constexpr uint64_t MIN_STATIC_GUID = 1llu << 63;
+
 class ProfilingGuid
 {
 public:
diff --git a/src/profiling/ProfilingGuidGenerator.hpp b/src/profiling/ProfilingGuidGenerator.hpp
index ad3159f..97de4a8 100644
--- a/src/profiling/ProfilingGuidGenerator.hpp
+++ b/src/profiling/ProfilingGuidGenerator.hpp
@@ -22,25 +22,28 @@
     ProfilingGuidGenerator() : m_Sequence(0) {}
 
     /// Return the next random Guid in the sequence
-    // NOTE: dummy implementation for the moment
     inline ProfilingDynamicGuid NextGuid() override
     {
-        // NOTE: skipping the zero for testing purposes
-        ProfilingDynamicGuid guid(++m_Sequence);
+        ProfilingDynamicGuid guid(m_Sequence);
+        m_Sequence++;
+        if (m_Sequence >= MIN_STATIC_GUID)
+        {
+            // Reset the sequence to 0 when it reaches the upper bound of dynamic guid
+            m_Sequence = 0;
+        }
         return guid;
     }
 
     /// Create a ProfilingStaticGuid based on a hash of the string
-    // NOTE: dummy implementation for the moment
     inline ProfilingStaticGuid GenerateStaticId(const std::string& str) override
     {
-        uint64_t guid = static_cast<uint64_t>(m_StringHasher(str));
-        return guid;
+        uint64_t staticHash = m_Hash(str) | MIN_STATIC_GUID;
+        return ProfilingStaticGuid(staticHash);
     }
 
 private:
-    std::hash<std::string> m_StringHasher;
     uint64_t m_Sequence;
+    std::hash<std::string> m_Hash;
 };
 
 } // namespace profiling
diff --git a/src/profiling/test/ProfilingGuidTest.cpp b/src/profiling/test/ProfilingGuidTest.cpp
index f72cc1c..c0dd986 100644
--- a/src/profiling/test/ProfilingGuidTest.cpp
+++ b/src/profiling/test/ProfilingGuidTest.cpp
@@ -5,6 +5,11 @@
 
 #include <armnn/Types.hpp>
 
+#include "LabelsAndEventClasses.hpp"
+#include "ProfilingGuidGenerator.hpp"
+
+#include <set>
+
 #include <boost/test/unit_test.hpp>
 
 using namespace armnn::profiling;
@@ -59,4 +64,90 @@
     BOOST_TEST(guid1 >= guid2);
 }
 
+std::string GenerateRandomString()
+{
+    // Random a string lengh from 3 - 100
+    int minLength = 3;
+    int maxLength = 100;
+
+    // Random a character from lower case alphabets, upper case alphabets, numbers and special characters
+    int minAscii = 32; // space 32
+    int maxAscii = 126; // ~
+
+    int stringLen = rand() % (maxLength - minLength + 1) + minLength;
+    char str[stringLen + 1];
+    for (int i = 0; i < stringLen; ++i)
+    {
+        int randAscii = rand() % (maxAscii - minAscii + 1) + minAscii;
+        str[i] = char(randAscii);
+    }
+    str[stringLen] = '\0';
+    return std::string(str);
+}
+
+void CheckStaticGuid(uint64_t guid, uint64_t expectedGuid)
+{
+    BOOST_TEST(guid == expectedGuid);
+    BOOST_TEST(guid >= MIN_STATIC_GUID);
+}
+
+void CheckDynamicGuid(uint64_t guid, uint64_t expectedGuid)
+{
+    BOOST_TEST(guid == expectedGuid);
+    BOOST_TEST(guid < MIN_STATIC_GUID);
+}
+
+BOOST_AUTO_TEST_CASE(StaticGuidGeneratorCollisionTest)
+{
+    ProfilingGuidGenerator generator;
+    std::set<uint64_t> guids;
+    std::set<std::string> strs;
+    std::map<uint64_t,std::string> guidMap;
+    int collision = 0;
+    for (int i = 0; i < 1000000; ++i)
+    {
+        std::string str = GenerateRandomString();
+        if(strs.find(str) != strs.end())
+        {
+            continue;
+        }
+        strs.insert(str);
+        ProfilingStaticGuid guid = generator.GenerateStaticId(str.c_str());
+        if (guids.find(guid) != guids.end())
+        {
+            collision++;
+        }
+        guids.insert(guid);
+    }
+    BOOST_TEST(collision == 0);
+}
+
+BOOST_AUTO_TEST_CASE(StaticGuidGeneratorTest)
+{
+    ProfilingGuidGenerator generator;
+
+    ProfilingStaticGuid staticGuid0 = generator.GenerateStaticId("name");
+    CheckStaticGuid(staticGuid0, LabelsAndEventClasses::NAME_GUID);
+    BOOST_TEST(staticGuid0 != generator.GenerateStaticId("Name"));
+
+    ProfilingStaticGuid staticGuid1 = generator.GenerateStaticId("type");
+    CheckStaticGuid(staticGuid1, LabelsAndEventClasses::TYPE_GUID);
+    BOOST_TEST(staticGuid1 != generator.GenerateStaticId("Type"));
+
+    ProfilingStaticGuid staticGuid2 = generator.GenerateStaticId("index");
+    CheckStaticGuid(staticGuid2, LabelsAndEventClasses::INDEX_GUID);
+    BOOST_TEST(staticGuid2 != generator.GenerateStaticId("Index"));
+}
+
+BOOST_AUTO_TEST_CASE(DynamicGuidGeneratorTest)
+{
+    ProfilingGuidGenerator generator;
+
+    for (unsigned int i = 0; i < 100; ++i)
+    {
+        ProfilingDynamicGuid guid = generator.NextGuid();
+        CheckDynamicGuid(guid, i);
+    }
+}
+
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/profiling/test/SendTimelinePacketTests.cpp b/src/profiling/test/SendTimelinePacketTests.cpp
index 26b49df..771e117 100644
--- a/src/profiling/test/SendTimelinePacketTests.cpp
+++ b/src/profiling/test/SendTimelinePacketTests.cpp
@@ -415,10 +415,9 @@
     ProfilingService& profilingService = ProfilingService::Instance();
     profilingService.ResetExternalProfilingOptions(options, true);
     ProfilingStaticGuid staticGuid = profilingService.GenerateStaticId("dummy");
-    // TODO this will change again...
     std::hash<std::string> hasher;
     uint64_t hash = static_cast<uint64_t>(hasher("dummy"));
-    ProfilingStaticGuid expectedStaticValue(hash);
+    ProfilingStaticGuid expectedStaticValue(hash | MIN_STATIC_GUID);
     BOOST_CHECK(staticGuid == expectedStaticValue);
     ProfilingDynamicGuid dynamicGuid = profilingService.NextGuid();
     uint64_t dynamicGuidValue = static_cast<uint64_t>(dynamicGuid);
@@ -448,23 +447,23 @@
     std::hash<std::string> hasher;
 
     uint64_t hash = static_cast<uint64_t>(hasher(LabelsAndEventClasses::NAME_LABEL));
-    ProfilingStaticGuid expectedNameGuid(hash);
+    ProfilingStaticGuid expectedNameGuid(hash | MIN_STATIC_GUID);
     BOOST_CHECK(LabelsAndEventClasses::NAME_GUID == expectedNameGuid);
 
     hash = static_cast<uint64_t>(hasher(LabelsAndEventClasses::TYPE_LABEL));
-    ProfilingStaticGuid expectedTypeGuid(hash);
+    ProfilingStaticGuid expectedTypeGuid(hash | MIN_STATIC_GUID);
     BOOST_CHECK(LabelsAndEventClasses::TYPE_GUID == expectedTypeGuid);
 
     hash = static_cast<uint64_t>(hasher(LabelsAndEventClasses::INDEX_LABEL));
-    ProfilingStaticGuid expectedIndexGuid(hash);
+    ProfilingStaticGuid expectedIndexGuid(hash | MIN_STATIC_GUID);
     BOOST_CHECK(LabelsAndEventClasses::INDEX_GUID == expectedIndexGuid);
 
     hash = static_cast<uint64_t>(hasher("ARMNN_PROFILING_SOL"));
-    ProfilingStaticGuid expectedSol(hash);
+    ProfilingStaticGuid expectedSol(hash | MIN_STATIC_GUID);
     BOOST_CHECK(LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS == expectedSol);
 
     hash = static_cast<uint64_t>(hasher("ARMNN_PROFILING_EOL"));
-    ProfilingStaticGuid expectedEol(hash);
+    ProfilingStaticGuid expectedEol(hash | MIN_STATIC_GUID);
     BOOST_CHECK(LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS == expectedEol);
 }
 
diff --git a/src/profiling/test/TimelineUtilityMethodsTests.cpp b/src/profiling/test/TimelineUtilityMethodsTests.cpp
index f784afc..2eb96e6 100644
--- a/src/profiling/test/TimelineUtilityMethodsTests.cpp
+++ b/src/profiling/test/TimelineUtilityMethodsTests.cpp
@@ -368,6 +368,9 @@
     SendTimelinePacket 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();
+
     ProfilingGuid entityGuid(123);
     const std::string entityName = "some entity";
     ProfilingStaticGuid labelTypeGuid(456);
@@ -475,6 +478,9 @@
     const std::string entityName = "some entity";
     const std::string entityType = "some type";
 
+    // Generate first guid to ensure that the named typed entity guid is not 0 on local single test.
+    ProfilingService::Instance().NextGuid();
+
     BOOST_CHECK_THROW(timelineUtilityMethods.CreateNamedTypedChildEntity(parentEntityGuid, "", entityType),
                       InvalidArgumentException);
     BOOST_CHECK_THROW(timelineUtilityMethods.CreateNamedTypedChildEntity(parentEntityGuid, entityName, ""),
@@ -559,6 +565,9 @@
     SendTimelinePacket 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();
+
     // Try declaring an invalid (empty) label
     BOOST_CHECK_THROW(timelineUtilityMethods.DeclareLabel(""), InvalidArgumentException);
 
@@ -569,15 +578,13 @@
     const std::string labelName = "valid label";
     ProfilingGuid labelGuid = 0;
     BOOST_CHECK_NO_THROW(labelGuid = timelineUtilityMethods.DeclareLabel(labelName));
-    // TODO when the implementation of the profiling GUID generator is done, enable the following test
-    //BOOST_CHECK(labelGuid != ProfilingGuid(0));
+    BOOST_CHECK(labelGuid != ProfilingGuid(0));
 
-    // TODO when the implementation of the profiling GUID generator is done, enable the following tests
     // Try adding the same label as before
-    //ProfilingGuid newLabelGuid = 0;
-    //BOOST_CHECK_NO_THROW(labelGuid = timelineUtilityMethods.DeclareLabel(labelName));
-    //BOOST_CHECK(newLabelGuid != ProfilingGuid(0));
-    //BOOST_CHECK(newLabelGuid == labelGuid);
+    ProfilingGuid newLabelGuid = 0;
+    BOOST_CHECK_NO_THROW(newLabelGuid = timelineUtilityMethods.DeclareLabel(labelName));
+    BOOST_CHECK(newLabelGuid != ProfilingGuid(0));
+    BOOST_CHECK(newLabelGuid == labelGuid);
 }
 
 BOOST_AUTO_TEST_CASE(CreateNameTypeEntityInvalidTest)
@@ -603,6 +610,9 @@
     const std::string entityName = "Entity0";
     const std::string entityType = "Type0";
 
+    // Generate first guid to ensure that the named typed entity guid is not 0 on local single test.
+    ProfilingService::Instance().NextGuid();
+
     ProfilingDynamicGuid guid = timelineUtilityMethods.CreateNamedTypedEntity(entityName, entityType);
     BOOST_CHECK(guid != ProfilingGuid(0));
 
@@ -673,6 +683,9 @@
     SendTimelinePacket 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();
+
     ProfilingGuid entityGuid(123);
     ProfilingStaticGuid eventClassGuid(456);
     ProfilingDynamicGuid eventGuid(0);