Using murmurhash2 instead of fnv

Rafael EspĂ­ndola via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 9 07:03:06 PDT 2016


One annoying property of fnv is that it does one multiplication per
byte. Murmurhash2 does 3 per every 8 bytes.

With the attached hack linking libxul.so goes from 7.496263743s to 6.661119354.

If there is no objections I will write a proper patch for it.

Cheers,
Rafael
-------------- next part --------------
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
index 7b197ce..0c63318 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -1693,16 +1693,58 @@ template <class ELFT> void BuildIdSection<ELFT>::writeTo(uint8_t *Buf) {
   HashBuf = Buf + 16;
 }
 
+uint64_t MurmurHash64A(const void *key, int len, uint64_t seed) {
+  const uint64_t m = 0xc6a4a7935bd1e995LLU;
+  const int r = 47;
+
+  uint64_t h = seed ^ (len * m);
+
+  const uint64_t *data = (const uint64_t *)key;
+  const uint64_t *end = data + (len / 8);
+
+  while (data != end) {
+    uint64_t k = *data++;
+
+    k *= m;
+    k ^= k >> r;
+    k *= m;
+
+    h ^= k;
+    h *= m;
+  }
+
+  const unsigned char *data2 = (const unsigned char *)data;
+  switch (len & 7) {
+  case 7:
+    h ^= uint64_t(data2[6]) << 48;
+  case 6:
+    h ^= uint64_t(data2[5]) << 40;
+  case 5:
+    h ^= uint64_t(data2[4]) << 32;
+  case 4:
+    h ^= uint64_t(data2[3]) << 24;
+  case 3:
+    h ^= uint64_t(data2[2]) << 16;
+  case 2:
+    h ^= uint64_t(data2[1]) << 8;
+  case 1:
+    h ^= uint64_t(data2[0]);
+    h *= m;
+  };
+
+  h ^= h >> r;
+  h *= m;
+  h ^= h >> r;
+
+  return h;
+}
+
 template <class ELFT>
 void BuildIdFnv1<ELFT>::writeBuildId(ArrayRef<uint8_t> Buf) {
   const endianness E = ELFT::TargetEndianness;
 
   // 64-bit FNV-1 hash
-  uint64_t Hash = 0xcbf29ce484222325;
-  for (uint8_t B : Buf) {
-    Hash *= 0x100000001b3;
-    Hash ^= B;
-  }
+  uint64_t Hash = MurmurHash64A(Buf.data(), Buf.size(), 0);
   write64<E>(this->HashBuf, Hash);
 }
 


More information about the llvm-commits mailing list