All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Update jhash.h with the new version of Jenkins' hash
@ 2009-02-11 10:19 Jozsef Kadlecsik
  2009-02-11 20:19 ` Michał Mirosław
                   ` (2 more replies)
  0 siblings, 3 replies; 22+ messages in thread
From: Jozsef Kadlecsik @ 2009-02-11 10:19 UTC (permalink / raw)
  To: linux-kernel; +Cc: netdev, netfilter-devel, Rusty Russell

Hi,

The current jhash.h implements the lookup2() hash function by Bob Jenkins. 
However, lookup2() is outdated as Bob wrote a new hash function called 
lookup3(). The new hash function

- mixes better than lookup2(): it passes the check that every input bit 
  changes every output bit 50% of the time, while lookup2() failed it.
- performs better: compiled with -O2 on Core2 Duo, lookup3() is 20-40% 
  faster than lookup2() depending on the key length.

The patch replaces the lookup2() implementation of the 'jhash*' 
functions with that of lookup3() in linux/jhash.h.

You can read a longer comparison of the Jenkins and other hash functions 
at http://burtleburtle.net/bob/hash/doobs.html.

Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>

diff --git a/include/linux/jhash.h b/include/linux/jhash.h
index 2a2f99f..2000b9f 100644
--- a/include/linux/jhash.h
+++ b/include/linux/jhash.h
@@ -3,80 +3,95 @@
 
 /* jhash.h: Jenkins hash support.
  *
- * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
+ * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net)
  *
  * http://burtleburtle.net/bob/hash/
  *
  * These are the credits from Bob's sources:
  *
- * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
- * hash(), hash2(), hash3, and mix() are externally useful functions.
- * Routines to test the hash are included if SELF_TEST is defined.
- * You can use this free for any purpose.  It has no warranty.
+ * lookup3.c, by Bob Jenkins, May 2006, Public Domain.
  *
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * These are functions for producing 32-bit hashes for hash table lookup.
+ * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() 
+ * are externally useful functions.  Routines to test the hash are included 
+ * if SELF_TEST is defined.  You can use this free for any purpose.  It's in
+ * the public domain.  It has no warranty.
+ *
+ * Copyright (C) 2009 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
  *
  * I've modified Bob's hash to be useful in the Linux kernel, and
- * any bugs present are surely my fault.  -DaveM
+ * any bugs present are my fault.  Jozsef
  */
 
-/* NOTE: Arguments are modified. */
-#define __jhash_mix(a, b, c) \
+#define __rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/* __jhash_mix - mix 3 32-bit values reversibly. */
+#define __jhash_mix(a,b,c) \
+{ \
+  a -= c;  a ^= __rot(c, 4);  c += b; \
+  b -= a;  b ^= __rot(a, 6);  a += c; \
+  c -= b;  c ^= __rot(b, 8);  b += a; \
+  a -= c;  a ^= __rot(c,16);  c += b; \
+  b -= a;  b ^= __rot(a,19);  a += c; \
+  c -= b;  c ^= __rot(b, 4);  b += a; \
+}
+
+/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */
+#define __jhash_final(a,b,c) \
 { \
-  a -= b; a -= c; a ^= (c>>13); \
-  b -= c; b -= a; b ^= (a<<8); \
-  c -= a; c -= b; c ^= (b>>13); \
-  a -= b; a -= c; a ^= (c>>12);  \
-  b -= c; b -= a; b ^= (a<<16); \
-  c -= a; c -= b; c ^= (b>>5); \
-  a -= b; a -= c; a ^= (c>>3);  \
-  b -= c; b -= a; b ^= (a<<10); \
-  c -= a; c -= b; c ^= (b>>15); \
+  c ^= b; c -= __rot(b,14); \
+  a ^= c; a -= __rot(c,11); \
+  b ^= a; b -= __rot(a,25); \
+  c ^= b; c -= __rot(b,16); \
+  a ^= c; a -= __rot(c,4);  \
+  b ^= a; b -= __rot(a,14); \
+  c ^= b; c -= __rot(b,24); \
 }
 
 /* The golden ration: an arbitrary value */
-#define JHASH_GOLDEN_RATIO	0x9e3779b9
+#define JHASH_GOLDEN_RATIO	0xdeadbeef
 
 /* The most generic version, hashes an arbitrary sequence
  * of bytes.  No alignment or length assumptions are made about
- * the input key.
+ * the input key. The result depends on endianness.
  */
 static inline u32 jhash(const void *key, u32 length, u32 initval)
 {
-	u32 a, b, c, len;
+	u32 a,b,c;
 	const u8 *k = key;
 
-	len = length;
-	a = b = JHASH_GOLDEN_RATIO;
-	c = initval;
-
-	while (len >= 12) {
-		a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24));
-		b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24));
-		c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24));
-
-		__jhash_mix(a,b,c);
+	/* Set up the internal state */
+	a = b = c = JHASH_GOLDEN_RATIO + length + initval;
 
+	/* all but the last block: affect some 32 bits of (a,b,c) */
+	while (length > 12) {
+    		a += (k[0] + ((u32)k[1]<<8) + ((u32)k[2]<<16) + ((u32)k[3]<<24));
+		b += (k[4] + ((u32)k[5]<<8) + ((u32)k[6]<<16) + ((u32)k[7]<<24));
+		c += (k[8] + ((u32)k[9]<<8) + ((u32)k[10]<<16) + ((u32)k[11]<<24));
+		__jhash_mix(a, b, c);
+		length -= 12;
 		k += 12;
-		len -= 12;
 	}
 
-	c += length;
-	switch (len) {
-	case 11: c += ((u32)k[10]<<24);
-	case 10: c += ((u32)k[9]<<16);
-	case 9 : c += ((u32)k[8]<<8);
-	case 8 : b += ((u32)k[7]<<24);
-	case 7 : b += ((u32)k[6]<<16);
-	case 6 : b += ((u32)k[5]<<8);
+	/* last block: affect all 32 bits of (c) */
+	/* all the case statements fall through */
+	switch (length) {
+	case 12: c += (u32)k[11]<<24;
+	case 11: c += (u32)k[10]<<16;
+	case 10: c += (u32)k[9]<<8;
+	case 9 : c += k[8];
+	case 8 : b += (u32)k[7]<<24;
+	case 7 : b += (u32)k[6]<<16;
+	case 6 : b += (u32)k[5]<<8;
 	case 5 : b += k[4];
-	case 4 : a += ((u32)k[3]<<24);
-	case 3 : a += ((u32)k[2]<<16);
-	case 2 : a += ((u32)k[1]<<8);
+	case 4 : a += (u32)k[3]<<24;
+	case 3 : a += (u32)k[2]<<16;
+	case 2 : a += (u32)k[1]<<8;
 	case 1 : a += k[0];
-	};
-
-	__jhash_mix(a,b,c);
+		__jhash_final(a, b, c);
+	case 0 :
+		break;
+	}
 
 	return c;
 }
@@ -86,58 +101,57 @@ static inline u32 jhash(const void *key, u32 length, u32 initval)
  */
 static inline u32 jhash2(const u32 *k, u32 length, u32 initval)
 {
-	u32 a, b, c, len;
+	u32 a, b, c;
 
-	a = b = JHASH_GOLDEN_RATIO;
-	c = initval;
-	len = length;
+	/* Set up the internal state */
+	a = b = c = JHASH_GOLDEN_RATIO + (length<<2) + initval;
 
-	while (len >= 3) {
+	/* handle most of the key */
+	while (length > 3) {
 		a += k[0];
 		b += k[1];
 		c += k[2];
 		__jhash_mix(a, b, c);
-		k += 3; len -= 3;
+		length -= 3;
+		k += 3;
 	}
 
-	c += length * 4;
-
-	switch (len) {
-	case 2 : b += k[1];
-	case 1 : a += k[0];
-	};
-
-	__jhash_mix(a,b,c);
+	/* handle the last 3 u32's */
+	/* all the case statements fall through */ 
+	switch (length) {
+	case 3: c += k[2];
+	case 2: b += k[1];
+	case 1: a += k[0];
+		__jhash_final(a, b, c);
+	case 0:     /* case 0: nothing left to add */
+		break;
+	}
 
 	return c;
 }
 
-
 /* A special ultra-optimized versions that knows they are hashing exactly
  * 3, 2 or 1 word(s).
- *
- * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
- *       done at the end is not done here.
  */
 static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
 {
-	a += JHASH_GOLDEN_RATIO;
-	b += JHASH_GOLDEN_RATIO;
-	c += initval;
+	a += JHASH_GOLDEN_RATIO + initval;
+	b += JHASH_GOLDEN_RATIO + initval;
+	c += JHASH_GOLDEN_RATIO + initval;
 
-	__jhash_mix(a, b, c);
+	__jhash_final(a, b, c);
 
 	return c;
 }
 
 static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
 {
-	return jhash_3words(a, b, 0, initval);
+	return jhash_3words(0, a, b, initval);
 }
 
 static inline u32 jhash_1word(u32 a, u32 initval)
 {
-	return jhash_3words(a, 0, 0, initval);
+	return jhash_3words(0, 0, a, initval);
 }
 
 #endif /* _LINUX_JHASH_H */


Best regards,
Jozsef
-
E-mail  : kadlec@blackhole.kfki.hu, kadlec@mail.kfki.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : KFKI Research Institute for Particle and Nuclear Physics
          H-1525 Budapest 114, POB. 49, Hungary

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-11 10:19 [PATCH] Update jhash.h with the new version of Jenkins' hash Jozsef Kadlecsik
@ 2009-02-11 20:19 ` Michał Mirosław
  2009-02-11 22:50   ` Jozsef Kadlecsik
  2009-02-12  0:12 ` wli
  2009-02-12  2:58 ` Rusty Russell
  2 siblings, 1 reply; 22+ messages in thread
From: Michał Mirosław @ 2009-02-11 20:19 UTC (permalink / raw)
  To: Jozsef Kadlecsik; +Cc: linux-kernel, netdev, netfilter-devel, Rusty Russell

Hi,

On Wed, Feb 11, 2009 at 11:19:20AM +0100, Jozsef Kadlecsik wrote:
>  /* The golden ration: an arbitrary value */
> -#define JHASH_GOLDEN_RATIO	0x9e3779b9
> +#define JHASH_GOLDEN_RATIO	0xdeadbeef

I have a stupid question: if this is arbitrary value, then why not
just get rid of it (IOW use zero as it's used in addition)?

Best Regards,
Michał Mirosław

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-11 20:19 ` Michał Mirosław
@ 2009-02-11 22:50   ` Jozsef Kadlecsik
  2009-02-11 23:23     ` Michał Mirosław
  0 siblings, 1 reply; 22+ messages in thread
From: Jozsef Kadlecsik @ 2009-02-11 22:50 UTC (permalink / raw)
  To: Michał Mirosław
  Cc: linux-kernel, netdev, netfilter-devel, Rusty Russell

On Wed, 11 Feb 2009, Micha? Miros?aw wrote:

> On Wed, Feb 11, 2009 at 11:19:20AM +0100, Jozsef Kadlecsik wrote:
> >  /* The golden ration: an arbitrary value */
> > -#define JHASH_GOLDEN_RATIO	0x9e3779b9
> > +#define JHASH_GOLDEN_RATIO	0xdeadbeef
> 
> I have a stupid question: if this is arbitrary value, then why not
> just get rid of it (IOW use zero as it's used in addition)?

lookup3() is a quite generic hash function and it supports 0-byte strings 
as input keys too. If the input key is a 0-byte string and the arbitrary 
value is zero, then the hash value simply equal to the initval. In order 
to avoid that case, the arbitrary value must be nonzero.

Best regards,
Jozsef
-
E-mail  : kadlec@blackhole.kfki.hu, kadlec@mail.kfki.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : KFKI Research Institute for Particle and Nuclear Physics
          H-1525 Budapest 114, POB. 49, Hungary

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-11 22:50   ` Jozsef Kadlecsik
@ 2009-02-11 23:23     ` Michał Mirosław
  0 siblings, 0 replies; 22+ messages in thread
From: Michał Mirosław @ 2009-02-11 23:23 UTC (permalink / raw)
  To: Jozsef Kadlecsik; +Cc: linux-kernel, netdev, netfilter-devel, Rusty Russell

On Wed, Feb 11, 2009 at 11:50:38PM +0100, Jozsef Kadlecsik wrote:
> On Wed, 11 Feb 2009, Micha? Miros?aw wrote:
> > On Wed, Feb 11, 2009 at 11:19:20AM +0100, Jozsef Kadlecsik wrote:
> > >  /* The golden ration: an arbitrary value */
> > > -#define JHASH_GOLDEN_RATIO	0x9e3779b9
> > > +#define JHASH_GOLDEN_RATIO	0xdeadbeef
> > I have a stupid question: if this is arbitrary value, then why not
> > just get rid of it (IOW use zero as it's used in addition)?
> lookup3() is a quite generic hash function and it supports 0-byte strings 
> as input keys too. If the input key is a 0-byte string and the arbitrary 
> value is zero, then the hash value simply equal to the initval. In order 
> to avoid that case, the arbitrary value must be nonzero.

Double-hashing, of course! I really need more sleep. Sorry for the noise. :>

Best Regards,
Michał Mirosław


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-11 10:19 [PATCH] Update jhash.h with the new version of Jenkins' hash Jozsef Kadlecsik
  2009-02-11 20:19 ` Michał Mirosław
@ 2009-02-12  0:12 ` wli
  2009-02-12  0:29   ` David Miller
  2009-02-12  9:11   ` Jozsef Kadlecsik
  2009-02-12  2:58 ` Rusty Russell
  2 siblings, 2 replies; 22+ messages in thread
From: wli @ 2009-02-12  0:12 UTC (permalink / raw)
  To: Jozsef Kadlecsik; +Cc: linux-kernel, netdev, netfilter-devel, Rusty Russell

On Wed, Feb 11, 2009 at 11:19:20AM +0100, Jozsef Kadlecsik wrote:
>  /* The golden ration: an arbitrary value */
> -#define JHASH_GOLDEN_RATIO	0x9e3779b9
> +#define JHASH_GOLDEN_RATIO	0xdeadbeef

The golden ratio is not an arbitrary value, nor is it a food ration.
It is (sqrt(5)+1)/2. and the original value of JHASH_GOLDEN_RATIO
approximated its reciprocal and/or fractional part in fixed point.

(double)0xdeadbeef/((unsigned long long)1 << 32) is a rather poor
approximation of (sqrt(5)-1)/2. If this value which is not the
golden ratio is arbitrary, calling it something different from
JHASH_GOLDEN_RATIO would surprise the code's readers much less.


-- wli

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-12  0:12 ` wli
@ 2009-02-12  0:29   ` David Miller
  2009-02-12  0:41     ` Jan Engelhardt
  2009-02-12  9:11   ` Jozsef Kadlecsik
  1 sibling, 1 reply; 22+ messages in thread
From: David Miller @ 2009-02-12  0:29 UTC (permalink / raw)
  To: wli; +Cc: kadlec, linux-kernel, netdev, netfilter-devel, rusty

From: wli@movementarian.org
Date: Wed, 11 Feb 2009 19:12:23 -0500

> (double)0xdeadbeef/((unsigned long long)1 << 32) is a rather poor
> approximation of (sqrt(5)-1)/2. If this value which is not the
> golden ratio is arbitrary, calling it something different from
> JHASH_GOLDEN_RATIO would surprise the code's readers much less.

Then we can change the name, whatever...

But really, anyone truly interested will read the friggin' web site
where all the design documents and hash test results live.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-12  0:29   ` David Miller
@ 2009-02-12  0:41     ` Jan Engelhardt
  2009-02-12  9:05       ` Jarek Poplawski
  0 siblings, 1 reply; 22+ messages in thread
From: Jan Engelhardt @ 2009-02-12  0:41 UTC (permalink / raw)
  To: David Miller; +Cc: wli, kadlec, linux-kernel, netdev, netfilter-devel, rusty


On Thursday 2009-02-12 01:29, David Miller wrote:
>
>> (double)0xdeadbeef/((unsigned long long)1 << 32) is a rather poor
>> approximation of (sqrt(5)-1)/2. If this value which is not the
>> golden ratio is arbitrary, calling it something different from
>> JHASH_GOLDEN_RATIO would surprise the code's readers much less.
>
>Then we can change the name, whatever...
>
>But really, anyone truly interested will read the friggin' web site
>where all the design documents and hash test results live.

Why should we use deadbeef over golden_ratio anyway? It's just a
random constant. And I'd take the gold over beef anytime ;-)

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-11 10:19 [PATCH] Update jhash.h with the new version of Jenkins' hash Jozsef Kadlecsik
  2009-02-11 20:19 ` Michał Mirosław
  2009-02-12  0:12 ` wli
@ 2009-02-12  2:58 ` Rusty Russell
  2 siblings, 0 replies; 22+ messages in thread
From: Rusty Russell @ 2009-02-12  2:58 UTC (permalink / raw)
  To: Jozsef Kadlecsik; +Cc: linux-kernel, netdev, netfilter-devel

On Wednesday 11 February 2009 20:49:20 Jozsef Kadlecsik wrote:
> Hi,
> 
> The current jhash.h implements the lookup2() hash function by Bob Jenkins. 
> However, lookup2() is outdated as Bob wrote a new hash function called 
> lookup3(). The new hash function
> 
> - mixes better than lookup2(): it passes the check that every input bit 
>   changes every output bit 50% of the time, while lookup2() failed it.
> - performs better: compiled with -O2 on Core2 Duo, lookup3() is 20-40% 
>   faster than lookup2() depending on the key length.

Hi Joszef,

My concern was that it's also bigger (and we inline it).  Performance is
pretty much a wash since we so rarely hash more than a few words.

Any stats on code size changes?
Rusty.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-12  0:41     ` Jan Engelhardt
@ 2009-02-12  9:05       ` Jarek Poplawski
  2009-02-12  9:55         ` Jarek Poplawski
  0 siblings, 1 reply; 22+ messages in thread
From: Jarek Poplawski @ 2009-02-12  9:05 UTC (permalink / raw)
  To: Jan Engelhardt
  Cc: David Miller, wli, kadlec, linux-kernel, netdev, netfilter-devel, rusty

On 12-02-2009 01:41, Jan Engelhardt wrote:
...
> And I'd take the gold over beef anytime ;-)

Better be careful! History, like Greek myths, or even quite recent,
could be surprising...

Jarek P.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-12  0:12 ` wli
  2009-02-12  0:29   ` David Miller
@ 2009-02-12  9:11   ` Jozsef Kadlecsik
  2009-02-12  9:16     ` Patrick McHardy
                       ` (2 more replies)
  1 sibling, 3 replies; 22+ messages in thread
From: Jozsef Kadlecsik @ 2009-02-12  9:11 UTC (permalink / raw)
  To: wli; +Cc: linux-kernel, netdev, netfilter-devel, Rusty Russell

On Wed, 11 Feb 2009, wli@movementarian.org wrote:

> On Wed, Feb 11, 2009 at 11:19:20AM +0100, Jozsef Kadlecsik wrote:
> >  /* The golden ration: an arbitrary value */
> > -#define JHASH_GOLDEN_RATIO	0x9e3779b9
> > +#define JHASH_GOLDEN_RATIO	0xdeadbeef
> 
> The golden ratio is not an arbitrary value, nor is it a food ration.
> It is (sqrt(5)+1)/2. and the original value of JHASH_GOLDEN_RATIO
> approximated its reciprocal and/or fractional part in fixed point.
> 
> (double)0xdeadbeef/((unsigned long long)1 << 32) is a rather poor
> approximation of (sqrt(5)-1)/2. If this value which is not the
> golden ratio is arbitrary, calling it something different from
> JHASH_GOLDEN_RATIO would surprise the code's readers much less.

OK, here follows the patch with the arbitrary initial parameter renamed.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
The current jhash.h implements the lookup2() hash function by Bob Jenkins. 
However, lookup2() is outdated as Bob wrote a new hash function called 
lookup3(). The new hash function

- mixes better than lookup2(): it passes the check that every input bit 
  changes every output bit 50% of the time, while lookup2() failed it.
- performs better: compiled with -O2 on Core2 Duo, lookup3() 20-40% faster
  than lookup2() depending on the key length.

The patch replaces the lookup2() implementation of the 'jhash*' 
functions with that of lookup3().

You can read a longer comparison of the two and other hash functions at 
http://burtleburtle.net/bob/hash/doobs.html.

Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>

diff --git a/include/linux/jhash.h b/include/linux/jhash.h
index 2a2f99f..765a9d6 100644
--- a/include/linux/jhash.h
+++ b/include/linux/jhash.h
@@ -3,80 +3,95 @@
 
 /* jhash.h: Jenkins hash support.
  *
- * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
+ * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net)
  *
  * http://burtleburtle.net/bob/hash/
  *
  * These are the credits from Bob's sources:
  *
- * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
- * hash(), hash2(), hash3, and mix() are externally useful functions.
- * Routines to test the hash are included if SELF_TEST is defined.
- * You can use this free for any purpose.  It has no warranty.
+ * lookup3.c, by Bob Jenkins, May 2006, Public Domain.
  *
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * These are functions for producing 32-bit hashes for hash table lookup.
+ * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() 
+ * are externally useful functions.  Routines to test the hash are included 
+ * if SELF_TEST is defined.  You can use this free for any purpose.  It's in
+ * the public domain.  It has no warranty.
+ *
+ * Copyright (C) 2009 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
  *
  * I've modified Bob's hash to be useful in the Linux kernel, and
- * any bugs present are surely my fault.  -DaveM
+ * any bugs present are my fault.  Jozsef
  */
 
-/* NOTE: Arguments are modified. */
-#define __jhash_mix(a, b, c) \
+#define __rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/* __jhash_mix - mix 3 32-bit values reversibly. */
+#define __jhash_mix(a,b,c) \
+{ \
+  a -= c;  a ^= __rot(c, 4);  c += b; \
+  b -= a;  b ^= __rot(a, 6);  a += c; \
+  c -= b;  c ^= __rot(b, 8);  b += a; \
+  a -= c;  a ^= __rot(c,16);  c += b; \
+  b -= a;  b ^= __rot(a,19);  a += c; \
+  c -= b;  c ^= __rot(b, 4);  b += a; \
+}
+
+/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */
+#define __jhash_final(a,b,c) \
 { \
-  a -= b; a -= c; a ^= (c>>13); \
-  b -= c; b -= a; b ^= (a<<8); \
-  c -= a; c -= b; c ^= (b>>13); \
-  a -= b; a -= c; a ^= (c>>12);  \
-  b -= c; b -= a; b ^= (a<<16); \
-  c -= a; c -= b; c ^= (b>>5); \
-  a -= b; a -= c; a ^= (c>>3);  \
-  b -= c; b -= a; b ^= (a<<10); \
-  c -= a; c -= b; c ^= (b>>15); \
+  c ^= b; c -= __rot(b,14); \
+  a ^= c; a -= __rot(c,11); \
+  b ^= a; b -= __rot(a,25); \
+  c ^= b; c -= __rot(b,16); \
+  a ^= c; a -= __rot(c,4);  \
+  b ^= a; b -= __rot(a,14); \
+  c ^= b; c -= __rot(b,24); \
 }
 
-/* The golden ration: an arbitrary value */
-#define JHASH_GOLDEN_RATIO	0x9e3779b9
+/* An arbitrary initial parameter */
+#define JHASH_INIT_PARAM	0xdeadbeef
 
 /* The most generic version, hashes an arbitrary sequence
  * of bytes.  No alignment or length assumptions are made about
- * the input key.
+ * the input key. The result depends on endianness.
  */
 static inline u32 jhash(const void *key, u32 length, u32 initval)
 {
-	u32 a, b, c, len;
+	u32 a,b,c;
 	const u8 *k = key;
 
-	len = length;
-	a = b = JHASH_GOLDEN_RATIO;
-	c = initval;
-
-	while (len >= 12) {
-		a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24));
-		b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24));
-		c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24));
-
-		__jhash_mix(a,b,c);
+	/* Set up the internal state */
+	a = b = c = JHASH_INIT_PARAM + length + initval;
 
+	/* all but the last block: affect some 32 bits of (a,b,c) */
+	while (length > 12) {
+    		a += (k[0] + ((u32)k[1]<<8) + ((u32)k[2]<<16) + ((u32)k[3]<<24));
+		b += (k[4] + ((u32)k[5]<<8) + ((u32)k[6]<<16) + ((u32)k[7]<<24));
+		c += (k[8] + ((u32)k[9]<<8) + ((u32)k[10]<<16) + ((u32)k[11]<<24));
+		__jhash_mix(a, b, c);
+		length -= 12;
 		k += 12;
-		len -= 12;
 	}
 
-	c += length;
-	switch (len) {
-	case 11: c += ((u32)k[10]<<24);
-	case 10: c += ((u32)k[9]<<16);
-	case 9 : c += ((u32)k[8]<<8);
-	case 8 : b += ((u32)k[7]<<24);
-	case 7 : b += ((u32)k[6]<<16);
-	case 6 : b += ((u32)k[5]<<8);
+	/* last block: affect all 32 bits of (c) */
+	/* all the case statements fall through */
+	switch (length) {
+	case 12: c += (u32)k[11]<<24;
+	case 11: c += (u32)k[10]<<16;
+	case 10: c += (u32)k[9]<<8;
+	case 9 : c += k[8];
+	case 8 : b += (u32)k[7]<<24;
+	case 7 : b += (u32)k[6]<<16;
+	case 6 : b += (u32)k[5]<<8;
 	case 5 : b += k[4];
-	case 4 : a += ((u32)k[3]<<24);
-	case 3 : a += ((u32)k[2]<<16);
-	case 2 : a += ((u32)k[1]<<8);
+	case 4 : a += (u32)k[3]<<24;
+	case 3 : a += (u32)k[2]<<16;
+	case 2 : a += (u32)k[1]<<8;
 	case 1 : a += k[0];
-	};
-
-	__jhash_mix(a,b,c);
+		__jhash_final(a, b, c);
+	case 0 :
+		break;
+	}
 
 	return c;
 }
@@ -86,58 +101,57 @@ static inline u32 jhash(const void *key, u32 length, u32 initval)
  */
 static inline u32 jhash2(const u32 *k, u32 length, u32 initval)
 {
-	u32 a, b, c, len;
+	u32 a, b, c;
 
-	a = b = JHASH_GOLDEN_RATIO;
-	c = initval;
-	len = length;
+	/* Set up the internal state */
+	a = b = c = JHASH_INIT_PARAM + (length<<2) + initval;
 
-	while (len >= 3) {
+	/* handle most of the key */
+	while (length > 3) {
 		a += k[0];
 		b += k[1];
 		c += k[2];
 		__jhash_mix(a, b, c);
-		k += 3; len -= 3;
+		length -= 3;
+		k += 3;
 	}
 
-	c += length * 4;
-
-	switch (len) {
-	case 2 : b += k[1];
-	case 1 : a += k[0];
-	};
-
-	__jhash_mix(a,b,c);
+	/* handle the last 3 u32's */
+	/* all the case statements fall through */ 
+	switch (length) {
+	case 3: c += k[2];
+	case 2: b += k[1];
+	case 1: a += k[0];
+		__jhash_final(a, b, c);
+	case 0:     /* case 0: nothing left to add */
+		break;
+	}
 
 	return c;
 }
 
-
 /* A special ultra-optimized versions that knows they are hashing exactly
  * 3, 2 or 1 word(s).
- *
- * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
- *       done at the end is not done here.
  */
 static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
 {
-	a += JHASH_GOLDEN_RATIO;
-	b += JHASH_GOLDEN_RATIO;
-	c += initval;
+	a += JHASH_INIT_PARAM + initval;
+	b += JHASH_INIT_PARAM + initval;
+	c += JHASH_INIT_PARAM + initval;
 
-	__jhash_mix(a, b, c);
+	__jhash_final(a, b, c);
 
 	return c;
 }
 
 static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
 {
-	return jhash_3words(a, b, 0, initval);
+	return jhash_3words(0, a, b, initval);
 }
 
 static inline u32 jhash_1word(u32 a, u32 initval)
 {
-	return jhash_3words(a, 0, 0, initval);
+	return jhash_3words(0, 0, a, initval);
 }
 
 #endif /* _LINUX_JHASH_H */

Best regards,
Jozsef
-
E-mail  : kadlec@blackhole.kfki.hu, kadlec@mail.kfki.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : KFKI Research Institute for Particle and Nuclear Physics
          H-1525 Budapest 114, POB. 49, Hungary

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-12  9:11   ` Jozsef Kadlecsik
@ 2009-02-12  9:16     ` Patrick McHardy
  2009-02-12  9:41       ` Jozsef Kadlecsik
  2009-02-12 13:46     ` Kyle Moffett
  2009-02-12 19:58     ` Eric W. Biederman
  2 siblings, 1 reply; 22+ messages in thread
From: Patrick McHardy @ 2009-02-12  9:16 UTC (permalink / raw)
  To: Jozsef Kadlecsik
  Cc: wli, linux-kernel, netdev, netfilter-devel, Rusty Russell

Jozsef Kadlecsik wrote:
> -#define __jhash_mix(a, b, c) \
> +#define __rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
> +
> +/* __jhash_mix - mix 3 32-bit values reversibly. */
> +#define __jhash_mix(a,b,c) \
> +{ \
> +  a -= c;  a ^= __rot(c, 4);  c += b; \
> +  b -= a;  b ^= __rot(a, 6);  a += c; \
> +  c -= b;  c ^= __rot(b, 8);  b += a; \
> +  a -= c;  a ^= __rot(c,16);  c += b; \
> +  b -= a;  b ^= __rot(a,19);  a += c; \
> +  c -= b;  c ^= __rot(b, 4);  b += a; \
> +}

include/linux/bitops.h includes multiple rot variants. rol32()
looks approriate.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-12  9:16     ` Patrick McHardy
@ 2009-02-12  9:41       ` Jozsef Kadlecsik
  0 siblings, 0 replies; 22+ messages in thread
From: Jozsef Kadlecsik @ 2009-02-12  9:41 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: linux-kernel, netdev, netfilter-devel, Rusty Russell

On Thu, 12 Feb 2009, Patrick McHardy wrote:

> Jozsef Kadlecsik wrote:
> > -#define __jhash_mix(a, b, c) \
> > +#define __rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
> > +
> > +/* __jhash_mix - mix 3 32-bit values reversibly. */
> > +#define __jhash_mix(a,b,c) \
> > +{ \
> > +  a -= c;  a ^= __rot(c, 4);  c += b; \
> > +  b -= a;  b ^= __rot(a, 6);  a += c; \
> > +  c -= b;  c ^= __rot(b, 8);  b += a; \
> > +  a -= c;  a ^= __rot(c,16);  c += b; \
> > +  b -= a;  b ^= __rot(a,19);  a += c; \
> > +  c -= b;  c ^= __rot(b, 4);  b += a; \
> > +}
> 
> include/linux/bitops.h includes multiple rot variants. rol32()
> looks approriate.

Thank Patrick, patch updated with rol32():

Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>

diff --git a/include/linux/jhash.h b/include/linux/jhash.h
index 2a2f99f..e48ecc2 100644
--- a/include/linux/jhash.h
+++ b/include/linux/jhash.h
@@ -1,82 +1,97 @@
 #ifndef _LINUX_JHASH_H
 #define _LINUX_JHASH_H
 
+#include <linux/bitops.h>
+
 /* jhash.h: Jenkins hash support.
  *
- * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
+ * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net)
  *
  * http://burtleburtle.net/bob/hash/
  *
  * These are the credits from Bob's sources:
  *
- * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
- * hash(), hash2(), hash3, and mix() are externally useful functions.
- * Routines to test the hash are included if SELF_TEST is defined.
- * You can use this free for any purpose.  It has no warranty.
+ * lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+ *
+ * These are functions for producing 32-bit hashes for hash table lookup.
+ * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() 
+ * are externally useful functions.  Routines to test the hash are included 
+ * if SELF_TEST is defined.  You can use this free for any purpose.  It's in
+ * the public domain.  It has no warranty.
  *
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2009 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
  *
  * I've modified Bob's hash to be useful in the Linux kernel, and
- * any bugs present are surely my fault.  -DaveM
+ * any bugs present are my fault.  Jozsef
  */
 
-/* NOTE: Arguments are modified. */
-#define __jhash_mix(a, b, c) \
+/* __jhash_mix - mix 3 32-bit values reversibly. */
+#define __jhash_mix(a,b,c) \
+{ \
+  a -= c;  a ^= rol32(c, 4);  c += b; \
+  b -= a;  b ^= rol32(a, 6);  a += c; \
+  c -= b;  c ^= rol32(b, 8);  b += a; \
+  a -= c;  a ^= rol32(c,16);  c += b; \
+  b -= a;  b ^= rol32(a,19);  a += c; \
+  c -= b;  c ^= rol32(b, 4);  b += a; \
+}
+
+/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */
+#define __jhash_final(a,b,c) \
 { \
-  a -= b; a -= c; a ^= (c>>13); \
-  b -= c; b -= a; b ^= (a<<8); \
-  c -= a; c -= b; c ^= (b>>13); \
-  a -= b; a -= c; a ^= (c>>12);  \
-  b -= c; b -= a; b ^= (a<<16); \
-  c -= a; c -= b; c ^= (b>>5); \
-  a -= b; a -= c; a ^= (c>>3);  \
-  b -= c; b -= a; b ^= (a<<10); \
-  c -= a; c -= b; c ^= (b>>15); \
+  c ^= b; c -= rol32(b,14); \
+  a ^= c; a -= rol32(c,11); \
+  b ^= a; b -= rol32(a,25); \
+  c ^= b; c -= rol32(b,16); \
+  a ^= c; a -= rol32(c,4);  \
+  b ^= a; b -= rol32(a,14); \
+  c ^= b; c -= rol32(b,24); \
 }
 
-/* The golden ration: an arbitrary value */
-#define JHASH_GOLDEN_RATIO	0x9e3779b9
+/* An arbitrary initial parameter */
+#define JHASH_INIT_PARAM	0xdeadbeef
 
 /* The most generic version, hashes an arbitrary sequence
  * of bytes.  No alignment or length assumptions are made about
- * the input key.
+ * the input key. The result depends on endianness.
  */
 static inline u32 jhash(const void *key, u32 length, u32 initval)
 {
-	u32 a, b, c, len;
+	u32 a,b,c;
 	const u8 *k = key;
 
-	len = length;
-	a = b = JHASH_GOLDEN_RATIO;
-	c = initval;
-
-	while (len >= 12) {
-		a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24));
-		b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24));
-		c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24));
-
-		__jhash_mix(a,b,c);
+	/* Set up the internal state */
+	a = b = c = JHASH_INIT_PARAM + length + initval;
 
+	/* all but the last block: affect some 32 bits of (a,b,c) */
+	while (length > 12) {
+    		a += (k[0] + ((u32)k[1]<<8) + ((u32)k[2]<<16) + ((u32)k[3]<<24));
+		b += (k[4] + ((u32)k[5]<<8) + ((u32)k[6]<<16) + ((u32)k[7]<<24));
+		c += (k[8] + ((u32)k[9]<<8) + ((u32)k[10]<<16) + ((u32)k[11]<<24));
+		__jhash_mix(a, b, c);
+		length -= 12;
 		k += 12;
-		len -= 12;
 	}
 
-	c += length;
-	switch (len) {
-	case 11: c += ((u32)k[10]<<24);
-	case 10: c += ((u32)k[9]<<16);
-	case 9 : c += ((u32)k[8]<<8);
-	case 8 : b += ((u32)k[7]<<24);
-	case 7 : b += ((u32)k[6]<<16);
-	case 6 : b += ((u32)k[5]<<8);
+	/* last block: affect all 32 bits of (c) */
+	/* all the case statements fall through */
+	switch (length) {
+	case 12: c += (u32)k[11]<<24;
+	case 11: c += (u32)k[10]<<16;
+	case 10: c += (u32)k[9]<<8;
+	case 9 : c += k[8];
+	case 8 : b += (u32)k[7]<<24;
+	case 7 : b += (u32)k[6]<<16;
+	case 6 : b += (u32)k[5]<<8;
 	case 5 : b += k[4];
-	case 4 : a += ((u32)k[3]<<24);
-	case 3 : a += ((u32)k[2]<<16);
-	case 2 : a += ((u32)k[1]<<8);
+	case 4 : a += (u32)k[3]<<24;
+	case 3 : a += (u32)k[2]<<16;
+	case 2 : a += (u32)k[1]<<8;
 	case 1 : a += k[0];
-	};
-
-	__jhash_mix(a,b,c);
+		__jhash_final(a, b, c);
+	case 0 :
+		break;
+	}
 
 	return c;
 }
@@ -86,58 +101,57 @@ static inline u32 jhash(const void *key, u32 length, u32 initval)
  */
 static inline u32 jhash2(const u32 *k, u32 length, u32 initval)
 {
-	u32 a, b, c, len;
+	u32 a, b, c;
 
-	a = b = JHASH_GOLDEN_RATIO;
-	c = initval;
-	len = length;
+	/* Set up the internal state */
+	a = b = c = JHASH_INIT_PARAM + (length<<2) + initval;
 
-	while (len >= 3) {
+	/* handle most of the key */
+	while (length > 3) {
 		a += k[0];
 		b += k[1];
 		c += k[2];
 		__jhash_mix(a, b, c);
-		k += 3; len -= 3;
+		length -= 3;
+		k += 3;
 	}
 
-	c += length * 4;
-
-	switch (len) {
-	case 2 : b += k[1];
-	case 1 : a += k[0];
-	};
-
-	__jhash_mix(a,b,c);
+	/* handle the last 3 u32's */
+	/* all the case statements fall through */ 
+	switch (length) {
+	case 3: c += k[2];
+	case 2: b += k[1];
+	case 1: a += k[0];
+		__jhash_final(a, b, c);
+	case 0:     /* case 0: nothing left to add */
+		break;
+	}
 
 	return c;
 }
 
-
 /* A special ultra-optimized versions that knows they are hashing exactly
  * 3, 2 or 1 word(s).
- *
- * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
- *       done at the end is not done here.
  */
 static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
 {
-	a += JHASH_GOLDEN_RATIO;
-	b += JHASH_GOLDEN_RATIO;
-	c += initval;
+	a += JHASH_INIT_PARAM + initval;
+	b += JHASH_INIT_PARAM + initval;
+	c += JHASH_INIT_PARAM + initval;
 
-	__jhash_mix(a, b, c);
+	__jhash_final(a, b, c);
 
 	return c;
 }
 
 static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
 {
-	return jhash_3words(a, b, 0, initval);
+	return jhash_3words(0, a, b, initval);
 }
 
 static inline u32 jhash_1word(u32 a, u32 initval)
 {
-	return jhash_3words(a, 0, 0, initval);
+	return jhash_3words(0, 0, a, initval);
 }
 
 #endif /* _LINUX_JHASH_H */

Best regards,
Jozsef
-
E-mail  : kadlec@blackhole.kfki.hu, kadlec@mail.kfki.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : KFKI Research Institute for Particle and Nuclear Physics
          H-1525 Budapest 114, POB. 49, Hungary

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-12  9:05       ` Jarek Poplawski
@ 2009-02-12  9:55         ` Jarek Poplawski
  0 siblings, 0 replies; 22+ messages in thread
From: Jarek Poplawski @ 2009-02-12  9:55 UTC (permalink / raw)
  To: Jan Engelhardt
  Cc: David Miller, wli, kadlec, linux-kernel, netdev, netfilter-devel, rusty

On Thu, Feb 12, 2009 at 09:05:13AM +0000, Jarek Poplawski wrote:
> On 12-02-2009 01:41, Jan Engelhardt wrote:
> ...
> > And I'd take the gold over beef anytime ;-)
> 
> Better be careful! History, like Greek myths, or even quite recent,
> could be surprising...

...But love over gold looks like safe bet! (love over beef too ;-)

Jarek P.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-12  9:11   ` Jozsef Kadlecsik
  2009-02-12  9:16     ` Patrick McHardy
@ 2009-02-12 13:46     ` Kyle Moffett
  2009-02-17 17:13       ` Jozsef Kadlecsik
  2009-02-12 19:58     ` Eric W. Biederman
  2 siblings, 1 reply; 22+ messages in thread
From: Kyle Moffett @ 2009-02-12 13:46 UTC (permalink / raw)
  To: Jozsef Kadlecsik
  Cc: wli, linux-kernel, netdev, netfilter-devel, Rusty Russell

On Thu, Feb 12, 2009 at 4:11 AM, Jozsef Kadlecsik
<kadlec@blackhole.kfki.hu> wrote:
> The current jhash.h implements the lookup2() hash function by Bob Jenkins.
> However, lookup2() is outdated as Bob wrote a new hash function called
> lookup3(). The new hash function
>
> - mixes better than lookup2(): it passes the check that every input bit
>  changes every output bit 50% of the time, while lookup2() failed it.
> - performs better: compiled with -O2 on Core2 Duo, lookup3() 20-40% faster
>  than lookup2() depending on the key length.

Well, there's another question which is not addressed by Bob Jenkins'
design docs:

Kernel code usually runs cache-cold, whereas Bob Jenkins did most of
his testing cache-hot in tight loops.  If you compile both lookup2 and
lookup3 with -Os and run them in a loop with a cache flush, how well
do they compare then?

Cheers,
Kyle Moffett

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-12  9:11   ` Jozsef Kadlecsik
  2009-02-12  9:16     ` Patrick McHardy
  2009-02-12 13:46     ` Kyle Moffett
@ 2009-02-12 19:58     ` Eric W. Biederman
  2 siblings, 0 replies; 22+ messages in thread
From: Eric W. Biederman @ 2009-02-12 19:58 UTC (permalink / raw)
  To: Jozsef Kadlecsik
  Cc: wli, linux-kernel, netdev, netfilter-devel, Rusty Russell

Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> writes:

> On Wed, 11 Feb 2009, wli@movementarian.org wrote:
>
>> On Wed, Feb 11, 2009 at 11:19:20AM +0100, Jozsef Kadlecsik wrote:
>> >  /* The golden ration: an arbitrary value */
>> > -#define JHASH_GOLDEN_RATIO	0x9e3779b9
>> > +#define JHASH_GOLDEN_RATIO	0xdeadbeef
>> 

0xdeadbeef is a really bad choice of an arbitrary value.  It is
already used in multiple places.  Only a few of which are currently
listed in linux/poison.h and if I happened to see that number in a
debug trace having to sort through all of the possible sources looks
like a major pain.

I don't really care what we call it but somehow 0xdeadbeef strikes me
as wrong and something that will make debugging harder.

Eric

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-12 13:46     ` Kyle Moffett
@ 2009-02-17 17:13       ` Jozsef Kadlecsik
  2009-02-18  5:11         ` Rusty Russell
  2009-02-18 11:50         ` Ilpo Järvinen
  0 siblings, 2 replies; 22+ messages in thread
From: Jozsef Kadlecsik @ 2009-02-17 17:13 UTC (permalink / raw)
  To: Kyle Moffett; +Cc: linux-kernel, netdev, netfilter-devel, Rusty Russell

Hi,

On Thu, 12 Feb 2009, Kyle Moffett wrote:

> On Thu, Feb 12, 2009 at 4:11 AM, Jozsef Kadlecsik
> <kadlec@blackhole.kfki.hu> wrote:
> > The current jhash.h implements the lookup2() hash function by Bob Jenkins.
> > However, lookup2() is outdated as Bob wrote a new hash function called
> > lookup3(). The new hash function
> >
> > - mixes better than lookup2(): it passes the check that every input bit
> >  changes every output bit 50% of the time, while lookup2() failed it.
> > - performs better: compiled with -O2 on Core2 Duo, lookup3() 20-40% faster
> >  than lookup2() depending on the key length.
> 
> Well, there's another question which is not addressed by Bob Jenkins'
> design docs:
> 
> Kernel code usually runs cache-cold, whereas Bob Jenkins did most of
> his testing cache-hot in tight loops.  If you compile both lookup2 and
> lookup3 with -Os and run them in a loop with a cache flush, how well
> do they compare then?

In order to get as much data as possible, I dusted off the good old cttest 
program which was used long time ago to test and pick the currently used 
lookup2 function. I added lookup3 to cttest, converted the internals to 
follow the current netfilter/conntrack hash lookup usage and introduced a 
large enough input buffer to force cold cache. I also added the superfast 
hash by Paul Hsieh and murmur2 hash of Austin Appleby, to check those as 
well.

The test program and all the generated html pages and graphs are at
http://www.kfki.hu/~kadlec/sw/netfilter/ct3/. Here follows just a terse 
summary:

- Superfasthash is definitely not good enough as it can too easily 
  produce just too much clashes.
- The murmur2 hash is the fastest one and looks quite good, still it
  had got some trouble at specific hash table sizes.
- No weakness could be spotted with the lookup3 hash.
- When compiling with -Os, the hashes from fastest to slowest are:
  murmur2, lookup3, superfast, lookup2.
- When compiling with -O2, the hashes from fastest to slowest are:
  murmur2, superfast, lookup3 and lookup2.

On Thu, 12 Feb 2009, Rusty Russell wrote:

> My concern was that it's also bigger (and we inline it).  Performance is
> pretty much a wash since we so rarely hash more than a few words.

In netfilter/conntrack (;-) we call the hash function for every packet, so 
even if a small number of cycle can be gained at one lookup, I think it's 
worth. And in the IPv4/IPv6 neutral nf_conntrack we hash 9 words.

> Any stats on code size changes?

The minimal code here

#include <stdint.h>

typedef uint64_t u64;
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;

#ifdef JHASH
#include "jhash.h"
#else
#include "jhash3.h"
#endif

u32 hash(const u32 *key, u32 len, u32 initval)
{
        return jhash2(key, len, initval);
}
/* eof */

compiled with -Os, then stripped, give:

-rw-r--r-- 1 kadlec kadlec 1080 2009-02-17 14:10 lookup2.o
-rw-r--r-- 1 kadlec kadlec 1024 2009-02-17 14:10 lookup3.o

So I think the currently used lookup2 can safely be replaced with lookup3.

Best regards,
Jozsef
-
E-mail  : kadlec@blackhole.kfki.hu, kadlec@mail.kfki.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : KFKI Research Institute for Particle and Nuclear Physics
          H-1525 Budapest 114, POB. 49, Hungary

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-17 17:13       ` Jozsef Kadlecsik
@ 2009-02-18  5:11         ` Rusty Russell
  2009-02-18 11:50         ` Ilpo Järvinen
  1 sibling, 0 replies; 22+ messages in thread
From: Rusty Russell @ 2009-02-18  5:11 UTC (permalink / raw)
  To: Jozsef Kadlecsik; +Cc: Kyle Moffett, linux-kernel, netdev, netfilter-devel

On Wednesday 18 February 2009 03:43:04 Jozsef Kadlecsik wrote:
> On Thu, 12 Feb 2009, Rusty Russell wrote:
> > Any stats on code size changes?
> compiled with -Os, then stripped, give:
> 
> -rw-r--r-- 1 kadlec kadlec 1080 2009-02-17 14:10 lookup2.o
> -rw-r--r-- 1 kadlec kadlec 1024 2009-02-17 14:10 lookup3.o

The "size" command is more usual.  This looks like a total win to me.

Thanks for being so thorough!
Rusty.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-17 17:13       ` Jozsef Kadlecsik
  2009-02-18  5:11         ` Rusty Russell
@ 2009-02-18 11:50         ` Ilpo Järvinen
  1 sibling, 0 replies; 22+ messages in thread
From: Ilpo Järvinen @ 2009-02-18 11:50 UTC (permalink / raw)
  To: Jozsef Kadlecsik
  Cc: Kyle Moffett, LKML, Netdev, netfilter-devel, Rusty Russell

On Tue, 17 Feb 2009, Jozsef Kadlecsik wrote:

> On Thu, 12 Feb 2009, Rusty Russell wrote:
> 
> > My concern was that it's also bigger (and we inline it).  Performance is
> > pretty much a wash since we so rarely hash more than a few words.
> 
> In netfilter/conntrack (;-) we call the hash function for every packet, so 
> even if a small number of cycle can be gained at one lookup, I think it's 
> worth. And in the IPv4/IPv6 neutral nf_conntrack we hash 9 words.

FYI, I once looked into inlining cost and jhash functions were among the 
most wasteful (kernel-wide). Multiple jhash bodies were 100+ bytes, and 
the overall cost was 10k+. I never got to the final submit of the 
uninlining patch though...


-- 
 i.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-10 19:40 Jozsef Kadlecsik
  2009-02-10 21:19 ` Scott Feldman
@ 2009-02-11  1:17 ` David Miller
  1 sibling, 0 replies; 22+ messages in thread
From: David Miller @ 2009-02-11  1:17 UTC (permalink / raw)
  To: kadlec; +Cc: netdev, netfilter-devel

From: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Date: Tue, 10 Feb 2009 20:40:47 +0100 (CET)

> Please consider applying the following patch:
> 
> The current jhash.h implements the lookup2() hash function by Bob Jenkins. 
> However, lookup2() is outdated as Bob wrote a new hash function called 
> lookup3(). The new hash function
> 
> - mixes better than lookup2(): it passes the check that every input bit 
>   changes every output bit 50% of the time, while lookup2() failed it.
> - performs better: compiled with -O2 on Core2 Duo, lookup3() 20-40% faster
>   than lookup2() depending on the key length.
> 
> The patch replaces the lookup2() implementation of the 'jhash*' 
> functions with that of lookup3().
> 
> You can read a longer comparison of the two and other hash functions at 
> http://burtleburtle.net/bob/hash/doobs.html.
> 
> Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>

I support this change and I also don't think it makes sense
to have a jhash3.h new header file, that's just a waste of
time.  Either the new stuff is better or it isn't, and that
whole "matching hashes" argument is pure garbage.

But this kind of change isn't for me to decide, changing jhash
impacts the entire tree not just networking, and also I know
that Rusty Russell was investigating making this change and
he even did his own timings on various platforms.

Therefore this needs to be proposed on linux-kernel with appropriate
parties CC:'d.

Thanks.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-10 21:19 ` Scott Feldman
@ 2009-02-10 22:03   ` Jozsef Kadlecsik
  0 siblings, 0 replies; 22+ messages in thread
From: Jozsef Kadlecsik @ 2009-02-10 22:03 UTC (permalink / raw)
  To: Scott Feldman; +Cc: davem, netdev, netfilter-devel

On Tue, 10 Feb 2009, Scott Feldman wrote:

> Jozsef Kadlecsik wrote:
> > The patch replaces the lookup2() implementation of the 'jhash*' functions
> > with that of lookup3().
> 
> Should the lookup3() be added to rather than replacing lookup2()?  In case
> some hardware vendor used the lookup2() version for weird things like flow
> classification.

Do you imagine a case where a system with lookup3() communicates with 
another one with lookup2() and they want to exchange data identified by 
the hash keys? But the normal approach is to use a random seed (initval), 
so even two systems with lookup2() won't generate the same hash value for 
the same key.

Grepping through the whole kernel, at a lot of places jhash used with zero 
initval. :-(.

Sure, it's safer to add a new header file instead, see below.
 
> >  /* The golden ration: an arbitrary value */
> > -#define JHASH_GOLDEN_RATIO	0x9e3779b9
> > +#define JHASH_GOLDEN_RATIO	0xdeadbeef
> 
> The #define seems mis-named now.

It's the new arbitrary value, taken from the original source :-).
----
The current jhash.h implements the lookup2() hash function by Bob Jenkins.
However, lookup2() is outdated as Bob wrote a new hash function called
lookup3(). The new hash function

- mixes better than lookup2(): it passes the check that every input bit
  changes every output bit 50% of the time, while lookup2() failed it.
- performs better: compiled with -O2 on Core2 Duo, lookup3() 20-40% faster
  than lookup2() depending on the key length.

The patch adds jhash3.h which implements the lookup3() function(s) for
the Linux kernel.

Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
---
 include/linux/jhash3.h |  157 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 157 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/jhash3.h

diff --git a/include/linux/jhash3.h b/include/linux/jhash3.h
new file mode 100644
index 0000000..99a203d
--- /dev/null
+++ b/include/linux/jhash3.h
@@ -0,0 +1,157 @@
+#ifndef _LINUX_JHASH3_H
+#define _LINUX_JHASH3_H
+
+/* jhash3.h: Jenkins hash support.
+ *
+ * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net)
+ *
+ * http://burtleburtle.net/bob/hash/
+ *
+ * These are the credits from Bob's sources:
+ *
+ * lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+ *
+ * These are functions for producing 32-bit hashes for hash table lookup.
+ * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() 
+ * are externally useful functions.  Routines to test the hash are included 
+ * if SELF_TEST is defined.  You can use this free for any purpose.  It's in
+ * the public domain.  It has no warranty.
+ *
+ * Copyright (C) 2009 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
+ *
+ * I've modified Bob's hash to be useful in the Linux kernel, and
+ * any bugs present are my fault.  Jozsef
+ */
+
+#define __rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/* __jhash3_mix - mix 3 32-bit values reversibly. */
+#define __jhash3_mix(a,b,c) \
+{ \
+  a -= c;  a ^= __rot(c, 4);  c += b; \
+  b -= a;  b ^= __rot(a, 6);  a += c; \
+  c -= b;  c ^= __rot(b, 8);  b += a; \
+  a -= c;  a ^= __rot(c,16);  c += b; \
+  b -= a;  b ^= __rot(a,19);  a += c; \
+  c -= b;  c ^= __rot(b, 4);  b += a; \
+}
+
+/* __jhash3_final - final mixing of 3 32-bit values (a,b,c) into c */
+#define __jhash3_final(a,b,c) \
+{ \
+  c ^= b; c -= __rot(b,14); \
+  a ^= c; a -= __rot(c,11); \
+  b ^= a; b -= __rot(a,25); \
+  c ^= b; c -= __rot(b,16); \
+  a ^= c; a -= __rot(c,4);  \
+  b ^= a; b -= __rot(a,14); \
+  c ^= b; c -= __rot(b,24); \
+}
+
+/* The golden ration: an arbitrary value */
+#define JHASH3_GOLDEN_RATIO	0xdeadbeef
+
+/* The most generic version, hashes an arbitrary sequence
+ * of bytes.  No alignment or length assumptions are made about
+ * the input key. The result depends on endianness.
+ */
+static inline u32 jhash3(const void *key, u32 length, u32 initval)
+{
+	u32 a,b,c;
+	const u8 *k = key;
+
+	/* Set up the internal state */
+	a = b = c = JHASH3_GOLDEN_RATIO + length + initval;
+
+	/* all but the last block: affect some 32 bits of (a,b,c) */
+	while (length > 12) {
+    		a += (k[0] + ((u32)k[1]<<8) + ((u32)k[2]<<16) + ((u32)k[3]<<24));
+		b += (k[4] + ((u32)k[5]<<8) + ((u32)k[6]<<16) + ((u32)k[7]<<24));
+		c += (k[8] + ((u32)k[9]<<8) + ((u32)k[10]<<16) + ((u32)k[11]<<24));
+		__jhash3_mix(a, b, c);
+		length -= 12;
+		k += 12;
+	}
+
+	/* last block: affect all 32 bits of (c) */
+	/* all the case statements fall through */
+	switch (length) {
+	case 12: c += (u32)k[11]<<24;
+	case 11: c += (u32)k[10]<<16;
+	case 10: c += (u32)k[9]<<8;
+	case 9 : c += k[8];
+	case 8 : b += (u32)k[7]<<24;
+	case 7 : b += (u32)k[6]<<16;
+	case 6 : b += (u32)k[5]<<8;
+	case 5 : b += k[4];
+	case 4 : a += (u32)k[3]<<24;
+	case 3 : a += (u32)k[2]<<16;
+	case 2 : a += (u32)k[1]<<8;
+	case 1 : a += k[0];
+		__jhash3_final(a, b, c);
+	case 0 :
+		break;
+	}
+
+	return c;
+}
+
+/* A special optimized version that handles 1 or more of u32s.
+ * The length parameter here is the number of u32s in the key.
+ */
+static inline u32 jhash3_words(const u32 *k, u32 length, u32 initval)
+{
+	u32 a, b, c;
+
+	/* Set up the internal state */
+	a = b = c = JHASH3_GOLDEN_RATIO + (length<<2) + initval;
+
+	/* handle most of the key */
+	while (length > 3) {
+		a += k[0];
+		b += k[1];
+		c += k[2];
+		__jhash3_mix(a, b, c);
+		length -= 3;
+		k += 3;
+	}
+
+	/* handle the last 3 u32's */
+	/* all the case statements fall through */ 
+	switch (length) {
+	case 3: c += k[2];
+	case 2: b += k[1];
+	case 1: a += k[0];
+		__jhash3_final(a, b, c);
+	case 0:     /* case 0: nothing left to add */
+		break;
+	}
+
+	return c;
+}
+
+/* A special ultra-optimized versions that knows they are hashing exactly
+ * 3, 2 or 1 word(s).
+ */
+static inline u32 jhash3_3words(u32 a, u32 b, u32 c, u32 initval)
+{
+	a += JHASH3_GOLDEN_RATIO + initval;
+	b += JHASH3_GOLDEN_RATIO + initval;
+	c += JHASH3_GOLDEN_RATIO + initval;
+
+	__jhash3_final(a, b, c);
+
+	return c;
+}
+
+static inline u32 jhash3_2words(u32 a, u32 b, u32 initval)
+{
+	return jhash3_3words(0, a, b, initval);
+}
+
+static inline u32 jhash3_1word(u32 a, u32 initval)
+{
+	return jhash3_3words(0, 0, a, initval);
+}
+
+#endif /* _LINUX_JHASH3_H */
-- 
1.5.4.3

Best regards,
Jozsef
-
E-mail  : kadlec@blackhole.kfki.hu, kadlec@mail.kfki.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : KFKI Research Institute for Particle and Nuclear Physics
          H-1525 Budapest 114, POB. 49, Hungary

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH] Update jhash.h with the new version of Jenkins' hash
  2009-02-10 19:40 Jozsef Kadlecsik
@ 2009-02-10 21:19 ` Scott Feldman
  2009-02-10 22:03   ` Jozsef Kadlecsik
  2009-02-11  1:17 ` David Miller
  1 sibling, 1 reply; 22+ messages in thread
From: Scott Feldman @ 2009-02-10 21:19 UTC (permalink / raw)
  To: Jozsef Kadlecsik; +Cc: davem, netdev, netfilter-devel

Jozsef Kadlecsik wrote:
> The patch replaces the lookup2() implementation of the 'jhash*' 
> functions with that of lookup3().

Should the lookup3() be added to rather than replacing lookup2()?  In 
case some hardware vendor used the lookup2() version for weird things 
like flow classification.

>  /* The golden ration: an arbitrary value */
> -#define JHASH_GOLDEN_RATIO	0x9e3779b9
> +#define JHASH_GOLDEN_RATIO	0xdeadbeef

The #define seems mis-named now.

-scott

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH] Update jhash.h with the new version of Jenkins' hash
@ 2009-02-10 19:40 Jozsef Kadlecsik
  2009-02-10 21:19 ` Scott Feldman
  2009-02-11  1:17 ` David Miller
  0 siblings, 2 replies; 22+ messages in thread
From: Jozsef Kadlecsik @ 2009-02-10 19:40 UTC (permalink / raw)
  To: davem; +Cc: netdev, netfilter-devel

Hi Dave,

Please consider applying the following patch:

The current jhash.h implements the lookup2() hash function by Bob Jenkins. 
However, lookup2() is outdated as Bob wrote a new hash function called 
lookup3(). The new hash function

- mixes better than lookup2(): it passes the check that every input bit 
  changes every output bit 50% of the time, while lookup2() failed it.
- performs better: compiled with -O2 on Core2 Duo, lookup3() 20-40% faster
  than lookup2() depending on the key length.

The patch replaces the lookup2() implementation of the 'jhash*' 
functions with that of lookup3().

You can read a longer comparison of the two and other hash functions at 
http://burtleburtle.net/bob/hash/doobs.html.

Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>

diff --git a/include/linux/jhash.h b/include/linux/jhash.h
index 2a2f99f..2000b9f 100644
--- a/include/linux/jhash.h
+++ b/include/linux/jhash.h
@@ -3,80 +3,95 @@
 
 /* jhash.h: Jenkins hash support.
  *
- * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
+ * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net)
  *
  * http://burtleburtle.net/bob/hash/
  *
  * These are the credits from Bob's sources:
  *
- * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
- * hash(), hash2(), hash3, and mix() are externally useful functions.
- * Routines to test the hash are included if SELF_TEST is defined.
- * You can use this free for any purpose.  It has no warranty.
+ * lookup3.c, by Bob Jenkins, May 2006, Public Domain.
  *
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * These are functions for producing 32-bit hashes for hash table lookup.
+ * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() 
+ * are externally useful functions.  Routines to test the hash are included 
+ * if SELF_TEST is defined.  You can use this free for any purpose.  It's in
+ * the public domain.  It has no warranty.
+ *
+ * Copyright (C) 2009 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
  *
  * I've modified Bob's hash to be useful in the Linux kernel, and
- * any bugs present are surely my fault.  -DaveM
+ * any bugs present are my fault.  Jozsef
  */
 
-/* NOTE: Arguments are modified. */
-#define __jhash_mix(a, b, c) \
+#define __rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/* __jhash_mix - mix 3 32-bit values reversibly. */
+#define __jhash_mix(a,b,c) \
+{ \
+  a -= c;  a ^= __rot(c, 4);  c += b; \
+  b -= a;  b ^= __rot(a, 6);  a += c; \
+  c -= b;  c ^= __rot(b, 8);  b += a; \
+  a -= c;  a ^= __rot(c,16);  c += b; \
+  b -= a;  b ^= __rot(a,19);  a += c; \
+  c -= b;  c ^= __rot(b, 4);  b += a; \
+}
+
+/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */
+#define __jhash_final(a,b,c) \
 { \
-  a -= b; a -= c; a ^= (c>>13); \
-  b -= c; b -= a; b ^= (a<<8); \
-  c -= a; c -= b; c ^= (b>>13); \
-  a -= b; a -= c; a ^= (c>>12);  \
-  b -= c; b -= a; b ^= (a<<16); \
-  c -= a; c -= b; c ^= (b>>5); \
-  a -= b; a -= c; a ^= (c>>3);  \
-  b -= c; b -= a; b ^= (a<<10); \
-  c -= a; c -= b; c ^= (b>>15); \
+  c ^= b; c -= __rot(b,14); \
+  a ^= c; a -= __rot(c,11); \
+  b ^= a; b -= __rot(a,25); \
+  c ^= b; c -= __rot(b,16); \
+  a ^= c; a -= __rot(c,4);  \
+  b ^= a; b -= __rot(a,14); \
+  c ^= b; c -= __rot(b,24); \
 }
 
 /* The golden ration: an arbitrary value */
-#define JHASH_GOLDEN_RATIO	0x9e3779b9
+#define JHASH_GOLDEN_RATIO	0xdeadbeef
 
 /* The most generic version, hashes an arbitrary sequence
  * of bytes.  No alignment or length assumptions are made about
- * the input key.
+ * the input key. The result depends on endianness.
  */
 static inline u32 jhash(const void *key, u32 length, u32 initval)
 {
-	u32 a, b, c, len;
+	u32 a,b,c;
 	const u8 *k = key;
 
-	len = length;
-	a = b = JHASH_GOLDEN_RATIO;
-	c = initval;
-
-	while (len >= 12) {
-		a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24));
-		b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24));
-		c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24));
-
-		__jhash_mix(a,b,c);
+	/* Set up the internal state */
+	a = b = c = JHASH_GOLDEN_RATIO + length + initval;
 
+	/* all but the last block: affect some 32 bits of (a,b,c) */
+	while (length > 12) {
+    		a += (k[0] + ((u32)k[1]<<8) + ((u32)k[2]<<16) + ((u32)k[3]<<24));
+		b += (k[4] + ((u32)k[5]<<8) + ((u32)k[6]<<16) + ((u32)k[7]<<24));
+		c += (k[8] + ((u32)k[9]<<8) + ((u32)k[10]<<16) + ((u32)k[11]<<24));
+		__jhash_mix(a, b, c);
+		length -= 12;
 		k += 12;
-		len -= 12;
 	}
 
-	c += length;
-	switch (len) {
-	case 11: c += ((u32)k[10]<<24);
-	case 10: c += ((u32)k[9]<<16);
-	case 9 : c += ((u32)k[8]<<8);
-	case 8 : b += ((u32)k[7]<<24);
-	case 7 : b += ((u32)k[6]<<16);
-	case 6 : b += ((u32)k[5]<<8);
+	/* last block: affect all 32 bits of (c) */
+	/* all the case statements fall through */
+	switch (length) {
+	case 12: c += (u32)k[11]<<24;
+	case 11: c += (u32)k[10]<<16;
+	case 10: c += (u32)k[9]<<8;
+	case 9 : c += k[8];
+	case 8 : b += (u32)k[7]<<24;
+	case 7 : b += (u32)k[6]<<16;
+	case 6 : b += (u32)k[5]<<8;
 	case 5 : b += k[4];
-	case 4 : a += ((u32)k[3]<<24);
-	case 3 : a += ((u32)k[2]<<16);
-	case 2 : a += ((u32)k[1]<<8);
+	case 4 : a += (u32)k[3]<<24;
+	case 3 : a += (u32)k[2]<<16;
+	case 2 : a += (u32)k[1]<<8;
 	case 1 : a += k[0];
-	};
-
-	__jhash_mix(a,b,c);
+		__jhash_final(a, b, c);
+	case 0 :
+		break;
+	}
 
 	return c;
 }
@@ -86,58 +101,57 @@ static inline u32 jhash(const void *key, u32 length, u32 initval)
  */
 static inline u32 jhash2(const u32 *k, u32 length, u32 initval)
 {
-	u32 a, b, c, len;
+	u32 a, b, c;
 
-	a = b = JHASH_GOLDEN_RATIO;
-	c = initval;
-	len = length;
+	/* Set up the internal state */
+	a = b = c = JHASH_GOLDEN_RATIO + (length<<2) + initval;
 
-	while (len >= 3) {
+	/* handle most of the key */
+	while (length > 3) {
 		a += k[0];
 		b += k[1];
 		c += k[2];
 		__jhash_mix(a, b, c);
-		k += 3; len -= 3;
+		length -= 3;
+		k += 3;
 	}
 
-	c += length * 4;
-
-	switch (len) {
-	case 2 : b += k[1];
-	case 1 : a += k[0];
-	};
-
-	__jhash_mix(a,b,c);
+	/* handle the last 3 u32's */
+	/* all the case statements fall through */ 
+	switch (length) {
+	case 3: c += k[2];
+	case 2: b += k[1];
+	case 1: a += k[0];
+		__jhash_final(a, b, c);
+	case 0:     /* case 0: nothing left to add */
+		break;
+	}
 
 	return c;
 }
 
-
 /* A special ultra-optimized versions that knows they are hashing exactly
  * 3, 2 or 1 word(s).
- *
- * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
- *       done at the end is not done here.
  */
 static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
 {
-	a += JHASH_GOLDEN_RATIO;
-	b += JHASH_GOLDEN_RATIO;
-	c += initval;
+	a += JHASH_GOLDEN_RATIO + initval;
+	b += JHASH_GOLDEN_RATIO + initval;
+	c += JHASH_GOLDEN_RATIO + initval;
 
-	__jhash_mix(a, b, c);
+	__jhash_final(a, b, c);
 
 	return c;
 }
 
 static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
 {
-	return jhash_3words(a, b, 0, initval);
+	return jhash_3words(0, a, b, initval);
 }
 
 static inline u32 jhash_1word(u32 a, u32 initval)
 {
-	return jhash_3words(a, 0, 0, initval);
+	return jhash_3words(0, 0, a, initval);
 }
 
 #endif /* _LINUX_JHASH_H */


Best regards,
Jozsef
-
E-mail  : kadlec@blackhole.kfki.hu, kadlec@mail.kfki.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : KFKI Research Institute for Particle and Nuclear Physics
          H-1525 Budapest 114, POB. 49, Hungary

^ permalink raw reply related	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2009-02-18 11:51 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-02-11 10:19 [PATCH] Update jhash.h with the new version of Jenkins' hash Jozsef Kadlecsik
2009-02-11 20:19 ` Michał Mirosław
2009-02-11 22:50   ` Jozsef Kadlecsik
2009-02-11 23:23     ` Michał Mirosław
2009-02-12  0:12 ` wli
2009-02-12  0:29   ` David Miller
2009-02-12  0:41     ` Jan Engelhardt
2009-02-12  9:05       ` Jarek Poplawski
2009-02-12  9:55         ` Jarek Poplawski
2009-02-12  9:11   ` Jozsef Kadlecsik
2009-02-12  9:16     ` Patrick McHardy
2009-02-12  9:41       ` Jozsef Kadlecsik
2009-02-12 13:46     ` Kyle Moffett
2009-02-17 17:13       ` Jozsef Kadlecsik
2009-02-18  5:11         ` Rusty Russell
2009-02-18 11:50         ` Ilpo Järvinen
2009-02-12 19:58     ` Eric W. Biederman
2009-02-12  2:58 ` Rusty Russell
  -- strict thread matches above, loose matches on Subject: below --
2009-02-10 19:40 Jozsef Kadlecsik
2009-02-10 21:19 ` Scott Feldman
2009-02-10 22:03   ` Jozsef Kadlecsik
2009-02-11  1:17 ` David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.