diff options
author | Robert Haas <rhaas@postgresql.org> | 2015-12-15 13:32:54 -0500 |
---|---|---|
committer | Robert Haas <rhaas@postgresql.org> | 2015-12-15 13:32:54 -0500 |
commit | 6150a1b08a9fe7ead2b25240be46dddeae9d98e1 (patch) | |
tree | 50a43b8b4c8c5307e40bfdd7de76c901e211451e /src/backend/storage/buffer/buf_init.c | |
parent | 3fed417452b226d9bd85a3a54d7056b06eb14897 (diff) | |
download | postgresql-6150a1b08a9fe7ead2b25240be46dddeae9d98e1.tar.gz postgresql-6150a1b08a9fe7ead2b25240be46dddeae9d98e1.zip |
Move buffer I/O and content LWLocks out of the main tranche.
Move the content lock directly into the BufferDesc, so that locking and
pinning a buffer touches only one cache line rather than two. Adjust
the definition of BufferDesc slightly so that this doesn't make the
BufferDesc any larger than one cache line (at least on platforms where
a spinlock is only 1 or 2 bytes).
We can't fit the I/O locks into the BufferDesc and stay within one
cache line, so move those to a completely separate tranche. This
leaves a relatively limited number of LWLocks in the main tranche, so
increase the padding of those remaining locks to a full cache line,
rather than allowing adjacent locks to share a cache line, hopefully
reducing false sharing.
Performance testing shows that these changes make little difference
on laptop-class machines, but help significantly on larger servers,
especially those with more than 2 sockets.
Andres Freund, originally based on an earlier patch by Simon Riggs.
Review and cosmetic adjustments (including heavy rewriting of the
comments) by me.
Diffstat (limited to 'src/backend/storage/buffer/buf_init.c')
-rw-r--r-- | src/backend/storage/buffer/buf_init.c | 61 |
1 files changed, 51 insertions, 10 deletions
diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index 3ae2848da05..2a84a1ebade 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -20,6 +20,9 @@ BufferDescPadded *BufferDescriptors; char *BufferBlocks; +LWLockMinimallyPadded *BufferIOLWLockArray = NULL; +LWLockTranche BufferIOLWLockTranche; +LWLockTranche BufferContentLWLockTranche; /* @@ -65,22 +68,45 @@ void InitBufferPool(void) { bool foundBufs, - foundDescs; + foundDescs, + foundIOLocks; /* Align descriptors to a cacheline boundary. */ - BufferDescriptors = (BufferDescPadded *) CACHELINEALIGN( - ShmemInitStruct("Buffer Descriptors", - NBuffers * sizeof(BufferDescPadded) + PG_CACHE_LINE_SIZE, - &foundDescs)); + BufferDescriptors = (BufferDescPadded *) + CACHELINEALIGN( + ShmemInitStruct("Buffer Descriptors", + NBuffers * sizeof(BufferDescPadded) + + PG_CACHE_LINE_SIZE, + &foundDescs)); BufferBlocks = (char *) ShmemInitStruct("Buffer Blocks", NBuffers * (Size) BLCKSZ, &foundBufs); - if (foundDescs || foundBufs) + /* Align lwlocks to cacheline boundary */ + BufferIOLWLockArray = (LWLockMinimallyPadded *) + CACHELINEALIGN(ShmemInitStruct("Buffer IO Locks", + NBuffers * (Size) sizeof(LWLockMinimallyPadded) + + PG_CACHE_LINE_SIZE, + &foundIOLocks)); + + BufferIOLWLockTranche.name = "Buffer IO Locks"; + BufferIOLWLockTranche.array_base = BufferIOLWLockArray; + BufferIOLWLockTranche.array_stride = sizeof(LWLockMinimallyPadded); + LWLockRegisterTranche(LWTRANCHE_BUFFER_IO_IN_PROGRESS, + &BufferIOLWLockTranche); + + BufferContentLWLockTranche.name = "Buffer Content Locks"; + BufferContentLWLockTranche.array_base = + ((char *) BufferDescriptors) + offsetof(BufferDesc, content_lock); + BufferContentLWLockTranche.array_stride = sizeof(BufferDescPadded); + LWLockRegisterTranche(LWTRANCHE_BUFFER_CONTENT, + &BufferContentLWLockTranche); + + if (foundDescs || foundBufs || foundIOLocks) { - /* both should be present or neither */ - Assert(foundDescs && foundBufs); + /* should find all of these, or none of them */ + Assert(foundDescs && foundBufs && foundIOLocks); /* note: this path is only taken in EXEC_BACKEND case */ } else @@ -110,8 +136,11 @@ InitBufferPool(void) */ buf->freeNext = i + 1; - buf->io_in_progress_lock = LWLockAssign(); - buf->content_lock = LWLockAssign(); + LWLockInitialize(BufferDescriptorGetContentLock(buf), + LWTRANCHE_BUFFER_CONTENT); + + LWLockInitialize(BufferDescriptorGetIOLock(buf), + LWTRANCHE_BUFFER_IO_IN_PROGRESS); } /* Correct last entry of linked list */ @@ -144,5 +173,17 @@ BufferShmemSize(void) /* size of stuff controlled by freelist.c */ size = add_size(size, StrategyShmemSize()); + /* + * It would be nice to include the I/O locks in the BufferDesc, but that + * would increase the size of a BufferDesc to more than one cache line, and + * benchmarking has shown that keeping every BufferDesc aligned on a cache + * line boundary is important for performance. So, instead, the array of + * I/O locks is allocated in a separate tranche. Because those locks are + * not highly contentended, we lay out the array with minimal padding. + */ + size = add_size(size, mul_size(NBuffers, sizeof(LWLockMinimallyPadded))); + /* to allow aligning the above */ + size = add_size(size, PG_CACHE_LINE_SIZE); + return size; } |