[erlang-questions] I'm having a SNAFU moment: timer:sleep/1

Darach Ennis darach@REDACTED
Mon Jan 12 14:24:11 CET 2015


Hi Sergej,

I wasn't suggesting using directly. I was illustrating that erlang can
issue periodic
events with reasonable accuracy and timeliness whilst avoiding slew. Not
everyone
will want to drop to C to resolve but this is a nice solution for those
that do.

Cheers,

Darach.

On Mon, Jan 12, 2015 at 1:18 PM, Sergej Jurečko <sergej.jurecko@REDACTED>
wrote:

> At least put erlang:yield() at the end of the loop. But to me that is just
> a gigantic waste of CPU.
>
> This little c program as an external port does the job very nicely and
> hardly uses any resources.
> int main(int argc, char *argv[])
> {
>     char c[1];
>     c[0] = 'a';
>     for (;;)
>     {
>         usleep(3000);
>
>         if (write(1, c, 1) <= 0)
>             break;
>     }
>
>       return 0;
> }
>
> On Mon, Jan 12, 2015 at 2:10 PM, Darach Ennis <darach@REDACTED> wrote:
>
>> Hi Roberto,
>>
>> If you want to avoid clock slewing or you need a timely and periodic
>> event source you
>> can achieve this somewhat as follows, although the right solution will of
>> course depend
>> on multiple factors.
>>
>> -define(INTERVAL, 1000). % One second
>>
>> main(_) ->
>>   loop(now_ms(),0).
>>
>> trigger(Now,Delta,Count) ->
>>   io:format("At: ~p drift:~p rate:~p/sec~n", [Now, Delta - ?INTERVAL,
>> Count]).
>>
>> loop(Epoch,Count) ->
>>   Now = now_ms(),
>>   Delta = Now - Epoch,
>>   case Delta >= ?INTERVAL of
>>       true ->
>>           trigger(Now,Delta,Count),
>>           loop(Epoch+?INTERVAL,0);
>>       false ->
>>           loop(Epoch,Count+1)
>>   end.
>>
>> now_ms() ->
>>   {Mega,Secs,Micros} = os:timestamp(),
>>   (Mega*1000000 + Secs)*1000 + (Micros div 1000).
>>
>> This loops at a rate of ~7 million loops/second on my laptop and fires
>> without
>> slew or significant drift consistently calling the trigger/3 function
>> every second. The rub is I
>> burn a little more core/process for the privilege than with mechanism
>> that induce slew such
>> as with timer or erlang:send_after directly. C'est la vie. Accuracy and
>> timeliness aren't free.
>>
>> In a gen_server you could use a combination of erlang:send_after and a
>> clock based on
>> os:timestamp and an epoch as above so that you end up with a clock that
>> is 'accurate enough'
>> for most use cases, and cheap enough for whatever value you ascribe to
>> such tradeoffs given
>> the specifics of your use case.
>>
>> Your mileage may vary.
>>
>> Cheers,
>>
>> Darach.
>>
>> On Mon, Jan 12, 2015 at 11:43 AM, Jesper Louis Andersen <
>> jesper.louis.andersen@REDACTED> wrote:
>>
>>> Hi Roberto,
>>>
>>> I'm not sure what you would expect here. timer:sleep/1 has an
>>> implementation like this:
>>>
>>> sleep(T) ->
>>>     receive
>>>     after T -> ok
>>>     end.
>>>
>>> which is what other people told you also. In general, such timing
>>> constructs have no guarantee about when they will fire, only that they will
>>> fire after the time has elapsed. So what you are seeing is somewhat
>>> expected behaviour. The more fine-grained and the more timers you have, the
>>> less precise things will get. In a way, this is one of the properties which
>>> makes Erlang a soft-realtime system and not a hard-realtime one, although
>>> the precise definition of soft/hard realtime are subtly different.
>>>
>>> I believe there were some effort being made by the OTP team to address
>>> lock contention around the timer wheel, so the code might change behaviour
>>> by quite a lot in the future. It might even have to get worse for
>>> single-process timers in order to become better for multi-process timers.
>>>
>>>
>>> On Mon Jan 12 2015 at 12:20:15 PM Roberto Ostinelli <roberto@REDACTED>
>>> wrote:
>>>
>>>> Indeed. From very basic try-outs:
>>>>
>>>> 1>  test:sleep_periodical(6, 1000).
>>>> Finished in 6022381 microseconds.
>>>> ok
>>>> 2>  test:sleep_periodical(12, 500).
>>>> Finished in 6042683 microseconds.
>>>> ok
>>>> 3>  test:sleep_periodical(24, 250).
>>>> Finished in 6062096 microseconds.
>>>> ok
>>>> 4>  test:sleep_periodical(48, 125).
>>>> Finished in 6133169 microseconds.
>>>> ok
>>>> 5> test:sleep_periodical(96, 62).
>>>> Finished in 6320419 microseconds.
>>>> ok
>>>> 6> test:sleep_periodical(192, 31).
>>>> Finished in 6492321 microseconds.
>>>> ok
>>>> 7> test:sleep_periodical(384, 16).
>>>> Finished in 7327693 microseconds.
>>>> ok
>>>>
>>>> So it somewhat is ok until we get in the 125ms range.
>>>>
>>>>
>>>>
>>>> On Mon, Jan 12, 2015 at 12:12 PM, Sergej Jurečko <
>>>> sergej.jurecko@REDACTED> wrote:
>>>>
>>>>> timer:sleep is not even remotely as accurate for those low numbers. It
>>>>> can not go lower than 20ms or so from what i remember.
>>>>>
>>>>> I have had this issue once when I needed low interval for timer. I
>>>>> used an external c app which printed to stdout every 5ms. I dont think
>>>>> there is any way in erlang to get a timer that low.
>>>>>
>>>>> Sergej
>>>>> On Jan 12, 2015 11:46 AM, "Roberto Ostinelli" <roberto@REDACTED>
>>>>> wrote:
>>>>>
>>>>>> Additionally:
>>>>>>
>>>>>> 6> test:sleep_periodical(1000, 1).
>>>>>> Finished in 1999097 microsecond
>>>>>>
>>>>>> So:
>>>>>>
>>>>>>    - Looping 1,000 times and sleeping 1 ms each time takes 2.00
>>>>>>    seconds (instead of 1).
>>>>>>
>>>>>> Looks like it's ms related, not total count.
>>>>>>
>>>>>> Best,
>>>>>> r.
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Mon, Jan 12, 2015 at 11:40 AM, Roberto Ostinelli <
>>>>>> roberto@REDACTED> wrote:
>>>>>>
>>>>>>> Dear list,
>>>>>>> I've probably missed out something since I'm not understanding what
>>>>>>> is going here.
>>>>>>>
>>>>>>> I'm basically just trying to send messages periodically, though I
>>>>>>> found out that I wasn't seeing the behavior that I was expecting. It looks
>>>>>>> like the timer has some erratic behavior.
>>>>>>>
>>>>>>> I've stripped out the code to the bare minimum and it looks like
>>>>>>> this:
>>>>>>>
>>>>>>> -module(test).
>>>>>>> -export([sleep_periodical/2]).
>>>>>>> -export([sleep_loop/2]).
>>>>>>>
>>>>>>> sleep_periodical(Num, IntervalMs) ->
>>>>>>> {Time, _Value} = timer:tc(?MODULE, sleep_loop, [Num, IntervalMs]),
>>>>>>> io:format("Finished in ~p microseconds.~n", [Time]).
>>>>>>>
>>>>>>> sleep_loop(Num, IntervalMs) ->
>>>>>>> SleepFun = fun(_) -> timer:sleep(IntervalMs) end,
>>>>>>> lists:foreach(SleepFun, lists:seq(1, Num)).
>>>>>>>
>>>>>>>
>>>>>>> When I run this code, I see the following:
>>>>>>>
>>>>>>> Erlang/OTP 17 [erts-6.3] [source] [64-bit] [smp:8:8]
>>>>>>> [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
>>>>>>>
>>>>>>> Eshell V6.3  (abort with ^G)
>>>>>>> 1> c(test).
>>>>>>> {ok,test}
>>>>>>> 2> test:sleep_periodical(1000, 10).
>>>>>>> Finished in 12257397 microseconds.
>>>>>>> ok
>>>>>>> 3> test:sleep_periodical(2000, 10).
>>>>>>> Finished in 24518070 microseconds.
>>>>>>> ok
>>>>>>> 4> test:sleep_periodical(10000, 1).
>>>>>>> Finished in 20000280 microseconds.
>>>>>>> ok
>>>>>>> 5> test:sleep_periodical(20000, 1).
>>>>>>> Finished in 40000685 microseconds.
>>>>>>> ok
>>>>>>>
>>>>>>> So:
>>>>>>>
>>>>>>>    - Looping 1,000 times and sleeping 10 ms each time takes 12.26
>>>>>>>    seconds (instead of 10).
>>>>>>>    - Looping 2,000 times and sleeping 10 ms each time takes 24.52
>>>>>>>    seconds (instead of 20).
>>>>>>>    - Looping 10,000 times and sleeping 1 ms each time takes 20.00
>>>>>>>    seconds (instead of 10).
>>>>>>>    - Looping 20,000 times and sleeping 1 ms each time takes 40.00
>>>>>>>    seconds (instead of 20).
>>>>>>>
>>>>>>> Up to 10,000 times it takes 12,16% (1/8) more time, from 10,000
>>>>>>> times it takes 100% (double).
>>>>>>>
>>>>>>> Can some kind soul explain what I'm doing wrong here and how to
>>>>>>> achieve the desired results?
>>>>>>>
>>>>>>> I'm on OSX, Erlang 17.4.
>>>>>>>
>>>>>>> Help! ^^_
>>>>>>> r.
>>>>>>>
>>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> erlang-questions mailing list
>>>>>> erlang-questions@REDACTED
>>>>>> http://erlang.org/mailman/listinfo/erlang-questions
>>>>>>
>>>>>>
>>>> _______________________________________________
>>>> erlang-questions mailing list
>>>> erlang-questions@REDACTED
>>>> http://erlang.org/mailman/listinfo/erlang-questions
>>>>
>>>
>>> _______________________________________________
>>> erlang-questions mailing list
>>> erlang-questions@REDACTED
>>> http://erlang.org/mailman/listinfo/erlang-questions
>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20150112/7d7cf223/attachment.htm>


More information about the erlang-questions mailing list