You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
4.8 KiB

пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
пре 3 година
  1. -module(tpMsgSD). %% 进程消息时序分析
  2. -include("eTpf.hrl").
  3. -export([
  4. pfs/2 %% 分析单个文件
  5. , pfm/2 %% 分析多个文件
  6. ]).
  7. -record(state, {
  8. meta = #{} :: map(),
  9. events = [],
  10. pids
  11. }).
  12. -spec pfs(file:filename_all(), list()) -> ok.
  13. pfs(InputFile, Pids) ->
  14. {ok, FinalState} = tpFReader:fold(fun handleEvent/2, #state{pids = preparePids(Pids)}, InputFile),
  15. flush(FinalState).
  16. -spec pfm(file:filename(), list()) -> ok.
  17. pfm(InputFiles, Pids) ->
  18. PfFiles = filelib:wildcard(InputFiles),
  19. doPfm(PfFiles, #state{pids = preparePids(Pids)}).
  20. doPfm([], State) ->
  21. flush(State);
  22. doPfm([InputFile | PfFiles], State) ->
  23. {ok, NewState} = tpFReader:fold(fun handleEvent/2, State, InputFile),
  24. doPfm(PfFiles, NewState).
  25. handleEvent({send, From, _, Info, ?eTpfHole}, State = #state{meta = Meta}) ->
  26. NewMeta =
  27. case Meta of
  28. #{From := OldInfo} ->
  29. Meta#{From => maps:merge(OldInfo, Info)};
  30. _ ->
  31. Meta#{From => Info}
  32. end,
  33. State#state{meta = NewMeta};
  34. handleEvent({send, From, _, _, To} = Event, State) ->
  35. maybeKeepEvent(Event, From, To, State);
  36. handleEvent({send_to_non_existing_process, From, _, _, To} = Event, State) ->
  37. maybeKeepEvent(Event, From, To, State);
  38. handleEvent({spawn, From, _, To, _} = Event, State) ->
  39. maybeKeepEvent(Event, From, To, State);
  40. handleEvent({exit, Pid0, _, _} = Event, State = #state{events = Events, pids = Pids}) ->
  41. Pid = hidePidNode(Pid0),
  42. case lists:member(Pid, Pids) of
  43. true ->
  44. State#state{events = [Event | Events]};
  45. _ ->
  46. State
  47. end;
  48. %% Ignore all other events. We only care about messages and spawns/exits.
  49. handleEvent(_, State) ->
  50. State.
  51. maybeKeepEvent(Event, From0, To0, State = #state{events = Events, pids = Pids}) ->
  52. From = hidePidNode(From0),
  53. To = hidePidNode(To0),
  54. case {lists:member(From, Pids), lists:member(To, Pids)} of
  55. {true, true} -> State#state{events = [Event | Events]};
  56. _ -> State
  57. end.
  58. preparePids(Pids) ->
  59. Pids.
  60. %% [hide_pid_node(Pid) || Pid <- Pids].
  61. hidePidNode(Pid) when is_pid(Pid) ->
  62. Pid;
  63. %%hide_pid_node(pid_to_list(Pid));
  64. hidePidNode([$<, _, $. | Tail]) -> "<***." ++ Tail;
  65. hidePidNode([$<, _, _, $. | Tail]) -> "<***." ++ Tail;
  66. hidePidNode([$<, _, _, _, $. | Tail]) -> "<***." ++ Tail;
  67. hidePidNode([$<, _, _, _, _, $. | Tail]) -> "<***." ++ Tail;
  68. hidePidNode([$<, _, _, _, _, _, $. | Tail]) -> "<***." ++ Tail;
  69. hidePidNode(Name) -> Name.
  70. flush(#state{events = Events} = State) ->
  71. %% Sort by timestamp from oldest to newest.
  72. SortEvents = lists:keysort(3, Events),
  73. %% Initialize the formatting state.
  74. put(num_calls, 0),
  75. %% Output everything.
  76. HeaderBin = <<"seqdiag {\n"
  77. " edge_length = 300;\n"
  78. " activation = none;\n"
  79. "\n">>,
  80. writeEvents(SortEvents, State, HeaderBin),
  81. io:format(
  82. "The file seq.diag was created. Use seqdiag to make a PNG.~n"
  83. "$ seqdiag -Tpng --no-transparency seq.diag~n"
  84. "~n"
  85. "To use a custom font, use the -f modifier:~n"
  86. "$ seqdiag -Tpng --no-transparency -f /usr/share/fonts/TTF/verdana.ttf seq.diag~n"
  87. "~n"
  88. "You can also edit the file to remove uninteresting messages.~n"
  89. "One line in the file is equal to a message sent by a process to another.~n"),
  90. ok.
  91. writeEvents([], _State, BinAcc) ->
  92. LastBinAcc = <<BinAcc/binary, "}\n">>,
  93. ok = file:write_file(<<"seq.diag">>, LastBinAcc);
  94. writeEvents([Event | SortEvents], State, BinAcc) ->
  95. EventBin = formatEvent(Event, State),
  96. writeEvents(SortEvents, State, <<BinAcc/binary, EventBin/binary>>).
  97. formatEvent({spawn, From, _, To, MFA}, State) ->
  98. eFmt:formatBin(<<" \"~w~s\" ->> \"~w~s\" [label=\"spawn ~9999P\"];~n">>, [From, label(From, State), To, label(To, State), MFA, 8]);
  99. formatEvent({exit, Pid, _, Reason}, State) ->
  100. PidLabel = label(Pid, State),
  101. eFmt:formatBin(<<" \"~w~s\" ->> \"~w~s\" [label=\"exit ~9999P\"];~n">>, [Pid, PidLabel, Pid, PidLabel, Reason, 8]);
  102. formatEvent({Type, From, _, {'$gen_call', {From, Ref}, Msg}, To}, State) ->
  103. NumCalls = get(num_calls) + 1,
  104. put(num_calls, NumCalls),
  105. put(Ref, NumCalls),
  106. eFmt:formatBin(<<" \"~w~s\" ~s \"~w~s\" [label=\"gen:call #~w ~9999P\"];~n">>, [From, label(From, State), case Type of send ->
  107. "->"; _ -> "-->" end, To, label(To, State), NumCalls, Msg, 8]);
  108. formatEvent(Event = {Type, From, _, {Ref, Msg}, To}, State) ->
  109. case get(Ref) of
  110. undefined ->
  111. defFormatEvent(Event, State);
  112. NumCall ->
  113. eFmt:formatBin(<<" \"~w~s\" ~s \"~w~s\" [label=\"#~w ~9999P\"];~n">>, [From, label(From, State), case Type of send ->
  114. "->"; _ -> "-->" end, To, label(To, State), NumCall, Msg, 8])
  115. end;
  116. formatEvent(Event, State) ->
  117. defFormatEvent(Event, State).
  118. defFormatEvent({Type, From, _, Msg, To}, State) ->
  119. eFmt:formatBin(<<" \"~w~s\" ~s \"~w~s\" [label=\"~9999P\"];~n">>, [From, label(From, State), case Type of send ->
  120. "->"; _ -> "-->" end, To, label(To, State), Msg, 8]).
  121. label(P, #state{meta = Meta}) ->
  122. case maps:get(P, Meta, #{}) of
  123. #{process_type := PT} ->
  124. eFmt:formatBin(" (~w)", [PT]);
  125. _ ->
  126. <<"">>
  127. end.