2. cprof - The Call Count Profiler
2 cprof - 调用计数分析器
cprof
是一个分析工具,可用于了解系统中不同功能被调用的频率。
cprof
使用类似于本地呼叫追踪的断点,但包含计数器,以收集分析数据。因此,不需要特殊编译要分析的任何模块。
cprof
以减少的总呼叫计数顺序呈现所有分析模块,并且对于每个模块,还以降低的呼叫计数顺序呈现所有分析功能。可以指定呼叫计数限制以过滤低于限制的所有功能。
分析按以下步骤进行:
cprof:start/0..3
通过在其上设置呼叫计数断点,开始使用指定功能的归零呼叫计数器进行分析。Mod:Fun()
运行要分析的代码。cprof:pause/0..3
暂停指定功能的呼叫计数器。这最大限度地减少了运行在后台或外壳中的干扰分析的代码的影响。呼叫计数器在主机字长度“达到上限”时自动暂停。对于32位主机,最大计数器值为2147483647. cprof:analyse/0..2
收集呼叫计数器并计算结果。cprof:restart/0..3
对于指定的功能,从零开始重新启动计数器。可以用来收集一组新的计数器,而不必停止并开始呼叫计数分析。cprof:stop/0..3
通过从指定函数中删除调用计数断点来停止分析。
可以将函数指定为系统中的全部,全部位于一个模块中,所有模块中的一个函数,一个函数或所有尚未加载的模块中的所有函数。到目前为止,BIF不能被追踪电话号码。
分析结果可以是所有模块,也可以是一个模块。在任何一种情况下,都可以给出一个呼叫计数限制,以在呼叫计数低于限制的情况下过滤功能。所有模块的分析并没有
包含该模块cprof
本身,它只能通过指定它作为一个单一模块,用于分析进行分析。
与其他形式的跟踪相比,呼叫计数跟踪非常轻便,因为不需要生成跟踪消息。一些测量表明在10%附近的性能下降。
以下部分显示了使用分析的一些示例cprof
。另见cprof(3)
。
2.1例:背景工作
从Erlang shell:
1> cprof:start(), cprof:pause(). % Stop counters just after start
3476
2> cprof:analyse().
{30,
[{erl_eval,11,
[{{erl_eval,expr,3},3},
{{erl_eval,'-merge_bindings/2-fun-0-',2},2},
{{erl_eval,expand_module_name,2},1},
{{erl_eval,merge_bindings,2},1},
{{erl_eval,binding,2},1},
{{erl_eval,expr_list,5},1},
{{erl_eval,expr_list,3},1},
{{erl_eval,exprs,4},1}]},
{orddict,8,
[{{orddict,find,2},6},
{{orddict,dict_to_list,1},1},
{{orddict,to_list,1},1}]},
{packages,7,[{{packages,is_segmented_1,1},6},
{{packages,is_segmented,1},1}]},
{lists,4,[{{lists,foldl,3},3},{{lists,reverse,1},1}]}]}
3> cprof:analyse(cprof).
{cprof,3,[{{cprof,tr,2},2},{{cprof,pause,0},1}]}
4> cprof:stop().
3476
这个例子展示了shell为了解释第一个命令行而执行的后台工作。大部分工作都是由erl_eval
和完成的orddict
。
本例中捕获的内容是shell在解释实际调用to cprof:start()
和之间发生的命令行时所执行的部分工作cprof:analyse()
。
2.2示例:一个模块
从Erlang shell:
1> cprof:start(),R=calendar:day_of_the_week(1896,4,27),cprof:pause(),R.
1
2> cprof:analyse(calendar).
{calendar,9,
[{{calendar,df,2},1},
{{calendar,dm,1},1},
{{calendar,dy,1},1},
{{calendar,last_day_of_the_month1,2},1},
{{calendar,last_day_of_the_month,2},1},
{{calendar,is_leap_year1,1},1},
{{calendar,is_leap_year,1},1},
{{calendar,day_of_the_week,3},1},
{{calendar,date_to_gregorian_days,3},1}]}
3> cprof:stop().
3271
这个例子告诉我们“Aktiebolaget LM Ericsson&Co”是星期一注册的(因为第一个命令的返回值是1),并且calendar
模块需要9个函数调用来计算它。
使用cprof:analyse()
在此示例中,还显示了与第一个示例中大致相同的背景工作。
2.3示例:在代码中
编写一个模块:
-module(sort).
-export([do/1]).
do(N) ->
cprof:stop(),
cprof:start(),
do(N, []).
do(0, L) ->
R = lists:sort(L),
cprof:pause(),
R;
do(N, L) ->
do(N-1, [random:uniform(256)-1 | L]).
从Erlang shell:
1> c(sort).
{ok,sort}
2> l(random).
{module,random}
3> sort:do(1000).
[0,0,1,1,1,1,1,1,2,2,2,3,3,3,3,3,4,4,4,5,5,5,5,6,6,6,6,6,6|...]
4> cprof:analyse().
{9050,
[{lists_sort,6047,
[{{lists_sort,merge3_2,6},923},
{{lists_sort,merge3_1,6},879},
{{lists_sort,split_2,5},661},
{{lists_sort,rmerge3_1,6},580},
{{lists_sort,rmerge3_2,6},543},
{{lists_sort,merge3_12_3,6},531},
{{lists_sort,merge3_21_3,6},383},
{{lists_sort,split_2_1,6},338},
{{lists_sort,rmerge3_21_3,6},299},
{{lists_sort,rmerge3_12_3,6},205},
{{lists_sort,rmerge2_2,4},180},
{{lists_sort,rmerge2_1,4},171},
{{lists_sort,merge2_1,4},127},
{{lists_sort,merge2_2,4},121},
{{lists_sort,mergel,2},79},
{{lists_sort,rmergel,2},27}]},
{random,2001,
[{{random,uniform,1},1000},
{{random,uniform,0},1000},
{{random,seed0,0},1}]},
{sort,1001,[{{sort,do,2},1001}]},
{lists,1,[{{lists,sort,1},1}]}]}
5> cprof:stop().
5369
这个例子显示了一些lists:sort/1
工作原理的细节。它在模块中使用了6047个函数调用lists_sort
来完成工作。
这一次,由于shell没有涉及,因此在分析过程中没有其他工作在系统中完成。如果您尝试使用新启动的Erlang模拟器重试相同的示例,但省略了该命令l(random)
,则分析将显示更多由code_server
其他人完成的自动加载模块的函数调用random
。