On Sun, Feb 12, 2023 at 11:01 PM Andres Freund <[email protected]> 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 <[email protected]>
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