Make HashUtil implements as cpp, So reduce duplicated implmenets 07/322207/14
authorEunki Hong <eunkiki.hong@samsung.com>
Sun, 6 Apr 2025 05:05:43 +0000 (14:05 +0900)
committerEunki Hong <eunkiki.hong@samsung.com>
Wed, 9 Apr 2025 14:17:39 +0000 (23:17 +0900)
Let we make basement of hash calculate optimization

+

Include below patchset, due to line coverage
https://review.tizen.org/gerrit/c/platform/core/uifw/dali-core/+/322289

Change-Id: I8b4679b737f5adfa0c09932af17f02d61bdea8a4
Signed-off-by: Eunki Hong <eunkiki.hong@samsung.com>
dali/internal/common/hash-utils.cpp [new file with mode: 0644]
dali/internal/common/hash-utils.h
dali/internal/file.list
dali/internal/render/shaders/program.cpp

diff --git a/dali/internal/common/hash-utils.cpp b/dali/internal/common/hash-utils.cpp
new file mode 100644 (file)
index 0000000..3fdce90
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADERS
+#include <dali/internal/common/hash-utils.h>
+
+// EXTERNAL INCLUDES
+#include <cstdint> // uint8_t
+
+namespace Dali::Internal::HashUtils
+{
+HashType HashRawByteBufferMultipleComponent(const uint8_t* __restrict__ buffer, std::size_t bufferSize, HashType& hash)
+{
+  // TODO : use ARM_NEON here in future
+  static constexpr HashType SCALE_LEVEL_1 = Dali::Power<33, 1>::value;
+  static constexpr HashType SCALE_LEVEL_2 = Dali::Power<33, 2>::value;
+  static constexpr HashType SCALE_LEVEL_3 = Dali::Power<33, 3>::value;
+  static constexpr HashType SCALE_LEVEL_4 = Dali::Power<33, 4>::value;
+  static constexpr HashType SCALE_LEVEL_5 = Dali::Power<33, 5>::value;
+  static constexpr HashType SCALE_LEVEL_6 = Dali::Power<33, 6>::value;
+  static constexpr HashType SCALE_LEVEL_7 = Dali::Power<33, 7>::value;
+  static constexpr HashType SCALE_LEVEL_8 = Dali::Power<33, 8>::value;
+
+  while(bufferSize & (~0x7)) // bufferSize >= 8
+  {
+    // clang-format off
+    hash = hash * SCALE_LEVEL_8 +
+           *(buffer + 0) * SCALE_LEVEL_7 +
+           *(buffer + 1) * SCALE_LEVEL_6 +
+           *(buffer + 2) * SCALE_LEVEL_5 +
+           *(buffer + 3) * SCALE_LEVEL_4 +
+           *(buffer + 4) * SCALE_LEVEL_3 +
+           *(buffer + 5) * SCALE_LEVEL_2 +
+           *(buffer + 6) * SCALE_LEVEL_1 +
+           *(buffer + 7);
+    // clang-format on
+    buffer += 8;
+    bufferSize -= 8;
+  }
+
+  if(bufferSize & 0x4) // bufferSize >= 4. Note that 0 <= bufferSize < 8 in here.
+  {
+    // clang-format off
+    hash = hash * SCALE_LEVEL_4 +
+           *(buffer + 0) * SCALE_LEVEL_3 +
+           *(buffer + 1) * SCALE_LEVEL_2 +
+           *(buffer + 2) * SCALE_LEVEL_1 +
+           *(buffer + 3);
+    // clang-format on
+    buffer += 4;
+    bufferSize &= 0x3;
+  }
+
+  // Now bufferSize is 0, 1, 2, 3. We can optimize here by switch-case
+  switch(bufferSize)
+  {
+    case 3:
+    {
+      hash = hash * 33 + *(buffer++);
+      DALI_FALLTHROUGH;
+    }
+    case 2:
+    {
+      hash = hash * 33 + *(buffer++);
+      DALI_FALLTHROUGH;
+    }
+    case 1:
+    {
+      hash = hash * 33 + *(buffer++);
+      DALI_FALLTHROUGH;
+    }
+    case 0:
+    default:
+    {
+      break;
+    }
+  }
+
+  return hash;
+}
+
+} // namespace Dali::Internal::HashUtils
index 81639ec4ccb01adddfacaba8f6f00a7243938369..5fe123390f70469c82207a4d417069b5fd14368c 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_HASH_UTILS_H
 
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 namespace Dali::Internal::HashUtils
 {
-constexpr std::size_t INITIAL_HASH_VALUE = 5381;
+using HashType = std::size_t;
+
+constexpr HashType INITIAL_HASH_VALUE = 5381;
 
 /*
  * djb2 (http://www.cse.yorku.ca/~oz/hash.html)
  */
 
-[[maybe_unused]] inline std::size_t HashString(const char* string, std::size_t& hash)
+[[maybe_unused]] inline HashType HashString(const char* string, HashType& hash)
 {
   while(int c = *string++)
   {
@@ -44,7 +46,7 @@ constexpr std::size_t INITIAL_HASH_VALUE = 5381;
   return hash;
 }
 
-[[maybe_unused]] inline std::size_t HashString(const char* string, std::size_t& hash, char terminator)
+[[maybe_unused]] inline HashType HashString(const char* string, HashType& hash, char terminator)
 {
   char c;
   while((c = *string++) && c != terminator)
@@ -54,16 +56,7 @@ constexpr std::size_t INITIAL_HASH_VALUE = 5381;
   return hash;
 }
 
-[[maybe_unused]] inline std::size_t HashStringView(const std::string_view& string, std::size_t& hash)
-{
-  for(auto c : string)
-  {
-    hash = hash * 33 + c;
-  }
-  return hash;
-}
-
-[[maybe_unused]] inline std::size_t HashStringView(const std::string_view& string, std::size_t& hash, char terminator)
+[[maybe_unused]] inline HashType HashStringView(const std::string_view& string, HashType& hash, char terminator)
 {
   for(auto c : string)
   {
@@ -71,50 +64,53 @@ constexpr std::size_t INITIAL_HASH_VALUE = 5381;
     {
       break;
     }
-    hash = hash * 33 + static_cast<std::size_t>(c);
+    hash = hash * 33 + static_cast<HashType>(c);
   }
   return hash;
 }
 
-[[maybe_unused]] inline std::size_t HashBuffer(const std::vector<std::uint8_t>& buffer, std::size_t& hash)
+// Hash functions with specified length, which we could optimize for
+[[maybe_unused]] HashType HashRawByteBufferMultipleComponent(const uint8_t* __restrict__ buffer, std::size_t bufferSize, HashType& hash);
+
+[[maybe_unused]] inline HashType HashRawByteBuffer(const uint8_t* __restrict__ buffer, std::size_t bufferSize, HashType& hash)
 {
-  for(const auto& c : buffer)
+  if(bufferSize > 8)
   {
-    hash = hash * 33 + c;
+    return HashRawByteBufferMultipleComponent(buffer, bufferSize, hash);
   }
-  return hash;
-}
 
-[[maybe_unused]] inline std::size_t HashBuffer(const Dali::Vector<std::uint8_t>& buffer, std::size_t& hash)
-{
-  for(const auto& c : buffer)
+  while(bufferSize--)
   {
-    hash = hash * 33 + c;
+    hash = hash * 33 + *(buffer++);
   }
   return hash;
 }
 
+[[maybe_unused]] inline HashType HashStringView(const std::string_view& string, HashType& hash)
+{
+  return HashRawByteBuffer(reinterpret_cast<const uint8_t*>(string.data()), string.size(), hash);
+}
+
+[[maybe_unused]] inline HashType HashBuffer(const std::vector<std::uint8_t>& buffer, HashType& hash)
+{
+  return HashRawByteBuffer(buffer.data(), buffer.size(), hash);
+}
+
+[[maybe_unused]] inline HashType HashBuffer(const Dali::Vector<std::uint8_t>& buffer, HashType& hash)
+{
+  return HashRawByteBuffer(buffer.Begin(), buffer.Count(), hash);
+}
+
 template<typename T>
-[[maybe_unused]] inline std::size_t HashRawBuffer(const T* buffer, std::size_t bufferSize, std::size_t& hash)
+[[maybe_unused]] inline HashType HashRawBuffer(const T* __restrict__ buffer, std::size_t bufferSize, HashType& hash)
 {
-  if constexpr(sizeof(T) == 1u)
-  {
-    while(bufferSize--)
-    {
-      hash = hash * 33 + *(buffer++);
-    }
-    return hash;
-  }
-  else
-  {
-    return HashRawBuffer(reinterpret_cast<const std::uint8_t*>(buffer), sizeof(T) * bufferSize, hash);
-  }
+  return HashRawByteBuffer(reinterpret_cast<const uint8_t*>(buffer), sizeof(T) * bufferSize, hash);
 }
 
 template<typename T>
-[[maybe_unused]] inline std::size_t HashRawValue(const T& value, std::size_t& hash)
+[[maybe_unused]] inline HashType HashRawValue(const T& value, HashType& hash)
 {
-  return HashRawBuffer(reinterpret_cast<const std::uint8_t*>(&value), sizeof(T), hash);
+  return HashRawBuffer(reinterpret_cast<const uint8_t*>(&value), sizeof(T), hash);
 }
 
 } // namespace Dali::Internal::HashUtils
index e8956ec52d147427e216ad630b95f975135a9dda..63f3a5e954965d0a9117832cc5d665e038716aa4 100644 (file)
@@ -6,6 +6,7 @@ SET( internal_src_files
   ${internal_src_dir}/common/blending-options.cpp
   ${internal_src_dir}/common/core-impl.cpp
   ${internal_src_dir}/common/dummy-memory-pool.cpp
+  ${internal_src_dir}/common/hash-utils.cpp
   ${internal_src_dir}/common/math.cpp
   ${internal_src_dir}/common/matrix-utils.cpp
   ${internal_src_dir}/common/message-buffer.cpp
index b97caac4f729e9f90c7e1381eaffe7168430abb3..d13a74ba7e8ed556a6b067fd9524ffe3e6ba6fdb 100644 (file)
@@ -144,7 +144,7 @@ void Program::BuildRequirements(
       //
       // If the name represents an element in an array of structs, it will contain an
       // index operator, but should be hashed in full.
-      auto hashValue = CalculateHash(item.name);
+      auto hashValue = CalculateHash(std::string_view(item.name.data(), item.name.size()));
       mReflection.emplace_back(ReflectionUniformInfo{hashValue, false, item});
 
       // update buffer index
@@ -166,7 +166,7 @@ void Program::BuildRequirements(
   auto samplers = graphicsReflection.GetSamplers(); // Only holds first element of arrays without [].
   for(const auto& sampler : samplers)
   {
-    mReflection.emplace_back(ReflectionUniformInfo{CalculateHash(sampler.name), false, sampler});
+    mReflection.emplace_back(ReflectionUniformInfo{CalculateHash(std::string_view(sampler.name.data(), sampler.name.size())), false, sampler});
   }
 
   // check for potential collisions