public inbox for [email protected]  
help / color / mirror / Atom feed
From: David Rowley <[email protected]>
To: Andres Freund <[email protected]>
Cc: PostgreSQL Development <[email protected]>
Cc: Robert Haas <[email protected]>
Cc: Michael Paquier <[email protected]>
Cc: Tomas Vondra <[email protected]>
Subject: Re: Avoid stack frame setup in performance critical routines using tail calls
Date: Tue, 20 Jul 2021 19:37:46 +1200
Message-ID: <CAApHDvpmhKQTcbAT3ryr+_b8v9B53C1AXkV=EeQeUJ+mOQCH9Q@mail.gmail.com> (raw)
In-Reply-To: <[email protected]>
References: <[email protected]>
	<CAApHDvpQQc67NbYJkM0GZWVw_wZvUvOuuANCPiOyobV=q1=owA@mail.gmail.com>
	<[email protected]>
	<CAApHDvpfr07JBykytxDXLxMjtExgmSKRUaR4dXkAt5xaGumUBA@mail.gmail.com>
	<[email protected]>

On Tue, 20 Jul 2021 at 19:04, Andres Freund <[email protected]> wrote:
> > * AllocateSetAlloc.txt
> > * palloc.txt
> > * percent.txt
>
> Huh, that's interesting. You have some control flow enforcement stuff turned on (the endbr64). And it looks like it has a non zero cost (or maybe it's just skid). Did you enable that intentionally? If not, what compiler/version/distro is it? I think at least on GCC that's -fcf-protection=...

It's ubuntu 21.04 with gcc 10.3 (specifically gcc version 10.3.0
(Ubuntu 10.3.0-1ubuntu1)

I've attached the same results from compiling with clang 12
(12.0.0-3ubuntu1~21.04.1)

David

 Percent |	Source code & Disassembly of postgres for cycles (707 samples, percent: local period)
-----------------------------------------------------------------------------------------------------
         :
         :
         :
         :            Disassembly of section .text:
         :
         :            00000000008e7c10 <AllocSetAlloc>:
         :            AllocSetAlloc():
         :
         :            /*
         :            * If requested size exceeds maximum for chunks, allocate an entire block
         :            * for this request.
         :            */
         :            if (unlikely(size > set->allocChunkLimit))
    7.48 :   8e7c10: cmp    %rsi,0xc8(%rdi)
    3.26 :   8e7c17: jb     8e7c81 <AllocSetAlloc+0x71>
    0.00 :   8e7c19: xor    %eax,%eax
         :            AllocSetFreeIndex():
         :            if (size > (1 << ALLOC_MINBITS))
    0.44 :   8e7c1b: cmp    $0x9,%rsi
    0.00 :   8e7c1f: jb     8e7c2d <AllocSetAlloc+0x1d>
         :            idx = 31 - __builtin_clz((uint32) size - 1) - ALLOC_MINBITS + 1;
    0.00 :   8e7c21: add    $0xffffffff,%esi
    0.98 :   8e7c24: bsr    %esi,%eax
    9.59 :   8e7c27: xor    $0xffffffe0,%eax
    1.44 :   8e7c2a: add    $0x1e,%eax
         :            AllocSetAlloc():
         :            * corresponding free list to see if there is a free chunk we could reuse.
         :            * If one is found, remove it from the free list, make it again a member
         :            * of the alloc set and return its data address.
         :            */
         :            fidx = AllocSetFreeIndex(size);
         :            chunk = set->freelist[fidx];
    1.67 :   8e7c2d: movslq %eax,%rcx
    4.10 :   8e7c30: mov    0x58(%rdi,%rcx,8),%rax
         :            if (chunk != NULL)
   15.97 :   8e7c35: test   %rax,%rax
    0.28 :   8e7c38: je     8e7c45 <AllocSetAlloc+0x35>
         :            {
         :            Assert(chunk->size >= size);
         :
         :            set->freelist[fidx] = (AllocChunk) chunk->aset;
    0.00 :   8e7c3a: mov    0x8(%rax),%rdx
   13.33 :   8e7c3e: mov    %rdx,0x58(%rdi,%rcx,8)
    0.28 :   8e7c43: jmp    8e7c73 <AllocSetAlloc+0x63>
    0.00 :   8e7c45: mov    $0x8,%eax
         :            }
         :
         :            /*
         :            * Choose the actual chunk size to allocate.
         :            */
         :            chunk_size = (1 << ALLOC_MINBITS) << fidx;
    0.71 :   8e7c4a: shl    %cl,%eax
    0.15 :   8e7c4c: movslq %eax,%rsi
         :
         :            /*
         :            * If there is enough room in the active allocation block, we will put the
         :            * chunk into that block.  Else must start a new one.
         :            */
         :            if ((block = set->blocks) != NULL)
    0.43 :   8e7c4f: mov    0x50(%rdi),%rdx
    1.13 :   8e7c53: test   %rdx,%rdx
    0.14 :   8e7c56: je     8e7c7c <AllocSetAlloc+0x6c>
         :            {
         :            Size            availspace = block->endptr - block->freeptr;
    0.00 :   8e7c58: mov    0x18(%rdx),%rax
    6.98 :   8e7c5c: mov    0x20(%rdx),%rcx
    2.30 :   8e7c60: sub    %rax,%rcx
         :
         :            if (unlikely(availspace < (chunk_size + ALLOC_CHUNKHDRSZ)))
    0.00 :   8e7c63: lea    0x10(%rsi),%r8
    0.14 :   8e7c67: cmp    %r8,%rcx
    2.02 :   8e7c6a: jb     8e7c86 <AllocSetAlloc+0x76>
         :            chunk = (AllocChunk) (block->freeptr);
         :
         :            /* Prepare to initialize the chunk header. */
         :            VALGRIND_MAKE_MEM_UNDEFINED(chunk, ALLOC_CHUNKHDRSZ);
         :
         :            chunk->size = chunk_size;
    2.04 :   8e7c6c: mov    %rsi,(%rax)
         :
         :            block->freeptr += (chunk_size + ALLOC_CHUNKHDRSZ);
   20.16 :   8e7c6f: add    %r8,0x18(%rdx)
    0.28 :   8e7c73: mov    %rdi,0x8(%rax)
    4.70 :   8e7c77: add    $0x10,%rax
         :            Assert(block->freeptr <= block->endptr);
         :
         :            return AllocSetAllocReturnChunk(set, size, chunk, chunk_size);
         :            }
    0.00 :   8e7c7b: ret
         :            return AllocSetAllocFromNewBlock(set, size, chunk_size);
    0.00 :   8e7c7c: jmp    8e8470 <AllocSetAllocFromNewBlock>
         :            return AllocSetAllocLarge(set, size, flags);
    0.00 :   8e7c81: jmp    8e8330 <AllocSetAllocLarge>
         :            return AllocSetAllocCarveOldAndAlloc(set, size, chunk_size,
    0.00 :   8e7c86: jmp    8e83e0 <AllocSetAllocCarveOldAndAlloc>

 Percent |	Source code & Disassembly of postgres for cycles (123 samples, percent: local period)
-----------------------------------------------------------------------------------------------------
         :
         :
         :
         :            Disassembly of section .text:
         :
         :            00000000008ee3a0 <palloc>:
         :            palloc():
         :            MemoryContextStatsDetail(TopMemoryContext, 100, false);
         :            }
         :
         :            void *
         :            palloc(Size size)
         :            {
    9.12 :   8ee3a0: mov    %rdi,%rsi
         :            /* duplicates MemoryContextAlloc to avoid increased overhead */
         :            void       *ret;
         :            MemoryContext context = CurrentMemoryContext;
    2.47 :   8ee3a3: mov    0x295a86(%rip),%rdi        # b83e30 <CurrentMemoryContext>
         :
         :            AssertArg(MemoryContextIsValid(context));
         :            AssertNotInCriticalSection(context);
         :            context->isReset = false;
   22.83 :   8ee3aa: movb   $0x0,0x4(%rdi)
         :
         :            ret = context->methods->alloc(context, size, 0);
   34.25 :   8ee3ae: mov    0x10(%rdi),%rax
    7.68 :   8ee3b2: mov    (%rax),%rax
   23.66 :   8ee3b5: xor    %edx,%edx
    0.00 :   8ee3b7: jmp    *%rax

     2.27%  postgres  postgres            [.] AllocSetAlloc
     0.59%  postgres  postgres            [.] pfree
     0.44%  postgres  postgres            [.] MemoryContextAllocZero
     0.39%  postgres  postgres            [.] palloc
     0.34%  postgres  postgres            [.] MemoryContextAllocZeroAligned
     0.27%  postgres  postgres            [.] palloc0
     0.17%  postgres  postgres            [.] AllocSetAllocCarveOldAndAlloc
     0.09%  postgres  postgres            [.] MemoryContextAlloc
     0.02%  postgres  postgres            [.] AllocSetAllocLarge
     0.01%  postgres  postgres            [.] AllocSetAllocFromNewBlock


Attachments:

  [text/plain] AllocSetAlloc_clang.txt (4.5K, ../CAApHDvpmhKQTcbAT3ryr+_b8v9B53C1AXkV=EeQeUJ+mOQCH9Q@mail.gmail.com/2-AllocSetAlloc_clang.txt)
  download | inline:
 Percent |	Source code & Disassembly of postgres for cycles (707 samples, percent: local period)
-----------------------------------------------------------------------------------------------------
         :
         :
         :
         :            Disassembly of section .text:
         :
         :            00000000008e7c10 <AllocSetAlloc>:
         :            AllocSetAlloc():
         :
         :            /*
         :            * If requested size exceeds maximum for chunks, allocate an entire block
         :            * for this request.
         :            */
         :            if (unlikely(size > set->allocChunkLimit))
    7.48 :   8e7c10: cmp    %rsi,0xc8(%rdi)
    3.26 :   8e7c17: jb     8e7c81 <AllocSetAlloc+0x71>
    0.00 :   8e7c19: xor    %eax,%eax
         :            AllocSetFreeIndex():
         :            if (size > (1 << ALLOC_MINBITS))
    0.44 :   8e7c1b: cmp    $0x9,%rsi
    0.00 :   8e7c1f: jb     8e7c2d <AllocSetAlloc+0x1d>
         :            idx = 31 - __builtin_clz((uint32) size - 1) - ALLOC_MINBITS + 1;
    0.00 :   8e7c21: add    $0xffffffff,%esi
    0.98 :   8e7c24: bsr    %esi,%eax
    9.59 :   8e7c27: xor    $0xffffffe0,%eax
    1.44 :   8e7c2a: add    $0x1e,%eax
         :            AllocSetAlloc():
         :            * corresponding free list to see if there is a free chunk we could reuse.
         :            * If one is found, remove it from the free list, make it again a member
         :            * of the alloc set and return its data address.
         :            */
         :            fidx = AllocSetFreeIndex(size);
         :            chunk = set->freelist[fidx];
    1.67 :   8e7c2d: movslq %eax,%rcx
    4.10 :   8e7c30: mov    0x58(%rdi,%rcx,8),%rax
         :            if (chunk != NULL)
   15.97 :   8e7c35: test   %rax,%rax
    0.28 :   8e7c38: je     8e7c45 <AllocSetAlloc+0x35>
         :            {
         :            Assert(chunk->size >= size);
         :
         :            set->freelist[fidx] = (AllocChunk) chunk->aset;
    0.00 :   8e7c3a: mov    0x8(%rax),%rdx
   13.33 :   8e7c3e: mov    %rdx,0x58(%rdi,%rcx,8)
    0.28 :   8e7c43: jmp    8e7c73 <AllocSetAlloc+0x63>
    0.00 :   8e7c45: mov    $0x8,%eax
         :            }
         :
         :            /*
         :            * Choose the actual chunk size to allocate.
         :            */
         :            chunk_size = (1 << ALLOC_MINBITS) << fidx;
    0.71 :   8e7c4a: shl    %cl,%eax
    0.15 :   8e7c4c: movslq %eax,%rsi
         :
         :            /*
         :            * If there is enough room in the active allocation block, we will put the
         :            * chunk into that block.  Else must start a new one.
         :            */
         :            if ((block = set->blocks) != NULL)
    0.43 :   8e7c4f: mov    0x50(%rdi),%rdx
    1.13 :   8e7c53: test   %rdx,%rdx
    0.14 :   8e7c56: je     8e7c7c <AllocSetAlloc+0x6c>
         :            {
         :            Size            availspace = block->endptr - block->freeptr;
    0.00 :   8e7c58: mov    0x18(%rdx),%rax
    6.98 :   8e7c5c: mov    0x20(%rdx),%rcx
    2.30 :   8e7c60: sub    %rax,%rcx
         :
         :            if (unlikely(availspace < (chunk_size + ALLOC_CHUNKHDRSZ)))
    0.00 :   8e7c63: lea    0x10(%rsi),%r8
    0.14 :   8e7c67: cmp    %r8,%rcx
    2.02 :   8e7c6a: jb     8e7c86 <AllocSetAlloc+0x76>
         :            chunk = (AllocChunk) (block->freeptr);
         :
         :            /* Prepare to initialize the chunk header. */
         :            VALGRIND_MAKE_MEM_UNDEFINED(chunk, ALLOC_CHUNKHDRSZ);
         :
         :            chunk->size = chunk_size;
    2.04 :   8e7c6c: mov    %rsi,(%rax)
         :
         :            block->freeptr += (chunk_size + ALLOC_CHUNKHDRSZ);
   20.16 :   8e7c6f: add    %r8,0x18(%rdx)
    0.28 :   8e7c73: mov    %rdi,0x8(%rax)
    4.70 :   8e7c77: add    $0x10,%rax
         :            Assert(block->freeptr <= block->endptr);
         :
         :            return AllocSetAllocReturnChunk(set, size, chunk, chunk_size);
         :            }
    0.00 :   8e7c7b: ret
         :            return AllocSetAllocFromNewBlock(set, size, chunk_size);
    0.00 :   8e7c7c: jmp    8e8470 <AllocSetAllocFromNewBlock>
         :            return AllocSetAllocLarge(set, size, flags);
    0.00 :   8e7c81: jmp    8e8330 <AllocSetAllocLarge>
         :            return AllocSetAllocCarveOldAndAlloc(set, size, chunk_size,
    0.00 :   8e7c86: jmp    8e83e0 <AllocSetAllocCarveOldAndAlloc>

  [text/plain] palloc_clang.txt (1.3K, ../CAApHDvpmhKQTcbAT3ryr+_b8v9B53C1AXkV=EeQeUJ+mOQCH9Q@mail.gmail.com/3-palloc_clang.txt)
  download | inline:
 Percent |	Source code & Disassembly of postgres for cycles (123 samples, percent: local period)
-----------------------------------------------------------------------------------------------------
         :
         :
         :
         :            Disassembly of section .text:
         :
         :            00000000008ee3a0 <palloc>:
         :            palloc():
         :            MemoryContextStatsDetail(TopMemoryContext, 100, false);
         :            }
         :
         :            void *
         :            palloc(Size size)
         :            {
    9.12 :   8ee3a0: mov    %rdi,%rsi
         :            /* duplicates MemoryContextAlloc to avoid increased overhead */
         :            void       *ret;
         :            MemoryContext context = CurrentMemoryContext;
    2.47 :   8ee3a3: mov    0x295a86(%rip),%rdi        # b83e30 <CurrentMemoryContext>
         :
         :            AssertArg(MemoryContextIsValid(context));
         :            AssertNotInCriticalSection(context);
         :            context->isReset = false;
   22.83 :   8ee3aa: movb   $0x0,0x4(%rdi)
         :
         :            ret = context->methods->alloc(context, size, 0);
   34.25 :   8ee3ae: mov    0x10(%rdi),%rax
    7.68 :   8ee3b2: mov    (%rax),%rax
   23.66 :   8ee3b5: xor    %edx,%edx
    0.00 :   8ee3b7: jmp    *%rax

  [text/plain] percent_clang.txt (642B, ../CAApHDvpmhKQTcbAT3ryr+_b8v9B53C1AXkV=EeQeUJ+mOQCH9Q@mail.gmail.com/4-percent_clang.txt)
  download | inline:
     2.27%  postgres  postgres            [.] AllocSetAlloc
     0.59%  postgres  postgres            [.] pfree
     0.44%  postgres  postgres            [.] MemoryContextAllocZero
     0.39%  postgres  postgres            [.] palloc
     0.34%  postgres  postgres            [.] MemoryContextAllocZeroAligned
     0.27%  postgres  postgres            [.] palloc0
     0.17%  postgres  postgres            [.] AllocSetAllocCarveOldAndAlloc
     0.09%  postgres  postgres            [.] MemoryContextAlloc
     0.02%  postgres  postgres            [.] AllocSetAllocLarge
     0.01%  postgres  postgres            [.] AllocSetAllocFromNewBlock

view thread (7+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected], [email protected], [email protected], [email protected]
  Subject: Re: Avoid stack frame setup in performance critical routines using tail calls
  In-Reply-To: <CAApHDvpmhKQTcbAT3ryr+_b8v9B53C1AXkV=EeQeUJ+mOQCH9Q@mail.gmail.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox