ttb_et.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 267 行

ERL
267
字号
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %%     $Id$%%-module(ttb_et).-author('siri@erix.ericsson.se').-include("et.hrl").-export([handler/4]).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ----------- TTB format handler -----------handler(Out,Trace,Traci,initial) ->    S = self(),    spawn(fun() -> init_et(S) end),    receive {et_started,Collector} -> ok end,    handler(Out,Trace,Traci,Collector);handler(_,end_of_trace,_Traci,Col) ->    get_returns(Col),    ok;handler(_,Trace,_Traci,Col) ->    {ok,NewCol} = et_collector:report(Col,Trace),    NewCol.%%% ----------- Collector Filter -----------collector(Event) when is_record(Event,event) ->     %% if collector is selected from viewer menu    true; collector(Trace) ->    et_selector:parse_event(undefined,Trace).%% After applying collector filter to all events, iterate over%% all events backwards and collect call/return information:%%%% MFA collected from return_to events is added to call and%% return_from events as {caller,MFA} and {return_to,MFA} respecively.%% MFA collected from call events is added to return_to events as%% {return_from,MFA}%%%% This information can then be used by any filter for generating to-%% and from fields.get_returns(Col) ->    Fun = fun(Event,Acc) -> collect_return_info(Event,Acc,Col) end,    et_collector:iterate(Col, last, '-infinity', Fun, dict:new()).collect_return_info(#event{label=L,from=Pid}=E,Acc,_Col)  when L==return_to;L==return_from->    %% Stacking all return_to and return_from events    dict:update(Pid,fun(Old) -> [E|Old] end, [E], Acc);collect_return_info(#event{label=call,from=Pid,contents=Contents}=E,Acc,Col) ->    %% Popping return_from and return_to events    %% If both exist, return_from will _always_ be first!!!    MFA = get_mfarity(Contents),    {Caller,NewAcc} =	case dict:find(Pid,Acc) of	    {ok,[#event{label=return_from}=RetFrom,		 #event{label=return_to}=RetTo | Rets]} ->		RetToCont = RetTo#event.contents,		C = get_mfarity(RetToCont),		NewRetTo = RetTo#event{contents=RetToCont++[{return_from,MFA}]},		RetFromCont = RetFrom#event.contents,		NewRetFrom = 		    RetFrom#event{contents=RetFromCont++[{return_to,C}]},		et_collector:report(Col,NewRetTo),		et_collector:report(Col,NewRetFrom),		{C, dict:store(Pid,Rets,Acc)};	    {ok,[#event{label=return_to}=RetTo | Rets]} ->		%% No return_from		RetToCont = RetTo#event.contents,		C = get_mfarity(RetToCont),		NewRetTo = RetTo#event{contents=RetToCont++[{return_from,MFA}]},		et_collector:report(Col,NewRetTo),		{C, dict:store(Pid,Rets,Acc)};	    {ok,[#event{label=return_from}=RetFrom | Rets]} ->		%% No return_to, check if caller(pam_result) is in call event		C = get_caller(Contents),		RetFromCont = RetFrom#event.contents,		NewRetFrom = 		    RetFrom#event{contents=RetFromCont++[{return_to,C}]},		et_collector:report(Col,NewRetFrom),		{C, dict:store(Pid,Rets,Acc)};	    _noreturn ->		{nocaller,Acc}	end,    NewE = E#event{contents=Contents++[{caller,Caller}]},    et_collector:report(Col,NewE),    NewAcc;collect_return_info(_E,Acc,_Col) ->    Acc.init_et(Parent) ->    process_flag(trap_exit,true),%    ets:new(ttb_et_table,[set,named_table,public]),%    ets:insert(ttb_et_table,{traci,Traci}),    EtOpt = [{active_filter,processes},	     {dict_insert, {filter, collector}, fun collector/1},	     {dict_insert, {filter, processes}, fun processes/1},	     {dict_insert, {filter, modules}, fun modules/1},	     {dict_insert, {filter, mods_and_procs}, fun mods_and_procs/1},	     {dict_insert, {filter, functions}, fun functions/1},	     {dict_insert, {filter, funcs_and_procs}, fun funcs_and_procs/1},	     {hide_actions, false},	     {max_events, infinity},	     {max_actors, infinity}],    {ok, Viewer} = et_viewer:start_link(EtOpt),    Collector = et_viewer:get_collector_pid(Viewer),    Parent ! {et_started,Collector},    receive	{'EXIT',Viewer,shutdown} ->	    ok    end.	    %%% ----------- Viewer Filters -----------processes(E0) ->    E = label(E0),    {{FromProc,FromNode},{ToProc,ToNode}} = 	get_actors(E#event.from,E#event.to),    {true,E#event{from = io_lib:format("~w~n~w",[FromProc,FromNode]),		  to = io_lib:format("~w~n~w",[ToProc,ToNode])}}.mods_and_procs(E) ->    ActorFun = fun({M,_F,_A},{Proc,Node}) -> 		       io_lib:format("~w~n~w~n~w",[M,Proc,Node])	       end,    calltrace_filter(E,ActorFun).modules(E) ->    ActorFun = fun({M,_F,_A},{_Proc,Node}) -> 		       io_lib:format("~w~n~w",[M,Node])	       end,    calltrace_filter(E,ActorFun).funcs_and_procs(E) ->    ActorFun = fun({M,F,A},{Proc,Node}) -> 		       io_lib:format("~s~n~w~n~w",[mfa(M,F,A),Proc,Node])	       end,    calltrace_filter(E,ActorFun).    functions(E) ->    ActorFun = fun({M,F,A},{_Proc,Node}) -> 		       io_lib:format("~s~n~w",[mfa(M,F,A),Node])	       end,    calltrace_filter(E,ActorFun).    %% Common filter used by mods_and_procs/1 and modules/1calltrace_filter(E,ActorFun) ->    {From,To} = get_actors(E#event.from,E#event.to),    calltrace_filter(E,From,To,ActorFun).    calltrace_filter(#event{label=call}=E,From,To,ActorFun) ->    Cont = E#event.contents,    MFA = get_mfarity(Cont),    case lists:keysearch(caller,1,Cont) of	{value,{_,{_CM,_CF,_CA}=Caller}} ->	    {true, E#event{label = label(call,MFA), 			   from = ActorFun(Caller,From),			   to = ActorFun(MFA,To)}};	{value,{_, _}} ->	    {true, E#event{label = label(call,MFA), 			   from = ActorFun(MFA,From),			   to = ActorFun(MFA,To)}}    end;calltrace_filter(#event{label=return_from}=E,From,To,ActorFun) ->    Cont = E#event.contents,    MFA = get_mfarity(Cont),    case lists:keysearch(return_to,1,Cont) of	{value,{_,{_M2,_F2,_A2}=MFA2}} ->	    {true, E#event{label = label(return_from,MFA),			   from = ActorFun(MFA,From),			   to = ActorFun(MFA2,To)}};	{value,{_, _}} ->	    {true, E#event{label = label(return_from,MFA), 			   from = ActorFun(MFA,From),			   to = ActorFun(MFA,To)}}    end;calltrace_filter(#event{label=return_to}=E,From,To,ActorFun) ->    Cont = E#event.contents,    {value,{_,{_M2,_F2,_A2}=MFA2}} = lists:keysearch(return_from,1,Cont),    case get_mfarity(Cont) of	{_M,_F,_A}=MFA ->	    {true, E#event{label = label(return_to,MFA), 			   from = ActorFun(MFA2,From),			   to = ActorFun(MFA,To)}};	undefined ->	    {true, E#event{label = "return_to unknown", 			   from = ActorFun(MFA2,From),			   to = ActorFun(MFA2,To)}}    end;calltrace_filter(_E,_From,_To,_ActorFun) ->    false.label(Event=#event{label=L,contents=C}) ->    case lists:keysearch(mfa,1,C) of	{value,{mfa,MFA}} -> Event#event{label=label(L,MFA)};	false -> Event    end.label(L,{M,F,A}) -> label(L,M,F,A);label(L,Other) -> io_lib:format("~w ~w",[L,Other]).label(call,M,F,A) -> "call " ++ mfa(M,F,A);label(return_from,M,F,A) -> "return_from " ++ mfa(M,F,A);label(return_to,M,F,A) -> "return_to " ++ mfa(M,F,A);label(spawn,M,F,A) -> "spawn " ++ mfa(M,F,A);label(out,M,F,A) -> "out " ++ mfa(M,F,A);label(in,M,F,A) -> "in " ++ mfa(M,F,A).mfa(M,F,A) -> atom_to_list(M) ++ ":" ++ fa(F,A).fa(F,A) -> atom_to_list(F) ++ "/" ++ integer_to_list(arity(A)).arity(L) when is_list(L) -> length(L);arity(I) when is_integer(I) -> I.    get_actors(From,To) ->    case {get_proc(From),get_proc(To)} of	{{_FP,_FN},{_TP,_TN}}=R -> R;	{{FP,FN},T} -> {{FP,FN},{T,FN}};	{F,{TP,TN}} -> {{F,TN},{TP,TN}};	{F,T} -> {{F,unknown},{T,unknown}}    end.	    get_proc({_Pid,Name,Node}) when is_atom(Name) -> {Name,Node};get_proc({Pid,_initfunc,Node}) -> {Pid,Node};get_proc(P) when is_pid(P); is_port(P) -> {P,node(P)};get_proc(P) -> P.get_mfarity(List) ->    case get_mfa(List) of	{M,F,A} -> {M,F,arity(A)};	Other -> Other    end.get_mfa(List) ->    {value,{mfa,MFA}} = lists:keysearch(mfa,1,List),    MFA.get_caller(List) ->    case lists:keysearch(pam_result,1,List) of	{value,{pam_result,{M,F,A}}} -> {M,F,arity(A)};	{value,{pam_result,undefined}} -> undefined;	{value,{pam_result,_Other}} -> nocaller;	false -> nocaller    end.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?