[HACKERS] [PATCH v4] [libpq] Try to avoid manually masking SIGPIPEs on every send()

2009-07-23 Thread Jeremy Kerr
Currently, libpq will wrap each send() call on the connection with
two system calls to mask SIGPIPEs. This results in 3 syscalls instead
of one, and (on Linux) can lead to high contention on the signal
mask locks in threaded apps.

We have a couple of other methods to avoid SIGPIPEs:
sockopt(SO_NOSIGPIPE) and the MSG_NOSIGNAL flag to send().

This change attempts to use these if they're available at compile-
and run-time. If not, we drop back to manipulating the signal mask as
before.

Signed-off-by: Jeremy Kerr j...@ozlabs.org

---
v4: roll into one patch, use macros

---
 src/interfaces/libpq/fe-connect.c |   42 
 src/interfaces/libpq/fe-secure.c  |  131 ++
 src/interfaces/libpq/libpq-int.h  |2 
 3 files changed, 136 insertions(+), 39 deletions(-)

*** a/src/interfaces/libpq/fe-connect.c
--- b/src/interfaces/libpq/fe-connect.c
***
*** 1089,1094  keep_going:  /* We 
will come back to here until there is
--- 1089,1097 
while (conn-addr_cur != NULL)
{
struct addrinfo *addr_cur = 
conn-addr_cur;
+ #ifdef SO_NOSIGPIPE
+   int optval;
+ #endif /* SO_NOSIGPIPE */
  
/* Remember current address for 
possible error msg */
memcpy(conn-raddr.addr, 
addr_cur-ai_addr,
***
*** 1153,1158  keep_going:  /* We 
will come back to here until there is
--- 1156,1200 
}
  #endif   /* F_SETFD */
  
+   /* We have three methods of blocking 
sigpipe during
+* send() calls to this socket:
+*
+*  - setsockopt(sock, SO_NOSIGPIPE)
+*  - send(sock, ..., MSG_NOSIGNAL)
+*  - setting the signal mask to 
SIG_IGN during send()
+*
+* The first two reduce the number of 
syscalls (for the
+* third, we require three syscalls to 
implement a send()),
+* so use them if they're available. 
Their availability is
+* flagged in the following members of 
PGconn:
+*
+* conn-sigpipe_so - we 
have set up SO_NOSIGPIPE
+* conn-sigpipe_flag   - we're 
specifying MSG_NOSIGNAL
+*
+* If we can use SO_NOSIGPIPE, then set 
sigpipe_so here and
+* we don't need to care about anything 
else. Otherwise,
+* try MSG_NOSIGNAL by setting 
sigpipe_flag. If we get an
+* error with MSG_NOSIGNAL, we clear 
the flag and revert
+* to manual masking.
+*/
+   conn-sigpipe_so = false;
+ #ifdef MSG_NOSIGNAL
+   conn-sigpipe_flag = true;
+ #else /* !MSG_NOSIGNAL */
+   conn-sigpipe_flag = false;
+ #endif /* MSG_NOSIGNAL */
+ 
+ #ifdef SO_NOSIGPIPE
+   optval = 1;
+   if (!setsockopt(conn-sock, SOL_SOCKET, 
SO_NOSIGPIPE,
+   (char *)optval, 
sizeof(optval)))
+   {
+   conn-sigpipe_so = true;
+   conn-sigpipe_flag = false;
+   }
+ #endif /* SO_NOSIGPIPE */
+ 
+ 
/*
 * Start/make connection.  This should 
not block, since we
 * are in nonblock mode.  If it does, 
well, too bad.
*** a/src/interfaces/libpq/fe-secure.c
--- b/src/interfaces/libpq/fe-secure.c
***
*** 118,161  static long win32_ssl_create_mutex = 0;
  
  /*
   * Macros to handle disabling and then restoring the state of SIGPIPE 
handling.
-  * Note that DISABLE_SIGPIPE() must appear at the start of a block.
   */
  
  #ifndef WIN32
  #ifdef ENABLE_THREAD_SAFETY
  
! #define DISABLE_SIGPIPE(failaction) \
!   sigset_tosigmask; \
!   boolsigpipe_pending; \
!   boolgot_epipe = false

Re: [HACKERS] [PATCH 1/2 v3] [libpq] rework sigpipe-handling macros

2009-07-20 Thread Jeremy Kerr
Hi Tom,

 That code is not broken as it stands, and doesn't appear to really
 gain anything from the proposed change.  Why should we risk any
 portability questions when the code isn't going to get either simpler
 or shorter?

OK, after attempting a macro version of this, we end up with:

#define DECLARE_SIGPIPE_INFO(var) struct sigpipe_info var;

#define DISABLE_SIGPIPE(info, conn) \
((SIGPIPE_MASKED(conn)) ? 0 : \
((info)-got_epipe = false, \
pg_block_sigpipe((info)-oldsigmask, 
(info)-sigpipe_pending))  0)

- kinda ugly, uses the ?: and , operators to return the result of 
pg_block_sigpipe. We could avoid the comma with a block though.

If we want to keep the current 'failaction' style of macro:

#define DISABLE_SIGPIPE(info, conn, failaction) \
   do { \
if (!SIGPIPE_MASKED(conn)) { \
(info)-got_epipe = false; \
if (pg_block_sigpipe((info)-oldsigmask, \
(info)-sigpipe_pending))  0) { \
failaction; \
} \
} \
} while (0)

We could ditch struct sigpipe info, but that means we need to declare 
three separate vars in DECLARE_SIGPIPE_INFO() instead of the one, and it 
doesn't clean up the macro code much. I'd rather reduce the amount of 
stuff that we declare behind the caller's back.

Compared to the static-function version:

static inline int disable_sigpipe(PGconn *conn, struct sigpipe_info 
*info)
{
if (sigpipe_masked(conn))
return 0;

info-got_epipe = false;
return pq_block_sigpipe(info-oldsigmask, info-sigpipe_pending)  0;
}

Personally, I think the static functions are a lot cleaner, and don't 
think we lose any portability from using these (since inline is #define-
ed out on compilers that don't support it). On non-inlining compilers, 
we do gain an extra function call, but we're about to enter the kernel 
anyway, so this will probably be lost in the noise (especially if we 
save the sigpipe-masking syscalls).

But in the end, it's not up to me - do you still prefer the macro 
approach?

Cheers,


Jeremy


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH v4] Avoid manual shift-and-test logic in AllocSetFreeIndex

2009-07-20 Thread Jeremy Kerr
Hi Greg,

Thanks for the benchmark app, thought I'd pitch in with some ppc 
results:

  clz 1.530s
 lookup table 1.720s
   float hack 4.424s
 unrolled 5.280s
   normal 5.369s

POWER5+:
 clz 2.046s
lookup table 2.188s
  float hack 7.786s
unrolled 6.353s
  normal 7.033s

POWER6:
 clz 1.063s
lookup table 1.199s
  float hack 3.575s
unrolled 2.290s
  normal 3.456s

Cheers,


Jeremy


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH 1/2 v3] [libpq] rework sigpipe-handling macros

2009-07-19 Thread Jeremy Kerr
Hi Robert,

 Perhaps we should use macros.

I was trying to avoid macros, as this means we lose type- and syntax- 
checking at the call-site, and end up with slightly messier code. 
However, I understand that this is probably personal preference for me 
:)

How about just 'static' functions? (ie, drop the 'inline'). This way, 
the compiler is free to inline where suitable, and non-inlining 
compilers will do the right thing too.

However, I'd rather make decisions on data, rather than guessing. Is the 
actual problem here that some compilers just don't support the 'inline' 
keyword?

Cheers,


Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH v3] Avoid manual shift-and-test logic in AllocSetFreeIndex

2009-07-19 Thread Jeremy Kerr
Hi Robert,

 That having been said, Jeremy, you probably want to take a look at
 those comments and I have a few responses to them as well.

OK, thanks for the heads-up.

 following comment:
  Applied and built cleanly. Regress passes. Trying to hunt down ppc
  box to see if performance enhancement can be seen.

 Question: are we only doing this because of PowerPC?

No, this patch will benefit any architecture that has a gcc 
implementation of __builtin_clz. I know that both x86 and powerpc gcc 
support this.

 What is going to happen on x86 and other architectures?  x86 is not
 the center of the universe, but at a very minimum we need to make sure
 that things don't go backwards on what is a very common platform.  Has
 anyone done any benchmarking of this?

Yes, Atsushi Ogawa did some benchmarking with this patch on x86, his 
numbers are here:

 http://archives.postgresql.org/message-id/4a2895c4.9050...@hi-ho.ne.jp

In fact, Atushi originally submitted a patch using inline asm (using 
bsr) to do this on x86. Coincidentally, I was working on a powerpc 
implementation (using cntlz) at the same time, so submitted a patch 
using the gcc builtin that would work on both (and possibly other) 
architectures.

 A related question: the original email for this patch says that it
 results in a performance increase of about 2% on PPC.  But since it
 gives no details on exactly what the test was that improved by 2%,
 it's hard to judge the impact of this.  If this means that
 AllocSetFreeIndex() is 2% faster, I think we should reject this patch
 and move on.  It's not worth introducing architecture-specific code
 to get a performance improvement that probably won't even move the
 needle on a macro-benchmark.  On the other hand, if the test was
 something like a pgbench run, then this is really very impressive. 
 But we don't know which it is.

The 2% improvement I saw is for a sysbench OLTP run. I'm happy to re-do 
the run and report specific numbers if you need them.

 Zdenek Kotala added this comment:
  I have several objections:
 
  - inline is forbidden to use in PostgreSQL - you need exception or
  do it differently
 
  - type mismatch - Size vs unsigned int vs 32. you should use only
  Size and sizeof(Size)

OK, happy to make these changes. What's the commitfest process here, 
should I redo the patch and re-send to -hackers?

(inline again: should I just make this a static, the compiler can inline 
where possible? or do you want a macro?)

  And general comment:
 
  Do we want to have this kind of code which is optimized for one
  compiler and platform.

One compiler, multiple platforms.

  See openSSL or MySQL, they have many
  optimizations which work fine on one platform with specific version
  of compiler and specific version of OS. But if you select different
  version of compiler or different compiler you can get very
  different performance result (e.g. MySQL 30% degradation, OpenSSL
  RSA 3x faster and so on).

I don't think we're going to see a lot of variation here (besides the 
difference where __builtin_clz isn't available). Given that this is 
implemented with a couple of instructions, I'm confident that we won't 
see any degradation for platforms that support __builtin_clz. For the 
other cases, we just use the exiting while-loop algorithm so there 
should be no change (unless we mess up the inlining...).

  I think in this case, it makes sense to have optimization here, but
  we should do it like spinlocks are implemented and put this code
  into /port.

Unless I'm missing something, spinlocks are done the same way - we have 
one file, src/include/storage/s_lock.h, which is mostly different 
implementations of the lock primitives for different platforms, 
separated by preprocessor tests.

Essentially, this is just one line of code, protected by 
HAVE_BUILTIN_CLZ (which is a feature-test, rather than a specific 
platform or compiler test), and is only used in one place. I don't think 
that warrants a separate file.

Cheers,


Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH 1/2 v3] [libpq] rework sigpipe-handling macros

2009-07-19 Thread Jeremy Kerr
Tom,

 However, I think the whole patch is pretty useless.  That code is not
 broken as it stands, and doesn't appear to really gain anything from
 the proposed change.  Why should we risk any portability questions
 when the code isn't going to get either simpler or shorter?

This patch clears the way for the proceeding change (2/2). We use the 
new inline functions to implement the proper checks to see if the 
sigpipe-masking syscalls are needed.

We also need disable_sigpipe to be called when it's not the start of a 
block, hence the separate type definition.

Cheers,


Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] [PATCH v4] Avoid manual shift-and-test logic in AllocSetFreeIndex

2009-07-19 Thread Jeremy Kerr
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 j...@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);
}
  

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH 1/2 v3] [libpq] rework sigpipe-handling macros

2009-07-14 Thread Jeremy Kerr
Hi, Alvaro,

 Does this work in compilers other than GCC?  I think we use some
 kludges to protect against them ... see pg_list.h for the canonical
 example.

As I understand it, we're not using static inlines in pg_list.h to 
prevent multiple objects from exporting the same symbols if the 
functions don't end up as 'static inline' (ie, because the compiler 
doesn't support that).

In this case, we're only compiling the inlines into a single object, so 
even if the compiler doesn't support inlines, we'll just end up with 
out-of-line function calls, which should work too.

However, this is only my assumption about those compilers (I don't have 
access to other compilers to test); happy to fix these up if the inlines 
won't work.

Cheers,


Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] [PATCH 0/2 v3] SIGPIPE masking in local socket connections

2009-06-30 Thread Jeremy Kerr
A new approach to avioding manipulating the signal mask during for every
send - this time round, use SO_NOSIGPIPE and MSG_NOSIGNAL if available.

The patches have been tested on Linux and OSX, and I've confirmed that
'struct foo { };' will compile with a MSVC compiler. I'd still like a
little more testing though, is there a machine that allows both
SO_NOSIGPIPE and MSG_NOSIGNAL?

v3: respin as context diffs

Again, comments most welcome,


Jeremy

---
Jeremy Kerr (2):
  [libpq] rework sigpipe-handling macros
  [libpq] Try to avoid manually masking SIGPIPEs on every send()


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] [PATCH 2/2 v3] [libpq] Try to avoid manually masking SIGPIPEs on every send()

2009-06-30 Thread Jeremy Kerr
Currently, libpq will wrap each send() call on the connection with
two system calls to mask SIGPIPEs. This results in 3 syscalls instead
of one, and (on Linux) can lead to high contention on the signal
mask locks in threaded apps.

We have a couple of other methods to avoid SIGPIPEs:
sockopt(SO_NOSIGPIPE) and the MSG_NOSIGNAL flag to send().

This change attempts to use these if they're available at compile-
and run-time. If not, we drop back to manipulating the signal mask as
before.

Signed-off-by: Jeremy Kerr j...@ozlabs.org

---
 src/interfaces/libpq/fe-connect.c |   40 ++
 src/interfaces/libpq/fe-secure.c  |   83 +-
 src/interfaces/libpq/libpq-int.h  |2 
 3 files changed, 107 insertions(+), 18 deletions(-)

*** a/src/interfaces/libpq/fe-connect.c
--- b/src/interfaces/libpq/fe-connect.c
***
*** 1085,1090  keep_going:  /* We 
will come back to here until there is
--- 1085,1091 
while (conn-addr_cur != NULL)
{
struct addrinfo *addr_cur = 
conn-addr_cur;
+   int optval;
  
/* Remember current address for 
possible error msg */
memcpy(conn-raddr.addr, 
addr_cur-ai_addr,
***
*** 1149,1154  keep_going:  /* We 
will come back to here until there is
--- 1150,1194 
}
  #endif   /* F_SETFD */
  
+   /* We have three methods of blocking 
sigpipe during
+* send() calls to this socket:
+*
+*  - setsockopt(sock, SO_NOSIGPIPE)
+*  - send(sock, ..., MSG_NOSIGNAL)
+*  - setting the signal mask to 
SIG_IGN during send()
+*
+* The first two reduce the number of 
syscalls (for the
+* third, we require three syscalls to 
implement a send()),
+* so use them if they're available. 
Their availability is
+* flagged in the following members of 
PGconn:
+*
+* conn-sigpipe_so - we 
have set up SO_NOSIGPIPE
+* conn-sigpipe_flag   - we're 
specifying MSG_NOSIGNAL
+*
+* If we can use SO_NOSIGPIPE, then set 
sigpipe_so here and
+* we don't need to care about anything 
else. Otherwise,
+* try MSG_NOSIGNAL by setting 
sigpipe_flag. If we get an
+* error with MSG_NOSIGNAL, we clear 
the flag and revert
+* to manual masking.
+*/
+   conn-sigpipe_so = false;
+ #ifdef MSG_NOSIGNAL
+   conn-sigpipe_flag = true;
+ #else /* !MSG_NOSIGNAL */
+   conn-sigpipe_flag = false;
+ #endif /* MSG_NOSIGNAL */
+ 
+ #ifdef SO_NOSIGPIPE
+   optval = 1;
+   if (!setsockopt(conn-sock, SOL_SOCKET, 
SO_NOSIGPIPE,
+   (char *)optval, 
sizeof(optval)))
+   {
+   conn-sigpipe_so = true;
+   conn-sigpipe_flag = false;
+   }
+ #endif /* SO_NOSIGPIPE */
+ 
+ 
/*
 * Start/make connection.  This should 
not block, since we
 * are in nonblock mode.  If it does, 
well, too bad.
*** a/src/interfaces/libpq/fe-secure.c
--- b/src/interfaces/libpq/fe-secure.c
***
*** 122,127  static long win32_ssl_create_mutex = 0;
--- 122,139 
   */
  
  #ifndef WIN32
+ 
+ static inline int sigpipe_masked(PGconn *conn)
+ {
+   /* If we're on an SSL connection, we can only use SO_NOSIGPIPE masking.
+* Otherwise, we can handle SO_NOSIGPIPE or the MSG_NOSIGNAL flag */
+ #ifdef USE_SSL
+   if (conn-ssl)
+   return conn-sigpipe_so;
+ #endif
+   return conn-sigpipe_so || conn-sigpipe_flag;
+ }
+ 
  #ifdef ENABLE_THREAD_SAFETY
  
  struct sigpipe_info {
***
*** 130,137

[HACKERS] [PATCH 1/2 v3] [libpq] rework sigpipe-handling macros

2009-06-30 Thread Jeremy Kerr
Currently, the sigpipe-masking code in libpq is implemented as
a set of macros, which depend on declaring local variables.

This change adds a (private) struct sigpipe_info to contain the
compile-dependent data required for sigpipe masking and restoring.
The caller can then declare a struct sigpipe info explicitly, and
pass this to the subsequent sigpipe-masking code.

This allows us to separate the variable declarations from the code,
and gives the caller more flexibility for controlling the scope of
these variables.

Also, since we don't need to declare variables in the macros, we
can change the code to be implemented as static inlines.

Signed-off-by: Jeremy Kerr j...@ozlabs.org

---
 src/interfaces/libpq/fe-secure.c |   88 ---
 1 file changed, 55 insertions(+), 33 deletions(-)

*** a/src/interfaces/libpq/fe-secure.c
--- b/src/interfaces/libpq/fe-secure.c
***
*** 119,163  static long win32_ssl_create_mutex = 0;
  
  /*
   * Macros to handle disabling and then restoring the state of SIGPIPE 
handling.
-  * Note that DISABLE_SIGPIPE() must appear at the start of a block.
   */
  
  #ifndef WIN32
  #ifdef ENABLE_THREAD_SAFETY
  
! #define DISABLE_SIGPIPE(failaction) \
!   sigset_tosigmask; \
!   boolsigpipe_pending; \
!   boolgot_epipe = false; \
! \
!   if (pq_block_sigpipe(osigmask, sigpipe_pending)  0) \
!   failaction
  
! #define REMEMBER_EPIPE(cond) \
!   do { \
!   if (cond) \
!   got_epipe = true; \
!   } while (0)
  
! #define RESTORE_SIGPIPE() \
!   pq_reset_sigpipe(osigmask, sigpipe_pending, got_epipe)
  
  #else /* !ENABLE_THREAD_SAFETY */
  
! #define DISABLE_SIGPIPE(failaction) \
!   pqsigfunc   oldsighandler = pqsignal(SIGPIPE, SIG_IGN)
  
! #define REMEMBER_EPIPE(cond)
  
! #define RESTORE_SIGPIPE() \
!   pqsignal(SIGPIPE, oldsighandler)
  
  #endif/* ENABLE_THREAD_SAFETY */
  #else /* WIN32 */
  
! #define DISABLE_SIGPIPE(failaction)
! #define REMEMBER_EPIPE(cond)
! #define RESTORE_SIGPIPE()
  
  #endif/* WIN32 */
  
--- 119,180 
  
  /*
   * Macros to handle disabling and then restoring the state of SIGPIPE 
handling.
   */
  
  #ifndef WIN32
  #ifdef ENABLE_THREAD_SAFETY
  
! struct sigpipe_info {
!   sigset_toldsigmask;
!   boolsigpipe_pending;
!   boolgot_epipe;
! };
  
! static inline int disable_sigpipe(struct sigpipe_info *info)
! {
!   info-got_epipe = false;
!   return pq_block_sigpipe(info-oldsigmask, info-sigpipe_pending)  0;
! }
  
! static inline void remember_epipe(struct sigpipe_info *info, bool cond)
! {
!   if (cond)
!   info-got_epipe = true;
! }
! 
! static inline void restore_sigpipe(struct sigpipe_info *info)
! {
!   pq_reset_sigpipe(info-oldsigmask, info-sigpipe_pending, 
info-got_epipe);
! }
  
  #else /* !ENABLE_THREAD_SAFETY */
  
! struct sigpipe_info {
!   pqsigfunc   oldhandler;
! };
  
! static inline int disable_sigpipe(struct sigpipe_info *info)
! {
!   info-oldhandler = pqsignal(SIGPIPE, SIG_IGN);
!   return 0;
! }
! 
! static inline void remember_epipe(struct sigpipe_info *info, bool cond)
! {
! }
  
! static inline void restore_sigpipe(struct sigpipe_info *info)
! {
!   pqsignal(SIGPIPE, info-oldhandler);
! }
  
  #endif/* ENABLE_THREAD_SAFETY */
  #else /* WIN32 */
  
! struct sigpipe_info { };
! static inline int disable_sigpipe(struct sigpipe_info *info) { return 0; }
! static inline void remember_epipe(struct sigpipe_info *info, bool cond) { }
! static inline void restore_sigpipe(struct sigpipe_info *info) { }
  
  #endif/* WIN32 */
  
***
*** 286,294  pqsecure_read(PGconn *conn, void *ptr, size_t len)
if (conn-ssl)
{
int err;
  
/* SSL_read can write to the socket, so we need to disable 
SIGPIPE */
!   DISABLE_SIGPIPE(return -1);
  
  rloop:
n = SSL_read(conn-ssl, ptr, len);
--- 303,313 
if (conn-ssl)
{
int err;
+   struct sigpipe_info info;
  
/* SSL_read can write to the socket, so we need to disable 
SIGPIPE */
!   if (disable_sigpipe(info))
!   return -1;
  
  rloop:
n = SSL_read(conn-ssl, ptr, len);
***
*** 315,321  rloop:
  
if (n == -1)
{
!   REMEMBER_EPIPE(SOCK_ERRNO == 
EPIPE);

printfPQExpBuffer(conn-errorMessage,

libpq_gettext(SSL SYSCALL error: %s\n),

SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf

[HACKERS] [PATCH v3] Avoid manual shift-and-test logic in AllocSetFreeIndex

2009-06-30 Thread Jeremy Kerr
Move the shift-and-test login into a separate fls() function, which
can use __builtin_clz() if it's available.

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

Results in a ~2% performance increase on PowerPC.

Signed-off-by: Jeremy Kerr j...@ozlabs.org

---
v3: respin as context diff

---
 configure.in  |   13 +
 src/backend/utils/mmgr/aset.c |   34 +++---
 2 files changed, 40 insertions(+), 7 deletions(-)

*** 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
***
*** 255,260  static MemoryContextMethods AllocSetMethods = {
--- 255,285 
  #define AllocAllocInfo(_cxt, _chunk)
  #endif
  
+ /*
+  * fls: find last set bit.
+  *
+  * Returns the 1-based index of the most-significant bit in x. The MSB
+  * is bit number 32, the LSB is bit number 1. If x is zero, the result is
+  * undefined.
+  */
+ static inline int
+ fls(unsigned int x)
+ {
+ #ifdef HAVE_BUILTIN_CLZ
+   return 32 - __builtin_clz(x);
+ #else
+   int ls = 0;
+ 
+   while (x != 0)
+   {
+   ls++;
+   x = 1;
+   }
+ 
+   return ls;
+ #endif
+ }
+ 
  /* --
   * AllocSetFreeIndex -
   *
***
*** 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);
}
  
--- 293,301 
  {
int idx = 0;
  
!   if (size  (1  ALLOC_MINBITS))
{
!   idx = fls((size - 1)  ALLOC_MINBITS);
Assert(idx  ALLOCSET_NUM_FREELISTS);
}
  

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH] backend: compare word-at-a-time in bcTruelen

2009-06-26 Thread Jeremy Kerr
Stephen,

 Is it just the size that matters, or is it when there are few spaces
 at the end?

It's the number of spaces at the end. If we knew this number, then we 
wouldn't have to do any comparisons at all :)

Cheers,


Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH] backend: compare word-at-a-time in bcTruelen

2009-06-26 Thread Jeremy Kerr
Stephen,

 If the updated function is always faster when the overall string is at
 least, say, 16 characters long,

But that's not the case - the cost of the function (and the speedup from 
the previous version) depends on the number of spaces that there are at 
the end.

For the new function to be faster, we need to know that there are more 
than 6 (on average, depending on alignment) trailing spaces. The number 
of non-space characters in the string won't affect performance (other 
than that there is probably a correlation between total string length 
and number of spaces, but we can't be certain of that).

 If the new function is always slower, regardless of overall string
 length, when there's only 1 extra space at the end

Yes, that is correct.

Cheers,


Jeremy


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH] backend: compare word-at-a-time in bcTruelen

2009-06-25 Thread Jeremy Kerr
Hi Stephen,

 What would be really useful would be best case and worst case
 scenarios.

I've put together some data from a microbenchmark of the bcTrulen 
function, patched and unpatched.

As for best-case, if you have a long string of trailing spaces, we can 
go through them at theoretically one quarter of cost (a test benchmark 
on x86 shows an actual reduction of 11 to 3 sec with a string of 100 
spaces).

Worst-case behaviour is with smaller numbers of spaces. Here are the 
transition points (ie, where doing the word-wise comparison is faster 
than byte-wise) that I see from my benchmark:

align   spaces
3   7
2   6
1   5
0   4

 - where 'align' is the alignment of the first byte to compare (ie, at 
the end of the string). This is pretty much as-expected, as these 
transition points are the first opportunity that the new function has to 
do a word compare.

In the worst cases, I see a 53% cost increase on x86 (with the string 
'aaa ') and a 97% increase on PowerPC ('a  ').

So, it all depends on the number of padding spaces we'd expect to see on 
workload data. Fortunately, we see the larger reductions on the more 
expensive operations (ie, longer strings).

Cheers,


Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH] backend: compare word-at-a-time in bcTruelen

2009-06-25 Thread Jeremy Kerr
Tom,

  I've put together some data from a microbenchmark of the bcTrulen
  function, patched and unpatched.

 Uh, where's the data?

If you're after the raw data for a run, I've put it up:

 http://ozlabs.org/~jk/projects/db/data/bctruelen.csv

I've also packaged up the quick-and-dirty benchmark I've been using:

 http://ozlabs.org/~jk/projects/db/bctrulen.tar.gz

to recreate as-needed. ./benchmark.sh will run tests for varying-length 
strings (so changing the alignment) and varying numbers of trailing 
spaces. ./benchmark-bctruelen str will perform an individual old/new 
comparison.

 Unfortunately, the cases with lots of padding spaces are probably
 much less probable than the cases with fewer.  It would be unpleasant
 for example if this patch resulted in a severe performance
 degradation for a canonical example of char(n) being used properly,
 such as char(2) for US state abbreviations.

Yep, makes sense. The other consideration is stock-ticker symbols, I 
assume they may also be stored in CHAR(small n) columns.

Cheers,


Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] [PATCH] backend: compare word-at-a-time in bcTruelen

2009-06-23 Thread Jeremy Kerr
The current bcTruelen function uses a simple reverse array scan to
find the legth of a space-padded string. On some workloads (it shows
in sysbench), this can result in a lot of time spent in this function.

This change introduces a word-at-a-time comparison in bcTruelen, aiming
to reduce the number of compares where possible. Word-size compares
are performed on aligned sections of the string.

Results in a small performance increase; around 1-2% on my POWER6 test
box.

Signed-off-by: Jeremy Kerr j...@ozlabs.org

---
Resend: context diff this time

---
 src/backend/utils/adt/varchar.c |   24 +---
 1 file changed, 21 insertions(+), 3 deletions(-)

*** a/src/backend/utils/adt/varchar.c
--- b/src/backend/utils/adt/varchar.c
***
*** 624,639  varchartypmodout(PG_FUNCTION_ARGS)
  static int
  bcTruelen(BpChar *arg)
  {
char   *s = VARDATA_ANY(arg);
int i;
-   int len;
  
!   len = VARSIZE_ANY_EXHDR(arg);
!   for (i = len - 1; i = 0; i--)
{
if (s[i] != ' ')
break;
}
return i + 1;
  }
  
--- 624,657 
  static int
  bcTruelen(BpChar *arg)
  {
+   const uint32_t  spaces = 0x20202020;
+   const int   wordsize = sizeof(spaces);
char   *s = VARDATA_ANY(arg);
int i;
  
!   i = VARSIZE_ANY_EXHDR(arg) - 1;
! 
!   /* compare down to an aligned boundary */
!   for (; i  0  !PointerIsAligned(s + i - (wordsize - 1), uint32_t); 
i--)
{
if (s[i] != ' ')
+   return i + 1;
+   }
+ 
+   /* now that we're aligned, compare word at a time */
+   for (; i = wordsize - 1; i -= wordsize)
+   {
+   if (*(uint32_t *)(s + i - (wordsize - 1)) != spaces)
break;
}
+ 
+   /* check within the last non-matching word */
+   for (; i = 0; i--)
+   {
+   if (s[i] != ' ')
+   break;
+   }
+ 
return i + 1;
  }
  

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH] backend: compare word-at-a-time in bcTruelen

2009-06-23 Thread Jeremy Kerr
Robert,

 I'd still like to know the workload and exact numbers.

From up-thread:

 http://ozlabs.org/~jk/projects/db/data/postgres.bcTruelen/

- or were there other details you were looking for?

Cheers,

Jeremy


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH] backend: compare word-at-a-time in bcTruelen

2009-06-17 Thread Jeremy Kerr
Hi all,

 Speaking of which, what about some performance numbers?

OK, benchmarks done:

 http://ozlabs.org/~jk/projects/db/data/postgres.bcTruelen/

Summary: small increase in performance (~1-2% on my machine), at about 
1.5 standard deviations from the mean. Profiles show a decent drop in 
hits within bcTruelen.

However: Sysbench seems to be quite heavy with the fixed-width char 
types, so may end up calling bcTruelen more than most workloads. Would 
be nice to get some x86 numbers too, but I don't have a suitable machine 
here.

So: The increase in performance is positive on this workload, albeit 
fairly minor. Downside is increased code complexity.

Will re-send the patch once I work out how to get git to create a 
context diff...

Cheers,


Jeremy


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH] backend: compare word-at-a-time in bcTruelen

2009-06-16 Thread Jeremy Kerr
Hi all,

 That's correct. To check the alignment you would have to look at the
 actual pointer. I would suggest using the existing macros to handle
 alignment. Hm, though the only one I see offhand which is relevant is
 the moderately silly PointerIsAligned(). Still it would make the code
 clearer even if it's pretty simple.

Yes, the code (incorrectly) assumes that any multiple-of-4 index into 
the char array is aligned, and so the array itself must be aligned for 
this to work.

I'll rework the patch, testing the pointer alignment directly instead.

 Incidentally, the char foo[4] = {' ',' ',' ',' '} suggestion is, I
 think, bogus. There would be no alignment guarantee on that array.
 Personally I'm find with 0x20202020 with a comment explaining what it
 is.

The variable is called 'spaces', but I can add extra comments if 
preferred.

Cheers,


Jeremy



-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH] backend: compare word-at-a-time in bcTruelen

2009-06-16 Thread Jeremy Kerr
Hi Tom,

 Speaking of which, what about some performance numbers?  Like Heikki,
 I'm quite suspicious of whether there is any real-world gain to be
 had from this approach.

Will send numbers tomorrow, with the reworked patch.

Cheers,


Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] char() overhead on read-only workloads not so insignifcant as the docs claim it is...

2009-06-15 Thread Jeremy Kerr
Alvaro,

 Maybe bcTruelen could be optimized to step on one word at a time
 (perhaps by using XOR against a precomputed word filled with ' '),
 instead of one byte at a time ...

I have a patch for this, will send soon.

Regards,


Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] [PATCH] backend: compare word-at-a-time in bcTruelen

2009-06-15 Thread Jeremy Kerr
Signed-off-by: Jeremy Kerr j...@ozlabs.org

---
 src/backend/utils/adt/varchar.c |   24 +---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c
index 5f3c658..6889dff 100644
--- a/src/backend/utils/adt/varchar.c
+++ b/src/backend/utils/adt/varchar.c
@@ -624,16 +624,34 @@ varchartypmodout(PG_FUNCTION_ARGS)
 static int
 bcTruelen(BpChar *arg)
 {
+   const unsigned int spaces = 0x20202020;
+   const int   wordsize = sizeof(spaces);
char   *s = VARDATA_ANY(arg);
int i;
-   int len;
 
-   len = VARSIZE_ANY_EXHDR(arg);
-   for (i = len - 1; i = 0; i--)
+   i = VARSIZE_ANY_EXHDR(arg) - 1;
+
+   /* compare down to an aligned boundary */
+   for (; i = 0  i % wordsize != wordsize - 1; i--)
{
if (s[i] != ' ')
+   return i + 1;
+   }
+
+   /* now that we're aligned, compare word at a time */
+   for (; i = wordsize - 1; i -= wordsize)
+   {
+   if (*(unsigned int *)(s + i - (wordsize - 1)) != spaces)
break;
}
+
+   /* check within the last non-matching word */
+   for (; i = 0; i--)
+   {
+   if (s[i] != ' ')
+   break;
+   }
+
return i + 1;
 }
 

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH] backend: compare word-at-a-time in bcTruelen

2009-06-15 Thread Jeremy Kerr
Robert,

 This looks very non-portable to me.

Unsurprisingly, I'm new to postgres hacking and the large number of 
supported platforms :)

I was considering something like:

unsigned int spaces;
const unsigned int wordsize = sizeof(unsigned int);

memset(spaces, ' ', wordsize);

In most cases, the compiler should be able to optimise the memset out, 
but it may introduce overhead where this is not possible.

However, are there any supported platforms where sizeof(unsigned int) != 
4 ?

Cheers,


Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] [PATCH 0/2] SIGPIPE masking in local socket connections, v2

2009-06-10 Thread Jeremy Kerr
A new approach to avioding manipulating the signal mask during for every
send - this time round, use SO_NOSIGPIPE and MSG_NOSIGNAL if available.

The patches have been tested on Linux and OSX, and I've confirmed that
'struct foo { };' will compile with a MSVC compiler. I'd still like a
little more testing though, is there a machine that allows both
SO_NOSIGPIPE and MSG_NOSIGNAL?

Again, comments most welcome,


Jeremy

---
Jeremy Kerr (2):
  [libpq] rework sigpipe-handling macros
  [libpq] Try to avoid manually masking SIGPIPEs on every send()


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] [PATCH 1/2] [libpq] rework sigpipe-handling macros

2009-06-10 Thread Jeremy Kerr
Currently, the sigpipe-masking code in libpq is implemented as
a set of macros, which depend on declaring local variables.

This change adds a (private) struct sigpipe_info to contain the
compile-dependent data required for sigpipe masking and restoring.
The caller can then declare a struct sigpipe info explicitly, and
pass this to the subsequent sigpipe-masking code.

This allows us to separate the variable declarations from the code,
and gives the caller more flexibility for controlling the scope of
these variables.

Also, since we don't need to declare variables in the macros, we
can change the code to be implemented as static inlines.

Signed-off-by: Jeremy Kerr j...@ozlabs.org

---
 src/interfaces/libpq/fe-secure.c |   88 ---
 1 file changed, 55 insertions(+), 33 deletions(-)

diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c
index ee0a91e..13c97ac 100644
--- a/src/interfaces/libpq/fe-secure.c
+++ b/src/interfaces/libpq/fe-secure.c
@@ -119,45 +119,62 @@ static long win32_ssl_create_mutex = 0;
 
 /*
  * Macros to handle disabling and then restoring the state of SIGPIPE handling.
- * Note that DISABLE_SIGPIPE() must appear at the start of a block.
  */
 
 #ifndef WIN32
 #ifdef ENABLE_THREAD_SAFETY
 
-#define DISABLE_SIGPIPE(failaction) \
-   sigset_tosigmask; \
-   boolsigpipe_pending; \
-   boolgot_epipe = false; \
-\
-   if (pq_block_sigpipe(osigmask, sigpipe_pending)  0) \
-   failaction
+struct sigpipe_info {
+   sigset_toldsigmask;
+   boolsigpipe_pending;
+   boolgot_epipe;
+};
 
-#define REMEMBER_EPIPE(cond) \
-   do { \
-   if (cond) \
-   got_epipe = true; \
-   } while (0)
+static inline int disable_sigpipe(struct sigpipe_info *info)
+{
+   info-got_epipe = false;
+   return pq_block_sigpipe(info-oldsigmask, info-sigpipe_pending)  0;
+}
 
-#define RESTORE_SIGPIPE() \
-   pq_reset_sigpipe(osigmask, sigpipe_pending, got_epipe)
+static inline void remember_epipe(struct sigpipe_info *info, bool cond)
+{
+   if (cond)
+   info-got_epipe = true;
+}
+
+static inline void restore_sigpipe(struct sigpipe_info *info)
+{
+   pq_reset_sigpipe(info-oldsigmask, info-sigpipe_pending, 
info-got_epipe);
+}
 
 #else  /* !ENABLE_THREAD_SAFETY */
 
-#define DISABLE_SIGPIPE(failaction) \
-   pqsigfunc   oldsighandler = pqsignal(SIGPIPE, SIG_IGN)
+struct sigpipe_info {
+   pqsigfunc   oldhandler;
+};
 
-#define REMEMBER_EPIPE(cond)
+static inline int disable_sigpipe(struct sigpipe_info *info)
+{
+   info-oldhandler = pqsignal(SIGPIPE, SIG_IGN);
+   return 0;
+}
+
+static inline void remember_epipe(struct sigpipe_info *info, bool cond)
+{
+}
 
-#define RESTORE_SIGPIPE() \
-   pqsignal(SIGPIPE, oldsighandler)
+static inline void restore_sigpipe(struct sigpipe_info *info)
+{
+   pqsignal(SIGPIPE, info-oldhandler);
+}
 
 #endif /* ENABLE_THREAD_SAFETY */
 #else  /* WIN32 */
 
-#define DISABLE_SIGPIPE(failaction)
-#define REMEMBER_EPIPE(cond)
-#define RESTORE_SIGPIPE()
+struct sigpipe_info { };
+static inline int disable_sigpipe(struct sigpipe_info *info) { return 0; }
+static inline void remember_epipe(struct sigpipe_info *info, bool cond) { }
+static inline void restore_sigpipe(struct sigpipe_info *info) { }
 
 #endif /* WIN32 */
 
@@ -286,9 +303,11 @@ pqsecure_read(PGconn *conn, void *ptr, size_t len)
if (conn-ssl)
{
int err;
+   struct sigpipe_info info;
 
/* SSL_read can write to the socket, so we need to disable 
SIGPIPE */
-   DISABLE_SIGPIPE(return -1);
+   if (disable_sigpipe(info))
+   return -1;
 
 rloop:
n = SSL_read(conn-ssl, ptr, len);
@@ -315,7 +334,7 @@ rloop:
 
if (n == -1)
{
-   REMEMBER_EPIPE(SOCK_ERRNO == 
EPIPE);
+   remember_epipe(info, 
SOCK_ERRNO == EPIPE);

printfPQExpBuffer(conn-errorMessage,

libpq_gettext(SSL SYSCALL error: %s\n),

SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
@@ -351,7 +370,7 @@ rloop:
break;
}
 
-   RESTORE_SIGPIPE();
+   restore_sigpipe(info);
}
else
 #endif
@@ -367,8 +386,10 @@ ssize_t
 pqsecure_write(PGconn *conn, const void *ptr, size_t len)
 {
ssize_t n;
+   struct sigpipe_info info;
 
-   DISABLE_SIGPIPE(return -1);
+   if (disable_sigpipe(info))
+   return -1;
 
 #ifdef USE_SSL

[HACKERS] [PATCH 2/2] [libpq] Try to avoid manually masking SIGPIPEs on every send()

2009-06-10 Thread Jeremy Kerr
Currently, libpq will wrap each send() call on the connection with
two system calls to mask SIGPIPEs. This results in 3 syscalls instead
of one, and (on Linux) can lead to high contention on the signal
mask locks in threaded apps.

We have a couple of other methods to avoid SIGPIPEs:
sockopt(SO_NOSIGPIPE) and the MSG_NOSIGNAL flag to send().

This change attempts to use these if they're available at compile-
and run-time. If not, we drop back to manipulating the signal mask as
before.

Signed-off-by: Jeremy Kerr j...@ozlabs.org

---
 src/interfaces/libpq/fe-connect.c |   39 +
 src/interfaces/libpq/fe-secure.c  |   83 +-
 src/interfaces/libpq/libpq-int.h  |2 
 3 files changed, 106 insertions(+), 18 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c 
b/src/interfaces/libpq/fe-connect.c
index 7f4ae4c..8265268 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -1085,6 +1085,7 @@ keep_going:   
/* We will come back to here until there is
while (conn-addr_cur != NULL)
{
struct addrinfo *addr_cur = 
conn-addr_cur;
+   int optval;
 
/* Remember current address for 
possible error msg */
memcpy(conn-raddr.addr, 
addr_cur-ai_addr,
@@ -1149,6 +1150,44 @@ keep_going:  
/* We will come back to here until there is
}
 #endif   /* F_SETFD */
 
+   /* We have three methods of blocking 
sigpipe during
+* send() calls to this socket:
+*
+*  - setsockopt(sock, SO_NOSIGPIPE)
+*  - send(sock, ..., MSG_NOSIGNAL)
+*  - setting the signal mask to 
SIG_IGN during send()
+*
+* The first two reduce the number of 
syscalls (for the
+* third, we require three syscalls to 
implement a send()),
+* so use them if they're available. 
Their availability is
+* flagged in the following members of 
PGconn:
+*
+* conn-sigpipe_so - we 
have set up SO_NOSIGPIPE
+* conn-sigpipe_flag   - we're 
specifying MSG_NOSIGNAL
+*
+* If we can use SO_NOSIGPIPE, then set 
sigpipe_so here and
+* we don't need to care about anything 
else. Otherwise,
+* try MSG_NOSIGNAL by setting 
sigpipe_flag. If we get an
+* error with MSG_NOSIGNAL, we clear 
the flag and revert
+* to manual masking.
+*/
+   conn-sigpipe_so = false;
+#ifdef MSG_NOSIGNAL
+   conn-sigpipe_flag = true;
+#else /* !MSG_NOSIGNAL */
+   conn-sigpipe_flag = false;
+#endif /* MSG_NOSIGNAL */
+
+#ifdef SO_NOSIGPIPE
+   if (!setsockopt(conn-sock, SOL_SOCKET, 
SO_NOSIGPIPE,
+   (char *)optval, 
sizeof(optval)))
+   {
+   conn-sigpipe_so = true;
+   conn-sigpipe_flag = false;
+   }
+#endif /* SO_NOSIGPIPE */
+
+
/*
 * Start/make connection.  This should 
not block, since we
 * are in nonblock mode.  If it does, 
well, too bad.
diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c
index 13c97ac..949cd0f 100644
--- a/src/interfaces/libpq/fe-secure.c
+++ b/src/interfaces/libpq/fe-secure.c
@@ -122,6 +122,18 @@ static long win32_ssl_create_mutex = 0;
  */
 
 #ifndef WIN32
+
+static inline int sigpipe_masked(PGconn *conn)
+{
+   /* If we're on an SSL connection, we can only use SO_NOSIGPIPE masking.
+* Otherwise, we can handle SO_NOSIGPIPE or the MSG_NOSIGNAL flag */
+#ifdef USE_SSL
+   if (conn-ssl)
+   return conn-sigpipe_so;
+#endif
+   return conn-sigpipe_so || conn-sigpipe_flag;
+}
+
 #ifdef

Re: [HACKERS] [PATCH 2/2] [libpq] Try to avoid manually masking SIGPIPEs on every send()

2009-06-10 Thread Jeremy Kerr
Marko,

 optval seems used without initialization.

Dang, I was checking for the SO_NOSIGPIPE flag, and didn't check for 
optval. New patch coming...

Cheers,


Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] [PATCH v2] [libpq] Try to avoid manually masking SIGPIPEs on every send()

2009-06-10 Thread Jeremy Kerr
Currently, libpq will wrap each send() call on the connection with
two system calls to mask SIGPIPEs. This results in 3 syscalls instead
of one, and (on Linux) can lead to high contention on the signal
mask locks in threaded apps.

We have a couple of other methods to avoid SIGPIPEs:
sockopt(SO_NOSIGPIPE) and the MSG_NOSIGNAL flag to send().

This change attempts to use these if they're available at compile-
and run-time. If not, we drop back to manipulating the signal mask as
before.

Signed-off-by: Jeremy Kerr j...@ozlabs.org

---
v2: initialise optval

---
 src/interfaces/libpq/fe-connect.c |   40 ++
 src/interfaces/libpq/fe-secure.c  |   83 +-
 src/interfaces/libpq/libpq-int.h  |2 
 3 files changed, 107 insertions(+), 18 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c 
b/src/interfaces/libpq/fe-connect.c
index 7f4ae4c..92ab4e0 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -1085,6 +1085,7 @@ keep_going:   
/* We will come back to here until there is
while (conn-addr_cur != NULL)
{
struct addrinfo *addr_cur = 
conn-addr_cur;
+   int optval;
 
/* Remember current address for 
possible error msg */
memcpy(conn-raddr.addr, 
addr_cur-ai_addr,
@@ -1149,6 +1150,45 @@ keep_going:  
/* We will come back to here until there is
}
 #endif   /* F_SETFD */
 
+   /* We have three methods of blocking 
sigpipe during
+* send() calls to this socket:
+*
+*  - setsockopt(sock, SO_NOSIGPIPE)
+*  - send(sock, ..., MSG_NOSIGNAL)
+*  - setting the signal mask to 
SIG_IGN during send()
+*
+* The first two reduce the number of 
syscalls (for the
+* third, we require three syscalls to 
implement a send()),
+* so use them if they're available. 
Their availability is
+* flagged in the following members of 
PGconn:
+*
+* conn-sigpipe_so - we 
have set up SO_NOSIGPIPE
+* conn-sigpipe_flag   - we're 
specifying MSG_NOSIGNAL
+*
+* If we can use SO_NOSIGPIPE, then set 
sigpipe_so here and
+* we don't need to care about anything 
else. Otherwise,
+* try MSG_NOSIGNAL by setting 
sigpipe_flag. If we get an
+* error with MSG_NOSIGNAL, we clear 
the flag and revert
+* to manual masking.
+*/
+   conn-sigpipe_so = false;
+#ifdef MSG_NOSIGNAL
+   conn-sigpipe_flag = true;
+#else /* !MSG_NOSIGNAL */
+   conn-sigpipe_flag = false;
+#endif /* MSG_NOSIGNAL */
+
+#ifdef SO_NOSIGPIPE
+   optval = 1;
+   if (!setsockopt(conn-sock, SOL_SOCKET, 
SO_NOSIGPIPE,
+   (char *)optval, 
sizeof(optval)))
+   {
+   conn-sigpipe_so = true;
+   conn-sigpipe_flag = false;
+   }
+#endif /* SO_NOSIGPIPE */
+
+
/*
 * Start/make connection.  This should 
not block, since we
 * are in nonblock mode.  If it does, 
well, too bad.
diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c
index 13c97ac..949cd0f 100644
--- a/src/interfaces/libpq/fe-secure.c
+++ b/src/interfaces/libpq/fe-secure.c
@@ -122,6 +122,18 @@ static long win32_ssl_create_mutex = 0;
  */
 
 #ifndef WIN32
+
+static inline int sigpipe_masked(PGconn *conn)
+{
+   /* If we're on an SSL connection, we can only use SO_NOSIGPIPE masking.
+* Otherwise, we can handle SO_NOSIGPIPE or the MSG_NOSIGNAL flag */
+#ifdef USE_SSL
+   if (conn-ssl)
+   return conn-sigpipe_so

Re: [HACKERS] [RFC,PATCH] Avoid manual shift-and-test logic in AllocSetFreeIndex

2009-06-04 Thread Jeremy Kerr
Hi Atsushi,

 If size = 8, fls((size - 1)  ALLOC_MINBITS) is fls(0).
 The result of fls(0) is undefined.

Yep, got caught out by this because my previous fls() supported zero.

 I think we have to never call fls(0) from AllocSetFreeIndex().
 My proposal code:

  if (size  (1  ALLOC_MINBITS))
  {
  idx = fls((size - 1)  ALLOC_MINBITS);
  Assert(idx  ALLOCSET_NUM_FREELISTS);
  }

Looks good, I'll send an updated patch.

Also, are you still seeing the same improvement with the __builtin_clz 
as your inline asm implementation?

Cheers,


Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] [PATCH v2] Avoid manual shift-and-test logic in AllocSetFreeIndex

2009-06-04 Thread Jeremy Kerr
Move the shift-and-test login into a separate fls() function, which
can use __builtin_clz() if it's available.

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

Results in a ~2% performance increase on PowerPC.

Signed-off-by: Jeremy Kerr j...@ozlabs.org

---
v2: prevent fls(0)

---
 configure.in  |   13 +
 src/backend/utils/mmgr/aset.c |   34 +++---
 2 files changed, 40 insertions(+), 7 deletions(-)

diff --git a/configure.in b/configure.in
index b8d2685..6a317b0 100644
--- a/configure.in
+++ b/configure.in
@@ -1361,6 +1361,19 @@ case $host_os in
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
diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c
index 0e2d4d5..9eb3117 100644
--- a/src/backend/utils/mmgr/aset.c
+++ b/src/backend/utils/mmgr/aset.c
@@ -255,6 +255,31 @@ static MemoryContextMethods AllocSetMethods = {
 #define AllocAllocInfo(_cxt, _chunk)
 #endif
 
+/*
+ * fls: find last set bit.
+ *
+ * Returns the 1-based index of the most-significant bit in x. The MSB
+ * is bit number 32, the LSB is bit number 1. If x is zero, the result is
+ * undefined.
+ */
+static inline int
+fls(unsigned int x)
+{
+#ifdef HAVE_BUILTIN_CLZ
+   return 32 - __builtin_clz(x);
+#else
+   int ls = 0;
+
+   while (x != 0)
+   {
+   ls++;
+   x = 1;
+   }
+
+   return ls;
+#endif
+}
+
 /* --
  * AllocSetFreeIndex -
  *
@@ -268,14 +293,9 @@ AllocSetFreeIndex(Size size)
 {
int idx = 0;
 
-   if (size  0)
+   if (size  (1  ALLOC_MINBITS))
{
-   size = (size - 1)  ALLOC_MINBITS;
-   while (size != 0)
-   {
-   idx++;
-   size = 1;
-   }
+   idx = fls((size - 1)  ALLOC_MINBITS);
Assert(idx  ALLOCSET_NUM_FREELISTS);
}
 

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [RFC,PATCH] Avoid manual shift-and-test logic in AllocSetFreeIndex

2009-06-04 Thread Jeremy Kerr
Hi Atsushi,

 In my benchmark program, it is a little different performance
 in fls implementation and inline asm implementation.
 However, the result of a pgbench is almost the same improvement.

 Here is the result of my benchmark.

Excellent, thank you for getting this extra set of numbers.

Cheers,


Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH v2] Add bit operations util header

2009-06-03 Thread Jeremy Kerr
Florian,

  +#if defined(__GNUC__)  \
  +   (defined(__ppc__) || defined(__powerpc__) || \
  +defined(__ppc64__) || defined (__powerpc64__))

 If you require GCC anyway, you can use __builtin_clz instead.
 (It's been available since GCC 4.1 at least.)

Because now we have to test the compiler *and* the version as well?

But I do agree that using the builtins makes for much better code; I'm 
looking at a future change that does this.

Cheers,


Jeremy


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH v2] Add bit operations util header

2009-06-03 Thread Jeremy Kerr
Hi Tom,

 The other thing I didn't like about the patch was the assumption that
 it's okay to have a static inline function in a header.  You can
 get away with that in gcc but *not* in other compilers.

Gee, you user-space guys have it tough! :D

Point taken, will rework.

 Look at the existing coding patterns for, eg, list_head; then go thou
 and do likewise.  Or, since there's currently no need for the code
 outside aset.c, forget about putting it in a header and just plop it
 into aset.c.

OK, I'll add a configure check and conditionally use the builtin if it's 
available. I have some other patches that could be improved by using 
other builtins, so it would be a good opportunity to figure out a nice 
pattern for doing this.

Cheers,


Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] [RFC,PATCH] Avoid manual shift-and-test logic in AllocSetFreeIndex

2009-06-03 Thread Jeremy Kerr
Move the shift-and-test login into a separate fls() function, which
can use __builtin_clz() if it's available.

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

Results in a ~2% performance increase on PowerPC.

Signed-off-by: Jeremy Kerr j...@ozlabs.org

---
 configure.in  |   13 +
 src/backend/utils/mmgr/aset.c |   32 ++--
 2 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/configure.in b/configure.in
index b8d2685..6a317b0 100644
--- a/configure.in
+++ b/configure.in
@@ -1361,6 +1361,19 @@ case $host_os in
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
diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c
index 0e2d4d5..af352b8 100644
--- a/src/backend/utils/mmgr/aset.c
+++ b/src/backend/utils/mmgr/aset.c
@@ -255,6 +255,31 @@ static MemoryContextMethods AllocSetMethods = {
 #define AllocAllocInfo(_cxt, _chunk)
 #endif
 
+/*
+ * fls: find last set bit.
+ *
+ * Returns the 1-based index of the most-significant bit in x. The MSB
+ * is bit number 32, the LSB is bit number 1. If x is zero, the result is
+ * undefined.
+ */
+static inline int
+fls(unsigned int x)
+{
+#ifdef HAVE_BUILTIN_CLZ
+   return 32 - __builtin_clz(x);
+#else
+   int ls = 0;
+
+   while (x != 0)
+   {
+   ls++;
+   x = 1;
+   }
+
+   return ls;
+#endif
+}
+
 /* --
  * AllocSetFreeIndex -
  *
@@ -270,12 +295,7 @@ AllocSetFreeIndex(Size size)
 
if (size  0)
{
-   size = (size - 1)  ALLOC_MINBITS;
-   while (size != 0)
-   {
-   idx++;
-   size = 1;
-   }
+   idx = fls((size - 1)  ALLOC_MINBITS);
Assert(idx  ALLOCSET_NUM_FREELISTS);
}
 

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [RFC,PATCH] SIGPIPE masking in local socket connections

2009-06-02 Thread Jeremy Kerr
Tom,

 The consideration is that the application fails completely on server
 disconnect (because it gets SIGPIPE'd).  This was long ago deemed
 unacceptable, and we aren't likely to change our opinion on that.

OK, understood. I'm guessing MSG_NOSIGNAL on the send() isn't portable 
enough here?

 What disturbs me about your report is the suggestion that there are
 paths through that code that fail to protect against SIGPIPE.  If so,
 we need to fix that.

I just missed the comment that pqsecure_read may end up writing to the 
socket in the SSL case, so looks like all is fine here. We shouldn't see 
a SIGPIPE from the recv() alone.

Cheers,


Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [RFC,PATCH] SIGPIPE masking in local socket connections

2009-06-02 Thread Jeremy Kerr
Tom,

 A feature that is exercised via setsockopt is probably fairly safe,
 since you can check for failure of the setsockopt call and then do
 it the old way.  MSG_NOSIGNAL is a recv() flag, no?

It's a flag to send().

 The question is whether you could expect that the recv() would fail if
 it had any unrecognized flags.  Not sure if I trust that. SO_NOSIGPIPE
 seems safer.

Yep, a once-off test would be better. However, I don't seem to have a 
NOSIGPIPE sockopt here :(

Cheers,


Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] faster version of AllocSetFreeIndex for x86 architecture

2009-06-02 Thread Jeremy Kerr
Hi,

 I made a faster version of AllocSetFreeIndex for x86 architecture.

Neat, I have a version for PowerPC too.

In order to prevent writing multiple copies of AllocSetFreeIndex, I 
propose that we add a fls() function (find last set); this can be 
defined in an architecture-independent manner (ie, shift mask  test in 
a loop), and re-defined for arches that have faster ways of doing the 
same (ie, cntlz instruction on powerpc).

We can then change AllocSetFreeIndex to use fls().

Patches coming...



Jeremy

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] [PATCH 1/2] Add bit operations util header

2009-06-02 Thread Jeremy Kerr
Add a utility header for simple bit operatios - bitops.h.

At present, just contains the fls() (find last set bit) function.

Signed-off-by: Jeremy Kerr j...@ozlabs.org

---
 src/include/utils/bitops.h |   52 +
 1 file changed, 52 insertions(+)

diff --git a/src/include/utils/bitops.h b/src/include/utils/bitops.h
new file mode 100644
index 000..de11624
--- /dev/null
+++ b/src/include/utils/bitops.h
@@ -0,0 +1,52 @@
+/*-
+ *
+ * bitops.h
+ *   Simple bit operations.
+ *
+ * Portions Copyright (c) 2009, PostgreSQL Global Development Group
+ *
+ * $PostgreSQL$
+ *
+ *-
+ */
+#ifndef BITOPS_H
+#define BITOPS_H
+
+#if defined(__ppc__) || defined(__powerpc__) || \
+   defined(__ppc64__) || defined (__powerpc64__)
+
+static inline int
+fls(unsigned int x)
+{
+   int lz;
+   asm(cntlz %0,%1 : =r (lz) : r (x));
+   return 32 - lz;
+}
+
+#else /* !powerpc */
+
+/* Architecture-independent implementations */
+
+/*
+ * fls: find last set bit.
+ *
+ * Returns the 1-based index of the most-significant bit in x. The MSB
+ * is bit number 32, the LSB is bit number 1. If x is zero, returns zero.
+ */
+static inline int
+fls(unsigned int x)
+{
+   int ls = 0;
+
+   while (x != 0)
+   {
+   ls++;
+   x = 1;
+   }
+
+   return ls;
+}
+
+#endif
+
+#endif /* BITOPS_H */

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] [PATCH 2/2] Use fls() to find chunk set

2009-06-02 Thread Jeremy Kerr
Results in a ~2% performance increase by using the powerpc fls()
implementation.

Signed-off-by: Jeremy Kerr j...@ozlabs.org

---
 src/backend/utils/mmgr/aset.c |8 ++--
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c
index 0e2d4d5..762cf72 100644
--- a/src/backend/utils/mmgr/aset.c
+++ b/src/backend/utils/mmgr/aset.c
@@ -65,6 +65,7 @@
 #include postgres.h
 
 #include utils/memutils.h
+#include utils/bitops.h
 
 /* Define this to detail debug alloc information */
 /* #define HAVE_ALLOCINFO */
@@ -270,12 +271,7 @@ AllocSetFreeIndex(Size size)
 
if (size  0)
{
-   size = (size - 1)  ALLOC_MINBITS;
-   while (size != 0)
-   {
-   idx++;
-   size = 1;
-   }
+   idx = fls((size - 1)  ALLOC_MINBITS);
Assert(idx  ALLOCSET_NUM_FREELISTS);
}
 

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] [PATCH v2] Add bit operations util header

2009-06-02 Thread Jeremy Kerr
Add a utility header for simple bit operatios - bitops.h.

At present, just contains the fls() (find last set bit) function.

Signed-off-by: Jeremy Kerr j...@ozlabs.org

---
v2: only use inline asm with gcc

---
 src/include/utils/bitops.h |   53 +
 1 file changed, 53 insertions(+)

diff --git a/src/include/utils/bitops.h b/src/include/utils/bitops.h
new file mode 100644
index 000..4f2bbc9
--- /dev/null
+++ b/src/include/utils/bitops.h
@@ -0,0 +1,53 @@
+/*-
+ *
+ * bitops.h
+ *   Simple bit operations.
+ *
+ * Portions Copyright (c) 2009, PostgreSQL Global Development Group
+ *
+ * $PostgreSQL$
+ *
+ *-
+ */
+#ifndef BITOPS_H
+#define BITOPS_H
+
+#if defined(__GNUC__)  \
+   (defined(__ppc__) || defined(__powerpc__) || \
+defined(__ppc64__) || defined (__powerpc64__))
+
+static inline int
+fls(unsigned int x)
+{
+   int lz;
+   asm(cntlz %0,%1 : =r (lz) : r (x));
+   return 32 - lz;
+}
+
+#else /* !(gcc  powerpc) */
+
+/* Architecture-independent implementations */
+
+/*
+ * fls: find last set bit.
+ *
+ * Returns the 1-based index of the most-significant bit in x. The MSB
+ * is bit number 32, the LSB is bit number 1. If x is zero, returns zero.
+ */
+static inline int
+fls(unsigned int x)
+{
+   int ls = 0;
+
+   while (x != 0)
+   {
+   ls++;
+   x = 1;
+   }
+
+   return ls;
+}
+
+#endif
+
+#endif /* BITOPS_H */

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] [RFC,PATCH] Only disable sigpipe during SSL write

2009-06-01 Thread Jeremy Kerr
If the connection isn't over SSL, there's no need to do the disable.

This effectively halves the number of syscalls performed by libpq when
SSL is not in use.

Signed-off-by: Jeremy Kerr j...@ozlabs.org

---
 src/interfaces/libpq/fe-secure.c |7 +++
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c
index eb579cf..2101315 100644
--- a/src/interfaces/libpq/fe-secure.c
+++ b/src/interfaces/libpq/fe-secure.c
@@ -368,13 +368,13 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
 {
ssize_t n;
 
-   DISABLE_SIGPIPE(return -1);
-
 #ifdef USE_SSL
if (conn-ssl)
{
int err;
 
+   DISABLE_SIGPIPE(return -1);
+
n = SSL_write(conn-ssl, ptr, len);
err = SSL_get_error(conn-ssl, n);
switch (err)
@@ -433,15 +433,14 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
n = -1;
break;
}
+   RESTORE_SIGPIPE();
}
else
 #endif
{
n = send(conn-sock, ptr, len, 0);
-   REMEMBER_EPIPE(n  0  SOCK_ERRNO == EPIPE);
}
 
-   RESTORE_SIGPIPE();
 
return n;
 }

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] [RFC,PATCH] SIGPIPE masking in local socket connections

2009-06-01 Thread Jeremy Kerr
Currently, I'm seeing the psecure_{red,write} functions being invoked
when connecting to postgres via a unix domain socket. psecure_write
seems to alter the signal mask of the process to disable sigpipe
reporting. psecure_read only does this when the connection is using SSL.

When using a multithreaded client application on Linux, this can result
in poor scalability. Each change to the signal mask requires an
current-sighand-siglock, which becomes highly contended between
the client threads. It also means we do 3 syscalls per write: mask
sigpipe, write, unmask sigpipe.

The following patch changes psecure_write to be more like psecure_read -
it only alters the signal mask if the connection is over SSL. It's only
an RFC, as I'm not entirely sure about the reasoning behind blocking
SIGPIPE for the non-SSL case - there may be other considerations here.

With this change I see the following performance improvement
during a sysbench OLTP run:

 http://ozlabs.org/~jk/projects/db/data/sigpipe-perf.png

 load: sysbench --test=oltp --oltp-read-only=on, connecting locally,
 machine: POWER6, 64-way, 4.2GHz

Comments most welcome,


Jeremy

---
Jeremy Kerr (1):
  Only disable sigpipe during SSL write


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers