From 0e828036050eb59db83ad703fa719b44184642fd Mon Sep 17 00:00:00 2001 From: SisMaker <1713699517@qq.com> Date: Sun, 6 Jun 2021 00:41:28 +0800 Subject: [PATCH] =?UTF-8?q?ft:=20=E4=BB=A3=E7=A0=81=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/messages/tpMsgRS.erl | 294 +++++++++++++++++++-------------------- src/messages/tpMsgSD.erl | 182 ++++++++++++------------ 2 files changed, 238 insertions(+), 238 deletions(-) diff --git a/src/messages/tpMsgRS.erl b/src/messages/tpMsgRS.erl index 77aa789..bbedd1c 100644 --- a/src/messages/tpMsgRS.erl +++ b/src/messages/tpMsgRS.erl @@ -3,199 +3,199 @@ -include("eTpf.hrl"). -export([ - pfs/1 %% 分析单个文件 -, pfm/1 %% 分析多个文件 + pfs/1 %% 分析单个文件 + , pfm/2 %% 分析多个文件 ]). -record(state, { - meta = #{} :: map(), - senders = #{} :: #{pid() => pos_integer()}, - receivers = #{} :: #{pid() => pos_integer()}, - pairs = #{} :: #{{pid(), pid()} => pos_integer()}, - nonExisting = #{} :: #{pid() => pos_integer()}, - lastMsgs = #{} :: #{pid() => atom()} + meta = #{} :: map(), + senders = #{} :: #{pid() => pos_integer()}, + receivers = #{} :: #{pid() => pos_integer()}, + pairs = #{} :: #{{pid(), pid()} => pos_integer()}, + nonExisting = #{} :: #{pid() => pos_integer()}, + lastMsgs = #{} :: #{pid() => atom()} }). -spec pfs(file:filename_all()) -> ok. pfs(InputFile) -> - {ok, FinalState} = tpFReader:fold(fun handleEvent/2, #state{}, InputFile), - flush(FinalState). + {ok, FinalState} = tpFReader:fold(fun handleEvent/2, #state{}, InputFile), + flush(FinalState). --spec pfm(file:filename()) -> ok. -pfm(InputFiles) -> - PfFiles = filelib:wildcard(InputFiles), - doPfm(PfFiles, #state{}). +-spec pfm(file:filename(), filelib:dirname()) -> ok. +pfm(InputFiles, Cwd) -> + PfFiles = filelib:wildcard(InputFiles, Cwd), + doPfm(PfFiles, #state{}). doPfm([], State) -> - flush(State); + flush(State); doPfm([InputFile | PfFiles], State) -> - {ok, NewState} = tpFReader:fold(fun handleEvent/2, State, InputFile), - doPfm(PfFiles, NewState). + {ok, NewState} = tpFReader:fold(fun handleEvent/2, State, InputFile), + doPfm(PfFiles, NewState). %% @todo Later we may want to look at the latency of gen_server call/reply. %% @todo Later we may want to look at particular messages, have some sort of callback. handleEvent({send, From, _, Info, ?eTpfHole}, State = #state{meta = Meta}) -> - NewMeta = - case Meta of - #{From := OldInfo} -> - Meta#{From => maps:merge(OldInfo, Info)}; - _ -> - Meta#{From => Info} - end, - State#state{meta = NewMeta}; + NewMeta = + case Meta of + #{From := OldInfo} -> + Meta#{From => maps:merge(OldInfo, Info)}; + _ -> + Meta#{From => Info} + end, + State#state{meta = NewMeta}; handleEvent({send, From, _, Msg, To}, State = #state{senders = Senders, receivers = Receivers, pairs = Pairs, lastMsgs = LastMsgs}) -> - SendersCnt = maps:get(From, Senders, 0), - ReceiversCnt = maps:get(To, Receivers, 0), - PairsCnt = maps:get({From, To}, Pairs, 0), - State#state{ - senders = Senders#{From => SendersCnt + 1}, - receivers = Receivers#{To => ReceiversCnt + 1}, - pairs = Pairs#{{From, To} => PairsCnt + 1}, - lastMsgs = LastMsgs#{From => Msg} - }; + SendersCnt = maps:get(From, Senders, 0), + ReceiversCnt = maps:get(To, Receivers, 0), + PairsCnt = maps:get({From, To}, Pairs, 0), + State#state{ + senders = Senders#{From => SendersCnt + 1}, + receivers = Receivers#{To => ReceiversCnt + 1}, + pairs = Pairs#{{From, To} => PairsCnt + 1}, + lastMsgs = LastMsgs#{From => Msg} + }; handleEvent({send_to_non_existing_process, From, _, Msg, _}, State = #state{nonExisting = NonExisting, lastMsgs = LastMsgs}) -> - Count = maps:get(From, NonExisting, 0), - State#state{ - nonExisting = NonExisting#{From => Count + 1}, - lastMsgs = LastMsgs#{From => Msg}}; + Count = maps:get(From, NonExisting, 0), + State#state{ + nonExisting = NonExisting#{From => Count + 1}, + lastMsgs = LastMsgs#{From => Msg}}; %% Ignore all other events. We only care about messages. handleEvent(_, State) -> - State. + State. %% Output of the profiling. flush(State) -> - flushMostActiveSenders(State), - flushMostActiveReceivers(State), - flush_most_non_existing(State), - flushMostActivePairUnidirectional(State), - flushMostActivePairBidirectional(State), - io:format("~n"), - flushDigraph(State), - ok. + flushMostActiveSenders(State), + flushMostActiveReceivers(State), + flush_most_non_existing(State), + flushMostActivePairUnidirectional(State), + flushMostActivePairBidirectional(State), + io:format("~n"), + flushDigraph(State), + ok. flushMostActiveSenders(State = #state{senders = Senders}) -> - List = lists:sublist(lists:reverse(lists:keysort(2, maps:to_list(Senders))), 1, 100), - formatByCnt(<<"They sent the most messages">>, List, State). + List = lists:sublist(lists:reverse(lists:keysort(2, maps:to_list(Senders))), 1, 100), + formatByCnt(<<"They sent the most messages">>, List, State). flushMostActiveReceivers(State = #state{receivers = Receivers}) -> - List = lists:sublist(lists:reverse(lists:keysort(2, maps:to_list(Receivers))), 1, 100), - formatByCnt(<<"They received the most messages">>, List, State). + List = lists:sublist(lists:reverse(lists:keysort(2, maps:to_list(Receivers))), 1, 100), + formatByCnt(<<"They received the most messages">>, List, State). flush_most_non_existing(State = #state{nonExisting = NonExisting}) -> - List = lists:sublist(lists:reverse(lists:keysort(2, maps:to_list(NonExisting))), 1, 100), - formatByCnt(<<"They sent the most messages to dead processes">>, List, State). + List = lists:sublist(lists:reverse(lists:keysort(2, maps:to_list(NonExisting))), 1, 100), + formatByCnt(<<"They sent the most messages to dead processes">>, List, State). formatByCnt(Title, List, State) -> - MsgCols = case io:columns() of {ok, Cols} -> Cols;_ -> 80 end, - io:format( - "~n~s~n~s~n~n" - "Process ID Count (Label) OR Message sent~n" - "---------- ----- -----------------------~n", - [Title, lists:duplicate(byte_size(Title), $=)] - ), - [ - begin - {Prefix, Label, Suffix} = labelOrMsg(P, State), - io:format("~-15w ~-10b ~s~" ++ integer_to_list(MsgCols) ++ "P~s~n", [P, C, Prefix, Label, 5, Suffix]) - end || {P, C} <- List - ], - ok. + MsgCols = case io:columns() of {ok, Cols} -> Cols;_ -> 80 end, + io:format( + "~n~s~n~s~n~n" + "Process ID Count (Label) OR Message sent~n" + "---------- ----- -----------------------~n", + [Title, lists:duplicate(byte_size(Title), $=)] + ), + [ + begin + {Prefix, Label, Suffix} = labelOrMsg(P, State), + io:format("~-15w ~-10b ~s~" ++ integer_to_list(MsgCols) ++ "P~s~n", [P, C, Prefix, Label, 5, Suffix]) + end || {P, C} <- List + ], + ok. labelOrMsg(P, #state{meta = Meta, lastMsgs = LastMsgs}) -> - case maps:get(P, Meta, #{}) of - #{process_type := PT} -> - {"(", PT, ")"}; - _ -> - {"", maps:get(P, LastMsgs, ''), ""} - end. + case maps:get(P, Meta, #{}) of + #{process_type := PT} -> + {"(", PT, ")"}; + _ -> + {"", maps:get(P, LastMsgs, ''), ""} + end. flushMostActivePairUnidirectional(State = #state{pairs = Pairs}) -> - List = lists:sublist(lists:reverse(lists:keysort(2, maps:to_list(Pairs))), 1, 100), - Title = <<"They sent the most messages to one other process">>, - MsgCols = case io:columns() of {ok, Cols} -> Cols; _ -> 80 end, - io:format( - "~n~s~n~s~n~n" - "From pid To pid Count (Label) OR Message sent~n" - "-------- ------ ----- -----------------------~n", - [Title, lists:duplicate(byte_size(Title), $=)] - ), - [ - begin - {Prefix, Label, Suffix} = labelOrMsg(F, State), - io:format("~-15w ~-15w ~-10b ~s~" ++ integer_to_list(MsgCols) ++ "P~s~n", [F, T, C, Prefix, Label, 5, Suffix]) - end || {{F, T}, C} <- List - ], - ok. + List = lists:sublist(lists:reverse(lists:keysort(2, maps:to_list(Pairs))), 1, 100), + Title = <<"They sent the most messages to one other process">>, + MsgCols = case io:columns() of {ok, Cols} -> Cols; _ -> 80 end, + io:format( + "~n~s~n~s~n~n" + "From pid To pid Count (Label) OR Message sent~n" + "-------- ------ ----- -----------------------~n", + [Title, lists:duplicate(byte_size(Title), $=)] + ), + [ + begin + {Prefix, Label, Suffix} = labelOrMsg(F, State), + io:format("~-15w ~-15w ~-10b ~s~" ++ integer_to_list(MsgCols) ++ "P~s~n", [F, T, C, Prefix, Label, 5, Suffix]) + end || {{F, T}, C} <- List + ], + ok. flushMostActivePairBidirectional(State = #state{pairs = Pairs}) -> - TemPairs = maps:fold(fun mergePairs/3, #{}, Pairs), - List = lists:sublist(lists:reverse(lists:keysort(2, maps:to_list(TemPairs))), 1, 100), - Title = <<"They sent the most messages to each other">>, - MsgCols = case io:columns() of {ok, Cols} -> Cols;_ -> 80 end, - io:format( - "~n~s~n~s~n~n" - "Count Pid 1 (Label) OR Message sent~n" - " Pid 2 by the corresponding process~n" - "----- ----- ----------------------------~n", - [Title, lists:duplicate(byte_size(Title), $=)] - ), - [ - begin - {FPrefix, FLabel, FSuffix} = labelOrMsg(F, State), - {TPrefix, TLabel, TSuffix} = labelOrMsg(T, State), - io:format( - "~-10b ~-15w ~s~" ++ integer_to_list(MsgCols) ++ "P~s~n" - " ~-15w ~s~" ++ integer_to_list(MsgCols) ++ "P~s~n", [C, F, FPrefix, FLabel, 5, FSuffix, T, TPrefix, TLabel, 5, TSuffix]) - end || {{F, T}, C} <- List - ], - ok. + TemPairs = maps:fold(fun mergePairs/3, #{}, Pairs), + List = lists:sublist(lists:reverse(lists:keysort(2, maps:to_list(TemPairs))), 1, 100), + Title = <<"They sent the most messages to each other">>, + MsgCols = case io:columns() of {ok, Cols} -> Cols;_ -> 80 end, + io:format( + "~n~s~n~s~n~n" + "Count Pid 1 (Label) OR Message sent~n" + " Pid 2 by the corresponding process~n" + "----- ----- ----------------------------~n", + [Title, lists:duplicate(byte_size(Title), $=)] + ), + [ + begin + {FPrefix, FLabel, FSuffix} = labelOrMsg(F, State), + {TPrefix, TLabel, TSuffix} = labelOrMsg(T, State), + io:format( + "~-10b ~-15w ~s~" ++ integer_to_list(MsgCols) ++ "P~s~n" + " ~-15w ~s~" ++ integer_to_list(MsgCols) ++ "P~s~n", [C, F, FPrefix, FLabel, 5, FSuffix, T, TPrefix, TLabel, 5, TSuffix]) + end || {{F, T}, C} <- List + ], + ok. flushDigraph(#state{pairs = Pairs} = State) -> - TemPairs = maps:fold(fun groupPairs/3, #{}, Pairs), - List = maps:to_list(TemPairs), - HeaderBin = - <<"digraph {\n" - " concentrate=true;\n" - " splines=ortho;\n" - " edge [arrowhead=none, labelfontsize=12.0, minlen=3];\n" - "\n">>, - - writeEvents(List, State, HeaderBin), - - io:format( - "The file digraph.gv was created. Use GraphViz to make a PNG.~n" - "$ dot -Tpng -O digraph.gv~n" - "~n" - "You can also edit the file to remove uninteresting processes.~n" - "One line in the file is equal to a connection between two processes.~n"), - ok. + TemPairs = maps:fold(fun groupPairs/3, #{}, Pairs), + List = maps:to_list(TemPairs), + HeaderBin = + <<"digraph {\n" + " concentrate=true;\n" + " splines=ortho;\n" + " edge [arrowhead=none, labelfontsize=12.0, minlen=3];\n" + "\n">>, + + writeEvents(List, State, HeaderBin), + + io:format( + "The file digraph.gv was created. Use GraphViz to make a PNG.~n" + "$ dot -Tpng -O digraph.gv~n" + "~n" + "You can also edit the file to remove uninteresting processes.~n" + "One line in the file is equal to a connection between two processes.~n"), + ok. writeEvents([], _State, BinAcc) -> - LastBinAcc = <>, - ok = file:write_file(<<"digraph.gv">>, LastBinAcc); + LastBinAcc = <>, + ok = file:write_file(<<"digraph.gv">>, LastBinAcc); writeEvents([{{F, T}, {FC, TC}} | List], State, BinAcc) -> - EventBin = eFmt:formatBin(<<" \"~w~s\" -> \"~w~s\" [taillabel=~b, headlabel=~b];~n">>, [F, label(F, State), T, label(T, State), FC, TC]), - writeEvents(List, State, <>). + EventBin = eFmt:formatBin(<<" \"~w~s\" -> \"~w~s\" [taillabel=~b, headlabel=~b];~n">>, [F, label(F, State), T, label(T, State), FC, TC]), + writeEvents(List, State, <>). label(P, #state{meta = Meta}) -> - case maps:get(P, Meta, #{}) of - #{process_type := PT} -> - eFmt:format(<<" (~w)">>, [PT]); - _ -> - <<"">> - end. + case maps:get(P, Meta, #{}) of + #{process_type := PT} -> + eFmt:format(<<" (~w)">>, [PT]); + _ -> + <<"">> + end. mergePairs({From, To}, Count, Acc) -> - Key = case From < To of true -> {From, To};_ -> {To, From} end, - OldCount = maps:get(Key, Acc, 0), - Acc#{Key => OldCount + Count}. + Key = case From < To of true -> {From, To};_ -> {To, From} end, + OldCount = maps:get(Key, Acc, 0), + Acc#{Key => OldCount + Count}. groupPairs({From, To}, Count, Acc) when From < To -> - Key = {From, To}, - {_, AccCount} = maps:get(Key, Acc, {0, 0}), - Acc#{Key => {Count, AccCount}}; + Key = {From, To}, + {_, AccCount} = maps:get(Key, Acc, {0, 0}), + Acc#{Key => {Count, AccCount}}; groupPairs({From, To}, Count, Acc) -> - Key = {To, From}, - {AccCount, _} = maps:get(Key, Acc, {0, 0}), - Acc#{Key => {AccCount, Count}}. + Key = {To, From}, + {AccCount, _} = maps:get(Key, Acc, {0, 0}), + Acc#{Key => {AccCount, Count}}. diff --git a/src/messages/tpMsgSD.erl b/src/messages/tpMsgSD.erl index 08ddeaa..1a7d263 100644 --- a/src/messages/tpMsgSD.erl +++ b/src/messages/tpMsgSD.erl @@ -3,73 +3,73 @@ -include("eTpf.hrl"). -export([ - pfs/2 %% 分析单个文件 - , pfm/2 %% 分析多个文件 + pfs/2 %% 分析单个文件 + , pfm/3 %% 分析多个文件 ]). -record(state, { - meta = #{} :: map(), - events = [], - pids + meta = #{} :: map(), + events = [], + pids }). -spec pfs(file:filename_all(), list()) -> ok. pfs(InputFile, Pids) -> - {ok, FinalState} = tpFReader:fold(fun handleEvent/2, #state{pids = preparePids(Pids)}, InputFile), - flush(FinalState). + {ok, FinalState} = tpFReader:fold(fun handleEvent/2, #state{pids = preparePids(Pids)}, InputFile), + flush(FinalState). --spec pfm(file:filename(), list()) -> ok. -pfm(InputFiles, Pids) -> - PfFiles = filelib:wildcard(InputFiles), - doPfm(PfFiles, #state{pids = preparePids(Pids)}). +-spec pfm(file:filename(), filelib:dirname(), list()) -> ok. +pfm(InputFiles, Cwd, Pids) -> + PfFiles = filelib:wildcard(InputFiles, Cwd), + doPfm(PfFiles, #state{pids = preparePids(Pids)}). doPfm([], State) -> - flush(State); + flush(State); doPfm([InputFile | PfFiles], State) -> - {ok, NewState} = tpFReader:fold(fun handleEvent/2, State, InputFile), - doPfm(PfFiles, NewState). + {ok, NewState} = tpFReader:fold(fun handleEvent/2, State, InputFile), + doPfm(PfFiles, NewState). handleEvent({send, From, _, Info, ?eTpfHole}, State = #state{meta = Meta}) -> - NewMeta = - case Meta of - #{From := OldInfo} -> - Meta#{From => maps:merge(OldInfo, Info)}; - _ -> - Meta#{From => Info} - end, - State#state{meta = NewMeta}; + NewMeta = + case Meta of + #{From := OldInfo} -> + Meta#{From => maps:merge(OldInfo, Info)}; + _ -> + Meta#{From => Info} + end, + State#state{meta = NewMeta}; handleEvent({send, From, _, _, To} = Event, State) -> - maybeKeepEvent(Event, From, To, State); + maybeKeepEvent(Event, From, To, State); handleEvent({send_to_non_existing_process, From, _, _, To} = Event, State) -> - maybeKeepEvent(Event, From, To, State); + maybeKeepEvent(Event, From, To, State); handleEvent({spawn, From, _, To, _} = Event, State) -> - maybeKeepEvent(Event, From, To, State); + maybeKeepEvent(Event, From, To, State); handleEvent({exit, Pid0, _, _} = Event, State = #state{events = Events, pids = Pids}) -> - Pid = hidePidNode(Pid0), - case lists:member(Pid, Pids) of - true -> - State#state{events = [Event | Events]}; - _ -> - State - end; + Pid = hidePidNode(Pid0), + case lists:member(Pid, Pids) of + true -> + State#state{events = [Event | Events]}; + _ -> + State + end; %% Ignore all other events. We only care about messages and spawns/exits. handleEvent(_, State) -> - State. + State. maybeKeepEvent(Event, From0, To0, State = #state{events = Events, pids = Pids}) -> - From = hidePidNode(From0), - To = hidePidNode(To0), - case {lists:member(From, Pids), lists:member(To, Pids)} of - {true, true} -> State#state{events = [Event | Events]}; - _ -> State - end. + From = hidePidNode(From0), + To = hidePidNode(To0), + case {lists:member(From, Pids), lists:member(To, Pids)} of + {true, true} -> State#state{events = [Event | Events]}; + _ -> State + end. preparePids(Pids) -> - Pids. + Pids. %% [hide_pid_node(Pid) || Pid <- Pids]. hidePidNode(Pid) when is_pid(Pid) -> - Pid; + Pid; %%hide_pid_node(pid_to_list(Pid)); hidePidNode([$<, _, $. | Tail]) -> "<***." ++ Tail; hidePidNode([$<, _, _, $. | Tail]) -> "<***." ++ Tail; @@ -79,66 +79,66 @@ hidePidNode([$<, _, _, _, _, _, $. | Tail]) -> "<***." ++ Tail; hidePidNode(Name) -> Name. flush(#state{events = Events} = State) -> - %% Sort by timestamp from oldest to newest. - SortEvents = lists:keysort(3, Events), - %% Initialize the formatting state. - put(num_calls, 0), - %% Output everything. - HeaderBin = <<"seqdiag {\n" - " edge_length = 300;\n" - " activation = none;\n" - "\n">>, - - writeEvents(SortEvents, State, HeaderBin), - - io:format( - "The file seq.diag was created. Use seqdiag to make a PNG.~n" - "$ seqdiag -Tpng --no-transparency seq.diag~n" - "~n" - "To use a custom font, use the -f modifier:~n" - "$ seqdiag -Tpng --no-transparency -f /usr/share/fonts/TTF/verdana.ttf seq.diag~n" - "~n" - "You can also edit the file to remove uninteresting messages.~n" - "One line in the file is equal to a message sent by a process to another.~n"), - ok. + %% Sort by timestamp from oldest to newest. + SortEvents = lists:keysort(3, Events), + %% Initialize the formatting state. + put(num_calls, 0), + %% Output everything. + HeaderBin = <<"seqdiag {\n" + " edge_length = 300;\n" + " activation = none;\n" + "\n">>, + + writeEvents(SortEvents, State, HeaderBin), + + io:format( + "The file seq.diag was created. Use seqdiag to make a PNG.~n" + "$ seqdiag -Tpng --no-transparency seq.diag~n" + "~n" + "To use a custom font, use the -f modifier:~n" + "$ seqdiag -Tpng --no-transparency -f /usr/share/fonts/TTF/verdana.ttf seq.diag~n" + "~n" + "You can also edit the file to remove uninteresting messages.~n" + "One line in the file is equal to a message sent by a process to another.~n"), + ok. writeEvents([], _State, BinAcc) -> - LastBinAcc = <>, - ok = file:write_file(<<"seq.diag">>, LastBinAcc); + LastBinAcc = <>, + ok = file:write_file(<<"seq.diag">>, LastBinAcc); writeEvents([Event | SortEvents], State, BinAcc) -> - EventBin = formatEvent(Event, State), - writeEvents(SortEvents, State, <>). + EventBin = formatEvent(Event, State), + writeEvents(SortEvents, State, <>). formatEvent({spawn, From, _, To, MFA}, State) -> - eFmt:formatBin(<<" \"~w~s\" ->> \"~w~s\" [label=\"spawn ~9999P\"];~n">>, [From, label(From, State), To, label(To, State), MFA, 8]); + eFmt:formatBin(<<" \"~w~s\" ->> \"~w~s\" [label=\"spawn ~9999P\"];~n">>, [From, label(From, State), To, label(To, State), MFA, 8]); formatEvent({exit, Pid, _, Reason}, State) -> - PidLabel = label(Pid, State), - eFmt:formatBin(<<" \"~w~s\" ->> \"~w~s\" [label=\"exit ~9999P\"];~n">>, [Pid, PidLabel, Pid, PidLabel, Reason, 8]); + PidLabel = label(Pid, State), + eFmt:formatBin(<<" \"~w~s\" ->> \"~w~s\" [label=\"exit ~9999P\"];~n">>, [Pid, PidLabel, Pid, PidLabel, Reason, 8]); formatEvent({Type, From, _, {'$gen_call', {From, Ref}, Msg}, To}, State) -> - NumCalls = get(num_calls) + 1, - put(num_calls, NumCalls), - put(Ref, NumCalls), - eFmt:formatBin(<<" \"~w~s\" ~s \"~w~s\" [label=\"gen:call #~w ~9999P\"];~n">>, [From, label(From, State), case Type of send -> - "->"; _ -> "-->" end, To, label(To, State), NumCalls, Msg, 8]); + NumCalls = get(num_calls) + 1, + put(num_calls, NumCalls), + put(Ref, NumCalls), + eFmt:formatBin(<<" \"~w~s\" ~s \"~w~s\" [label=\"gen:call #~w ~9999P\"];~n">>, [From, label(From, State), case Type of send -> + "->"; _ -> "-->" end, To, label(To, State), NumCalls, Msg, 8]); formatEvent(Event = {Type, From, _, {Ref, Msg}, To}, State) -> - case get(Ref) of - undefined -> - defFormatEvent(Event, State); - NumCall -> - eFmt:formatBin(<<" \"~w~s\" ~s \"~w~s\" [label=\"#~w ~9999P\"];~n">>, [From, label(From, State), case Type of send -> - "->"; _ -> "-->" end, To, label(To, State), NumCall, Msg, 8]) - end; + case get(Ref) of + undefined -> + defFormatEvent(Event, State); + NumCall -> + eFmt:formatBin(<<" \"~w~s\" ~s \"~w~s\" [label=\"#~w ~9999P\"];~n">>, [From, label(From, State), case Type of send -> + "->"; _ -> "-->" end, To, label(To, State), NumCall, Msg, 8]) + end; formatEvent(Event, State) -> - defFormatEvent(Event, State). + defFormatEvent(Event, State). defFormatEvent({Type, From, _, Msg, To}, State) -> - eFmt:formatBin(<<" \"~w~s\" ~s \"~w~s\" [label=\"~9999P\"];~n">>, [From, label(From, State), case Type of send -> - "->"; _ -> "-->" end, To, label(To, State), Msg, 8]). + eFmt:formatBin(<<" \"~w~s\" ~s \"~w~s\" [label=\"~9999P\"];~n">>, [From, label(From, State), case Type of send -> + "->"; _ -> "-->" end, To, label(To, State), Msg, 8]). label(P, #state{meta = Meta}) -> - case maps:get(P, Meta, #{}) of - #{process_type := PT} -> - eFmt:formatBin(" (~w)", [PT]); - _ -> - <<"">> - end. + case maps:get(P, Meta, #{}) of + #{process_type := PT} -> + eFmt:formatBin(" (~w)", [PT]); + _ -> + <<"">> + end.