diff --git a/HISTORY b/HISTORY
index 09fe1a89..c256792c 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1,6 +1,11 @@
SnapRAID HISTORY
================
+3.2 2013/6
+==========
+ * Better selection of the RAID6 implementation for different CPUs.
+ * Adds support for the new Spooky hash. It's faster in 64 bit architectures.
+
3.1 2013/5
==========
* Direct use of Windows API for disk access to improve error reporting.
diff --git a/Makefile.am b/Makefile.am
index 031b7b18..23fcf97c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -32,6 +32,7 @@ noinst_HEADERS = \
parity.h \
handle.h \
murmurhash3.c \
+ spookyhash2.c \
tommyarray.h \
tommychain.h \
tommyhash.h \
diff --git a/acinclude.m4 b/acinclude.m4
index ceed823a..1b92cc9e 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -17,4 +17,3 @@ fi
rm -f conftest*
])
-
diff --git a/cpu.h b/cpu.h
index 0609418a..9656d40a 100644
--- a/cpu.h
+++ b/cpu.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Andrea Mazzoleni
+ * Copyright (C) 2011,2013 Andrea Mazzoleni
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,26 +26,66 @@
#define X86_FEATURE_XMM2 (0*32+26) /* Streaming SIMD Extensions-2 */
#define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */
-static inline int cpu_has(uint32_t flag)
+static inline void cpuid(uint32_t func, uint32_t* reg)
{
- uint32_t eax = (flag >> 5) ? 0x80000001 : 1;
- uint32_t edx;
-
asm volatile(
-#if defined(__i386__)
+#if defined(__i386__) && defined(__PIC__)
/* allow compilation in PIC mode saving ebx */
- "push %%ebx\n"
+ "xchgl %%ebx, %1\n"
"cpuid\n"
- "pop %%ebx\n"
- : "+a" (eax), "=d" (edx)
- : : "ecx");
+ "xchgl %%ebx, %1\n"
+ : "=a" (reg[0]), "=r" (reg[1]), "=c" (reg[2]), "=d" (reg[3])
+ : "0" (func)
#else
"cpuid\n"
- : "+a" (eax), "=d" (edx)
- : : "ecx", "ebx");
+ : "=a" (reg[0]), "=b" (reg[1]), "=c" (reg[2]), "=d" (reg[3])
+ : "0" (func)
#endif
+ );
+}
- return (edx >> (flag & 31)) & 1;
+static inline int cpu_has(uint32_t flag)
+{
+ uint32_t reg[4];
+
+ cpuid((flag >> 5) ? 0x80000001 : 1, reg);
+
+ return (reg[3] >> (flag & 31)) & 1;
+}
+
+#define CPU_VENDOR_MAX 13
+
+static inline void cpu_info(char* vendor, unsigned* family, unsigned* model)
+{
+ uint32_t reg[4];
+ unsigned f, ef, m, em;
+
+ cpuid(0, reg);
+
+ ((uint32_t*)vendor)[0] = reg[1];
+ ((uint32_t*)vendor)[1] = reg[3];
+ ((uint32_t*)vendor)[2] = reg[2];
+ vendor[12] = 0;
+
+ cpuid(1, reg);
+
+ f = (reg[0] >> 8) & 0xF;
+ ef = (reg[0] >> 20) & 0xFF;
+ m = (reg[0] >> 4) & 0xF;
+ em = (reg[0] >> 16) & 0xF;
+
+ if (strcmp(vendor, "AuthenticAMD") == 0) {
+ if (f < 15) {
+ *family = f;
+ *model = m;
+ } else {
+ *family = f + ef;
+ *model = m + (em << 4);
+ }
+ } else {
+ *family = f + ef;
+ *model = m + (em << 4);
+ }
}
static inline int cpu_has_mmx(void)
@@ -61,6 +101,232 @@ static inline int cpu_has_sse2(void)
cpu_has(X86_FEATURE_XMM2);
}
+/**
+ * Check if the processor has a slow SSE2 support.
+ * If yes, it's better to use MMX.
+ */
+static inline int cpu_has_slowsse2(void)
+{
+ char vendor[CPU_VENDOR_MAX];
+ unsigned family;
+ unsigned model;
+
+ cpu_info(vendor, &family, &model);
+
+ if (strcmp(vendor, "GenuineIntel") == 0) {
+ /* Atom (x264)
+ * Intel(R) Atom(TM) CPU D525 @ 1.80GHz (info from user)
+ * Compiler gcc 4.7.2
+ * CPU GenuineIntel, family 6, model 28, flags mmx sse2 slowsse2 slowmult
+ * Memory is little-endian 64-bit
+ * memset 2259 [MB/s]
+ * Murmur3 378 [MB/s]
+ * Spooky2 3423 [MB/s]
+ * RAID5 int32x2 1601 [MB/s]
+ * RAID5 mmxx2 2226 [MB/s]
+ * RAID5 sse2x2 3122 [MB/s]
+ * RAID6 int32x2 677 [MB/s]
+ * RAID6 mmxx2 1633 [MB/s]
+ * RAID6 sse2x2 500 [MB/s]
+ */
+ if (family == 6 && model == 28)
+ return 1;
+
+ /* Pentium-M "banias" (info from x264) */
+ if (family == 6 && model == 9)
+ return 1;
+
+ /* Pentium-M "dothan" (info from x264) */
+ if (family == 6 && model == 13)
+ return 1;
+
+ /* Core1 "yonah" (info from x264) */
+ if (family == 6 && model == 14)
+ return 1;
+ }
+
+ if (strcmp(vendor, "AuthenticAMD") == 0) {
+ /* Bobcat/Zacade (info from x264 -> full family 20)
+ * AMD E-350 Processor (info from user)
+ * Compiler gcc 4.7.3
+ * CPU AuthenticAMD, family 20, model 1, flags mmx sse2 slowsse2
+ * Memory is little-endian 64-bit
+ * memset 2137 [MB/s]
+ * Murmur3 1140 [MB/s]
+ * Spooky2 2326 [MB/s]
+ * RAID5 int32x2 1853 [MB/s]
+ * RAID5 mmxx2 2019 [MB/s]
+ * RAID5 sse2x2 2908 [MB/s]
+ * RAID6 int32x2 884 [MB/s]
+ * RAID6 mmxx2 1502 [MB/s]
+ * RAID6 sse2x2 1168 [MB/s]
+ */
+ if (family == 20)
+ return 1;
+
+ /* AMD Turion(tm) II Neo N40L Dual-Core Processor (info from user)
+ * Compiler gcc 4.7.1
+ * CPU AuthenticAMD, family 16, model 6, flags mmx sse2
+ * Memory is little-endian 64-bit
+ * memset 4910 [MB/s]
+ * Murmur3 1160 [MB/s]
+ * Spooky2 3994 [MB/s]
+ * RAID5 int32x2 530 [MB/s]
+ * RAID5 mmxx2 1114 [MB/s]
+ * RAID5 sse2x1 2127 [MB/s]
+ * RAID5 sse2x2 2804 [MB/s]
+ * RAID6 int32x2 316 [MB/s]
+ * RAID6 mmxx2 655 [MB/s]
+ * RAID6 sse2x2 639 [MB/s]
+ */
+ if (family == 16 && model == 6)
+ return 1;
+
+ /* AMD Athlon(tm) II X4 620 (info from user)
+ * Compiler gcc 4.7.3
+ * CPU AuthenticAMD, family 16, model 5, flags mmx sse2
+ * Memory is little-endian 64-bit
+ * memset 2845 [MB/s]
+ * Murmur3 2262 [MB/s]
+ * Murmur3x64 3500 [MB/s]
+ * Spooky2 4362 [MB/s]
+ * Spooky2x86 4000 [MB/s]
+ * RAID5 int32x2 1064 [MB/s]
+ * RAID5 mmxx2 2064 [MB/s]
+ * RAID5 sse2x2 3289 [MB/s]
+ * RAID6 int32x2 639 [MB/s]
+ * RAID6 mmxx2 1325 [MB/s]
+ * RAID6 sse2x2 915 [MB/s]
+ */
+ if (family == 16 && model == 5)
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Check if the processor has a slow MULT implementation.
+ * If yes, it's better to use a hash not based on multiplication.
+ */
+static inline int cpu_has_slowmult(void)
+{
+ char vendor[CPU_VENDOR_MAX];
+ unsigned family;
+ unsigned model;
+
+ cpu_info(vendor, &family, &model);
+
+ if (strcmp(vendor, "GenuineIntel") == 0) {
+ /* Intel(R) Atom(TM) CPU D525 @ 1.80GHz (info from user)
+ * Compiler gcc 4.7.2
+ * CPU GenuineIntel, family 6, model 28, flags mmx sse2 slowsse2 slowmult
+ * Memory is little-endian 64-bit
+ * memset 2259 [MB/s]
+ * Murmur3 378 [MB/s]
+ * Spooky2 3423 [MB/s]
+ * RAID5 int32x2 1601 [MB/s]
+ * RAID5 mmxx2 2226 [MB/s]
+ * RAID5 sse2x2 3122 [MB/s]
+ * RAID6 int32x2 677 [MB/s]
+ * RAID6 mmxx2 1633 [MB/s]
+ * RAID6 sse2x2 500 [MB/s]
+ */
+ if (family == 6 && model == 28)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* other cases */
+
+/* Intel(R) Core(TM) i7-3740QM CPU @ 2.70GHz
+ * Compiler gcc 4.7.3
+ * CPU GenuineIntel, family 6, model 58, flags mmx sse2
+ * Memory is little-endian 32-bit
+ * memset0 34685 [MB/s]
+ * Murmur3 4170 [MB/s]
+ * Spooky2 2599 [MB/s]
+ * RAID5 int32x2 8919 [MB/s]
+ * RAID5 mmxx2 17170 [MB/s]
+ * RAID5 sse2x2 27478 [MB/s]
+ * RAID6 int32x2 1953 [MB/s]
+ * RAID6 mmxx2 7560 [MB/s]
+ * RAID6 sse2x2 13930 [MB/s]
+ */
+
+/* Intel(R) Core(TM) i7-3740QM CPU @ 2.70GHz
+ * Compiler gcc 4.7.3
+ * CPU GenuineIntel, family 6, model 58, flags mmx sse2
+ * Memory is little-endian 64-bit
+ * memset0 26164 [MB/s]
+ * Murmur3 4469 [MB/s]
+ * Spooky2 12834 [MB/s]
+ * RAID5 int32x2 10775 [MB/s]
+ * RAID5 mmxx2 19644 [MB/s]
+ * RAID5 sse2x2 29168 [MB/s]
+ * RAID6 int32x2 3288 [MB/s]
+ * RAID6 mmxx2 8374 [MB/s]
+ * RAID6 sse2x2 15547 [MB/s]
+ */
+
+/* Intel(R) Core(TM) i5 CPU 650 @ 3.20GHz
+ * Compiler gcc 4.7.1
+ * CPU GenuineIntel, family 6, model 37, flags mmx sse2
+ * Memory is little-endian 32-bit
+ * memset0 25468 [MB/s]
+ * Murmur3 3357 [MB/s]
+ * Spooky2 1861 [MB/s]
+ * RAID5 int32x2 5043 [MB/s]
+ * RAID5 mmxx2 9864 [MB/s]
+ * RAID5 sse2x2 16896 [MB/s]
+ * RAID6 int32x2 1100 [MB/s]
+ * RAID6 mmxx2 5056 [MB/s]
+ * RAID6 sse2x2 8726 [MB/s]
+ */
+
+/* AMD Athlon(tm) 64 X2 Dual Core Processor 3600+ 1913.377 MHz
+ * Compiler gcc 4.7.3
+ * CPU AuthenticAMD, family 15, model 107, flags mmx sse2
+ * Memory is little-endian 32-bit
+ * memset 2414 [MB/s]
+ * Murmur3 1213 [MB/s]
+ * Spooky2 947 [MB/s]
+ * RAID5 int32x2 532 [MB/s]
+ * RAID5 mmxx2 1121 [MB/s]
+ * RAID5 sse2x2 2061 [MB/s]
+ * RAID6 int32x2 280 [MB/s]
+ * RAID6 mmxx2 632 [MB/s]
+ * RAID6 sse2x2 909 [MB/s]
+ */
+
+/* ARM Feroceon 88FR131 rev 1 (v5l)
+ * Compiler gcc 4.7.2
+ * CPU is not and x86/x64
+ * Memory is little-endian 32-bit
+ * memset 763 [MB/s]
+ * Murmur3 237 [MB/s]
+ * Spooky2 216 [MB/s]
+ * RAID5 int32x2 233 [MB/s]
+ * RAID6 int32x2 103 [MB/s]
+ */
+
+/* Intel(R) Xeon(R) CPU E3-1270 V2 @ 3.50GHz $
+ * Compiler gcc 4.8.1
+ * CPU GenuineIntel, family 6, model 58, flags mmx sse2
+ * Memory is little-endian 64-bit
+ * memset 27842 [MB/s]
+ * Murmur3 4884 [MB/s]
+ * Spooky2 14039 [MB/s]
+ * RAID5 int32x2 11038 [MB/s]
+ * RAID5 mmxx2 20055 [MB/s]
+ * RAID5 sse2x2 30703 [MB/s]
+ * RAID6 int32x2 3267 [MB/s]
+ * RAID6 mmxx2 8883 [MB/s]
+ * RAID6 sse2x2 16433 [MB/s]
+ */
+
#endif
#endif
diff --git a/murmurhash3.c b/murmurhash3.c
index df3439ff..2de9fc67 100644
--- a/murmurhash3.c
+++ b/murmurhash3.c
@@ -28,25 +28,6 @@
// MurmurHash3 was written by Austin Appleby, and is placed in the public
// domain. The author hereby disclaims copyright to this source code.
-/* Rotate left */
-inline uint32_t rotl32(uint32_t x, int8_t r)
-{
- return (x << r) | (x >> (32 - r));
-}
-
-/* Swap endianess */
-#if WORDS_BIGENDIAN
-static inline uint32_t swap32(uint32_t v)
-{
- return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | ((v >> 24) & 0xff);
-}
-#else
-static inline uint32_t swap32(uint32_t v)
-{
- return v;
-}
-#endif
-
/* Finalization mix - force all bits of a hash block to avalanche */
static inline uint32_t fmix32(uint32_t h)
{
@@ -94,26 +75,33 @@ uint32_t c2 = 0xab0e9789;
uint32_t c3 = 0x38b34ae5;
uint32_t c4 = 0xa1e38b93;
-void MurmurHash3_x86_128(const void * key, unsigned len, uint32_t seed, void* out)
+void MurmurHash3_x86_128(const void* key, unsigned len, void* out)
{
- const uint8_t * data = (const uint8_t*)key;
+ const uint8_t* data = key;
unsigned nblocks = len / 16;
unsigned i;
- uint32_t h1 = seed;
- uint32_t h2 = seed;
- uint32_t h3 = seed;
- uint32_t h4 = seed;
+ uint32_t h1 = 0;
+ uint32_t h2 = 0;
+ uint32_t h3 = 0;
+ uint32_t h4 = 0;
const uint32_t* blocks = (const uint32_t*)data;
/* body */
for(i=0;i.
+ */
+
+/*
+ * Derivative work from SpookyV2.cpp/h
+ *
+ * WARNING!!!! Note that this implementation doesn't use the short hash optimization
+ * resulting in different hashes for any length shorter than 192 bytes
+ *
+ * SpookyHash
+ * http://burtleburtle.net/bob/hash/spooky.html
+ *
+ * Exact source used as reference:
+ * http://burtleburtle.net/bob/c/SpookyV2.h
+ * http://burtleburtle.net/bob/c/SpookyV2.cpp
+ */
+
+// Spooky Hash
+// A 128-bit noncryptographic hash, for checksums and table lookup
+// By Bob Jenkins. Public domain.
+// Oct 31 2010: published framework, disclaimer ShortHash isn't right
+// Nov 7 2010: disabled ShortHash
+// Oct 31 2011: replace End, ShortMix, ShortEnd, enable ShortHash again
+// April 10 2012: buffer overflow on platforms without unaligned reads
+// July 12 2012: was passing out variables in final to in/out in short
+// July 30 2012: I reintroduced the buffer overflow
+// August 5 2012: SpookyV2: d = should be d += in short hash, and remove extra mix from long hash
+//
+// Up to 3 bytes/cycle for long messages. Reasonably fast for short messages.
+// All 1 or 2 bit deltas achieve avalanche within 1% bias per output bit.
+//
+// This was developed for and tested on 64-bit x86-compatible processors.
+// It assumes the processor is little-endian. There is a macro
+// controlling whether unaligned reads are allowed (by default they are).
+// This should be an equally good hash on big-endian machines, but it will
+// compute different results on them than on little-endian machines.
+//
+// Google's CityHash has similar specs to SpookyHash, and CityHash is faster
+// on new Intel boxes. MD4 and MD5 also have similar specs, but they are orders
+// of magnitude slower. CRCs are two or more times slower, but unlike
+// SpookyHash, they have nice math for combining the CRCs of pieces to form
+// the CRCs of wholes. There are also cryptographic hashes, but those are even
+// slower than MD5.
+//
+
+#define Mix(data, s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11) \
+ s0 += data[0]; s2 ^= s10; s11^= s0; s0 = rotl64(s0,11); s11 += s1; \
+ s1 += data[1]; s3 ^= s11; s0 ^= s1; s1 = rotl64(s1,32); s0 += s2; \
+ s2 += data[2]; s4 ^= s0; s1 ^= s2; s2 = rotl64(s2,43); s1 += s3; \
+ s3 += data[3]; s5 ^= s1; s2 ^= s3; s3 = rotl64(s3,31); s2 += s4; \
+ s4 += data[4]; s6 ^= s2; s3 ^= s4; s4 = rotl64(s4,17); s3 += s5; \
+ s5 += data[5]; s7 ^= s3; s4 ^= s5; s5 = rotl64(s5,28); s4 += s6; \
+ s6 += data[6]; s8 ^= s4; s5 ^= s6; s6 = rotl64(s6,39); s5 += s7; \
+ s7 += data[7]; s9 ^= s5; s6 ^= s7; s7 = rotl64(s7,57); s6 += s8; \
+ s8 += data[8]; s10^= s6; s7 ^= s8; s8 = rotl64(s8,55); s7 += s9; \
+ s9 += data[9]; s11^= s7; s8 ^= s9; s9 = rotl64(s9,54); s8 += s10; \
+ s10+= data[10]; s0 ^= s8; s9 ^= s10; s10= rotl64(s10,22); s9 += s11; \
+ s11+= data[11]; s1 ^= s9; s10^= s11; s11= rotl64(s11,46); s10 += s0;
+
+#define EndPartial(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11) \
+ h11+= h1; h2 ^= h11; h1 = rotl64(h1,44); \
+ h0 += h2; h3 ^= h0; h2 = rotl64(h2,15); \
+ h1 += h3; h4 ^= h1; h3 = rotl64(h3,34); \
+ h2 += h4; h5 ^= h2; h4 = rotl64(h4,21); \
+ h3 += h5; h6 ^= h3; h5 = rotl64(h5,38); \
+ h4 += h6; h7 ^= h4; h6 = rotl64(h6,33); \
+ h5 += h7; h8 ^= h5; h7 = rotl64(h7,10); \
+ h6 += h8; h9 ^= h6; h8 = rotl64(h8,13); \
+ h7 += h9; h10^= h7; h9 = rotl64(h9,38); \
+ h8 += h10; h11^= h8; h10= rotl64(h10,53); \
+ h9 += h11; h0 ^= h9; h11= rotl64(h11,42); \
+ h10+= h0; h1 ^= h10; h0 = rotl64(h0,54); \
+
+#define End(data, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10,h11) \
+ h0 += data[0]; h1 += data[1]; h2 += data[2]; h3 += data[3]; \
+ h4 += data[4]; h5 += data[5]; h6 += data[6]; h7 += data[7]; \
+ h8 += data[8]; h9 += data[9]; h10+= data[10]; h11+= data[11]; \
+ EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11); \
+ EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11); \
+ EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
+
+// number of uint64_t's in internal state
+#define sc_numVars 12
+
+// size of the internal state
+#define sc_blockSize (sc_numVars*8)
+
+//
+// sc_const: a constant which:
+// * is not zero
+// * is odd
+// * is a not-very-regular mix of 1's and 0's
+// * does not need any other special mathematical properties
+//
+#define sc_const 0xdeadbeefdeadbeefLL
+
+void SpookyHash128(const void* message, size_t length, uint8_t* digest)
+{
+ uint64_t h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11;
+ uint64_t buf[sc_numVars];
+ uint64_t* end;
+ union {
+ const uint8_t* p8;
+ uint64_t* p64;
+ size_t i;
+ } u;
+ size_t remainder;
+
+ h0 = h3 = h6 = h9 = 0;
+ h1 = h4 = h7 = h10 = 0;
+ h2 = h5 = h8 = h11 = sc_const;
+
+ u.p8 = message;
+ end = u.p64 + (length/sc_blockSize)*sc_numVars;
+
+ /* body */
+
+ while (u.p64 < end) {
+#if WORDS_BIGENDIAN
+ unsigned i;
+ for(i=0;ipool[0] = 0;
state->pool_device = 0;
state->level = 1; /* default is the lowest protection */
- state->hash = HASH_MURMUR3; /* default is the fastest */
+
+ /* select the fastest hash */
+
+#if defined(__i386__) || defined(__x86_64__)
+ if (sizeof(void*) == 4 && !cpu_has_slowmult())
+ state->hash = HASH_MURMUR3;
+ else
+ state->hash = HASH_SPOOKY2;
+#else
+ if (sizeof(void*) == 4)
+ state->hash = HASH_MURMUR3;
+ else
+ state->hash = HASH_SPOOKY2;
+#endif
+ state->hash = HASH_MURMUR3;
+
tommy_list_init(&state->disklist);
tommy_list_init(&state->maplist);
tommy_list_init(&state->contentlist);
@@ -1416,6 +1432,9 @@ void state_read(struct snapraid_state* state)
} else if (strcmp(buffer, "murmur3") == 0) {
state->hash = HASH_MURMUR3;
hash = oathash8(hash, 'u');
+ } else if (strcmp(buffer, "spooky2") == 0) {
+ state->hash = HASH_SPOOKY2;
+ hash = oathash8(hash, 'k');
} else {
fprintf(stderr, "Invalid 'checksum' specification '%s' in '%s' at line %u\n", buffer, path, line);
exit(EXIT_FAILURE);
@@ -1630,10 +1649,17 @@ void state_write(struct snapraid_state* state)
sputsl("checksum md5", f);
hash = oathash8(hash, 'c');
hash = oathash8(hash, 'm');
- } else {
+ } else if (state->hash == HASH_MURMUR3) {
sputsl("checksum murmur3", f);
hash = oathash8(hash, 'c');
hash = oathash8(hash, 'u');
+ } else if (state->hash == HASH_SPOOKY2) {
+ sputsl("checksum spooky2", f);
+ hash = oathash8(hash, 'c');
+ hash = oathash8(hash, 'k');
+ } else {
+ fprintf(stderr, "Unexpected hash when writing the content file '%s'.\n", serrorfile(f));
+ exit(EXIT_FAILURE);
}
sputeol(f);
if (serror(f)) {
diff --git a/util.c b/util.c
index 45199493..7e50e9d3 100644
--- a/util.c
+++ b/util.c
@@ -795,13 +795,55 @@ char* strdup_nofail(const char* str)
return ptr;
}
+/****************************************************************************/
+/* hash */
+
+/* Rotate left 32 */
+inline uint32_t rotl32(uint32_t x, int8_t r)
+{
+ return (x << r) | (x >> (32 - r));
+}
+
+inline uint64_t rotl64(uint64_t x, int8_t r)
+{
+ return (x << r) | (x >> (64 - r));
+}
+
+/* Swap endianess */
+#if HAVE_BYTESWAP_H
+
+#include
+
+#define swap32(x) bswap_32(x)
+#define swap64(x) bswap_64(x)
+
+#else
+static inline uint32_t swap32(uint32_t v)
+{
+ return (rotl32(v, 8) & 0x00ff00ff)
+ | (rotl32(v, 24) & 0xff00ff00);
+}
+
+static inline uint64_t swap64(uint64_t v)
+{
+ return (rotl64(v, 8) & 0x000000ff000000ffLLU)
+ | (rotl64(v, 24) & 0x0000ff000000ff00LLU)
+ | (rotl64(v, 40) & 0x00ff000000ff0000LLU)
+ | (rotl64(v, 56) & 0xff000000ff000000LLU);
+}
+#endif
+
#include "murmurhash3.c"
+#include "spookyhash2.c"
void memhash(unsigned kind, void* digest, const void* src, unsigned size)
{
switch (kind) {
case HASH_MURMUR3 :
- MurmurHash3_x86_128(src, size, 0, digest);
+ MurmurHash3_x86_128(src, size, digest);
+ break;
+ case HASH_SPOOKY2 :
+ SpookyHash128(src, size, digest);
break;
default:
fprintf(stderr, "Internal inconsistency in hash function %u\n", kind);
diff --git a/util.h b/util.h
index 3354e7b2..a91f8bac 100644
--- a/util.h
+++ b/util.h
@@ -390,6 +390,7 @@ char* strdup_nofail(const char* str);
#define HASH_UNDEFINED 0
#define HASH_MD5 1
#define HASH_MURMUR3 2
+#define HASH_SPOOKY2 3
/**
* Computes the HASH of a memory block.