Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 7 Jun 1995 22:37:47 +1000
From:      Bruce Evans <bde@zeta.org.au>
To:        bde@zeta.org.au, freebsd-hackers@FreeBSD.ORG, james@miller.cs.uwm.edu
Subject:   Re: Interval timer/System clock
Message-ID:  <199506071237.WAA17067@godzilla.zeta.org.au>

next in thread | raw e-mail | index | archive | help
>> >and interval timers can't return at the time specified since that would
>> >break sleep.  Actaully, in FreeBSD they return 10ms late.
>> 
>> No, they return an average of 5ms late for random calls and about 10ms
>> late only for synchronous calls, provided of course the application
>> making them gets scheduled enough - on a heavily loaded system it
>> may only run every few hundred ms.

>Did you run the attached programs?  The interval timer and select timers
>returns 10ms late -- consistantly.  Specifing 10ms returns 20ms.  Specifying
>20ms returns 30ms.  The test programs were written with Multimedia/polling
>type applications in mind. 

Only your first one.  I know the timers will be 10ms late on a lightly
loaded FreeBSD system and unpredictably late on a loaded system (by the
definition of `loaded' - it may take more than 10ms to retrieve the
program from swap :-).  FreeBSD is not a real time system.

>> This is the correct incorrect fix :-).  It makes average timeout 5ms
>> too small instead of 5ms too large, and timeouts of 10ms may be reduced
>> to 0.

>I have never seen this behavior.  Even on an unloaded system.  I havn't
>even seen this behavior on an Alpha system where the processor is faster
>than a Pentium.  Are you sure this case is possible?

Yes.  It happens if the average call to sleep() is _not_ in sync with
the clock.

>> I think it is correct but haven't tested it.  POSIX sleep is difficult
>> to implement using interval timers (the current version fails to restore
>> the alarm timeout correctly), but the periodic alarm is not relevant so
>> changing relitexpire() won't affect sleep().

>So, I could fix the interval timer by subtracting 1 from the hzto() call
>in the realitexpire()... but what about select?  With the current
>implementation I don't see a solution.  Select will always return 10ms
>late.

Right.  Select() doesn't provide any better mechanism than sleep() to sync
with the clock.  At best the program can have a flow of execution something
like this:

	/*
	 * Now out of sync with clock.
	 */
	for (;;) {
		select(...);
		/*
		 * Now in sync with the clock (iff we got woken up promptly).
		 */
		do_some_work();
		/*
		 * Now out of sync with clock.
		 * However, the work took much less time than a clock tick
		 * then we're still almost in sync, so we can hope that
		 * the select() times out at the next clock tick.
		 */
	}

>> >Is there a clean solution that will fix this 1/2 tick problem and still
>> >allow select and the interval timers to work the way they do on other OSes?
>> >Or will FreeBSD be known as the system that is always 10ms late? :-)
>> 
>> >...
>> >#define WAIT_TIME	10000
>> 
>> A wait time of 1 can be made to work right.

>That is riduculous.  I have to specify a time < 10000uS to make 10ms work?

Yes.  The program gets woken up some time after the previous clock interrupt
occurs, say 30us.  If it then sleeps for 10000us, the next clock interrupt
occurs while it is sleeping.  To be woken up after the next clock interrupt,
it must sleep for about 99900us (allow 70us to schedule the sleep).

>A wait time of 1 means go as fast as the system clock can.  With 100hz clock 
>this means 10ms.  However, on FreeBSD a time of 1 means 20ms.  On a DEC system
>this means 5ms.

Right.  Use a time of 1us only to determine the clock interrupt frequency.
Then sleep for a time of

	time_between_your_wakeups - clock_interrupt_period * fraction

where `fraction' is a suitable value >= 0 and <= 1.  It may have to be < 1/2
to avoid bogus rounding to nearest.  It may have to be 0 to avoid bogus
rounding down.  For FreeBSD-current, it has to be 1 because hzto() always
adds 1.  In future, 1/2 will be a good value.

>This could be a cause of great confusion as Multimedia programs are developed.
>Typically, you want to poll several devices (network, frame grabber, sound
>cards) and update the screen every 10-20ms.  The times don't have to be
>accurate -- but they have to be consistant.  If a change isn't made to
>FreeBSD, then one would have to know about this and #ifdef every application
>for FreeBSD/Linux that uses select/interval timers.

FreeBSD isn't a real time system, so consistent timing is impossible to
guarantee, and you shouldn't be surprised to have to do more work to
get close to it.

Have you looked at the rtprio command and syscalls?  At rtprio 0, a
process is guaranteed priority over all user processes except of course
the others at rtprio 0.  I think the priority doesn't affect swapping,
so for consistent timing a real time process might want extra wakeups to
keep itself in core and early wakeups to allow time for swapping it in;
after an early wakeup it should check call gettimeofday() to check
exactly when it got woken up.  These methods may help even if rtprio is
not available.  However, they are no help for processes that always run
every clock tick.

>While it is possible to make the interval timers work by subtracting one
>from the reloaded value I don't think it is possible to make the select
>system call return on time with the current implementation.  This will
>make it very difficult to write portable programs that rely on timings
>of accuracies of 10ms.

Settle for 20ms under FreeBSD-current.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199506071237.WAA17067>