aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test/trace_meta_SUITE.erl
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /erts/emulator/test/trace_meta_SUITE.erl
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'erts/emulator/test/trace_meta_SUITE.erl')
-rw-r--r--erts/emulator/test/trace_meta_SUITE.erl758
1 files changed, 758 insertions, 0 deletions
diff --git a/erts/emulator/test/trace_meta_SUITE.erl b/erts/emulator/test/trace_meta_SUITE.erl
new file mode 100644
index 0000000000..d84cb3cdf2
--- /dev/null
+++ b/erts/emulator/test/trace_meta_SUITE.erl
@@ -0,0 +1,758 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%
+%%% Define to run outside of test server
+%%%
+%%% -define(STANDALONE,1).
+%%%
+%%%
+%%% Define for debug output
+%%%
+%%% -define(debug,1).
+
+-module(trace_meta_SUITE).
+
+%% Exported end user tests
+-export([basic_test/0, return_test/0, on_and_off_test/0, stack_grow_test/0,
+ info_test/0, tracer_test/0, combo_test/0, nosilent_test/0]).
+
+%% Internal exports
+-export([exported/1, exported_wrap/1, loop/4, id/1, receiver/1]).
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Test server related stuff
+%%
+
+-ifdef(STANDALONE).
+-define(config(A,B),config(A,B)).
+-export([config/2]).
+-else.
+-include("test_server.hrl").
+-endif.
+
+-ifdef(debug).
+-ifdef(STANDALONE).
+-define(line, erlang:display({?MODULE,?LINE}), ).
+-endif.
+-define(dbgformat(A,B),io:format(A,B)).
+-else.
+-ifdef(STANDALONE).
+-define(line, noop, ).
+-endif.
+-define(dbgformat(A,B),noop).
+-endif.
+
+-ifdef(STANDALONE).
+config(priv_dir,_) ->
+ ".".
+-else.
+%% When run in test server.
+-export([all/1, init_per_testcase/2, fin_per_testcase/2, not_run/1]).
+-export([basic/1, return/1, on_and_off/1, stack_grow/1,
+ info/1, tracer/1, combo/1, nosilent/1]).
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog=test_server:timetrap(test_server:minutes(5)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) ->
+ shutdown(),
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+all(doc) ->
+ ["Test meta tracing of local function calls and return trace."];
+all(suite) ->
+ case test_server:is_native(?MODULE) of
+ true -> [not_run];
+ false -> [basic, return, on_and_off, stack_grow,
+ info, tracer, combo, nosilent]
+ end.
+
+not_run(Config) when is_list(Config) ->
+ {skipped,"Native code"}.
+
+basic(suite) ->
+ [];
+basic(doc) ->
+ ["Tests basic meta trace"];
+basic(Config) when is_list(Config) ->
+ basic_test().
+
+return(suite) ->
+ [];
+return(doc) ->
+ ["Tests return trace"];
+return(Config) when is_list(Config) ->
+ return_test().
+
+on_and_off(suite) ->
+ [];
+on_and_off(doc) ->
+ ["Tests turning trace parameters on and off"];
+on_and_off(Config) when is_list(Config) ->
+ on_and_off_test().
+
+stack_grow(doc) ->
+ ["Tests the stack growth during return traces"];
+stack_grow(Config) when is_list(Config) ->
+ stack_grow_test().
+
+info(doc) ->
+ ["Tests the trace_info BIF"];
+info(Config) when is_list(Config) ->
+ info_test().
+
+tracer(suite) ->
+ [];
+tracer(doc) ->
+ ["Tests stopping and changing tracer process"];
+tracer(Config) when is_list(Config) ->
+ tracer_test().
+
+combo(suite) ->
+ [];
+combo(doc) ->
+ ["Tests combining local call trace with meta trace"];
+combo(Config) when is_list(Config) ->
+ combo_test().
+
+nosilent(suite) ->
+ [];
+nosilent(doc) ->
+ ["Tests that meta trace is not silenced by the silent process flag"];
+nosilent(Config) when is_list(Config) ->
+ nosilent_test().
+
+-endif.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Result examination macros
+
+-define(CT(P,MFA),{trace,P,call,MFA}).
+-define(CTT(P, MFA),{trace_ts,P,call,MFA,{_,_,_}}).
+-define(RF(P,MFA,V),{trace,P,return_from,MFA,V}).
+-define(RFT(P,MFA,V),{trace_ts,P,return_from,MFA,V,{_,_,_}}).
+-define(RT(P,MFA),{trace,P,return_to,MFA}).
+-define(RTT(P,MFA),{trace_ts,P,return_to,MFA,{_,_,_}}).
+-define(NM, receive_no_next(100)).
+
+%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% The Tests
+%%%
+
+basic_test() ->
+ ?line Pid = setup(),
+ ?line erlang:trace_pattern({?MODULE,'_','_'},[],[meta]),
+ ?line [1,1,1,0] = apply_slave(?MODULE,exported_wrap,[1]),
+ ?line ?CTT(Pid,{?MODULE,exported_wrap,[1]}) = receive_next(),
+ ?line ?CTT(Pid,{?MODULE,exported,[1]}) = receive_next(),
+ ?line ?CTT(Pid,{?MODULE,local,[1]}) = receive_next(),
+ ?line ?CTT(Pid,{?MODULE,local2,[1]}) = receive_next(),
+ ?line ?CTT(Pid,{?MODULE,local_tail,[1]}) = receive_next(),
+ ?line erlang:trace_pattern({?MODULE,'_','_'},false,[meta]),
+ ?line [1,1,1,0] = apply_slave(?MODULE,exported_wrap,[1]),
+ ?line ?NM,
+ ?line [1,1,1,0] = lambda_slave(fun() ->
+ exported_wrap(1)
+ end),
+ ?line ?NM,
+ ?line erlang:trace_pattern({?MODULE,'_','_'},[],[meta]),
+ ?line [1,1,1,0] = lambda_slave(fun() ->
+ exported_wrap(1)
+ end),
+ ?line ?CTT(Pid,{?MODULE,_,_}) = receive_next(), %% The fun
+ ?line ?CTT(Pid,{?MODULE,exported_wrap,[1]}) = receive_next(),
+ ?line ?CTT(Pid,{?MODULE,exported,[1]}) = receive_next(),
+ ?line ?CTT(Pid,{?MODULE,local,[1]}) = receive_next(),
+ ?line ?CTT(Pid,{?MODULE,local2,[1]}) = receive_next(),
+ ?line ?CTT(Pid,{?MODULE,local_tail,[1]}) = receive_next(),
+ ?line erlang:trace_pattern({?MODULE,'_','_'},false,[meta]),
+ ?line shutdown(),
+ ?line ?NM,
+ ok.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+return_test() ->
+ ?line Pid = setup(),
+ ?line erlang:trace_pattern({?MODULE,'_','_'},[{'_',[],[{return_trace}]}],
+ [meta]),
+ ?line erlang:trace_pattern({erlang,phash2,'_'},[{'_',[],[{return_trace}]}],
+ [meta]),
+ ?line [1,1,1,0] = apply_slave(?MODULE,exported_wrap,[1]),
+ ?line ?CTT(Pid,{?MODULE,exported_wrap,[1]}) = receive_next(),
+ ?line ?CTT(Pid,{?MODULE,exported,[1]}) = receive_next(),
+ ?line ?CTT(Pid,{?MODULE,local,[1]}) = receive_next(),
+ ?line ?CTT(Pid,{?MODULE,local2,[1]}) = receive_next(),
+ ?line ?CTT(Pid,{?MODULE,local_tail,[1]}) = receive_next(),
+ ?line ?CTT(Pid,{erlang,phash2,[1,1]}) = receive_next(),
+ ?line ?RFT(Pid,{erlang,phash2,2},0) = receive_next(),
+ ?line ?RFT(Pid,{?MODULE,local_tail,1},[1,0]) = receive_next(),
+ ?line ?RFT(Pid,{?MODULE,local2,1},[1,0]) = receive_next(),
+ ?line ?RFT(Pid,{?MODULE,local,1},[1,1,0]) = receive_next(),
+ ?line ?RFT(Pid,{?MODULE,exported,1},[1,1,1,0]) = receive_next(),
+ ?line ?RFT(Pid,{?MODULE,exported_wrap,1},[1,1,1,0]) = receive_next(),
+ ?line shutdown(),
+ ?line ?NM,
+ ok.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+on_and_off_test() ->
+ ?line Pid = setup(),
+ ?line 1 = erlang:trace_pattern({?MODULE,local_tail,1},[],[meta]),
+ ?line LocalTail = fun() ->
+ local_tail(1)
+ end,
+ ?line [1,0] = lambda_slave(LocalTail),
+ ?line ?CTT(Pid,{?MODULE,local_tail,[1]}) = receive_next(),
+ ?line 0 = erlang:trace_pattern({?MODULE,local_tail,1},[],[global]),
+ ?line [1,0] = lambda_slave(LocalTail),
+ ?line ?NM,
+ ?line 1 = erlang:trace_pattern({?MODULE,exported_wrap,1},[],[meta]),
+ ?line [1,1,1,0] = apply_slave(?MODULE,exported_wrap,[1]),
+ ?line ?CTT(Pid,{?MODULE,exported_wrap,[1]}) = receive_next(),
+ ?line 1 = erlang:trace_pattern({erlang,phash2,2},[],[meta]),
+ ?line [1,1,1,0] = apply_slave(?MODULE,exported_wrap,[1]),
+ ?line ?CTT(Pid,{?MODULE,exported_wrap,[1]}) = receive_next(),
+ ?line ?CTT(Pid,{erlang,phash2,[1,1]}) = receive_next(),
+ ?line shutdown(),
+ ?line erlang:trace_pattern({'_','_','_'},false,[meta]),
+ ?line N = erlang:trace_pattern({erlang,'_','_'},true,[meta]),
+ ?line case erlang:trace_pattern({erlang,'_','_'},false,[meta]) of
+ N ->
+ ok;
+ Else ->
+ exit({number_mismatch, {expected, N}, {got, Else}})
+ end,
+ ?line case erlang:trace_pattern({erlang,'_','_'},false,[meta]) of
+ N ->
+ ok;
+ Else2 ->
+ exit({number_mismatch, {expected, N}, {got, Else2}})
+ end,
+ ?line ?NM,
+ ok.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+stack_grow_test() ->
+ ?line Pid = setup(),
+ ?line 1 = erlang:trace_pattern({?MODULE,loop,4},
+ [{'_',[],[{return_trace}]}],[meta]),
+ ?line Num = 1 bsl 15,
+ ?line Surface =
+ fun (This, ?RFT(P,{?MODULE,loop,4},N), N) when P == Pid->
+ if N == Num ->
+ ?NM,
+ ok;
+ true ->
+ This(This, receive_next(), N+1)
+ end
+ end,
+ ?line Dive =
+ fun (This, ?CTT(P,{?MODULE,loop,[{hej,hopp},[a,b,c],4.5,N]}), N)
+ when P == Pid->
+ if N == 0 ->
+ Surface(Surface, receive_next(), 0);
+ true ->
+ This(This, receive_next(), N-1)
+ end
+ end,
+ ?line apply_slave(?MODULE,loop,[{hej,hopp},[a,b,c],4.5,Num]),
+% ?line apply_slave_async(?MODULE,loop,[{hej,hopp},[a,b,c],4.5,Num]),
+% ?line List = collect(test_server:seconds(5)),
+ ?line ok = Dive(Dive, receive_next(), Num),
+ ?line ?NM,
+ ok.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+info_test() ->
+ ?line setup(),
+ ?line Prog = [{['$1'],[{is_integer,'$1'}],[{message, false}]},
+ {'_',[],[]}],
+ ?line Self = self(),
+ ?line GoOn = make_ref(),
+
+ ?line Pid =
+ spawn_link(
+ fun () ->
+ erlang:trace_pattern({?MODULE,exported_wrap,1},
+ Prog, [{meta, Self}]),
+ Self ! {self(), GoOn}
+ end),
+ ?line receive {Pid, GoOn} -> ok end,
+ ?line {traced,false} = erlang:trace_info({?MODULE,exported_wrap,1}, traced),
+ ?line {match_spec, false} =
+ erlang:trace_info({?MODULE,exported_wrap,1}, match_spec),
+ ?line {meta, Self} = erlang:trace_info({?MODULE,exported_wrap,1}, meta),
+ ?line {meta_match_spec, MMS} =
+ erlang:trace_info({?MODULE,exported_wrap,1}, meta_match_spec),
+ ?line case MMS of
+ Prog ->
+ ok;
+ Wrong ->
+ exit({bad_result, {erlang,trace_info,
+ [{?MODULE,exported_wrap,1},
+ meta_match_spec]},
+ {expected, Prog}, {got, Wrong}})
+ end,
+ ?line erlang:garbage_collect(self()),
+ ?line receive
+ after 1 ->
+ ok
+ end,
+ ?line io:format("~p~n",[MMS]),
+ ?line {meta_match_spec,MMS2} =
+ erlang:trace_info({?MODULE,exported_wrap,1}, meta_match_spec),
+ ?line io:format("~p~n",[MMS2]),
+ ?line case MMS2 of
+ Prog ->
+ ok;
+ Wrong2 ->
+ exit({bad_result, {erlang,trace_info,
+ [{?MODULE,exported_wrap,1},
+ meta_match_spec]},
+ {expected, Prog}, {got, Wrong2}})
+ end,
+ ?line {all, [_|_]=L} = erlang:trace_info({?MODULE,exported_wrap,1}, all),
+ ?line {value, {meta, Self}} =
+ lists:keysearch(meta, 1, L),
+ ?line {value, {meta_match_spec, MMS}} =
+ lists:keysearch(meta_match_spec, 1, L),
+
+ ?line erlang:trace_pattern({?MODULE,exported_wrap,1}, true, [meta]),
+ ?line {meta_match_spec, []} =
+ erlang:trace_info({?MODULE,exported_wrap,1}, meta_match_spec),
+
+ ?line erlang:trace_pattern({?MODULE,exported_wrap,1}, false, [meta]),
+ ?line {meta, false} = erlang:trace_info({?MODULE,exported_wrap,1}, meta),
+ ?line {meta_match_spec, false} =
+ erlang:trace_info({?MODULE,exported_wrap,1}, meta_match_spec),
+ ?line {all, false} = erlang:trace_info({?MODULE,exported_wrap,1}, all),
+
+ ?line shutdown(),
+ ?line ?NM,
+ ok.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+tracer_test() ->
+ ?line Slave = setup(),
+ ?line Self = self(),
+
+ ?line MatchSpec = [{'_',[],[{return_trace}]}],
+ ?line Tracer1 = spawn_link(fun () -> relay_n(3, Self) end),
+ ?line Setter =
+ spawn_link(
+ fun () ->
+ erlang:trace_pattern({?MODULE,receiver,1},
+ MatchSpec,
+ [{meta,Tracer1}]),
+ erlang:trace_pattern({erlang,phash2,2},
+ MatchSpec,
+ [{meta,Tracer1}]),
+ Self ! {self(), done}
+ end),
+ ?line receive {Setter, done} -> ok end,
+ ?line Ref = make_ref(),
+ ?line apply_slave_async(?MODULE, receiver, [Ref]),
+ ?line {Tracer1,?CTT(Slave,{?MODULE,receiver,[Ref]})} = receive_next(100),
+ ?line {Tracer1,?CTT(Slave,{erlang,phash2,[1,1]})} = receive_next(100),
+ ?line {Tracer1,?RFT(Slave,{erlang,phash2,2},0)} = receive_next(100),
+ %% Initiate a return_trace that will fail since the tracer just stopped
+ ?line Slave ! Ref,
+ ?line receive_no_next(100),
+ %% The breakpoint has not been hit since the tracer stopped
+ ?line {meta,Tracer1} =
+ erlang:trace_info({?MODULE,receiver,1}, meta),
+ ?line {meta_match_spec, MatchSpec} =
+ erlang:trace_info({?MODULE,receiver,1}, meta_match_spec),
+ ?line {meta,Tracer1} =
+ erlang:trace_info({erlang,phash2,2}, meta),
+ ?line {meta_match_spec, MatchSpec} =
+ erlang:trace_info({erlang,phash2,2}, meta_match_spec),
+ %% Initiate trace messages that will fail
+ ?line Ref2 = make_ref(),
+ ?line apply_slave_async(?MODULE, receiver, [Ref2]),
+ ?line Slave ! Ref2,
+ ?line receive_no_next(100),
+ ?line {meta,[]} =
+ erlang:trace_info({?MODULE,receiver,1}, meta),
+ ?line {meta_match_spec, MatchSpec} =
+ erlang:trace_info({?MODULE,receiver,1}, meta_match_spec),
+ ?line {meta,[]} =
+ erlang:trace_info({erlang,phash2,2}, meta),
+ ?line {meta_match_spec, MatchSpec} =
+ erlang:trace_info({erlang,phash2,2}, meta_match_spec),
+ %% Change tracer
+ ?line Tracer2 = spawn_link(fun () -> relay_n(4, Self) end),
+ ?line erlang:trace_pattern({?MODULE,receiver,1},
+ MatchSpec,
+ [{meta,Tracer2}]),
+ ?line erlang:trace_pattern({erlang,phash2,2},
+ MatchSpec,
+ [{meta,Tracer2}]),
+ ?line Ref3 = make_ref(),
+ ?line apply_slave_async(?MODULE, receiver, [Ref3]),
+ ?line {Tracer2,?CTT(Slave,{?MODULE,receiver,[Ref3]})} = receive_next(),
+ ?line {Tracer2,?CTT(Slave,{erlang,phash2,[1,1]})} = receive_next(),
+ ?line {Tracer2,?RFT(Slave,{erlang,phash2,2},0)} = receive_next(),
+ %% Change tracer between call trace and return trace
+ ?line Tracer3 = spawn_link(fun () -> relay_n(4, Self) end),
+ ?line erlang:trace_pattern({?MODULE,receiver,1},
+ MatchSpec,
+ [{meta,Tracer3}]),
+ ?line erlang:trace_pattern({erlang,phash2,2},
+ MatchSpec,
+ [{meta,Tracer3}]),
+ ?line Slave ! Ref3,
+ %% The return trace should still come from Tracer2
+ ?line {Tracer2,?RFT(Slave,{?MODULE,receiver,1},Ref3)} = receive_next(),
+ ?line Ref4 = make_ref(),
+ %% Now should Tracer3 be used
+ ?line apply_slave_async(?MODULE, receiver, [Ref4]),
+ ?line Slave ! Ref4,
+ ?line {Tracer3,?CTT(Slave,{?MODULE,receiver,[Ref4]})} = receive_next(),
+ ?line {Tracer3,?CTT(Slave,{erlang,phash2,[1,1]})} = receive_next(),
+ ?line {Tracer3,?RFT(Slave,{erlang,phash2,2},0)} = receive_next(),
+ ?line {Tracer3,?RFT(Slave,{?MODULE,receiver,1},Ref4)} = receive_next(),
+ %% The breakpoint has not been hit since the tracer stopped
+ ?line {meta,Tracer3} =
+ erlang:trace_info({?MODULE,receiver,1}, meta),
+ ?line {meta_match_spec, MatchSpec} =
+ erlang:trace_info({?MODULE,receiver,1}, meta_match_spec),
+ ?line {meta,Tracer3} =
+ erlang:trace_info({erlang,phash2,2}, meta),
+ ?line {meta_match_spec, MatchSpec} =
+ erlang:trace_info({erlang,phash2,2}, meta_match_spec),
+
+ ?line shutdown(),
+ ?line ?NM,
+ ok.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+combo_test() ->
+ ?line Slave = setup(),
+ ?line Self = self(),
+
+ ?line MatchSpec = [{'_',[],[{return_trace}]}],
+ ?line Flags = lists:sort([call, return_to]),
+ ?line LocalTracer = spawn_link(fun () -> relay_n(6, Self) end),
+ ?line MetaTracer = spawn_link(fun () -> relay_n(4, Self) end),
+ ?line 1 = erlang:trace_pattern({?MODULE,receiver,1},
+ MatchSpec,
+ [local,{meta,MetaTracer}]),
+ ?line 1 = erlang:trace_pattern({erlang,phash2,2},
+ MatchSpec,
+ [local,{meta,MetaTracer}]),
+ ?line 1 = erlang:trace(Slave, true,
+ [{tracer,LocalTracer} | Flags]),
+ %%
+ ?line {all, TraceInfo1} =
+ erlang:trace_info({?MODULE,receiver,1}, all),
+ ?line {meta,MetaTracer} =
+ erlang:trace_info({?MODULE,receiver,1}, meta),
+ ?line {value,{meta,MetaTracer}} =
+ lists:keysearch(meta, 1, TraceInfo1),
+ ?line {meta_match_spec,MatchSpec} =
+ erlang:trace_info({?MODULE,receiver,1}, meta_match_spec),
+ ?line {value,{meta_match_spec,MatchSpec}} =
+ lists:keysearch(meta_match_spec, 1, TraceInfo1),
+ ?line {traced,local} =
+ erlang:trace_info({?MODULE,receiver,1}, traced),
+ ?line {value,{traced,local}} =
+ lists:keysearch(traced, 1, TraceInfo1),
+ ?line {match_spec,MatchSpec} =
+ erlang:trace_info({?MODULE,receiver,1}, match_spec),
+ ?line {value,{match_spec,MatchSpec}} =
+ lists:keysearch(match_spec, 1, TraceInfo1),
+ %%
+ ?line {all, TraceInfo2} =
+ erlang:trace_info({erlang,phash2,2}, all),
+ ?line {meta,MetaTracer} =
+ erlang:trace_info({erlang,phash2,2}, meta),
+ ?line {value,{meta,MetaTracer}} =
+ lists:keysearch(meta, 1, TraceInfo2),
+ ?line {meta_match_spec,MatchSpec} =
+ erlang:trace_info({erlang,phash2,2}, meta_match_spec),
+ ?line {value,{meta_match_spec,MatchSpec}} =
+ lists:keysearch(meta_match_spec, 1, TraceInfo2),
+ ?line {traced,local} =
+ erlang:trace_info({erlang,phash2,2}, traced),
+ ?line {value,{traced,local}} =
+ lists:keysearch(traced, 1, TraceInfo2),
+ ?line {match_spec,MatchSpec} =
+ erlang:trace_info({erlang,phash2,2}, match_spec),
+ ?line {value,{match_spec,MatchSpec}} =
+ lists:keysearch(match_spec, 1, TraceInfo2),
+ %%
+ ?line {flags,Flags1} = erlang:trace_info(Slave, flags),
+ ?line Flags = lists:sort(Flags1),
+ ?line {tracer,LocalTracer} = erlang:trace_info(Slave, tracer),
+ %%
+ ?line Ref = make_ref(),
+ ?line apply_slave_async(?MODULE, receiver, [Ref]),
+ ?line Slave ! Ref,
+ ?line ?CTT(Slave,{?MODULE,receiver,[Ref]}) = receive_next_bytag(MetaTracer),
+ ?line ?CTT(Slave,{erlang,phash2,[1,1]}) = receive_next_bytag(MetaTracer),
+ ?line ?RFT(Slave,{erlang,phash2,2},0) = receive_next_bytag(MetaTracer),
+ ?line ?RFT(Slave,{?MODULE,receiver,1},Ref) = receive_next_bytag(MetaTracer),
+ ?line ?CT(Slave,{?MODULE,receiver,[Ref]}) = receive_next_bytag(LocalTracer),
+ ?line ?CT(Slave,{erlang,phash2,[1,1]}) = receive_next_bytag(LocalTracer),
+ ?line case {receive_next_bytag(LocalTracer),
+ receive_next_bytag(LocalTracer)} of
+ {?RF(Slave,{erlang,phash2,2},0),
+ ?RT(Slave,{?MODULE,receiver,1})} ->
+ ?line ok;
+ {?RT(Slave,{?MODULE,receiver,1}),
+ ?RF(Slave,{erlang,phash2,2},0)} ->
+ ?line ok;
+ Error1 -> ?t:fail({unexpected_message, Error1})
+ end,
+ ?line case {receive_next_bytag(LocalTracer),
+ receive_next_bytag(LocalTracer)} of
+ {?RF(Slave,{?MODULE,receiver,1},Ref),
+ ?RT(Slave,{?MODULE,slave,1})} ->
+ ?line ok;
+ {?RT(Slave,{?MODULE,slave,1}),
+ ?RF(Slave,{?MODULE,receiver,1},Ref)} ->
+ ?line ok;
+ Error2 -> ?t:fail({unexpected_message, Error2})
+ end,
+
+ ?line shutdown(),
+ ?line ?NM,
+ ok.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Use case for Inviso meta tracing:
+%% Setup silent local call tracing, and start it using meta trace.
+
+nosilent_test() ->
+ ?line Pid = setup(),
+ ?line Trigger = {?MODULE,id,1},
+ ?line TriggerMS = [{[start],[],[{silent,false}]},
+ {[stop],[],[{silent,true},{return_trace}]}],
+ ?line 1 = erlang:trace(Pid, true, [call,silent,return_to]),
+ ?line erlang:trace_pattern({?MODULE,'_','_'},[],[local]),
+ ?line 1 = erlang:trace_pattern({?MODULE,local2,1},
+ [{'_',[],[{return_trace}]}],
+ [local]),
+ ?line 1 = erlang:trace_pattern({?MODULE,slave,1},false,[local]),
+ ?line 1 = erlang:trace_pattern(Trigger,false,[local]),
+ ?line 1 = erlang:trace_pattern(Trigger,TriggerMS,[meta]),
+ ?line [1,1,1,0] = apply_slave(?MODULE,exported_wrap,[1]),
+ ?line receive_no_next(17),
+ ?line start = apply_slave(?MODULE, id, [start]),
+ ?line ?CTT(Pid,{?MODULE,id,[start]}) = receive_next(),
+ ?line [2,2,2,0] = apply_slave(?MODULE,exported_wrap,[2]),
+ ?line ?CT(Pid,{?MODULE,exported_wrap,[2]}) = receive_next(),
+ ?line ?CT(Pid,{?MODULE,exported,[2]}) = receive_next(),
+ ?line ?CT(Pid,{?MODULE,local,[2]}) = receive_next(),
+ ?line ?CT(Pid,{?MODULE,local2,[2]}) = receive_next(),
+ ?line ?CT(Pid,{?MODULE,local_tail,[2]}) = receive_next(),
+ ?line ?RF(Pid,{?MODULE,local2,1}, [2,0]) = receive_next(),
+ ?line ?RT(Pid,{?MODULE,local,1}) = receive_next(),
+ ?line ?RT(Pid,{?MODULE,exported,1}) = receive_next(),
+ ?line ?RT(Pid,{?MODULE,slave,1}) = receive_next(),
+ ?line stop = apply_slave(?MODULE, id, [stop]),
+ ?line ?CTT(Pid,{?MODULE,id,[stop]}) = receive_next(),
+ ?line ?RFT(Pid,{?MODULE,id,1}, stop) = receive_next(),
+ ?line [3,3,3,0] = apply_slave(?MODULE,exported_wrap,[3]),
+ ?line receive_no_next(17),
+ ?line shutdown(),
+ ok.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Trace target functions
+
+loop(D1,D2,D3,0) ->
+ io:format("~p~n",[[D1,D2,D3]]),
+ 0;
+loop(D1,D2,D3,N) ->
+ max(N,loop(D1,D2,D3,N-1)).
+
+max(A,B) when A > B ->
+ A;
+max(_A,B) ->
+ B.
+
+id(X) ->
+ X.
+
+
+exported_wrap(Val) ->
+ exported(Val).
+
+exported(Val) ->
+ [Val | local(Val)]. %% Non tail recursive local call
+
+local(Val) ->
+ [Val | local2(Val)]. %% Non tail recursive local call
+
+local2(Val) ->
+ local_tail(Val). %% Tail recursive call
+
+local_tail(Val) ->
+ [Val , erlang:phash2(1,1)].
+
+
+
+receiver(Msg) ->
+ erlang:phash2(1,1),
+ receive Msg -> Msg end.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Trace target process and utilities
+
+slave(Sync) ->
+ Sync ! sync,
+ receive
+ {From,apply, M, F, A} ->
+ ?line ?dbgformat("Apply: ~p:~p/~p (~p)~n",[M,F,length(A),A]),
+ ?line Res = apply(M,F,A),
+ ?line ?dbgformat("done Apply: ~p:~p/~p (~p)~n",[M,F,length(A),A]),
+ From ! {apply, Res},
+ erlang:trace_pattern({?MODULE,slave,1},false,[meta]),
+ slave(From);
+ {From, lambda, Fun} ->
+ Res = Fun(),
+ From ! {lambda, Res},
+ erlang:trace_pattern({?MODULE,slave,1},false,[meta]),
+ slave(From);
+ die ->
+ exit(normal)
+ end.
+
+setup() ->
+ trace_off(),
+ Self = self(),
+ Pid = spawn(fun () -> slave(Self) end),
+ receive sync -> ok end,
+ put(slave,Pid),
+ Pid.
+
+shutdown() ->
+ trace_off(),
+ Pid = get(slave),
+ case (catch is_process_alive(Pid)) of
+ true ->
+ Ref = erlang:monitor(process,Pid),
+ Pid ! die,
+ receive
+ {'DOWN',Ref,process,Pid,_} ->
+ ok
+ end;
+ _ ->
+ ok
+ end.
+
+trace_off() ->
+ erlang:trace(all, false, [all]),
+ erlang:trace_pattern({'_','_','_'},false,[]),
+ erlang:trace_pattern({'_','_','_'},false,[local]),
+ erlang:trace_pattern({'_','_','_'},false,[meta]),
+ erlang:trace_pattern(on_load,false,[]),
+ erlang:trace_pattern(on_load,false,[local]),
+ erlang:trace_pattern(on_load,false,[meta]),
+ ok.
+
+apply_slave_async(M,F,A) ->
+ Slave = get(slave),
+ Pid =
+ spawn(
+ fun () ->
+ Slave ! {self(),apply, M, F, A},
+ receive
+ {apply, _} ->
+ receive
+ sync ->
+ ok
+ end
+ end
+ end),
+ Pid.
+
+apply_slave(M,F,A) ->
+ Pid = get(slave),
+ Pid ! {self(),apply, M, F, A},
+ receive
+ {apply, Res} ->
+ receive
+ sync ->
+ Res
+ end
+ end.
+
+lambda_slave(Fun) ->
+ Pid = get(slave),
+ Pid ! {self(), lambda, Fun},
+ receive
+ {lambda, Res} ->
+ receive
+ sync ->
+ Res
+ end
+ end.
+
+relay_n(0, _) ->
+ ok;
+relay_n(N, Dest) ->
+ receive Msg ->
+ Dest ! {self(), Msg},
+ relay_n(N-1, Dest)
+ end.
+
+
+receive_next() ->
+ receive_next(infinity).
+
+receive_next(TO) ->
+ receive
+ M ->
+ M
+ after TO ->
+ ?t:fail(timeout)
+ end.
+
+receive_no_next(TO) ->
+ receive
+ M ->
+ ?t:fail({unexpected_message, M})
+ after
+ TO ->
+ ok
+ end.
+
+receive_next_bytag(Tag) ->
+ receive_next_bytag(Tag, infinity).
+receive_next_bytag(Tag, TO) ->
+ receive
+ {Tag, Msg} ->
+ Msg
+ after
+ TO ->
+ timeout
+ end.