On Sun, Feb 12, 2023 at 11:01 PM Andres Freund <and...@anarazel.de> wrote:
>
> On 2023-02-12 19:59:00 +0530, Bharath Rupireddy wrote:
> > Thanks for looking at it. We know that we don't change the zbuffer in
> > the function, so can we avoid static const and have just a static
> > variable, like the attached
> > v1-0001-Use-static-variable-to-avoid-memset-calls-in-pg_p.patch? Do
> > you see any problem with it?
>
> Making it static const is better, because it allows the memory for the
> variable to be put in a readonly section.

Okay.

> >       /* Prepare to write out a lot of copies of our zero buffer at once. */
> >       for (i = 0; i < lengthof(iov); ++i)
> >       {
> > -             iov[i].iov_base = zbuffer.data;
> > +             iov[i].iov_base = (void *) (unconstify(PGAlignedBlock *, 
> > &zbuffer)->data);
> >               iov[i].iov_len = zbuffer_sz;
> >       }
>
> Another thing: I think we should either avoid iterating over all the IOVs if
> we don't need them, or, even better, initialize the array as a constant, once.

How about like the attached patch? It makes the iovec static variable
and points the zero buffer only once/for the first time to iovec. This
avoids for-loop on every call.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com
From 5533330b606affb614980a4b814d9e44e73d5489 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Mon, 13 Feb 2023 04:25:34 +0000
Subject: [PATCH v1] Optimize zero buffer handling in pg_pwrite_zeros()

1. Use static const zero-filled buffer to avoid memset-ing on
every call.
2. Use static iovec and point the zero-filled buffer for the
first time through to avoid for loop initializing iovec on every
call.

Reported-by: Andres Freund
Author: Bharath Rupireddy
Discussion: https://www.postgresql.org/message-id/20230211224424.r25uw4rsv6taukxk%40awork3.anarazel.de
---
 src/common/file_utils.c | 34 ++++++++++++++++++++++------------
 1 file changed, 22 insertions(+), 12 deletions(-)

diff --git a/src/common/file_utils.c b/src/common/file_utils.c
index 4dae534152..08688eb1b1 100644
--- a/src/common/file_utils.c
+++ b/src/common/file_utils.c
@@ -539,25 +539,35 @@ pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
 ssize_t
 pg_pwrite_zeros(int fd, size_t size)
 {
-	PGAlignedBlock zbuffer;		/* worth BLCKSZ */
-	size_t		zbuffer_sz;
-	struct iovec iov[PG_IOV_MAX];
+	/*
+	 * Zero-filled buffer worth BLCKSZ. We use static variable to avoid zeroing
+	 * the buffer on every call. Also, with the const qualifier, it is ensured
+	 * that the buffer is placed in read-only section of the process's memory.
+	 */
+	static const PGAlignedBlock zbuffer = {0};
+	static size_t	zbuffer_sz = BLCKSZ;
+	static bool	first_time = true;
+	static struct iovec	iov[PG_IOV_MAX] = {0};
 	int			blocks;
 	size_t		remaining_size = 0;
 	int			i;
 	ssize_t		written;
 	ssize_t		total_written = 0;
 
-	zbuffer_sz = sizeof(zbuffer.data);
-
-	/* Zero-fill the buffer. */
-	memset(zbuffer.data, 0, zbuffer_sz);
-
-	/* Prepare to write out a lot of copies of our zero buffer at once. */
-	for (i = 0; i < lengthof(iov); ++i)
+	/*
+	 * If first time through, point the zero buffer to iovec structure. This
+	 * avoids for loop on every call.
+	 */
+	if (first_time)
 	{
-		iov[i].iov_base = zbuffer.data;
-		iov[i].iov_len = zbuffer_sz;
+		/* Prepare to write out a lot of copies of our zero buffer at once. */
+		for (i = 0; i < lengthof(iov); ++i)
+		{
+			iov[i].iov_base = (void *) (unconstify(PGAlignedBlock *, &zbuffer)->data);
+			iov[i].iov_len = zbuffer_sz;
+		}
+
+		first_time = false;
 	}
 
 	/* Loop, writing as many blocks as we can for each system call. */
-- 
2.34.1

Reply via email to