diff options
Diffstat (limited to 'erts/emulator/test/trace_call_count_SUITE.erl')
-rw-r--r-- | erts/emulator/test/trace_call_count_SUITE.erl | 362 |
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. |