Re: [HACKERS] Postgres Speed or lack thereof - Mailing list pgsql-hackers

From Tom Lane
Subject Re: [HACKERS] Postgres Speed or lack thereof
Date
Msg-id 423.916677432@sss.pgh.pa.us
Whole thread Raw
In response to RE: [HACKERS] Postgres Speed or lack thereof  (Magnus Hagander <mha@sollentuna.net>)
Responses Re: [HACKERS] Postgres Speed or lack thereof
List pgsql-hackers
Magnus Hagander <mha@sollentuna.net> writes:
> I don't know, maybe recv() is more expensive than fgetc()?

Vastly.

recv() is a kernel call.  You have the overhead of getting control into
the kernel, normally several times more expensive than a function call;
of passing parameters back and forth from user space to kernel space
(for example, the kernel will probably have to translate and range-check
the buffer pointer you pass it, to ensure you can't fool the kernel into
scribbling on some other process's memory); of verifying that the
descriptor number you pass is open and you have permission to read it;
and of finding the associated data buffer.  Plus the scheduler may
run to reconsider whether to give control back to you, or switch off to
another user process.  Etc etc etc.

fgetc() is a plain C function that normally just has to fetch the next
byte out of a buffer that's already been read into your address space
--- that is, when you're using stdio, you pay all the above-described
kernel interaction overhead once per bufferload, not once per character.

If you use getc(), which is allowed to be a macro, you don't even pay
the function-call overhead; that form is probably less than a dozen
instructions, except when the buffer is empty.  Judging by the profile
numbers, recv()'ing a single character takes close to 1400 instructions
on my system.

> An interesting fact is that pq_getchar() doesn't show up at all. Could be
> because it's fast, but still executed many times, right?

Right, it doesn't run long enough to get itself into the top functions.
It's there though --- the dynamic profile shows:

-----------------------------------------------               0.03   18.83    5001/5001        ReadCommand [27]
[28]    10.4    0.03   18.83    5001         SocketBackend [28]               0.00   18.73    5000/5000
pq_getstr[30]               0.01    0.09    5001/5001        pq_getnchar [303]
 
-----------------------------------------------               0.00   18.73    5000/5000        SocketBackend [28]
[30]    10.4    0.00   18.73    5000         pq_getstr [30]               0.11   18.62    5000/5000        pqGetString
[29]
-----------------------------------------------               0.11   18.62    5000/5000        pq_getstr [30]
[29]    10.4    0.11   18.62    5000         pqGetString [29]               0.47   18.15  957186/957186      pq_getchar
[31]
-----------------------------------------------               0.47   18.15  957186/957186      pqGetString [29]
[31]    10.3    0.47   18.15  957186         pq_getchar [31]              18.15    0.00  957186/962187      recv [32]
-----------------------------------------------               0.09    0.00    5001/962187      pqGetNBytes [315]
     18.15    0.00  957186/962187      pq_getchar [31]
 
[32]    10.1   18.24    0.00  962187         recv [32]
-----------------------------------------------

In the old code with fgetc(), the execution time of fgetc() was probably
not much worse than pq_getchar --- ie, about half a second not 18
seconds for this test sequence...


What we need to do here is to re-introduce the buffering ability of
stdio into backend libpq.  If you compare the current frontend libpq,
you'll notice that it reads or writes the socket a bufferload at a time,
not a character at a time.
        regards, tom lane


pgsql-hackers by date:

Previous
From: Tom Lane
Date:
Subject: Re: [HACKERS] Syntax errors in current tree
Next
From: Bruce Momjian
Date:
Subject: Re: [HACKERS] Syntax errors in current tree