Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run a Erlang Process periodically with Precise Time (i.e. 10ms)

Tags:

erlang

timer

I want to run a periodic erlang process every 10ms (based on wall clock time), the 10ms should be as accurate as possible; what should be the right way to implement it?

like image 503
Greg Avatar asked Dec 29 '16 11:12

Greg


People also ask

How does the Erlang runtime system work?

The runtime system works towards aligning the two system times. Depending on the time warp mode used, this can be achieved by letting Erlang system time perform a time warp. A monotonically increasing time provided by the Erlang runtime system. Erlang monotonic time increases since some unspecified point in time.

What is the size of an Erlang process?

An Erlang process is lightweight compared to operating systems threads and processes. A newly spawned Erlang process uses 309 words of memory in the non-SMP emulator without HiPE support. (SMP support and HiPE support will both add to this size.)

How to trade memory for execution time in Erlang?

With the new message_queue_dataflag introduced in Erlang 19 you can trade memory for execution time in a new way. If the receiving process is overloaded and holding on to the main lock, it might be a good strategy to use the off_heapallocation in order to let the sending process quickly dump the message in an m-buf.

What is time correction in Erlang?

If time correction is enabled, the Erlang runtime system makes use of both OS system time and OS monotonic time , to adjust the frequency of the Erlang monotonic clock. Time correction ensures that Erlang monotonic time does not warp and that the frequency is relatively accurate.


1 Answers

If you want really reliable and accurate periodic process you should rely on actual wall clock time using erlang:monotonic_time/0,1. If you use method in Stratus3D's answer you will eventually fall behind.

start_link(Period) when Period > 0, is_integer(Period) ->
  gen_server:start_link({local, ?SERVER}, ?MODULE, Period, []).

...

init(Period) ->
    StartT = erlang:monotonic_time(millisecond),
    self() ! tick,
    {ok, {StartT, Period}}.

...

handle_info(tick, {StartT, Period} = S) ->
    Next = Period - (erlang:monotonic_time(millisecond)-StartT) rem Period,
    _Timer = erlang:send_after(Next, self(), tick),
    do_task(),
    {noreply, S}.

You can test in the shell:

spawn(fun() ->
    P = 1000,
    StartT = erlang:monotonic_time(millisecond),
    self() ! tick,
    (fun F() ->
        receive
          tick ->
            Next = P - (erlang:monotonic_time(millisecond)-StartT) rem P,
            erlang:send_after(Next, self(), tick),
            io:format("X~n", []),
            F()
        end
      end)()
  end).
like image 78
Hynek -Pichi- Vychodil Avatar answered Oct 16 '22 20:10

Hynek -Pichi- Vychodil