Check active timers in Erlang

妖精的绣舞 提交于 2020-01-02 01:36:06

问题


Is there a simple way to get a list of all currently waiting timers started with erlang:send_after, erlang:apply_after, etc. in Erlang?


回答1:


For debugging purposes you can use dbg :).

First create an ets table which will store all timer references.

1> ets:new(timer_dbg, ['public', 'named_table', 'bag']).
timer_dbg

Then create a dbg handler function, which checks for calls returning from erlang:send_after, and saves the returned timer reference to the table

2> Fun = fun({'trace', _Pid, 'return_from', {erlang, send_after, 3}, Ref}, []) ->
2>           ets:insert(timer_dbg, {Ref}), [];
2>          (_Msg, []) ->
2>           []
2>       end.
#Fun<erl_eval.12.113037538>

Set the function as trace handler. Also enable matching on the call to erlang:send_after() on all processes

3> dbg:tracer('process', {Fun, []}).
{ok,<0.35.0>}
4> dbg:p('all', 'c').
{ok,[{matched,nonode@nohost,26}]}
5> dbg:tpl(erlang, send_after, [{'_', [], [{'return_trace'}]}]).
{ok,[{matched,nonode@nohost,1},{saved,1}]}

Make some test calls to erlang:send_after()

6> erlang:send_after(1000, self(), {}).
#Ref<0.0.0.43>
7> erlang:send_after(1000, self(), {}).
#Ref<0.0.0.47>
8> erlang:send_after(1000, self(), {}).
#Ref<0.0.0.51>

Finally check that the table does contain those references:

9> ets:tab2list(timer_dbg).
[{#Ref<0.0.0.51>},{#Ref<0.0.0.43>},{#Ref<0.0.0.47>}]

This way you will store all timer references ever created by any process ever calling erlang:send_after(). You can map them over erlang:read_timer() to filter the alive timers.

You can trace calls to send_after in a similar manner. It is also possible to match on cancel_timer and manually remove the cancelled references from the table.

Also, if you don't have a message-intensive application, you should be able to match on messages and/or functions triggered by those timers, and remove the expired references from the list.




回答2:


thats a hack but use: ets:tab2list(timer_tab). For two timers it holds:

  ets:tab2list(timer_tab).                                            
[{{1288384968923398,#Ref<0.0.0.30>},
  timeout,
  {erlang,integer_to_list,[23]}},
 {{23334621698390115688,#Ref<0.0.0.189>},
  timeout,
  {erlang,integer_to_list,[23]}}]



回答3:


Looking at the code in erl_bif_timer.c I think crash dump is the only place where you can find a list of all BIF timers which were just active. :-)




回答4:


I run into the same necessity of tracking timers today.

It is on production, so I do not want to use dbg. These are erlang:timers so my previous solution is useless.

Instead I analysed nbif_timer parameter from binary_to_list(erlang:system_info(info)).

I believe (have not confirmed yet), it reports memory allocated for timers. On my system x64 it would be 17 words of 8 bytes = 136 bytes.

Monitoring this value clearly shows when system sets high number of timers.

enjoy.




回答5:


you could save the references returned by send_after, aply_after etc and use erlang:read_timer to check if it is still waiting (read_timer returns false if the timer has been canceled or isn't waiting anymore)



来源:https://stackoverflow.com/questions/4052451/check-active-timers-in-erlang

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!