]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-journal: use a dynamic check for valgrind
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 22 Feb 2023 10:35:25 +0000 (11:35 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 22 Feb 2023 10:39:44 +0000 (11:39 +0100)
I left this one as a separate commit because it is more involved.
We want people to compile with valgrind support, but we don't want to
use a slow hash function unless we're actually running under valgrind.
So the compile-time check is changed to a runtime check. When compiled
with optimization, the compiler should elide the checks on the constants,
and only leave the check for RUNNING_ON_VALGRIND. It is wrapped with
_unlikely_ so that the else branch is put in the hot path.

src/libsystemd/sd-journal/lookup3.c

index a6a32e09c5bd24001f6b770162573774831730b2..c2a640687c0df61a25156e4495271c6180da67fc 100644 (file)
@@ -4,6 +4,12 @@
 
 #include "lookup3.h"
 
+#if HAVE_VALGRIND_VALGRIND_H
+#  include <valgrind/valgrind.h>
+#else
+#  define RUNNING_ON_VALGRIND 0
+#endif
+
 /*
 -------------------------------------------------------------------------------
 lookup3.c, by Bob Jenkins, May 2006, Public Domain.
@@ -320,29 +326,28 @@ uint32_t jenkins_hashlittle( const void *key, size_t length, uint32_t initval)
      * still catch it and complain.  The masking trick does make the hash
      * noticeably faster for short strings (like English words).
      */
-#define VALGRIND_LIKE (HAVE_VALGRIND_VALGRIND_H || HAS_FEATURE_ADDRESS_SANITIZER || HAS_FEATURE_MEMORY_SANITIZER)
-
-#if !VALGRIND_LIKE
-
-    switch(length)
-    {
-    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
-    case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
-    case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
-    case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
-    case 8 : b+=k[1]; a+=k[0]; break;
-    case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
-    case 6 : b+=k[1]&0xffff; a+=k[0]; break;
-    case 5 : b+=k[1]&0xff; a+=k[0]; break;
-    case 4 : a+=k[0]; break;
-    case 3 : a+=k[0]&0xffffff; break;
-    case 2 : a+=k[0]&0xffff; break;
-    case 1 : a+=k[0]&0xff; break;
-    case 0 : return c;              /* zero length strings require no mixing */
-    }
+#define VALGRIND_LIKE (_unlikely_(HAS_FEATURE_ADDRESS_SANITIZER ||      \
+                                  HAS_FEATURE_MEMORY_SANITIZER ||       \
+                                  RUNNING_ON_VALGRIND))
 
-#else /* make valgrind happy */
-    {
+    if (!VALGRIND_LIKE) {
+      switch(length)
+      {
+      case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+      case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+      case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+      case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+      case 8 : b+=k[1]; a+=k[0]; break;
+      case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+      case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+      case 5 : b+=k[1]&0xff; a+=k[0]; break;
+      case 4 : a+=k[0]; break;
+      case 3 : a+=k[0]&0xffffff; break;
+      case 2 : a+=k[0]&0xffff; break;
+      case 1 : a+=k[0]&0xff; break;
+      case 0 : return c;              /* zero length strings require no mixing */
+      }
+    } else {
       const uint8_t *k8 = (const uint8_t *) k;
 
       switch(length)
@@ -363,8 +368,6 @@ uint32_t jenkins_hashlittle( const void *key, size_t length, uint32_t initval)
       }
     }
 
-#endif /* !valgrind */
-
   } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
     const uint16_t *k = (const uint16_t *)key;         /* read 16-bit chunks */
     const uint8_t  *k8;
@@ -507,29 +510,26 @@ void jenkins_hashlittle2(
      * still catch it and complain.  The masking trick does make the hash
      * noticeably faster for short strings (like English words).
      */
-#if !VALGRIND_LIKE
-
-    switch(length)
-    {
-    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
-    case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
-    case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
-    case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
-    case 8 : b+=k[1]; a+=k[0]; break;
-    case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
-    case 6 : b+=k[1]&0xffff; a+=k[0]; break;
-    case 5 : b+=k[1]&0xff; a+=k[0]; break;
-    case 4 : a+=k[0]; break;
-    case 3 : a+=k[0]&0xffffff; break;
-    case 2 : a+=k[0]&0xffff; break;
-    case 1 : a+=k[0]&0xff; break;
-    case 0 : *pc=c; *pb=b; return;  /* zero length strings require no mixing */
-    }
-
-#else /* make valgrind happy */
-
-    {
+    if (!VALGRIND_LIKE) {
+      switch(length)
+      {
+      case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+      case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+      case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+      case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+      case 8 : b+=k[1]; a+=k[0]; break;
+      case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+      case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+      case 5 : b+=k[1]&0xff; a+=k[0]; break;
+      case 4 : a+=k[0]; break;
+      case 3 : a+=k[0]&0xffffff; break;
+      case 2 : a+=k[0]&0xffff; break;
+      case 1 : a+=k[0]&0xff; break;
+      case 0 : *pc=c; *pb=b; return;  /* zero length strings require no mixing */
+      }
+    } else {
       const uint8_t *k8 = (const uint8_t *)k;
+
       switch(length)
       {
       case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
@@ -548,8 +548,6 @@ void jenkins_hashlittle2(
       }
     }
 
-#endif /* !valgrind */
-
   } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
     const uint16_t *k = (const uint16_t *)key;         /* read 16-bit chunks */
     const uint8_t  *k8;
@@ -683,29 +681,27 @@ uint32_t jenkins_hashbig( const void *key, size_t length, uint32_t initval)
      * still catch it and complain.  The masking trick does make the hash
      * noticeably faster for short strings (like English words).
      */
-#if !VALGRIND_LIKE
 
-    switch(length)
-    {
-    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
-    case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break;
-    case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break;
-    case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break;
-    case 8 : b+=k[1]; a+=k[0]; break;
-    case 7 : b+=k[1]&0xffffff00; a+=k[0]; break;
-    case 6 : b+=k[1]&0xffff0000; a+=k[0]; break;
-    case 5 : b+=k[1]&0xff000000; a+=k[0]; break;
-    case 4 : a+=k[0]; break;
-    case 3 : a+=k[0]&0xffffff00; break;
-    case 2 : a+=k[0]&0xffff0000; break;
-    case 1 : a+=k[0]&0xff000000; break;
-    case 0 : return c;              /* zero length strings require no mixing */
-    }
-
-#else  /* make valgrind happy */
-
-    {
+    if (!VALGRIND_LIKE) {
+      switch(length)
+      {
+      case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+      case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break;
+      case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break;
+      case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break;
+      case 8 : b+=k[1]; a+=k[0]; break;
+      case 7 : b+=k[1]&0xffffff00; a+=k[0]; break;
+      case 6 : b+=k[1]&0xffff0000; a+=k[0]; break;
+      case 5 : b+=k[1]&0xff000000; a+=k[0]; break;
+      case 4 : a+=k[0]; break;
+      case 3 : a+=k[0]&0xffffff00; break;
+      case 2 : a+=k[0]&0xffff0000; break;
+      case 1 : a+=k[0]&0xff000000; break;
+      case 0 : return c;              /* zero length strings require no mixing */
+      }
+    } else {
       const uint8_t *k8 = (const uint8_t *)k;
+
       switch(length)                   /* all the case statements fall through */
       {
       case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
@@ -724,8 +720,6 @@ uint32_t jenkins_hashbig( const void *key, size_t length, uint32_t initval)
       }
     }
 
-#endif /* !VALGRIND */
-
   } else {                        /* need to read the key one byte at a time */
     const uint8_t *k = (const uint8_t *)key;