gpt4 book ai didi

erlang - 在另一个进程上设置 seq_trace

转载 作者:行者123 更新时间:2023-12-02 09:42:10 24 4
gpt4 key购买 nike

我知道我可以在 erlang 中将 seq_trace 设置为当前正在执行的进程。但是如何从 shell 或远程 shell(如 dbg 跟踪)将其设置在另一个进程上?

最佳答案

您可以使用 dbg 在另一个进程上启用顺序跟踪。例如,假设我们有一个模块 x导出 call/2功能:

call(Pid, Msg) ->
Pid ! {self(), Msg},
receive
{Pid, Reply} -> Reply
end.

该函数实现了一个简单的调用响应。假设我们有一个模块 y具有循环接收器功能:

loop() ->
receive
{Pid, Msg} ->
seq_trace:print({?MODULE, self(), Pid, Msg}),
Pid ! {self(), {Msg, os:timestamp()}};
_ -> ok
end,
?MODULE:loop().

此函数需要 x:call/2 发送的形式的消息,当它收到一条消息时,如果启用,它会在顺序跟踪中打印一条消息,然后将原始消息发送回调用者并添加时间戳。它忽略所有其他消息。

我们还需要一个函数来收集顺序跟踪。递归systracer/1下面的函数只是收集 seq_trace将元组放入列表中,并生成 seq_trace 的列表询问时的消息:

systracer(Acc) ->
receive
{seq_trace,_,_,_}=S ->
systracer([S|Acc]);
{seq_trace,_,_}=S ->
systracer([S|Acc]);
{dump, Pid} ->
Pid ! lists:reverse(Acc),
systracer([]);
stop -> ok
end.

假设我们的 systracer/1函数从模块 x 导出也是如此。

让我们使用 Erlang shell 来设置这一切。首先,让我们生成 y:loop/0x:systracer/1 :

1> Y = spawn(y,loop,[]).
<0.36.0>
2> S = spawn(x,systracer,[[]]).
<0.38.0>
3> seq_trace:set_system_tracer(S).
false

产卵后x:systracer/1我们将进程设置为seq_trace系统跟踪器。现在我们需要开始dbg :

4> dbg:tracer(), dbg:p(all,call).
{ok,[{matched,nonode@nohost,28}]}

这些dbg调用非常标准,但您可以根据需要随意更改它们,特别是如果您计划使用 dbg在调试 session 期间也进行跟踪。

在实践中,当您使用 dbg 启用顺序跟踪时,您通常通过键入函数的特定参数来实现这一点。这使您能够获取特定于给定函数调用的跟踪,而无需获取该函数的所有调用的跟踪。沿着这些思路,我们将使用 dbg:tpl/3x:call/2 时打开顺序跟踪标志被调用,其第二个参数具有原子 trace 的值。首先,我们使用dbg:fun2ms/1创建适当的匹配规范来启用我们想要的顺序跟踪标志,然后我们将使用 dbg:tpl/3 应用匹配规范:

5> Ms = dbg:fun2ms(fun([_,trace]) -> set_seq_token(send,true), set_seq_token('receive',true), set_seq_token(print,true) end).
[{['_',trace],
[],
[{set_seq_token,send,true},
{set_seq_token,'receive',true},
{set_seq_token,print,true}]}]
6> dbg:tpl(x,call,Ms).
{ok,[{matched,nonode@nohost,1},{saved,1}]}

现在我们可以调用x:call/2第二个参数 trace导致顺序跟踪发生。我们从生成的进程中进行此调用,以避免在生成的跟踪中出现与 shell I/O 相关的消息:

7> spawn(fun() -> x:call(Y, trace), x:call(Y, foo) end).
(<0.46.0>) call x:call(<0.36.0>,trace)
<0.46.0>

第一行输出来自正常dbg跟踪,因为我们指定了 dbg:p(all, call)早些时候。为了获得连续的跟踪结果,我们需要从 systrace/1 获取转储。流程:

8> S ! {dump, self()}.
{dump,<0.34.0>}

这会将迄今为止收集的所有连续跟踪发送到我们的 shell 进程。我们可以使用shell flush()查看它们的命令:

9> flush().
Shell got [{seq_trace,0,{send,{0,1},<0.47.0>,<0.36.0>,{<0.47.0>,trace}}},
{seq_trace,0,{'receive',{0,1},<0.47.0>,<0.36.0>,{<0.47.0>,trace}}},
{seq_trace,0,{print,{1,2},<0.36.0>,[],{y,<0.36.0>,<0.47.0>,trace}}},
{seq_trace,0,
{send,{1,3},
<0.36.0>,<0.47.0>,
{<0.36.0>,{trace,{1423,709096,206121}}}}},
{seq_trace,0,
{'receive',{1,3},
<0.36.0>,<0.47.0>,
{<0.36.0>,{trace,{1423,709096,206121}}}}},
{seq_trace,0,{send,{3,4},<0.47.0>,<0.36.0>,{<0.47.0>,foo}}},
{seq_trace,0,{'receive',{3,4},<0.47.0>,<0.36.0>,{<0.47.0>,foo}}},
{seq_trace,0,{print,{4,5},<0.36.0>,[],{y,<0.36.0>,<0.47.0>,foo}}},
{seq_trace,0,
{send,{4,6},
<0.36.0>,<0.47.0>,
{<0.36.0>,{foo,{1423,709096,206322}}}}},
{seq_trace,0,
{'receive',{4,6},
<0.36.0>,<0.47.0>,
{<0.36.0>,{foo,{1423,709096,206322}}}}}]

果然,这些是我们期望看到的连续跟踪消息。首先,对于包含 trace 的消息原子,我们有来自 x:call/2 的发送接下来是y:loop/0中的接待和 seq_trace:print/1 的结果,然后从 y:loop/0 发送返回给 x:call/2 的调用者。然后,从x:call(Y,foo)开始在同一进程中调用,这意味着所有顺序跟踪标志仍处于启用状态,第一组顺序跟踪消息后面跟着类似的 x:call(Y,foo) 集。调用。

如果我们直接调用x:call(Y,foo)我们可以看到我们没有收到连续的跟踪消息:

10> spawn(fun() -> x:call(Y, foo) end).
<0.55.0>
11> S ! {dump, self()}.
{dump,<0.34.0>}
12> flush().
Shell got []

这是因为我们的匹配规范仅当第二个参数为 x:call/2 时才启用顺序跟踪。是原子trace .

有关详细信息,请参阅 seq_trace dbg 手册页,还可以阅读 match specification chapter of the Erlang Run-Time System Application (ERTS)User's Guide .

关于erlang - 在另一个进程上设置 seq_trace,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28353733/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com