On Sat, 6 Apr 2024 at 23:17, Jelte Fennema-Nio <postg...@jeltef.nl> wrote:
> Weird that on your machines you don't see a difference. Are you sure
> you didn't make a silly mistake, like not restarting postgres or
> something?

I'm sure. I spent quite a long time between the AMD and an Apple m2 trying.

I did see the same regression as you on the smaller numbers.  I
experimented with the attached which macro'ifies internal_flush() and
pg_noinlines internal_flush_buffer.

Can you try that to see if it gets rid of the regression on the first two tests?

David
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index 6497100a1a..824b2f11a3 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -120,8 +120,8 @@ static List *sock_paths = NIL;
 
 static char *PqSendBuffer;
 static int     PqSendBufferSize;       /* Size send buffer */
-static int     PqSendPointer;          /* Next index to store a byte in 
PqSendBuffer */
-static int     PqSendStart;            /* Next index to send a byte in 
PqSendBuffer */
+static size_t PqSendPointer;           /* Next index to store a byte in 
PqSendBuffer */
+static size_t PqSendStart;             /* Next index to send a byte in 
PqSendBuffer */
 
 static char PqRecvBuffer[PQ_RECV_BUFFER_SIZE];
 static int     PqRecvPointer;          /* Next index to read a byte from 
PqRecvBuffer */
@@ -133,6 +133,7 @@ static int  PqRecvLength;           /* End of data 
available in PqRecvBuffer */
 static bool PqCommBusy;                        /* busy sending data to the 
client */
 static bool PqCommReadingMsg;  /* in the middle of reading a message */
 
+#define internal_flush()       internal_flush_buffer(PqSendBuffer, 
&PqSendStart, &PqSendPointer)
 
 /* Internal functions */
 static void socket_comm_reset(void);
@@ -144,7 +145,8 @@ static bool socket_is_send_pending(void);
 static int     socket_putmessage(char msgtype, const char *s, size_t len);
 static void socket_putmessage_noblock(char msgtype, const char *s, size_t len);
 static int     internal_putbytes(const char *s, size_t len);
-static int     internal_flush(void);
+static pg_noinline int internal_flush_buffer(const char *s, size_t *start,
+                                                                               
         size_t *end);
 
 static int     Lock_AF_UNIX(const char *unixSocketDir, const char 
*unixSocketPath);
 static int     Setup_AF_UNIX(const char *sock_path);
@@ -1282,14 +1284,32 @@ internal_putbytes(const char *s, size_t len)
                        if (internal_flush())
                                return EOF;
                }
-               amount = PqSendBufferSize - PqSendPointer;
-               if (amount > len)
-                       amount = len;
-               memcpy(PqSendBuffer + PqSendPointer, s, amount);
-               PqSendPointer += amount;
-               s += amount;
-               len -= amount;
+
+               /*
+                * If the buffer is empty and data length is larger than the 
buffer
+                * size, send it without buffering. Otherwise, put as much data 
as
+                * possible into the buffer.
+                */
+               if (len >= PqSendBufferSize && PqSendStart == PqSendPointer)
+               {
+                       size_t start = 0;
+
+                       socket_set_nonblocking(false);
+                       if (internal_flush_buffer(s, &start, &len))
+                               return EOF;
+               }
+               else
+               {
+                       amount = PqSendBufferSize - PqSendPointer;
+                       if (amount > len)
+                               amount = len;
+                       memcpy(PqSendBuffer + PqSendPointer, s, amount);
+                       PqSendPointer += amount;
+                       s += amount;
+                       len -= amount;
+               }
        }
+
        return 0;
 }
 
@@ -1315,19 +1335,19 @@ socket_flush(void)
 }
 
 /* --------------------------------
- *             internal_flush - flush pending output
+ *             internal_flush_buffer - flush the given buffer content
  *
  * Returns 0 if OK (meaning everything was sent, or operation would block
  * and the socket is in non-blocking mode), or EOF if trouble.
  * --------------------------------
  */
-static int
-internal_flush(void)
+static pg_noinline int
+internal_flush_buffer(const char *s, size_t *start, size_t *end)
 {
        static int      last_reported_send_errno = 0;
 
-       char       *bufptr = PqSendBuffer + PqSendStart;
-       char       *bufend = PqSendBuffer + PqSendPointer;
+       char       *bufptr = (char*) s + *start;
+       char       *bufend = (char*) s + *end;
 
        while (bufptr < bufend)
        {
@@ -1373,7 +1393,7 @@ internal_flush(void)
                         * flag that'll cause the next CHECK_FOR_INTERRUPTS to 
terminate
                         * the connection.
                         */
-                       PqSendStart = PqSendPointer = 0;
+                       *start = *end = 0;
                        ClientConnectionLost = 1;
                        InterruptPending = 1;
                        return EOF;
@@ -1381,10 +1401,10 @@ internal_flush(void)
 
                last_reported_send_errno = 0;   /* reset after any successful 
send */
                bufptr += r;
-               PqSendStart += r;
+               *start += r;
        }
 
-       PqSendStart = PqSendPointer = 0;
+       *start = *end = 0;
        return 0;
 }
 

Reply via email to