[PATCH v4] Avoid manual shift-and-test logic in AllocSetFreeIndex - Mailing list pgsql-hackers

From Jeremy Kerr
Subject [PATCH v4] Avoid manual shift-and-test logic in AllocSetFreeIndex
Date
Msg-id 1248067995.540170.573982756831.1.gpush@pingu
Whole thread Raw
In response to Re: [PATCH v3] Avoid manual shift-and-test logic in AllocSetFreeIndex  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: [PATCH v4] Avoid manual shift-and-test logic in AllocSetFreeIndex
Re: [PATCH v4] Avoid manual shift-and-test logic in AllocSetFreeIndex
List pgsql-hackers
Rather than testing single bits in a loop, change AllocSetFreeIndex to
use the __builtin_clz() function to calculate the chunk index.

This requires a new check for __builtin_clz in the configure script.

Results in a ~2% performance increase on sysbench on PowerPC.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>

---
v4: don't use separate fls() function, remove hardcoded 32

---configure.in                  |   13 +++++++++++++src/backend/utils/mmgr/aset.c |   14 +++++++++++++-2 files
changed,26 insertions(+), 1 deletion(-)
 

*** a/configure.in
--- b/configure.in
***************
*** 1361,1366 **** case $host_os in
--- 1361,1379 ----         AC_FUNC_FSEEKO;; esac 
+ # GCC builtins
+ #
+ # We need AC_TRY_LINK here, as the prototype generated by AC_CHECK_FUNC
+ # will cause gcc to try to reference a non-builtin symbol.
+ 
+ AC_MSG_CHECKING([for __builtin_clz])
+ AC_TRY_LINK([],
+         [__builtin_clz(0);],
+         [AC_DEFINE(HAVE_BUILTIN_CLZ, 1,
+                 [Define to 1 if you have __builtin_clz().])
+             AC_MSG_RESULT(yes)],
+         [AC_MSG_RESULT(no)])
+   # # Pthreads
*** a/src/backend/utils/mmgr/aset.c
--- b/src/backend/utils/mmgr/aset.c
***************
*** 268,281 **** AllocSetFreeIndex(Size size) {     int            idx = 0; 
!     if (size > 0)     {         size = (size - 1) >> ALLOC_MINBITS;         while (size != 0)         {
idx++;            size >>= 1;         }         Assert(idx < ALLOCSET_NUM_FREELISTS);     } 
 
--- 268,293 ---- {     int            idx = 0; 
!     if (size > (1 << ALLOC_MINBITS))     {         size = (size - 1) >> ALLOC_MINBITS;
+ 
+ #ifdef HAVE_BUILTIN_CLZ
+         /* If possible, use __builtin_clz to calculate the chunk index - this
+          * should be O(1) rather than O(n). The builtin takes an unsigned int,
+          * so we need to cast from the possibly 64-bit Size type. This cast
+          * won't overflow, as the limit is at 2^(32 + ALLOC_MINBITS) bytes,
+          * which is larger than ALLOC_CHUNK_LIMIT.
+          */
+         idx = sizeof(unsigned int) * BITS_PER_BYTE -
+                 __builtin_clz((unsigned int)size);
+ #else         while (size != 0)         {             idx++;             size >>= 1;         }
+ #endif         Assert(idx < ALLOCSET_NUM_FREELISTS);     } 


pgsql-hackers by date:

Previous
From: Tom Lane
Date:
Subject: Re: join removal
Next
From: Nikhil Sontakke
Date:
Subject: Re: GRANT ON ALL IN schema