aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test/trace_call_count_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/test/trace_call_count_SUITE.erl')
-rw-r--r--erts/emulator/test/trace_call_count_SUITE.erl362
1 files changed, 362 insertions, 0 deletions
diff --git a/erts/emulator/test/trace_call_count_SUITE.erl b/erts/emulator/test/trace_call_count_SUITE.erl
new file mode 100644
index 0000000000..07aa7c8d8d
--- /dev/null
+++ b/erts/emulator/test/trace_call_count_SUITE.erl
@@ -0,0 +1,362 @@
+%%
+%% %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_call_count_SUITE).
+
+%% Exported end user tests
+-export([basic_test/0, on_and_off_test/0, info_test/0,
+ pause_and_restart_test/0, combo_test/0]).
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% 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, on_and_off/1, info/1,
+ pause_and_restart/1, combo/1]).
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog=test_server:timetrap(test_server:seconds(30)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) ->
+ erlang:trace_pattern({'_','_','_'}, false, [local,meta,call_count]),
+ erlang:trace_pattern(on_load, false, [local,meta,call_count]),
+ erlang:trace(all, false, [all]),
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(doc) ->
+ ["Test call count tracing of local function calls."];
+all(suite) ->
+ case test_server:is_native(?MODULE) of
+ true -> [not_run];
+ false -> [basic, on_and_off, info,
+ pause_and_restart, combo]
+ end.
+
+not_run(Config) when is_list(Config) ->
+ {skipped,"Native code"}.
+
+basic(suite) ->
+ [];
+basic(doc) ->
+ ["Tests basic call count trace"];
+basic(Config) when is_list(Config) ->
+ basic_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().
+
+info(suite) ->
+ [];
+info(doc) ->
+ ["Tests the trace_info BIF"];
+info(Config) when is_list(Config) ->
+ info_test().
+
+pause_and_restart(suite) ->
+ [];
+pause_and_restart(doc) ->
+ ["Tests pausing and restarting call counters"];
+pause_and_restart(Config) when is_list(Config) ->
+ pause_and_restart_test().
+
+combo(suite) ->
+ [];
+combo(doc) ->
+ ["Tests combining local call trace and meta trace with call count trace"];
+combo(Config) when is_list(Config) ->
+ combo_test().
+
+-endif. %-ifdef(STANDALONE). ... -else.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% 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,{_,_,_}}).
+
+%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% The Tests
+%%%
+
+basic_test() ->
+ ?line P = erlang:trace_pattern({'_','_','_'}, false, [call_count]),
+ ?line M = 1000,
+ %%
+ ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, true, [call_count]),
+ ?line 2 = erlang:trace_pattern({?MODULE,seq_r,'_'}, true, [call_count]),
+ ?line L = seq(1, M, fun(X) -> X+1 end),
+ ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count),
+ ?line {call_count,0} = erlang:trace_info({?MODULE,seq_r,3}, call_count),
+ ?line Lr = seq_r(1, M, fun(X) -> X+1 end),
+ ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count),
+ ?line {call_count,1} = erlang:trace_info({?MODULE,seq_r,3}, call_count),
+ ?line {call_count,M} = erlang:trace_info({?MODULE,seq_r,4}, call_count),
+ ?line L = lists:reverse(Lr),
+ %%
+ ?line P = erlang:trace_pattern({'_','_','_'}, false, [call_count]),
+ ok.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+on_and_off_test() ->
+ ?line P = erlang:trace_pattern({'_','_','_'}, false, [call_count]),
+ ?line M = 100,
+ %%
+ ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, true, [call_count]),
+ ?line L = seq(1, M, fun(X) -> X+1 end),
+ ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count),
+ ?line N = erlang:trace_pattern({?MODULE,'_','_'}, true, [call_count]),
+ ?line L = seq(1, M, fun(X) -> X+1 end),
+ ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count),
+ ?line P = erlang:trace_pattern({'_','_','_'}, true, [call_count]),
+ ?line L = seq(1, M, fun(X) -> X+1 end),
+ ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count),
+ ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, false, [call_count]),
+ ?line {call_count,false} = erlang:trace_info({?MODULE,seq,3}, call_count),
+ ?line L = seq(1, M, fun(X) -> X+1 end),
+ ?line {call_count,false} = erlang:trace_info({?MODULE,seq,3}, call_count),
+ ?line {call_count,0} = erlang:trace_info({?MODULE,seq_r,4}, call_count),
+ ?line Lr = seq_r(1, M, fun(X) -> X+1 end),
+ ?line {call_count,M} = erlang:trace_info({?MODULE,seq_r,4}, call_count),
+ ?line N = erlang:trace_pattern({?MODULE,'_','_'}, false, [call_count]),
+ ?line {call_count,false} = erlang:trace_info({?MODULE,seq_r,4}, call_count),
+ ?line Lr = seq_r(1, M, fun(X) -> X+1 end),
+ ?line {call_count,false} = erlang:trace_info({?MODULE,seq_r,4}, call_count),
+ ?line L = lists:reverse(Lr),
+ %%
+ ?line P = erlang:trace_pattern({'_','_','_'}, false, [call_count]),
+ ok.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+info_test() ->
+ ?line P = erlang:trace_pattern({'_','_','_'}, false, [call_count]),
+ %%
+ ?line 1 = erlang:trace_pattern({?MODULE,seq,3}, true, [call_count]),
+ ?line {call_count,0} = erlang:trace_info({?MODULE,seq,3}, call_count),
+ ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, pause, [call_count]),
+ ?line {call_count,0} = erlang:trace_info({?MODULE,seq,3}, call_count),
+ ?line {all,[_|_]=L} = erlang:trace_info({?MODULE,seq,3}, all),
+ ?line {value,{call_count,0}} = lists:keysearch(call_count, 1, L),
+ ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, restart, [call_count]),
+ ?line {call_count,0} = erlang:trace_info({?MODULE,seq,3}, call_count),
+ ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, false, [call_count]),
+ ?line {call_count,false} = erlang:trace_info({?MODULE,seq,3}, call_count),
+ ?line {all,false} = erlang:trace_info({?MODULE,seq,3}, all),
+ %%
+ ?line P = erlang:trace_pattern({'_','_','_'}, false, [call_count]),
+ ok.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+pause_and_restart_test() ->
+ ?line P = erlang:trace_pattern({'_','_','_'}, false, [call_count]),
+ ?line M = 100,
+ %%
+ ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, true, [call_count]),
+ ?line {call_count,0} = erlang:trace_info({?MODULE,seq,3}, call_count),
+ ?line L = seq(1, M, fun(X) -> X+1 end),
+ ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count),
+ ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, pause, [call_count]),
+ ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count),
+ ?line L = seq(1, M, fun(X) -> X+1 end),
+ ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count),
+ ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, restart, [call_count]),
+ ?line {call_count,0} = erlang:trace_info({?MODULE,seq,3}, call_count),
+ ?line L = seq(1, M, fun(X) -> X+1 end),
+ ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count),
+ %%
+ ?line P = erlang:trace_pattern({'_','_','_'}, false, [call_count]),
+ ok.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+combo_test() ->
+ ?line Self = self(),
+
+ ?line MetaMatchSpec = [{'_',[],[{return_trace}]}],
+ ?line Flags = lists:sort([call, return_to]),
+ ?line LocalTracer = spawn_link(fun () -> relay_n(5, Self) end),
+ ?line MetaTracer = spawn_link(fun () -> relay_n(9, Self) end),
+ ?line 2 = erlang:trace_pattern({?MODULE,seq_r,'_'}, [], [local]),
+ ?line 2 = erlang:trace_pattern({?MODULE,seq_r,'_'},
+ MetaMatchSpec,
+ [{meta,MetaTracer}, call_count]),
+ ?line 1 = erlang:trace(Self, true, [{tracer,LocalTracer} | Flags]),
+ %%
+ ?line {traced,local} =
+ erlang:trace_info({?MODULE,seq_r,3}, traced),
+ ?line {match_spec,[]} =
+ erlang:trace_info({?MODULE,seq_r,3}, match_spec),
+ ?line {meta,MetaTracer} =
+ erlang:trace_info({?MODULE,seq_r,3}, meta),
+ ?line {meta_match_spec,MetaMatchSpec} =
+ erlang:trace_info({?MODULE,seq_r,3}, meta_match_spec),
+ ?line {call_count,0} =
+ erlang:trace_info({?MODULE,seq_r,3}, call_count),
+ %%
+ ?line {all,[_|_]=TraceInfo} =
+ erlang:trace_info({?MODULE,seq_r,3}, all),
+ ?line {value,{traced,local}} =
+ lists:keysearch(traced, 1, TraceInfo),
+ ?line {value,{match_spec,[]}} =
+ lists:keysearch(match_spec, 1, TraceInfo),
+ ?line {value,{meta,MetaTracer}} =
+ lists:keysearch(meta, 1, TraceInfo),
+ ?line {value,{meta_match_spec,MetaMatchSpec}} =
+ lists:keysearch(meta_match_spec, 1, TraceInfo),
+ ?line {value,{call_count,0}} =
+ lists:keysearch(call_count, 1, TraceInfo),
+ %%
+ ?line [3,2,1] = seq_r(1, 3, fun(X) -> X+1 end),
+ %%
+ ?line List = collect(100),
+ ?line {MetaR, LocalR} =
+ lists:foldl(
+ fun ({P,X}, {M,L}) when P == MetaTracer ->
+ {[X|M],L};
+ ({P,X}, {M,L}) when P == LocalTracer ->
+ {M,[X|L]}
+ end,
+ {[],[]},
+ List),
+ ?line Meta = lists:reverse(MetaR),
+ ?line Local = lists:reverse(LocalR),
+ ?line [?CTT(Self,{?MODULE,seq_r,[1,3,_]}),
+ ?CTT(Self,{?MODULE,seq_r,[1,3,_,[]]}),
+ ?CTT(Self,{?MODULE,seq_r,[2,3,_,[1]]}),
+ ?CTT(Self,{?MODULE,seq_r,[3,3,_,[2,1]]}),
+ ?RFT(Self,{?MODULE,seq_r,4},[3,2,1]),
+ ?RFT(Self,{?MODULE,seq_r,4},[3,2,1]),
+ ?RFT(Self,{?MODULE,seq_r,4},[3,2,1]),
+ ?RFT(Self,{?MODULE,seq_r,3},[3,2,1])] = Meta,
+ ?line [?CT(Self,{?MODULE,seq_r,[1,3,_]}),
+ ?CT(Self,{?MODULE,seq_r,[1,3,_,[]]}),
+ ?CT(Self,{?MODULE,seq_r,[2,3,_,[1]]}),
+ ?CT(Self,{?MODULE,seq_r,[3,3,_,[2,1]]}),
+ ?RT(Self,{?MODULE,combo_test,0})] = Local,
+ ?line {call_count,1} = erlang:trace_info({?MODULE,seq_r,3}, call_count),
+ ?line {call_count,3} = erlang:trace_info({?MODULE,seq_r,4}, call_count),
+ %%
+ ?line erlang:trace_pattern({'_','_','_'}, false, [local,meta,call_count]),
+ ?line erlang:trace_pattern(on_load, false, [local,meta,call_count]),
+ ?line erlang:trace(all, false, [all]),
+ ok.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Local helpers
+
+%% Stack recursive seq
+seq(Stop, Stop, Succ) when is_function(Succ) ->
+ [Stop];
+seq(Start, Stop, Succ) when is_function(Succ) ->
+ [Start | seq(Succ(Start), Stop, Succ)].
+
+
+
+%% Tail recursive seq, result list is reversed
+seq_r(Start, Stop, Succ) when is_function(Succ) ->
+ seq_r(Start, Stop, Succ, []).
+
+seq_r(Stop, Stop, _, R) ->
+ [Stop | R];
+seq_r(Start, Stop, Succ, R) ->
+ seq_r(Succ(Start), Stop, Succ, [Start | R]).
+
+
+
+%% Message relay process
+relay_n(0, _) ->
+ ok;
+relay_n(N, Dest) ->
+ receive Msg ->
+ Dest ! {self(), Msg},
+ relay_n(N-1, Dest)
+ end.
+
+
+
+%% Collect received messages
+collect(Time) ->
+ Ref = erlang:start_timer(Time, self(), done),
+ L = lists:reverse(collect([], Ref)),
+ ?dbgformat("Got: ~p~n",[L]),
+ L.
+
+collect(A, 0) ->
+ receive
+ Mess ->
+ collect([Mess | A], 0)
+ after 0 ->
+ A
+ end;
+collect(A, Ref) ->
+ receive
+ {timeout, Ref, done} ->
+ collect(A, 0);
+ Mess ->
+ collect([Mess | A], Ref)
+ end.