Re: Use C11 alignas instead of palloc/malloc for alignment

From: Andres Freund <andres(at)anarazel(dot)de>
To: Peter Eisentraut <peter(at)eisentraut(dot)org>
Cc: pgsql-hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: Use C11 alignas instead of palloc/malloc for alignment
Date: 2026-09-08 15:03:32
Message-ID: qabqovdyyz7tu7skxr3aogpesziypo2h3avpfsujyeecsv6wpg@6mqii56llllj
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

On 2026-09-08 12:08:52 +0200, Peter Eisentraut wrote:
> From 9e5c5d6a660791aaab06bab10272260da109dfb6 Mon Sep 17 00:00:00 2001
> From: Peter Eisentraut <peter(at)eisentraut(dot)org>
> Date: Tue, 8 Sep 2026 11:42:24 +0200
> Subject: [PATCH 1/2] Use C11 alignas instead of palloc/malloc for alignment
>
> Replace several cases where palloc()/malloc()/etc. was used solely to
> obtain an aligned buffer. Use alignas with a local variable instead.
>
> The previous alignment guarantees are carried over. palloc-based
> allocations are replaced by alignas(MAXIMUM_ALIGNOF). Theoretically,
> malloc-based allocations should be replaced by alignas(max_align_t),
> but MSVC doesn't provide max_align_t, and so we use MAXIMUM_ALIGNOF
> here as well. They should be the same in practice.
>
> The allocations in InitWalRecovery() are not converted, because the
> comment says it is also this way to avoid wasting storage. The
> comment in XLogReaderAllocate(), on the other hand, was probably
> copied from InitWalRecovery(), but the part of the comment about
> wasting storage does not make sense in that context, so it is
> converted.
>
> FIXME: indent in xlogreader.h
> ---
> src/backend/access/transam/xloginsert.c | 28 ++++++++---------------
> src/backend/access/transam/xlogreader.c | 17 --------------
> src/backend/access/transam/xlogrecovery.c | 3 ++-
> src/backend/commands/sequence_xlog.c | 9 +++-----
> src/backend/storage/file/copydir.c | 12 ++--------
> src/backend/storage/ipc/dsm_impl.c | 10 ++++----
> src/backend/storage/smgr/md.c | 4 +---
> src/bin/pg_resetwal/pg_resetwal.c | 7 ++----
> src/include/access/xlogreader.h | 5 ++--
> 9 files changed, 26 insertions(+), 69 deletions(-)
>
> diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
> index c9aff944a2e..70cbe9d709b 100644
> --- a/src/backend/access/transam/xloginsert.c
> +++ b/src/backend/access/transam/xloginsert.c
> @@ -105,17 +105,6 @@ static uint64 mainrdata_len; /* total # of bytes in chain */
> /* flags for the in-progress insertion */
> static uint8 curinsert_flags = 0;
>
> -/*
> - * These are used to hold the record header while constructing a record.
> - * 'hdr_scratch' is not a plain variable, but is palloc'd at initialization,
> - * because we want it to be MAXALIGNed and padding bytes zeroed.
> - *
> - * For simplicity, it's allocated large enough to hold the headers for any
> - * WAL record.
> - */
> -static XLogRecData hdr_rdt;
> -static char *hdr_scratch = NULL;
> -
> #define SizeOfXlogOrigin (sizeof(ReplOriginId) + sizeof(char))
> #define SizeOfXLogTransactionId (sizeof(TransactionId) + sizeof(char))
>
> @@ -622,6 +611,16 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
> XLogRecPtr *fpw_lsn, int *num_fpi, uint64 *fpi_bytes,
> bool *topxid_included)
> {
> + /*
> + * These are used to hold the record header while constructing a record.
> + * 'hdr_scratch' must be MAXALIGNed and padding bytes zeroed.
> + *
> + * For simplicity, it's allocated large enough to hold the headers for any
> + * WAL record.
> + */
> + static XLogRecData hdr_rdt;
> + static alignas(MAXIMUM_ALIGNOF) char hdr_scratch[HEADER_SCRATCH_SIZE];

I think we really shouldn't add more function level statics at this point. At
least for file level static variables you can just slap a thread_local on and
it has a chance of working. But it won't with this.

> @@ -133,16 +133,13 @@ copydir(const char *fromdir, const char *todir, bool recurse)
> void
> copy_file(const char *fromfile, const char *tofile)
> {
> - char *buffer;
> + alignas(MAXIMUM_ALIGNOF) char buffer[8 * BLCKSZ];
> int srcfd;
> int dstfd;
> ssize_t nbytes;
> off_t offset;
> off_t flush_offset;
>
> - /* Size of copy buffer (read and write requests) */
> -#define COPY_BUF_SIZE (8 * BLCKSZ)
> -

I don't think it's a great idea to allocate that much on the stack... And for
performance we really ought to make this a substantially *bigger* buffer. So
this one I would just replace the comment with something indicating that we
are leaving it a dynamically allocated buffer for size *and* alignment reason.

Greetings,

Andres Freund

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Greg Burd 2026-09-08 15:08:36 Re: Speed up COPY FROM text/CSV parsing using SIMD
Previous Message Matthias van de Meent 2026-09-08 14:58:04 Re: Reduce build times of pg_trgm GIN indexes