Re: Avoiding roundoff error in pg_sleep()

From: Пополитов Владлен <v(dot)popolitov(at)postgrespro(dot)ru>
To: "Tom Lane" <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Re: Avoiding roundoff error in pg_sleep()
Date: 2025-09-25 18:54:34
Message-ID: 18abd6-68d59000-9-22a0aa40@102614107
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers


Hi
 
I suspect, that any user, that run something like pg_sleep(1000000000), 
start transaction, that stops autovacuum and creates other negative effects up to server crash,
and only this user can stop it by command interrupt (all signals only restart 
this sleep or kill whole server).
If I am correct, why Postgres needs this command?
 
Best regard,
Vladlen Popolitov.

On Thursday, September 25, 2025 21:42 MSK, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> wrote:

 
I chanced to notice that if you ask pg_sleep for 1ms delay,
what you actually get is 2ms, for example

regression=# \timing on
Timing is on.
regression=# do $$ begin
for i in 1..1000 loop
perform pg_sleep(0.001);
end loop; end $$;
DO
Time: 2081.175 ms (00:02.081)
regression=# do $$ begin
for i in 1..1000 loop
perform pg_sleep(0.002);
end loop; end $$;
DO
Time: 2177.407 ms (00:02.177)

A bit of gdb-ing confirms that the delay passed to WaitLatch() is 2ms,
so the problem is fundamentally one of floating-point roundoff error
in pg_sleep's calculation of delay_ms. I didn't try to figure out
exactly why that's happening. It may well vary depending on the
absolute magnitude of current values of GetCurrentTimestamp(),
because I don't recall having noticed any such behavior back when
this code was written.

Anyway, I propose trying to get rid of this misbehavior by avoiding
floating point in the delay computation, as attached. With this
patch I get less surprising behavior:

regression=# \timing on
Timing is on.
regression=# do $$ begin
for i in 1..1000 loop
perform pg_sleep(0.001);
end loop; end $$;
DO
Time: 1063.997 ms (00:01.064)
regression=# do $$ begin
for i in 1..1000 loop
perform pg_sleep(0.002);
end loop; end $$;
DO
Time: 2172.849 ms (00:02.173)

The code is a little more tied to TimestampTz being measured in
microseconds than it was before, but it wouldn't really be much
harder to fix if we ever change that.

regards, tom lane

 

-- 
 Best regards,

Vladlen Popolitov.

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Rahila Syed 2025-09-25 19:02:28 Sending unflushed WAL in physical replication
Previous Message Nathan Bossart 2025-09-25 18:50:20 Re: [PATCH] Hex-coding optimizations using SVE on ARM.