Avoiding roundoff error in pg_sleep()
Tom Lane <tgl@sss.pgh.pa.us>
From: Tom Lane <tgl@sss.pgh.pa.us>
To: pgsql-hackers@lists.postgresql.org
Date: 2025-09-25T18:42:32Z
Lists: pgsql-hackers
Attachments
- v1-reduce-roundoff-error-in-pg_sleep.patch (text/x-diff) patch v1
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
Commits
-
Try to avoid floating-point roundoff error in pg_sleep().
- 02c4bc88302a 19 (unreleased) landed