您的位置:首页 > 产品设计 > UI/UE

[Erlang_Question21]Erlang性能分析工具eprof fporf的应用

2015-08-12 13:47 417 查看
前段时间项目改代码突然cpu波动很大,排查了好久都没有找到原因,只能求助于性能测试工具

<<Erlang程序设计>>----Joe Armstorng[哈哈,登月第一人也叫Armstrong]
P416

cprof测试每个函数被调用了多少次,这个工具为轻量在运行系统上使用这个工具会给系统带来5%~10%的额外负载
fprof显示函数调用和被调用的埋单,并将结果输出到一个文件中,这个工具比较适合于在实验环境或模拟环境中对进行大规模的性能前一段,它会带来非常显著的系统负载.
eprof分分析一个Erlang程序中计算时间主要消耗在哪里,它实际是fprof的前任,不同在于:这适合规模小一些的性能前评估.

于是自己写了封装了一下,便于使用:
你可以使用seek_proc_info:help()查看到具体函数的作用:可以把这个当做cprof和fprof使用例子吧。

2> seek_proc_info:help().
Brief help:
seek_proc_info:queue(N) - show top N pids sorted by queue length
seek_proc_info:memory(N) - show top N pids sorted by memory usage
seek_proc_info:reds(N) - show top N pids sorted by reductions
Erlang shell with Ctrl+C
seek_proc_info:eprof_start() - start eprof on all available pids; DO NOT use on production system!
seek_proc_info:eprof_stop() - stop eprof and print result
seek_proc_info:fprof_start() - start fprof on all available pids; DO NOT use on production system!
seek_proc_info:fprof_stop() - stop eprof and print formatted result
seek_proc_info:fprof_start(N) - start and run fprof for N seconds; use seek_proc_info:fprof_analyze() to analyze collected statistics and print formatted result; use on production system with CARE
seek_proc_info:fprof_analyze() - analyze previously collected statistics using seek_proc_info:fprof_start(N) and print formatted result
seek_proc_info:help() - print this help
ok


只把你想监控的Application加到宏APPS里面,可以查看进程消息,内存,reduction情况。
源代码在下面,也可以自己改改看进程的其它信息哦。





%%%-------------------------------------------------------------------
%%% @author zhongwencool@gmail.com
%%% @doc
%%%   A interface for eprof and fprof
%%%   call ?MODULE:help() to see
%%% @end
%%% Created : 03. Sep 2014 3:09 PM
%%%-------------------------------------------------------------------
-module(seek_proc_info).

%% API
-export([eprof_start/0, eprof_stop/0,
fprof_start/0, fprof_start/1,
fprof_stop/0, fprof_analyze/0,
queue/1, memory/1,
reds/1, help/0
]).

-define(APPS, [kernel,mnesia]).

%%====================================================================
%% API
%%====================================================================
help() ->
io:format("Brief help:~n"
"~p:queue(N) - show top N pids sorted by queue length~n"
"~p:memory(N) - show top N pids sorted by memory usage~n"
"~p:reds(N) - show top N pids sorted by reductions~n"
"Erlang shell with Ctrl+C~n"
"~p:eprof_start() - start eprof on all available pids; "
"DO NOT use on production system!~n"
"~p:eprof_stop() - stop eprof and print result~n"
"~p:fprof_start() - start fprof on all available pids; "
"DO NOT use on production system!~n"
"~p:fprof_stop() - stop eprof and print formatted result~n"
"~p:fprof_start(N) - start and run fprof for N seconds; "
"use ~p:fprof_analyze() to analyze collected statistics and "
"print formatted result; use on production system with CARE~n"
"~p:fprof_analyze() - analyze previously collected statistics "
"using ~p:fprof_start(N) and print formatted result~n"
"~p:help() - print this help~n",
lists:duplicate(12, ?MODULE)).

eprof_start() ->
eprof:start(),
case lists:keyfind(running, 1, application:info()) of
{_, Apps} ->
case get_procs(?APPS, Apps) of
[] ->
{error, no_procs_found};
Procs ->
eprof:start_profiling(Procs)
end;
_ ->
{error, no_app_info}
end.

fprof_start() ->
fprof_start(0).

fprof_start(Duration) ->
case lists:keyfind(running, 1, application:info()) of
{_, Apps} ->
case get_procs(?APPS, Apps) of
[] ->
{error, no_procs_found};
Procs ->
fprof:trace([start, {procs, Procs}]),
io:format("Profiling started~n"),
if Duration > 0 ->
timer:sleep(Duration*1000),
fprof:trace([stop]),
fprof:stop();
true->
ok
end
end;
_ ->
{error, no_app_info}
end.

fprof_stop() ->
fprof:trace([stop]),
fprof:profile(),
fprof:analyse([totals, no_details, {sort, own},
no_callers, {dest, "fprof.analysis"}]),
fprof:stop(),
format_fprof_analyze().

fprof_analyze() ->
fprof_stop().

eprof_stop() ->
eprof:stop_profiling(),
eprof:analyze().

queue(N) ->
dump(N, lists:reverse(lists:ukeysort(1, all_pids(queue)))).

memory(N) ->
dump(N, lists:reverse(lists:ukeysort(3, all_pids(memory)))).

reds(N) ->
dump(N, lists:reverse(lists:ukeysort(4, all_pids(reductions)))).

%%====================================================================
%% Internal functions
%%====================================================================
get_procs(Apps, AppList) ->
io:format("Searching for processes to profile...~n", []),
Procs = lists:foldl(
fun({App, Leader},Acc) when is_pid(Leader) ->
case lists:member(App, Apps) of
true ->
[get_procs2(Leader)|Acc];
false ->
Acc
end;
(_,Acc) ->
Acc
end,[], AppList),
io:format("Found ~p processes~n", [length(Procs)]),
Procs.

get_procs2(Leader) ->
lists:filter(
fun(Pid) ->
case process_info(Pid, group_leader) of
{_, Leader} ->
true;
_ ->
false
end
end, processes()).

format_fprof_analyze() ->
case file:consult("fprof.analysis") of
{ok, [_, [{totals, _, _, TotalOWN}] | Rest]} ->
OWNs =
lists:flatmap(
fun({MFA, _, _, OWN}) ->
Percent = OWN*100/TotalOWN,
case round(Percent) of
0 -> [];
_ -> [{mfa_to_list(MFA), Percent}]
end
end, Rest),
ACCs = collect_accs(Rest),
MaxACC = find_max(ACCs),
MaxOWN = find_max(OWNs),
io:format("=== Sorted by OWN:~n"),
lists:foreach(
fun({MFA, Per}) ->
L = length(MFA),
S = lists:duplicate(MaxOWN - L + 2, $ ),
io:format("~s~s~.2f%~n", [MFA, S, Per])
end, lists:reverse(lists:keysort(2, OWNs))),
io:format("~n=== Sorted by ACC:~n"),
lists:foreach(
fun({MFA, Per}) ->
L = length(MFA),
S = lists:duplicate(MaxACC - L + 2, $ ),
io:format("~s~s~.2f%~n", [MFA, S, Per])
end, lists:reverse(lists:keysort(2, ACCs)));
Err ->
Err
end.

mfa_to_list({M, F, A}) ->
atom_to_list(M) ++ ":" ++ atom_to_list(F) ++ "/" ++ integer_to_list(A);
mfa_to_list(F) when is_atom(F) ->
atom_to_list(F).

find_max(List) ->
find_max(List, 0).

find_max([{V, _}|Tail], Acc) ->
find_max(Tail, lists:max([length(V), Acc]));
find_max([], Acc) ->
Acc.

collect_accs(List) ->
List1 = lists:filter(
fun({{sys, _, _}, _, _, _}) ->
false;
({suspend,_,_,_}) ->
false;
({{gen_fsm, _, _},_,_,_}) ->
false;
({{gen, _, _},_,_,_}) ->
false;
({{gen_server, _, _},_,_,_}) ->
false;
({{proc_lib, _, _},_,_,_}) ->
false;
(_) ->
true
end, List),
calculate(List1).

calculate(List1) ->
TotalACC = lists:sum([A || {_, _, A, _} <- List1]),
List2 = lists:foldl(fun({MFA, _, ACC, _},NewList) ->
Percent = ACC*100/TotalACC,
case round(Percent) of
0 -> NewList;
_ -> [{mfa_to_list(MFA), Percent}|NewList]
end
end,[],List1),
lists:reverse(List2).

all_pids(Type) ->
lists:foldl(
fun(P, Acc) when P == self() ->
Acc;
(P, Acc) ->
case catch process_info(
P,[message_queue_len, memory, reductions,
dictionary, current_function, registered_name]) of
[{_, Len}, {_, Memory}, {_, Reds},
{_, Dict}, {_, CurFun}, {_, RegName}] ->
IntQLen = get_internal_queue_len(Dict),
if Type == queue andalso Len == 0 andalso IntQLen == 0 ->
Acc;
true ->
[{lists:max([Len, IntQLen]),
Len,Memory, Reds, Dict, CurFun, P, RegName}|Acc]
end;
_ ->
Acc
end
end, [], processes()).

get_internal_queue_len(Dict) ->
case lists:keysearch('$internal_queue_len', 1, Dict) of
{value, {_, N}} -> N;
_ -> 0
end.

dump(N, Rs) ->
lists:foreach(
fun({_, MsgQLen, Memory, Reds, Dict, CurFun, Pid, RegName}) ->
io:format("** pid(~s)~n"
"** registered name: ~p~n"
"** memory: ~p~n"
"** reductions: ~p~n"
"** message queue len: ~p~n"
"** current_function: ~p~n"
"** dictionary: ~p~n~n",
[pid_to_list(Pid), RegName, Memory, Reds, MsgQLen, CurFun, Dict])
end, lists:sublist(Rs,N)).


View Code



洋葱、萝卜和西红柿,不相信世界上有南瓜这种东西。它们认为那是一种空想。南瓜不说话,只是默默地成长。——于尔克·舒比格《当世界年纪还小的时候》

写下来是好习惯:http://www.cnblogs.com/zhongwencool/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: