[RFC] pthread_once: Use unified variant instead of custom x86_64/i386

Torvald Riegel triegel@redhat.com
Sun Oct 19 20:46:00 GMT 2014


On Mon, 2014-04-07 at 15:47 +0200, Torvald Riegel wrote:
> On Fri, 2013-10-11 at 23:28 +0300, Torvald Riegel wrote:
> > Assuming the pthread_once unification I sent recently is applied, we
> > still have custom x86_64 and i386 variants of pthread_once.  The
> > algorithm they use is the same as the unified variant, so we would be
> > able to remove the custom variants if this doesn't affect performance.
> > 
> > The common case when pthread_once is executed is that the initialization
> > has already been performed; thus, this is the fast path that we can
> > focus on.  (I haven't looked specifically at the generated code for the
> > slow path, but the algorithm is the same and I assume that the overhead
> > of the synchronizing instructions and futex syscalls determines the
> > performance of it, not any differences between compiler-generated code
> > and the custom code.)
> > 
> > The fast path of the custom assembler version:
> > 	testl	$2, (%rdi)
> > 	jz	1f
> > 	xorl	%eax, %eax
> > 	retq
> > 
> > The fast path of the generic pthread_once C code, as it is after the
> > pthread_once unification patch:
> >   20:   48 89 5c 24 e8          mov    %rbx,-0x18(%rsp)
> >   25:   48 89 6c 24 f0          mov    %rbp,-0x10(%rsp)
> >   2a:   48 89 fb                mov    %rdi,%rbx
> >   2d:   4c 89 64 24 f8          mov    %r12,-0x8(%rsp)
> >   32:   48 89 f5                mov    %rsi,%rbp
> >   35:   48 83 ec 38             sub    $0x38,%rsp
> >   39:   41 b8 ca 00 00 00       mov    $0xca,%r8d
> >   3f:   8b 13                   mov    (%rbx),%edx
> >   41:   f6 c2 02                test   $0x2,%dl
> >   44:   74 16                   je     5c <__pthread_once+0x3c>
> >   46:   31 c0                   xor    %eax,%eax
> >   48:   48 8b 5c 24 20          mov    0x20(%rsp),%rbx
> >   4d:   48 8b 6c 24 28          mov    0x28(%rsp),%rbp
> >   52:   4c 8b 64 24 30          mov    0x30(%rsp),%r12
> >   57:   48 83 c4 38             add    $0x38,%rsp
> >   5b:   c3                      retq   
> > 
> > The only difference is more stack save/restore.  However, a quick run of
> > benchtests/pthread_once (see the patch I sent for review) on my laptop
> > doesn't show any noticeable differences between both (averages of 8 runs
> > of the microbenchmark differ by 0.2%).
> > 
> > When splitting out the slow path like this:
> > 
> > static int
> > __attribute__((noinline))
> > __pthread_once_slow (once_control, init_routine)
> > /* ... */
> > 
> > int
> > __pthread_once (once_control, init_routine)
> >      pthread_once_t *once_control;
> >      void (*init_routine) (void);
> > {
> >   int val;
> >   val = *once_control;
> >   atomic_read_barrier();
> >   if (__builtin_expect ((val & __PTHREAD_ONCE_DONE) != 0, 1))
> >     return 0;
> >   else
> >     return __pthread_once_slow(once_control, init_routine);
> > }
> > 
> > we get this for the C variants fast path:
> > 
> > 00000000000000e0 <__pthread_once>:
> >   e0:   8b 07                   mov    (%rdi),%eax
> >   e2:   a8 02                   test   $0x2,%al
> >   e4:   74 03                   je     e9 <__pthread_once+0x9>
> >   e6:   31 c0                   xor    %eax,%eax
> >   e8:   c3                      retq   
> >   e9:   31 c0                   xor    %eax,%eax
> >   eb:   e9 30 ff ff ff          jmpq   20 <__pthread_once_slow>
> > 
> > This is very close to the fast path of the custom assembler code.
> > 
> > I haven't looked further at i386, but the custom code is pretty similar
> > to the x86_64 variant.
> > 
> > 
> > What do you all prefer?:
> > 1) Keep the x86-specific assembler versions?
> > 2) Remove the x86-specific assembler versions and split out the slow
> > path?
> > 2) Just remove the x86-specific assembler versions?
> > 
> 
> Here is an updated patch for 2).
> 
> Without the fast path, I get the following without and with assembly (on
> my x86_64 laptop):
> 
> "pthread_once": {
> "": {
> "duration": 2.42853e+10, "iterations": 2.16569e+09, "max": 2217.22,
> "min": 11.024, "mean": 11.2137
> }
> }
> "pthread_once": {
> "": {
> "duration": 2.40695e+10, "iterations": 2.65473e+09, "max": 2185.57,
> "min": 9.016, "mean": 9.06665
> }
> }
> 
> With the fast path as split out, I get:
> "pthread_once": {
> "": {
> "duration": 2.40632e+10, "iterations": 2.6526e+09, "max": 2336.96,
> "min": 9.016, "mean": 9.07154
> }
> }
> 
> Okay to commit the fast path (after the pthread_once unification has
> been committed) and remove the x86 assembler variants?

This slipped through and this was never committed.  I took Richard's
advice into account, and the x86_64 code generated for the generic
version is now:
00000000000000d0 <__pthread_once>:
  d0:   8b 07                   mov    (%rdi),%eax
  d2:   a8 02                   test   $0x2,%al
  d4:   74 03                   je     d9 <__pthread_once+0x9>
  d6:   31 c0                   xor    %eax,%eax
  d8:   c3                      retq   
  d9:   e9 42 ff ff ff          jmpq   20 <__pthread_once_slow>


Attached is an updated patch, which I'll commit after two days if nobody
objects.

2014-10-20  Torvald Riegel  <triegel@redhat.com>

	[BZ #15215]
	* nptl/pthread_once.c (__pthread_once): Split out fast path to ...
	(__pthread_once_slow): ... here.
	* sysdeps/unix/sysv/linux/i386/pthread_once.S: Remove file.
	* sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Remove file.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: pthread_once-x86.patch
Type: text/x-patch
Size: 10874 bytes
Desc: not available
URL: <http://sourceware.org/pipermail/libc-alpha/attachments/20141019/9ca004eb/attachment.bin>


More information about the Libc-alpha mailing list