IVGCVSW-3691 Add utility function to generate valid UIDs for profiling objects

Change-Id: I59ad320bfd52c881671c5e4710fb70c5d0293aad
Signed-off-by: Matteo Martincigh <matteo.martincigh@arm.com>
diff --git a/src/profiling/ProfilingUtils.cpp b/src/profiling/ProfilingUtils.cpp
index 015a66e..ef67f03 100644
--- a/src/profiling/ProfilingUtils.cpp
+++ b/src/profiling/ProfilingUtils.cpp
@@ -10,6 +10,8 @@
 #include <boost/assert.hpp>
 
 #include <fstream>
+#include <limits>
+#include <mutex>
 
 namespace armnn
 {
@@ -17,6 +19,27 @@
 namespace profiling
 {
 
+uint16_t GetNextUid()
+{
+    // Static mutex for reading and modifying the global UID a single thread at the time
+    static std::mutex mutex;
+    std::unique_lock<std::mutex> lock(mutex);
+
+    // The UID used for profiling objects and events. The first valid UID is 1, as 0 is a reserved value
+    // (it is used to indicate that a record is not associated with any device)
+    static uint16_t uid{ 0 };
+
+    // Check that it is possible to generate the next UID without causing an overflow
+    if (uid == std::numeric_limits<uint16_t>::max())
+    {
+        throw RuntimeException("Generating the next UID for profiling would result in an overflow");
+    }
+
+    // Thread safe increment, the value that is incremented is the value checked for overflow,
+    // as this whole function is mutexed
+    return ++uid;
+}
+
 void WriteUint64(unsigned char* buffer, unsigned int offset, uint64_t value)
 {
     BOOST_ASSERT(buffer);
@@ -54,7 +77,7 @@
     BOOST_ASSERT(buffer);
 
     uint64_t value = 0;
-    value = static_cast<uint64_t>(buffer[offset]);
+    value  = static_cast<uint64_t>(buffer[offset]);
     value |= static_cast<uint64_t>(buffer[offset + 1]) << 8;
     value |= static_cast<uint64_t>(buffer[offset + 2]) << 16;
     value |= static_cast<uint64_t>(buffer[offset + 3]) << 24;
diff --git a/src/profiling/ProfilingUtils.hpp b/src/profiling/ProfilingUtils.hpp
index 410198a..0e94e61 100644
--- a/src/profiling/ProfilingUtils.hpp
+++ b/src/profiling/ProfilingUtils.hpp
@@ -16,6 +16,8 @@
 namespace profiling
 {
 
+uint16_t GetNextUid();
+
 void WriteUint64(unsigned char* buffer, unsigned int offset, uint64_t value);
 
 void WriteUint32(unsigned char* buffer, unsigned int offset, uint32_t value);
diff --git a/src/profiling/test/ProfilingTests.cpp b/src/profiling/test/ProfilingTests.cpp
index eda45e8..fe94092 100644
--- a/src/profiling/test/ProfilingTests.cpp
+++ b/src/profiling/test/ProfilingTests.cpp
@@ -11,7 +11,7 @@
 #include "../Packet.hpp"
 #include "../PacketVersionResolver.hpp"
 #include "../ProfilingStateMachine.hpp"
-
+#include "../ProfilingUtils.hpp"
 #include "../ProfilingService.hpp"
 
 #include <boost/test/unit_test.hpp>
@@ -502,4 +502,30 @@
     BOOST_CHECK(service.GetCurrentState() ==  ProfilingState::WaitingForAck);
 }
 
+void GetNextUidTestImpl(uint16_t& outUid)
+{
+    outUid = GetNextUid();
+}
+
+BOOST_AUTO_TEST_CASE(GetNextUidTest)
+{
+    uint16_t uid0 = 0;
+    uint16_t uid1 = 0;
+    uint16_t uid2 = 0;
+
+    std::thread thread1(GetNextUidTestImpl, std::ref(uid0));
+    std::thread thread2(GetNextUidTestImpl, std::ref(uid1));
+    std::thread thread3(GetNextUidTestImpl, std::ref(uid2));
+    thread1.join();
+    thread2.join();
+    thread3.join();
+
+    BOOST_TEST(uid0 > 0);
+    BOOST_TEST(uid1 > 0);
+    BOOST_TEST(uid2 > 0);
+    BOOST_TEST(uid0 != uid1);
+    BOOST_TEST(uid0 != uid2);
+    BOOST_TEST(uid1 != uid2);
+}
+
 BOOST_AUTO_TEST_SUITE_END()