瀏覽代碼

ft: 代码修改

master
SisMaker 3 年之前
父節點
當前提交
e11f7c3317
共有 3 個文件被更改,包括 478 次插入87 次删除
  1. +166
    -87
      src/eTpf.erl
  2. +201
    -0
      src/gcColl/tpGcColl.erl
  3. +111
    -0
      trace说明.md

+ 166
- 87
src/eTpf.erl 查看文件

@ -3,122 +3,201 @@
-include("eTpf.hrl").
-export([
sts/0
, stl/0
, stf/0
, trace/1
, trace/2
, trace/3
, trace/4
, stop/0
, stop/1
%%
sts/0 %% tpTracerShell
, stl/0 %% tpTracerLog
, stf/0 %% tpTracerFile
%% pt函数
, pts/0 %% tpTracerShell
, ptl/0 %% tpTracerLog
, ptf/0 %% tpTracerFile
%% pf函数
, rsPfs/1
, rsPfm/2
, sdPfs/2
, sdPfm/3
, flPfs/2
, flPfm/3
, cgPfs/2
, cgPfs/3
, cgPfm/3
, cgPfm/4
%% trace函数
, trace/1
, trace/2
, trace/3
, trace/4
, stop/0
, stop/1
]).
sts() ->
trace([{scope, [all]}]).
trace([{scope, [all]}]).
stl() ->
trace([{scope, [new_processes]}], tpTracerLog).
trace([{app, eSync}, {scope, [new_processes]}], tpTracerLog).
stf() ->
trace([{scope, [new_processes]}], tpTracerFile).
trace([{scope, [new_processes]}], tpTracerFile).
pts() ->
ok.
ptl() ->
ok.
ptf() ->
ok.
rsPfs(InputFile) ->
tpMsgRS:pfs(InputFile).
rsPfm(InputFiles, Cwd) ->
tpMsgRS:pfm(InputFiles, Cwd).
sdPfs(InputFile, Pids) ->
tpMsgSD:pfs(InputFile, Pids).
sdPfm(InputFiles, Cwd, Pids) ->
tpMsgSD:pfm(InputFiles, Cwd, Pids).
flPfs(InputFile, OutputPath) ->
tpFlame:pfs(InputFile, OutputPath).
flPfm(InputFiles, Cwd, OutputPath) ->
tpFlame:pfm(InputFiles, Cwd, OutputPath).
cgPfs(InputFile, Output) ->
tpCallGrind:pfs(InputFile, Output).
cgPfs(InputFile, Output, Opts) ->
tpCallGrind:pfs(InputFile, Output, Opts).
cgPfm(Wildcard, Cwd, Prefix) ->
tpCallGrind:pfm(Wildcard, Cwd, Prefix).
cgPfm(Wildcard, Cwd, Prefix, Opts) ->
tpCallGrind:pfm(Wildcard, Cwd, Prefix, Opts).
-spec trace(userInput()) -> ok.
trace(Input) ->
trace(Input, tpTracerShell).
trace(Input, tpTracerShell).
-spec trace(userInput(), module()) -> ok.
trace(Input, TracerMod) ->
trace(Input, TracerMod, #{}, #{}).
trace(Input, TracerMod, #{}, #{}).
-spec trace(userInput(), module(), tracerOpts()) -> ok.
trace(Input, TracerMod, TracerOpts) ->
trace(Input, TracerMod, TracerOpts, #{}).
trace(Input, TracerMod, TracerOpts, #{}).
-spec trace(userInput(), module(), tracerOpts(), traceOpts()) -> ok.
trace(Input, TracerMod, TracerOpts, TraceOpts) when is_list(Input) ->
InputList = case is_list(Input) of true -> Input; _ -> [Input] end,
do_trace(InputList, TracerMod, TracerOpts, TraceOpts).
do_trace(InputList, TracerMod, TracerOpts, TraceOpts) ->
_ = application:ensure_all_started(eTpf),
TracerId = maps:get(tracerId, TraceOpts, ?eTpfTracerId),
{ok, TracerPid} = supervisor:start_child(eTpf_sup, #{
id => TracerId,
start => {TracerMod, start_link, [TracerOpts]},
restart => temporary,
type => worker
}),
_Mode = maps:get(mode, TraceOpts, trace),
Tem0InputList = flattenInput(InputList, []),
Tem1InputList = ensurePattern(Tem0InputList),
LastInputList = ensureScope(Tem1InputList),
traceInput(LastInputList, TracerPid, TraceOpts),
ok.
InputList = case is_list(Input) of true -> Input; _ -> [Input] end,
doTrace(InputList, TracerMod, TracerOpts, TraceOpts).
stop() ->
stop(?eTpfTracerId).
stop(TracerId) ->
supervisor:terminate_child(eTpf_sup, TracerId).
doTrace(InputList, TracerMod, TracerOpts, TraceOpts) ->
_ = application:ensure_all_started(eTpf),
TracerId = maps:get(tracerId, TraceOpts, ?eTpfTracerId),
{ok, TracerPid} = supervisor:start_child(eTpf_sup, #{
id => TracerId,
start => {TracerMod, start_link, [TracerOpts]},
restart => temporary,
type => worker
}),
_Mode = maps:get(mode, TraceOpts, trace),
Tem0InputList = flattenInput(InputList, []),
Tem1InputList = ensurePattern(Tem0InputList),
LastInputList = ensureScope(Tem1InputList),
traceInput(LastInputList, TracerPid, TraceOpts),
ok.
flattenInput([], Acc) ->
lists:flatten(Acc);
lists:flatten(Acc);
flattenInput([{callback, Mod, Fun} | Tail], Acc) when is_atom(Mod), is_atom(Fun) ->
Input = flattenInput(Mod:Fun(), []),
flattenInput(Tail, [Input | Acc]);
Input = flattenInput(Mod:Fun(), []),
flattenInput(Tail, [Input | Acc]);
flattenInput([{app, App} | Tail], Acc) when is_atom(App) ->
_ = application:load(App),
{ok, Mods} = application:get_key(App, modules),
flattenInput(Tail, [Mods | Acc]);
_ = application:load(App),
{ok, Mods} = application:get_key(App, modules),
flattenInput(Tail, [Mods | Acc]);
flattenInput([Input | Tail], Acc) ->
flattenInput(Tail, [Input | Acc]).
flattenInput(Tail, [Input | Acc]).
ensurePattern(Input) ->
case [S || S = {scope, _} <- Input] of
Input -> ['_' | Input];
_ -> Input
end.
case [S || S = {scope, _} <- Input] of
Input -> ['_' | Input];
_ -> Input
end.
ensureScope(Input) ->
case [S || S = {scope, _} <- Input] of
[] -> [{scope, [processes]} | Input];
_ -> Input
end.
case [S || S = {scope, _} <- Input] of
[] -> [{scope, [processes]} | Input];
_ -> Input
end.
traceInput([], _, _) ->
ok;
ok;
traceInput([{scope, Scope} | Tail], TracerState, TraceOpts) ->
%% We currently enable the following trace flags:
%% - call: function calls
%% - procs: process exit events; plus others we ignore
%% - running: process being scheduled in/out
%% - timestamp: events include the current timestamp
%% - arity: function calls only include the arity, not arguments
%% - return_to: return from functions
%% - set_on_spawn: propagate trace flags to any children processes
%%
%% @todo It might be useful to count the number of sends
%% or receives a function does.
ExtraFlags = [running || maps:get(running, TraceOpts, false)] ++ [send || maps:get(send, TraceOpts, false)],
[
begin
erlang:trace(PidPortSpec, true, [call, procs, arity, return_to, set_on_spawn, {tracer, tpTracerNif, TracerState} | ExtraFlags])
end || PidPortSpec <- Scope
],
traceInput(Tail, TracerState, TraceOpts);
% tracer进行跟踪
% PidPortSpec
%% all All currently existing processes and ports and all that will be created in the future.
%% processes All currently existing processes and all that will be created in the future.
%% ports All currently existing ports and all that will be created in the future.
%% existing All currently existing processes and ports.
%% existing_processes All currently existing processes.
%% existing_ports All currently existing ports.
%% new All processes and ports that will be created in the future.
%% new_processes All processes that will be created in the future.
%% new_ports All ports that will be created in the future.
% FlagList
%% We currently enable the following trace flags:
%% - call: function calls
%% - procs: process exit events; plus others we ignore
%% - running: process being scheduled in/out
%% - timestamp: events include the current timestamp
%% - arity: function calls only include the arity, not arguments
%% - return_to: return from functions
%% - set_on_spawn: propagate trace flags to any children processes
%%
%% @todo It might be useful to count the number of sends
%% or receives a function does.
%ExtraFlags = [running || maps:get(running, TraceOpts, false)] ++ [send || maps:get(send, TraceOpts, false)],
[
begin
%erlang:trace(PidPortSpec, true, [call, procs, arity, return_to, set_on_spawn, {tracer, tpTracerNif, TracerState} | ExtraFlags])
erlang:trace(PidPortSpec, true, [procs, send, 'receive', running, exiting, arity, set_on_spawn, {tracer, tpTracerNif, TracerState}])
end || PidPortSpec <- Scope
],
traceInput(Tail, TracerState, TraceOpts);
traceInput([Mod | Tail], TracerState, TraceOpts) when is_atom(Mod) ->
MatchSpec =
case TraceOpts of
#{process_dump := true} ->
[{'_', [], [{message, {process_dump}}]}];
_ ->
true
end,
%% The module must be loaded before we attempt to trace it.
_ = code:ensure_loaded(Mod),
_ = erlang:trace_pattern({Mod, '_', '_'}, MatchSpec, [local]),
traceInput(Tail, TracerState, TraceOpts).
stop() ->
stop(?eTpfTracerId).
stop(TracerId) ->
supervisor:terminate_child(eTpf_sup, TracerId).
MatchSpec =
case TraceOpts of
#{process_dump := true} ->
[{'_', [], [{message, {process_dump}}]}];
_ ->
true
end,
%% The module must be loaded before we attempt to trace it.
_ = code:ensure_loaded(Mod),
_ = erlang:trace_pattern({Mod, '_', '_'}, MatchSpec, [local]),
io:format("IMY*************** ~p \n", [Mod]),
traceInput(Tail, TracerState, TraceOpts).

+ 201
- 0
src/gcColl/tpGcColl.erl 查看文件

@ -0,0 +1,201 @@
-module(tpGcColl). %%
-include("eTpf.hrl").
-export([
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()}
}).
-spec pfs(file:filename_all()) -> ok.
pfs(InputFile) ->
{ok, FinalState} = tpFReader:fold(fun handleEvent/2, #state{}, InputFile),
flush(FinalState).
-spec pfm(file:filename(), filelib:dirname()) -> ok.
pfm(InputFiles, Cwd) ->
PfFiles = lists:sort(filelib:wildcard(InputFiles, Cwd)),
doPfm(PfFiles, #state{}).
doPfm([], State) ->
flush(State);
doPfm([InputFile | PfFiles], State) ->
{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};
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}
};
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}};
%% Ignore all other events. We only care about messages.
handleEvent(_, 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 = #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).
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).
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).
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.
labelOrMsg(P, #state{meta = Meta, lastMsgs = LastMsgs}) ->
case maps:get(P, Meta, #{}) of
#{process_type := PT} ->
{"(", PT, ")"};
_ ->
{"", maps:get(P, LastMsgs, '<none>'), ""}
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.
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.
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.
writeEvents([], _State, BinAcc) ->
LastBinAcc = <<BinAcc/binary, "}\n">>,
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, <<BinAcc/binary, EventBin/binary>>).
label(P, #state{meta = Meta}) ->
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}.
groupPairs({From, To}, Count, Acc) when From < To ->
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}}.

+ 111
- 0
trace说明.md 查看文件

@ -0,0 +1,111 @@
# PidPortSpec
每个进程只能由一个tracer进行跟踪。因此,跟踪已跟踪进程会失败。
all All currently existing processes and ports and all that will be created in the future.
processes All currently existing processes and all that will be created in the future.
ports All currently existing ports and all that will be created in the future.
existing All currently existing processes and ports.
existing_processes All currently existing processes.
existing_ports All currently existing ports.
new All processes and ports that will be created in the future.
new_processes All processes that will be created in the future.
new_ports All ports that will be created in the future.
# FlagList
all 设置除tracer和 cpu_timestamp之外的所有跟踪标志
send 跟踪消息的发送 MsgTags: send and send_to_non_existing_process.
receive 跟踪消息的接收 MsgTags: receive.
call 跟踪某些函数调用。通过调用erlang:trace_pattern/3指定要跟踪的函数调用。 MsgTags: call and return_from.
silent 与call跟踪标志一起使用。当着标志设置后 MsgTags: call,return_from return_to 被禁止, 但如果有match specifications时他们正常执行。通过执行erlang:trace(_, false, [silent|_])或执行函数{silent, false}的匹配规范来 禁止静默模式 。
在silent 的跟踪标志有利于建立许多甚至在系统中的所有进程痕迹。然后可以使用匹配规范函数{silent,Bool}激活和停用跟踪,从而高度控制哪些函数使用哪些参数触发跟踪。
MsgTags: call, return_from, and return_to. Or rather, the absence of.
return_to 与call跟踪标志一起使用。跟踪从被跟踪函数返回到其调用者的返回. Only works for functions traced with option local to erlang:trace_pattern/3.
语义是当调用跟踪函数返回时发送跟踪消息,即当一串尾递归调用结束时。每个尾递归调用链仅发送一条跟踪消息,因此在使用此标志进行跟踪时,函数调用的尾递归属性将被保留。一起使用call和return_to trace 可以随时准确地知道进程在哪个函数中执行。 要获取包含函数返回值的跟踪消息,请改用{return_trace}匹配规范操作。
MsgTags: return_to.
procs 跟踪process-related的事件 MsgTags: spawn, spawned, exit, register, unregister, link, unlink, getting_linked, and getting_unlinked.
ports 跟踪 port-related 的事件. MsgTags: open, closed, register, unregister, getting_linked, and getting_unlinked.
running 跟踪 processes 调度. MsgTags: in and out.
exiting 跟踪 scheduling of exiting processes. MsgTags: in_exiting, out_exiting, and out_exited.
running_procs 跟踪进程的调度就像 running . 但是,此选项还包括进程在端口上下文中执行而不是自行调度时的调度事件。 MsgTags: in and out.
running_ports 跟踪 scheduling of ports. MsgTags: in and out.
garbage_collection 跟踪 garbage collections of processes. MsgTags: gc_minor_start, gc_max_heap_size, and gc_minor_end.
arity Used with the call trace flag. {M, F, Arity} is specified instead of {M, F, Args} in call trace messages.
set_on_spawn 使被跟踪进程创建的任何进程继承其跟踪标志,包括标志set_on_spawn。
set_on_first_spawn 使被跟踪进程创建的第一个进程继承其跟踪标志,不包括标志 set_on_first_spawn。
set_on_link Makes any process linked by a traced process inherit its trace flags, including flag set_on_link.
set_on_first_link Makes the first process linked to by a traced process inherit its trace flags, excluding flag set_on_first_link.
# 额外注释
如果未指定跟踪器,则调用进程将接收所有跟踪消息。
同时设置set_on_first_link与 set_on_link的时只有set_on_first_link生效 。同样对于 set_on_spawn和set_on_first_spawn。
如果一个match specification(仅适用于call、send 和'receive'跟踪)包含具有非布尔值的{message}action function,则该值将作为额外元素添加到消息元组的最后一个位置或之前时间戳(如果存在)。
# trace msg
{send, PidPort, Ts, Msg, To}
当PidPort发送消息Msg来处理To
{send_to_non_existing_process, PidPort, Ts, Msg, To}
当PidPort向不存在的进程To发送消息Msg 时。
{'receive', PidPort, Ts, Msg}
当PidPort收到消息Msg 时。如果Msg设置为超时,则接收语句可能已超时,或者进程收到带有有效负载timeout的消息。
{call, Pid, Ts, {M, F, Args}}
当Pid调用跟踪函数时。从不提供调用的返回值,只提供调用及其参数。跟踪标志arity可用于更改此消息的内容,以便 指定Arity而不是Args。
{return_to, Pid, Ts, {M, F, Arity}}
When Pid returns to the specified function. This trace message is sent if both the flags call and return_to are set,
and the function is set to be traced on local function calls. The message is only sent when returning from a chain of
tail recursive function calls, where at least one call generated a call trace message (that is, the functions match
specification matched, and {message, false} was not an action).
{return_from, Pid, Ts, {M, F, Arity}, ReturnValue}
When Pid returns from the specified function. This trace message is sent if flag call is set,
and the function has a match specification with a return_trace or exception_trace action.
{exception_from, Pid, Ts, {M, F, Arity}, {Class, Value}}
When Pid exits from the specified function because of an exception. This trace message is sent if flag call is set,
and the function has a match specification with an exception_trace action.
{spawn, Pid, Ts, Pid2, {M, F, Args}}
When Pid spawns a new process Pid2 with the specified function call as entry point.
Args is supposed to be the argument list, but can be any term if the spawn is erroneous.
{spawned, Pid, Ts, Pid2, {M, F, Args}}
When Pid is spawned by process Pid2 with the specified function call as entry point.
Args is supposed to be the argument list, but can be any term if the spawn is erroneous.
{exit, Pid, Ts, Reason} When Pid exits with reason Reason.
{register, PidPort, Ts, RegName} When PidPort gets the name RegName registered.
{unregister, PidPort, Ts, RegName} When PidPort gets the name RegName unregistered. This is done automatically when a registered process or port exits.
{link, Pid, Ts, Pid2} When Pid links to a process Pid2.
{unlink, Pid, Ts, Pid2} When Pid removes the link from a process Pid2.
{getting_linked, PidPort, Ts, Pid2} When PidPort gets linked to a process Pid2.
{getting_unlinked, PidPort, Ts, Pid2} When PidPort gets unlinked from a process Pid2.
{open, Port, Ts, Pid, Driver} When Pid opens a new port Port with the running Driver. Driver is the name of the driver as an atom.
{closed, Port, Ts, Reason} When Port closes with Reason.
{in | in_exiting, Pid, Ts, {M, F, Arity} | 0} When Pid is scheduled to run. The process runs in function {M, F, Arity}. On some rare occasions, the current function cannot be determined, then the last element is 0.
{out | out_exiting | out_exited, Pid, Ts, {M, F, Arity} | 0} When Pid is scheduled out. The process was running in function {M, F, Arity}. On some rare occasions, the current function cannot be determined, then the last element is 0.
{in, Port, Ts, Command | 0} When Port is scheduled to run. Command is the first thing the port will execute, it can however run several commands before being scheduled out. On some rare occasions, the current function cannot be determined, then the last element is 0. The possible commands are call, close, command, connect, control, flush, info, link, open, and unlink.
{out, Port, Ts, Command | 0} When Port is scheduled out. The last command run was Command. On some rare occasions, the current function cannot be determined, then the last element is 0. Command can contain the same commands as in
{gc_minor_start, Pid, Ts, Info} Sent when a young garbage collection is about to be started. Info is a list of two-element tuples, where the first element is a key, and the second is the value. Do not depend on any order of the tuples. The following keys are defined:
heap_size
The size of the used part of the heap.
heap_block_size
The size of the memory block used for storing the heap and the stack.
old_heap_size
The size of the used part of the old heap.
old_heap_block_size
The size of the memory block used for storing the old heap.
stack_size
The size of the stack.
recent_size
The size of the data that survived the previous garbage collection.
mbuf_size
The combined size of message buffers associated with the process.
bin_vheap_size
The total size of unique off-heap binaries referenced from the process heap.
bin_vheap_block_size
The total size of binaries allowed in the virtual heap in the process before doing a garbage collection.
bin_old_vheap_size
The total size of unique off-heap binaries referenced from the process old heap.
bin_old_vheap_block_size
The total size of binaries allowed in the virtual old heap in the process before doing a garbage collection.
wordsize
For the gc_minor_start event it is the size of the need that triggered the GC. For the corresponding gc_minor_end event it is the size of reclaimed memory = start heap_size - end heap_size.
All sizes are in words.
{gc_max_heap_size, Pid, Ts, Info} Sent when the max_heap_size is reached during garbage collection. Info contains the same kind of list as in message gc_start, but the sizes reflect the sizes that triggered max_heap_size to be reached.
{gc_minor_end, Pid, Ts, Info} Sent when young garbage collection is finished. Info contains the same kind of list as in message gc_minor_start, but the sizes reflect the new sizes after garbage collection.
{gc_major_start, Pid, Ts, Info} Sent when fullsweep garbage collection is about to be started. Info contains the same kind of list as in message gc_minor_start.
{gc_major_end, Pid, Ts, Info} Sent when fullsweep garbage collection is finished. Info contains the same kind of list as in message gc_minor_start, but the sizes reflect the new sizes after a fullsweep garbage collection.

Loading…
取消
儲存