检查Erlang中的活动计时器

时间:2010-10-29 13:46:35

标签: erlang

是否有一种简单的方法可以获取在Erlang中以erlang:send_aftererlang:apply_after等开头的所有当前等待计时器的列表?

5 个答案:

答案 0 :(得分:6)

出于调试目的,您可以使用dbg:)。

首先创建一个ets表,它将存储所有计时器引用。

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

然后创建一个dbg处理函数,它检查从erlang:send_after返回的调用,并将返回的计时器引用保存到表中

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>

将该功能设置为跟踪处理程序。同时在所有进程的erlang:send_after()调用上启用匹配

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}]}

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>

最后检查表是否包含这些引用:

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

这样您就可以存储曾经调用erlang:send_after()的任何进程创建的所有计时器引用。您可以将它们映射到erlang:read_timer()以过滤活动计时器。

您可以以类似方式跟踪send_after的来电。也可以在cancel_timer上匹配并手动从表中删除已取消的引用。

此外,如果您没有消息密集型应用程序,则应该能够匹配这些计时器触发的消息和/或功能,并从列表中删除过期的引用。

答案 1 :(得分:2)

查看erl_bif_timer.c中的代码我认为崩溃转储是唯一可以找到所有BIF计时器列表的地方。 : - )

答案 2 :(得分:2)

我今天遇到跟踪计时器的必要性。

它正在生产中,所以我不想使用dbg。这些是erlang:timers所以我之前的解决方案毫无用处。

相反,我从binary_to_list(erlang:system_info(info))分析了nbif_timer参数。

我相信(尚未确认),它会报告为计时器分配的内存。在我的系统x64上,它将是17个8字节= 136字节的字。

监控此值可清楚地显示系统何时设置大量计时器。

享受。

答案 3 :(得分:1)

这是一个黑客,但使用:ets:tab2list(timer_tab)。对于两个定时器它持有:

  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]}}]

答案 4 :(得分:0)

你可以保存send_after,aply_after等返回的引用,并使用erlang:read_timer来检查它是否还在等待(如果定时器被取消或者不再等待,read_timer返回false)