From bc274db5918286eae72acc8050a12ad6d6fe05bf Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 4 May 2016 14:55:24 +0200 Subject: runtime_tools: Add dbg functions tpe/2 and ctpe/1 To set/clear match specs for send and receive trace. 'e' for Event as we might want to add match specs for other trace events (proc exit,link,ulink,...). --- lib/runtime_tools/src/dbg.erl | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'lib/runtime_tools') diff --git a/lib/runtime_tools/src/dbg.erl b/lib/runtime_tools/src/dbg.erl index d5ff874206..b29bc42a8e 100644 --- a/lib/runtime_tools/src/dbg.erl +++ b/lib/runtime_tools/src/dbg.erl @@ -20,6 +20,7 @@ -module(dbg). -export([p/1,p/2,c/3,c/4,i/0,start/0,stop/0,stop_clear/0,tracer/0, tracer/2, tracer/3, get_tracer/0, get_tracer/1, tp/2, tp/3, tp/4, + tpe/2, ctpe/1, ctp/0, ctp/1, ctp/2, ctp/3, tpl/2, tpl/3, tpl/4, ctpl/0, ctpl/1, ctpl/2, ctpl/3, ctpg/0, ctpg/1, ctpg/2, ctpg/3, ltp/0, wtp/1, rtp/1, dtp/0, dtp/1, n/1, cn/1, ln/0, h/0, h/1]). @@ -128,7 +129,12 @@ tpl(Module, Pattern) when is_atom(Module) -> do_tp({Module, '_', '_'}, Pattern, [local]); tpl({_Module, _Function, _Arity} = X, Pattern) -> do_tp(X,Pattern,[local]). -do_tp({_Module, _Function, _Arity} = X, Pattern, Flags) + +tpe(Event, Pattern) when Event =:= send; + Event =:= 'receive' -> + do_tp(Event, Pattern, []). + +do_tp(X, Pattern, Flags) when is_integer(Pattern); is_atom(Pattern) -> case ets:lookup(get_pattern_table(), Pattern) of @@ -137,17 +143,16 @@ do_tp({_Module, _Function, _Arity} = X, Pattern, Flags) _ -> {error, unknown_pattern} end; -do_tp({Module, _Function, _Arity} = X, Pattern, Flags) when is_list(Pattern) -> +do_tp(X, Pattern, Flags) when is_list(Pattern) -> Nodes = req(get_nodes), - case Module of - '_' -> - ok; - M when is_atom(M) -> + case X of + {M,_,_} when is_atom(M) -> %% Try to load M on all nodes lists:foreach(fun(Node) -> rpc:call(Node, M, module_info, []) end, - Nodes) + Nodes); + _ -> ok end, case lint_tp(Pattern) of {ok,_} -> @@ -163,9 +168,9 @@ do_tp({Module, _Function, _Arity} = X, Pattern, Flags) when is_list(Pattern) -> end. %% All nodes are handled the same way - also the local node if it is traced -do_tp_on_nodes(Nodes, MFA, P, Flags) -> +do_tp_on_nodes(Nodes, X, P, Flags) -> lists:map(fun(Node) -> - case rpc:call(Node,erlang,trace_pattern,[MFA,P, Flags]) of + case rpc:call(Node,erlang,trace_pattern,[X,P, Flags]) of N when is_integer(N) -> {matched, Node, N}; Else -> @@ -210,6 +215,7 @@ ctpg(Module) when is_atom(Module) -> do_ctp({Module, '_', '_'}, [global]); ctpg({_Module, _Function, _Arity} = X) -> do_ctp(X,[global]). + do_ctp({Module, Function, Arity},[]) -> do_ctp({Module, Function, Arity},[global]), do_ctp({Module, Function, Arity},[local]); @@ -217,6 +223,11 @@ do_ctp({_Module, _Function, _Arity}=MFA,Flags) -> Nodes = req(get_nodes), {ok,do_tp_on_nodes(Nodes,MFA,false,Flags)}. +ctpe(Event) when Event =:= send; + Event =:= 'receive' -> + Nodes = req(get_nodes), + {ok,do_tp_on_nodes(Nodes,Event,false,[])}. + %% %% ltp() -> ok %% List saved and built-in trace patterns. -- cgit v1.2.3 From e8fa9bb9e4c9bbd38371dc47791fd4c1f3d932ff Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 4 May 2016 14:55:45 +0200 Subject: runtime_tools: Add send tpe testcase --- lib/runtime_tools/test/dbg_SUITE.erl | 81 ++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'lib/runtime_tools') diff --git a/lib/runtime_tools/test/dbg_SUITE.erl b/lib/runtime_tools/test/dbg_SUITE.erl index 9c9d6ca352..db4aad7341 100644 --- a/lib/runtime_tools/test/dbg_SUITE.erl +++ b/lib/runtime_tools/test/dbg_SUITE.erl @@ -22,6 +22,7 @@ %% Test functions -export([all/0, suite/0, big/1, tiny/1, simple/1, message/1, distributed/1, port/1, + send/1, ip_port/1, file_port/1, file_port2/1, file_port_schedfix/1, ip_port_busy/1, wrap_port/1, wrap_port_time/1, with_seq_trace/1, dead_suspend/1, local_trace/1, @@ -39,6 +40,7 @@ suite() -> all() -> [big, tiny, simple, message, distributed, port, ip_port, + send, file_port, file_port2, file_port_schedfix, ip_port_busy, wrap_port, wrap_port_time, with_seq_trace, dead_suspend, local_trace, saved_patterns, tracer_exit_on_stop, @@ -151,6 +153,74 @@ message(Config) when is_list(Config) -> {trace,S,call,{dbg,ln,[]},S}] = flush(), ok. +send(Config) when is_list(Config) -> + {ok, _} = start(), + try + S = self(), + Rcvr = spawn_link(fun F() -> + receive M -> + S ! M, + F() + end + end), + + {ok, [{matched, _, 1}]} = dbg:p(Rcvr, send), + R1 = Rcvr ! make_ref(), + receive R1 -> ok end, + [{trace, Rcvr, send, R1, S}] = flush(), + + {ok, [{matched, _node, 1}, {saved, 1}]} = dbg:tpe(send, [{[S,'_'],[],[]}]), + R2 = Rcvr ! make_ref(), + receive R2 -> ok end, + [{trace, Rcvr, send, R2, S}] = flush(), + + {ok, [{matched, _node, 1}, {saved, 2}]} = + dbg:tpe(send, [{['$1','_'],[{'==','$1',{self}}],[]}]), + R3 = Rcvr ! make_ref(), + receive R3 -> ok end, + [] = flush(), + + {ok, [{matched, _node, 1}, {saved, 3}]} = + dbg:tpe(send, [{['_','_'],[{'==',Rcvr,{self}}],[]}]), + R4 = Rcvr ! make_ref(), + receive R4 -> ok end, + [{trace, Rcvr, send, R4, S}] = flush(), + + {ok, [{matched, _node, 1}, {saved, 4}]} = + dbg:tpe(send, [{['_','_'],[{'==',Rcvr,{self}}],[{message, hello}]}]), + R5 = Rcvr ! make_ref(), + receive R5 -> ok end, + [{trace, Rcvr, send, R5, S, hello}] = flush(), + + {ok, [{matched, _node, 1}, {saved, 2}]} = dbg:tpe(send, 2), + R6 = Rcvr ! make_ref(), + receive R6 -> ok end, + [] = flush(), + + {ok, [{matched, _node, 1}]} = dbg:ctpe(send), + R7 = Rcvr ! make_ref(), + receive R7 -> ok end, + [{trace, Rcvr, send, R7, S, hello}] = flush(), + + R8 = make_ref(), + {ok, [{matched, _node, 1}, {saved, 5}]} = + dbg:tpe(send, [{['_','$2'],[{'==',R8,{element, 1, {element, 2, '$2'}}}], + [{message, hello}]}]), + Msg1 = Rcvr ! {test, {R8}, <<0:(8*1024)>>}, + receive Msg1 -> ok end, + [{trace, Rcvr, send, Msg1, S, hello}] = flush(), + + R9 = make_ref(), + Msg2 = Rcvr ! {test, {R9}, <<0:(8*1024)>>}, + receive Msg2 -> ok end, + [] = flush(), + + ok + + after + stop() + end. + %% Simple test of distributed tracing distributed(Config) when is_list(Config) -> {ok, _} = start(), @@ -859,6 +929,17 @@ flush(Acc) -> Acc end. +flush_trace() -> + flush_trace([]). +flush_trace(Acc) -> + receive + X when element(1,X) =:= trace; + element(1,X) =:= trace_ts + -> flush_trace(Acc ++ [X]) + after 1000 -> + Acc + end. + start() -> stop(), dbg:tracer(process, {fun myhandler/2, self()}). -- cgit v1.2.3 From 9265763bafb2e744a42693686a14fa214ebef261 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 3 May 2016 14:50:48 +0200 Subject: runtime_tools: more dbg send trace pattern tests --- lib/runtime_tools/test/dbg_SUITE.erl | 152 +++++++++++++++++++++-------------- 1 file changed, 91 insertions(+), 61 deletions(-) (limited to 'lib/runtime_tools') diff --git a/lib/runtime_tools/test/dbg_SUITE.erl b/lib/runtime_tools/test/dbg_SUITE.erl index db4aad7341..4374141157 100644 --- a/lib/runtime_tools/test/dbg_SUITE.erl +++ b/lib/runtime_tools/test/dbg_SUITE.erl @@ -155,65 +155,76 @@ message(Config) when is_list(Config) -> send(Config) when is_list(Config) -> {ok, _} = start(), + Node = start_slave(), + rpc:call(Node, code, add_patha, + [filename:join(proplists:get_value(data_dir, Config), "..")]), try - S = self(), - Rcvr = spawn_link(fun F() -> - receive M -> - S ! M, - F() - end - end), + Echo = fun F() -> + receive {From, M} -> + From ! M, + F() + end + end, + Rcvr = spawn_link(Echo), + RemoteRcvr = spawn_link(Node, Echo), {ok, [{matched, _, 1}]} = dbg:p(Rcvr, send), - R1 = Rcvr ! make_ref(), - receive R1 -> ok end, - [{trace, Rcvr, send, R1, S}] = flush(), - {ok, [{matched, _node, 1}, {saved, 1}]} = dbg:tpe(send, [{[S,'_'],[],[]}]), - R2 = Rcvr ! make_ref(), - receive R2 -> ok end, - [{trace, Rcvr, send, R2, S}] = flush(), + send_test(Rcvr, make_ref(), true), + + %% Test that the test case process is the receiving process + send_test(Rcvr, [{[self(),'_'],[],[]}]), + %% Test that self() is not the receiving process {ok, [{matched, _node, 1}, {saved, 2}]} = dbg:tpe(send, [{['$1','_'],[{'==','$1',{self}}],[]}]), - R3 = Rcvr ! make_ref(), - receive R3 -> ok end, - [] = flush(), - - {ok, [{matched, _node, 1}, {saved, 3}]} = - dbg:tpe(send, [{['_','_'],[{'==',Rcvr,{self}}],[]}]), - R4 = Rcvr ! make_ref(), - receive R4 -> ok end, - [{trace, Rcvr, send, R4, S}] = flush(), - - {ok, [{matched, _node, 1}, {saved, 4}]} = - dbg:tpe(send, [{['_','_'],[{'==',Rcvr,{self}}],[{message, hello}]}]), - R5 = Rcvr ! make_ref(), - receive R5 -> ok end, - [{trace, Rcvr, send, R5, S, hello}] = flush(), - - {ok, [{matched, _node, 1}, {saved, 2}]} = dbg:tpe(send, 2), - R6 = Rcvr ! make_ref(), - receive R6 -> ok end, - [] = flush(), + send_test(Rcvr, make_ref(), false), + + %% Test that self() is the sending process + send_test(Rcvr, [{['_','_'],[{'==',Rcvr,{self}}],[]}]), + + %% Test attaching a message + send_test(Rcvr, [{['_','_'],[{'==',Rcvr,{self}}],[{message, hello}]}], + make_ref(), hello), + + %% Test using a saved trace pattern + send_test(Rcvr, 2, make_ref(), false), + %% Test clearing of trace pattern {ok, [{matched, _node, 1}]} = dbg:ctpe(send), - R7 = Rcvr ! make_ref(), - receive R7 -> ok end, - [{trace, Rcvr, send, R7, S, hello}] = flush(), - - R8 = make_ref(), - {ok, [{matched, _node, 1}, {saved, 5}]} = - dbg:tpe(send, [{['_','$2'],[{'==',R8,{element, 1, {element, 2, '$2'}}}], - [{message, hello}]}]), - Msg1 = Rcvr ! {test, {R8}, <<0:(8*1024)>>}, - receive Msg1 -> ok end, - [{trace, Rcvr, send, Msg1, S, hello}] = flush(), - - R9 = make_ref(), - Msg2 = Rcvr ! {test, {R9}, <<0:(8*1024)>>}, - receive Msg2 -> ok end, - [] = flush(), + send_test(Rcvr, make_ref(), true), + + %% Test complex message inspection + Ref = make_ref(), + send_test(Rcvr, + [{['_','$2'],[{'==',Ref,{element,1,{element,2,'$2'}}}],[]}], + {test, {Ref}, <<0:(8*1024)>>}, true), + + send_test(Rcvr, {test, {make_ref()}, <<0:(8*1024)>>}, false), + + %% Test send to remote process + remote_send_test(Rcvr, RemoteRcvr, [], make_ref(), true), + + remote_send_test(Rcvr, RemoteRcvr, + [{['$1','_'],[{'==',{node, '$1'},{node}}],[]}], + make_ref(), false), + + remote_send_test(Rcvr, RemoteRcvr, + [{['$1','_'],[{'==',{node, '$1'},Node}],[]}], + make_ref(), true), + + %% Test that distributed dbg works + dbg:tracer(Node, process, {fun myhandler/2, self()}), + Rcvr2 = spawn_link(Echo), + RemoteRcvr2 = spawn_link(Node, Echo), + dbg:p(Rcvr2, [send]), + dbg:p(RemoteRcvr2, [send]), + dbg:tpe(send, [{['_', hej],[],[]}]), + + send_test(Rcvr2, make_ref(), false), + send_test(RemoteRcvr2, make_ref(), false), + send_test(Rcvr2, hej, true), + send_test(RemoteRcvr2, hej, true), ok @@ -221,6 +232,36 @@ send(Config) when is_list(Config) -> stop() end. +send_test(Pid, Pattern, Msg, TraceEvent) -> + {ok, [{matched, _, _}, _]} = dbg:tpe(send, Pattern), + send_test(Pid, Msg, TraceEvent). +send_test(Pid, Pattern) -> + send_test(Pid, Pattern, make_ref(), true). +send_test(Pid, Msg, TraceEvent) -> + S = self(), + Pid ! {S, Msg}, + receive Msg -> ok end, + send_test_rcv(Pid, Msg, S, TraceEvent). + +remote_send_test(Pid, RPid, Pattern, Msg, TraceEvent) -> + dbg:tpe(send, Pattern), + TMsg = {self(), Msg}, + Pid ! {RPid, TMsg}, + receive Msg -> ok end, + send_test_rcv(Pid, TMsg, RPid, TraceEvent). + +send_test_rcv(Pid, Msg, S, TraceEvent) -> + case flush() of + [] when not TraceEvent -> + ok; + [{trace, Pid, send, Msg, S}] when TraceEvent -> + ok; + [{trace, Pid, send, Msg, S, Message}] when TraceEvent == Message -> + ok; + Else -> + ct:fail({got_unexpected_message, Else}) + end. + %% Simple test of distributed tracing distributed(Config) when is_list(Config) -> {ok, _} = start(), @@ -929,17 +970,6 @@ flush(Acc) -> Acc end. -flush_trace() -> - flush_trace([]). -flush_trace(Acc) -> - receive - X when element(1,X) =:= trace; - element(1,X) =:= trace_ts - -> flush_trace(Acc ++ [X]) - after 1000 -> - Acc - end. - start() -> stop(), dbg:tracer(process, {fun myhandler/2, self()}). -- cgit v1.2.3 From ce0e097aaa206922bcb59babbd28a0e0355b59f8 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 3 May 2016 15:24:59 +0200 Subject: runtime_tools: Add dbg tests for receive trace patterns --- lib/runtime_tools/test/dbg_SUITE.erl | 115 ++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 2 deletions(-) (limited to 'lib/runtime_tools') diff --git a/lib/runtime_tools/test/dbg_SUITE.erl b/lib/runtime_tools/test/dbg_SUITE.erl index 4374141157..4b32696aa5 100644 --- a/lib/runtime_tools/test/dbg_SUITE.erl +++ b/lib/runtime_tools/test/dbg_SUITE.erl @@ -22,7 +22,7 @@ %% Test functions -export([all/0, suite/0, big/1, tiny/1, simple/1, message/1, distributed/1, port/1, - send/1, + send/1, recv/1, ip_port/1, file_port/1, file_port2/1, file_port_schedfix/1, ip_port_busy/1, wrap_port/1, wrap_port_time/1, with_seq_trace/1, dead_suspend/1, local_trace/1, @@ -40,7 +40,7 @@ suite() -> all() -> [big, tiny, simple, message, distributed, port, ip_port, - send, + send, recv, file_port, file_port2, file_port_schedfix, ip_port_busy, wrap_port, wrap_port_time, with_seq_trace, dead_suspend, local_trace, saved_patterns, tracer_exit_on_stop, @@ -262,6 +262,117 @@ send_test_rcv(Pid, Msg, S, TraceEvent) -> ct:fail({got_unexpected_message, Else}) end. +recv(Config) when is_list(Config) -> + {ok, _} = start(), + Node = start_slave(), + rpc:call(Node, code, add_patha, + [filename:join(proplists:get_value(data_dir, Config), "..")]), + try + Echo = fun F() -> + receive {From, M} -> + From ! M, + F() + end + end, + Rcvr = spawn_link(Echo), + RemoteRcvr = spawn_link(Node, Echo), + + {ok, [{matched, _, 1}]} = dbg:p(Rcvr, 'receive'), + + recv_test(Rcvr, make_ref(), true), + + %% Test that the test case process is the sending process + recv_test(Rcvr, [{[node(), self(), '_'],[],[]}]), + + %% Test that self() is the not sending process + {ok, [{matched, _node, 1}, {saved, 2}]} = + dbg:tpe('receive', [{[node(), '$1','_'],[{'==','$1',{self}}],[]}]), + recv_test(Rcvr, make_ref(), false), + + %% Test that self() is the receiving process + recv_test(Rcvr, [{'_',[{'==',Rcvr,{self}}],[]}]), + + %% Test attaching a message + recv_test(Rcvr, [{'_',[{'==',Rcvr,{self}}],[{message, hello}]}], + make_ref(), hello), + + %% Test using a saved trace pattern + recv_test(Rcvr, 2, make_ref(), false), + + %% Test clearing of trace pattern + {ok, [{matched, _node, 1}]} = dbg:ctpe('receive'), + recv_test(Rcvr, make_ref(), true), + + %% Test complex message inspection + Ref = make_ref(), + recv_test(Rcvr, + [{[node(), '_','$2'],[{'==',Ref,{element,1, + {element,2, + {element,2,'$2'}}}}],[]}], + {test, {Ref}, <<0:(8*1024)>>}, true), + + recv_test(Rcvr, {test, {make_ref()}, <<0:(8*1024)>>}, false), + + %% Test recv to remote process + remote_recv_test(RemoteRcvr, Rcvr, [], make_ref(), true), + + remote_recv_test(RemoteRcvr, Rcvr, + [{['$1',undefined,'_'],[{'==','$1',{node}}],[]}], + make_ref(), false), + + remote_recv_test(RemoteRcvr, Rcvr, + [{['$1',undefined,'_'],[{'==','$1',Node}],[]}], + make_ref(), true), + + %% Test that distributed dbg works + dbg:tracer(Node, process, {fun myhandler/2, self()}), + Rcvr2 = spawn_link(Echo), + RemoteRcvr2 = spawn_link(Node, Echo), + dbg:p(Rcvr2, ['receive']), + dbg:p(RemoteRcvr2, ['receive']), + dbg:tpe('receive', [{[node(), '_', '$1'],[{'==',{element,2,'$1'}, hej}],[]}]), + + recv_test(Rcvr2, make_ref(), false), + recv_test(RemoteRcvr2, make_ref(), false), + recv_test(Rcvr2, hej, true), + recv_test(RemoteRcvr2, hej, true), + + ok + + after + stop() + end. + +recv_test(Pid, Pattern, Msg, TraceEvent) -> + {ok, [{matched, _, _}, _]} = dbg:tpe('receive', Pattern), + recv_test(Pid, Msg, TraceEvent). +recv_test(Pid, Pattern) -> + recv_test(Pid, Pattern, make_ref(), true). +recv_test(Pid, Msg, TraceEvent) -> + S = self(), + Pid ! {S, Msg}, + receive Msg -> ok end, + recv_test_rcv(Pid, {S, Msg}, TraceEvent). + +remote_recv_test(RPid, Pid, Pattern, Msg, TraceEvent) -> + dbg:tpe('receive', Pattern), + TMsg = {self(), Msg}, + RPid ! {Pid, TMsg}, + receive Msg -> ok end, + recv_test_rcv(Pid, TMsg, TraceEvent). + +recv_test_rcv(Pid, Msg, TraceEvent) -> + case flush() of + [] when not TraceEvent -> + ok; + [{trace, Pid, 'receive', Msg}] when TraceEvent -> + ok; + [{trace, Pid, 'receive', Msg, Message}] when TraceEvent == Message -> + ok; + Else -> + ct:fail({got_unexpected_message, Else}) + end. + %% Simple test of distributed tracing distributed(Config) when is_list(Config) -> {ok, _} = start(), -- cgit v1.2.3 From d38d8a4cafe04d7ad63a4d0b168a25eb5e887440 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 4 May 2016 15:58:52 +0200 Subject: Change dbg:ctpe to go back to default i.e enable all send/receive trace. --- lib/runtime_tools/src/dbg.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/runtime_tools') diff --git a/lib/runtime_tools/src/dbg.erl b/lib/runtime_tools/src/dbg.erl index b29bc42a8e..1620f52789 100644 --- a/lib/runtime_tools/src/dbg.erl +++ b/lib/runtime_tools/src/dbg.erl @@ -226,7 +226,7 @@ do_ctp({_Module, _Function, _Arity}=MFA,Flags) -> ctpe(Event) when Event =:= send; Event =:= 'receive' -> Nodes = req(get_nodes), - {ok,do_tp_on_nodes(Nodes,Event,false,[])}. + {ok,do_tp_on_nodes(Nodes,Event,true,[])}. %% %% ltp() -> ok -- cgit v1.2.3