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

Sergej Jurečko sergej.jurecko@REDACTED
Mon Jan 12 14:18:11 CET 2015


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/14c88097/attachment.htm>


More information about the erlang-questions mailing list