[erlang-questions] Minimum time for timer:sleep()?

Bob Ippolito bob@REDACTED
Mon Mar 19 23:37:43 CET 2007


On 3/19/07, Bob Ippolito <bob@REDACTED> wrote:
> On 3/19/07, James Hague <james.hague@REDACTED> wrote:
> > Thanks everyone for the replies, though I still haven't worked out a
> > solution I'm happy with.  Here's the details of what I'm trying to do:
> >
> > I have an Erlang program that communicates with an external graphics
> > "driver" program.  This way I can put pretty pictures on the screen
> > but without having to micromanage everything from Erlang itself.  What
> > I was attempting to do was to get updates running more or less at 60
> > Hz (16 microseconds per frame).
> >
> > My first idea was to track execution time per frame, then sleep the
> > rest of the 16 millisecond slice.  This didn't work because sleep
> > waits a minimum of 10 milliseconds, regardless of the value passed in.
> >
> > My second idea was to spawn a process at the start of a frame, wait 16
> > milliseconds in that process, then send a message to the original
> > process,  This works, except the 16 millisecond time can vary quite a
> > bit: from 16.8 ms to 22+ ms in my tests.
> >
> > Any approaches to more precise timing would be appreciated!
>
> You could write a function that sleeps as much as it can by way of
> timer:sleep, and then busywaits the rest?
>
> How about something like this:
>
> -module(busywait).
>
> -export([add_microsec/2, microsleep/1, test/0]).
>
> -define(JITTER, 5).
>
> add_microsec(Micro, {Mega0, Sec0, Micro0}) ->
>     Micro1 = Micro0 + Micro,
>     Sec1 = Sec0 + (Micro1 div 1000000),
>     Mega1 = Mega0 + (Sec1 div 1000000),
>     {Mega1, (Sec1 rem 1000000), (Micro1 rem 1000000)}.
>
> busywait_until(Target, Loops) ->
>     case now() of
>         Now when Now >= Target ->
>             {Now, Loops};
>         _ ->
>             erlang:yield(),
>             busywait_until(Target, 1 + Loops)
>     end.
>
> microsleep(MicroSec) ->
>     Target = add_microsec(MicroSec, now()),
>     AdjMsec = MicroSec - ?JITTER,
>     case AdjMsec > 10000 of
>         true ->
>             timer:sleep(AdjMsec div 1000);
>         false ->
>             ok
>     end,
>     {Finish, Loops} = busywait_until(Target, 1),
>     {timer:now_diff(Finish, Target), Loops}.
>
> test() ->
>     {Accuracy, Loops} = microsleep(16 * 1000),
>     io:format("Jitter: ~p ms Iterations: ~p~n", [Accuracy, Loops]).
>

Of course that should be:
    io:format("Jitter: ~p us Iterations: ~p~n", [Accuracy, Loops]).

Or:
    io:format("Jitter: ~p ms Iterations: ~p~n", [0.001 * Accuracy, Loops]).

-bob



More information about the erlang-questions mailing list