Date: Fri, 23 Jul 2004 07:12:09 +1000 From: John Birrell <jb@cimlogic.com.au> To: Bruce Evans <bde@zeta.org.au> Cc: current@freebsd.org Subject: Re: nanosleep returning early Message-ID: <20040722211209.GB34260@freebsd3.cimlogic.com.au> In-Reply-To: <20040723014517.B2451@epsplex.bde.org> References: <20040721081310.GJ22160@freebsd3.cimlogic.com.au> <20040721220405.Y2346@epsplex.bde.org> <20040721215940.GK22160@freebsd3.cimlogic.com.au> <20040722225952.S1704@epsplex.bde.org> <20040723014517.B2451@epsplex.bde.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, Jul 23, 2004 at 02:25:16AM +1000, Bruce Evans wrote: > Now I think I know the reason. The interval between clock interrupts > is supposed to be 1/HZ seconds = `tick' microseconds, but it cannot > be set nearly that precisely, and the imprecision of inversely > proportional to HZ. The i8254 counter has a default nominal frequency > of 1193182 Hz. Suppose that this is perfectly accurate. Then to > implement clock interrupts at HZ hz, we want to program the i8254's > maximum count to 1193182/HZ in infinite precision, but counts must be > integers so we must round. The loss of precision is quite large for > HZ = 1000: 1193182 / 1000.0 = 1193.182; rounding this (to nearest) > gives 1193 and an error of 182 in 1193182 = 152 ppm. Also, the extra > tick added by tvtohz() is only 1000 uS long, so it only has a chance > of about 152/1000 to compensate for the rounding error. Finally, the > explicit check that the interval has elapsed cannot compensate for > errors larger than tc_tick/HZ because getnanouptime() is fuzzy. > > Rounding 1193.182 to nearest happens to round down; thus clock ticks > are shorter than `tick' microseconds, tvtohz()'s value is too small, > and nanosleep() may return too early. The loop limits the error to > about 1 tick in this case. The i8254 frequency may be calibrated or > set using sysctl to a more (or less) accurate value. Then the rounding > may go the other way so that tvtohz()'s value is too large and nanoleep() > may return too late. The loop cannot limit the error in this case. > The absolute error may be large for long sleeps. E.g., 152 ppm over > 1 day is 13 seconds. > > tvtohz()'s value may also be too large because the i8254 frequency > is not known accurately. It's nominal value is wrong by 10-100 Hz > on my systems. I minimize errors from this by calibrating all > timecounters using a common clock. Thanks for taking the trouble to explain this. 8-) -- John Birrell
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20040722211209.GB34260>