1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 2002-2011. All Rights Reserved. 5: %% 6: %% The contents of this file are subject to the Erlang Public License, 7: %% Version 1.1, (the "License"); you may not use this file except in 8: %% compliance with the License. You should have received a copy of the 9: %% Erlang Public License along with this software. If not, it can be 10: %% retrieved online at http://www.erlang.org/. 11: %% 12: %% Software distributed under the License is distributed on an "AS IS" 13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 14: %% the License for the specific language governing rights and limitations 15: %% under the License. 16: %% 17: %% %CopyrightEnd% 18: %% 19: 20: %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21: %%% 22: %%% Define to run outside of test server 23: %%% 24: %%% -define(STANDALONE,1). 25: %%% 26: %%% 27: %%% Define for debug output 28: %%% 29: %%% -define(debug,1). 30: 31: -module(trace_call_count_SUITE). 32: 33: %% Exported end user tests 34: -export([basic_test/0, on_and_off_test/0, info_test/0, 35: pause_and_restart_test/0, combo_test/0]). 36: 37: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 38: %% Test server related stuff 39: %% 40: 41: -ifdef(STANDALONE). 42: -define(config(A,B),config(A,B)). 43: -export([config/2]). 44: -else. 45: -include_lib("test_server/include/test_server.hrl"). 46: -endif. 47: 48: -ifdef(debug). 49: -ifdef(STANDALONE). 50: -define(line, erlang:display({?MODULE,?LINE}), ). 51: -endif. 52: -define(dbgformat(A,B),io:format(A,B)). 53: -else. 54: -ifdef(STANDALONE). 55: -define(line, noop, ). 56: -endif. 57: -define(dbgformat(A,B),noop). 58: -endif. 59: 60: -ifdef(STANDALONE). 61: config(priv_dir,_) -> 62: ".". 63: -else. 64: %% When run in test server. 65: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 66: init_per_group/2,end_per_group/2, 67: init_per_testcase/2, end_per_testcase/2, not_run/1]). 68: -export([basic/1, on_and_off/1, info/1, 69: pause_and_restart/1, combo/1]). 70: 71: init_per_testcase(_Case, Config) -> 72: ?line Dog=test_server:timetrap(test_server:seconds(30)), 73: [{watchdog, Dog}|Config]. 74: 75: end_per_testcase(_Case, Config) -> 76: erlang:trace_pattern({'_','_','_'}, false, [local,meta,call_count]), 77: erlang:trace_pattern(on_load, false, [local,meta,call_count]), 78: erlang:trace(all, false, [all]), 79: Dog=?config(watchdog, Config), 80: test_server:timetrap_cancel(Dog), 81: ok. 82: 83: suite() -> [{ct_hooks,[ts_install_cth]}]. 84: 85: all() -> 86: case test_server:is_native(trace_call_count_SUITE) of 87: true -> [not_run]; 88: false -> 89: [basic, on_and_off, info, pause_and_restart, combo] 90: end. 91: 92: groups() -> 93: []. 94: 95: init_per_suite(Config) -> 96: Config. 97: 98: end_per_suite(_Config) -> 99: ok. 100: 101: init_per_group(_GroupName, Config) -> 102: Config. 103: 104: end_per_group(_GroupName, Config) -> 105: Config. 106: 107: 108: not_run(Config) when is_list(Config) -> 109: {skipped,"Native code"}. 110: 111: basic(suite) -> 112: []; 113: basic(doc) -> 114: ["Tests basic call count trace"]; 115: basic(Config) when is_list(Config) -> 116: basic_test(). 117: 118: on_and_off(suite) -> 119: []; 120: on_and_off(doc) -> 121: ["Tests turning trace parameters on and off"]; 122: on_and_off(Config) when is_list(Config) -> 123: on_and_off_test(). 124: 125: info(suite) -> 126: []; 127: info(doc) -> 128: ["Tests the trace_info BIF"]; 129: info(Config) when is_list(Config) -> 130: info_test(). 131: 132: pause_and_restart(suite) -> 133: []; 134: pause_and_restart(doc) -> 135: ["Tests pausing and restarting call counters"]; 136: pause_and_restart(Config) when is_list(Config) -> 137: pause_and_restart_test(). 138: 139: combo(suite) -> 140: []; 141: combo(doc) -> 142: ["Tests combining local call trace and meta trace with call count trace"]; 143: combo(Config) when is_list(Config) -> 144: combo_test(). 145: 146: -endif. %-ifdef(STANDALONE). ... -else. 147: 148: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 149: %% Result examination macros 150: 151: -define(CT(P,MFA),{trace,P,call,MFA}). 152: -define(CTT(P, MFA),{trace_ts,P,call,MFA,{_,_,_}}). 153: -define(RF(P,MFA,V),{trace,P,return_from,MFA,V}). 154: -define(RFT(P,MFA,V),{trace_ts,P,return_from,MFA,V,{_,_,_}}). 155: -define(RT(P,MFA),{trace,P,return_to,MFA}). 156: -define(RTT(P,MFA),{trace_ts,P,return_to,MFA,{_,_,_}}). 157: 158: %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 159: %%% The Tests 160: %%% 161: 162: basic_test() -> 163: ?line P = erlang:trace_pattern({'_','_','_'}, false, [call_count]), 164: ?line M = 1000, 165: %% 166: ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, true, [call_count]), 167: ?line 2 = erlang:trace_pattern({?MODULE,seq_r,'_'}, true, [call_count]), 168: ?line L = seq(1, M, fun(X) -> X+1 end), 169: ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count), 170: ?line {call_count,0} = erlang:trace_info({?MODULE,seq_r,3}, call_count), 171: ?line Lr = seq_r(1, M, fun(X) -> X+1 end), 172: ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count), 173: ?line {call_count,1} = erlang:trace_info({?MODULE,seq_r,3}, call_count), 174: ?line {call_count,M} = erlang:trace_info({?MODULE,seq_r,4}, call_count), 175: ?line L = lists:reverse(Lr), 176: %% 177: ?line P = erlang:trace_pattern({'_','_','_'}, false, [call_count]), 178: ok. 179: 180: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 181: 182: on_and_off_test() -> 183: ?line P = erlang:trace_pattern({'_','_','_'}, false, [call_count]), 184: ?line M = 100, 185: %% 186: ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, true, [call_count]), 187: ?line L = seq(1, M, fun(X) -> X+1 end), 188: ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count), 189: ?line N = erlang:trace_pattern({?MODULE,'_','_'}, true, [call_count]), 190: ?line L = seq(1, M, fun(X) -> X+1 end), 191: ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count), 192: ?line P = erlang:trace_pattern({'_','_','_'}, true, [call_count]), 193: ?line L = seq(1, M, fun(X) -> X+1 end), 194: ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count), 195: ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, false, [call_count]), 196: ?line {call_count,false} = erlang:trace_info({?MODULE,seq,3}, call_count), 197: ?line L = seq(1, M, fun(X) -> X+1 end), 198: ?line {call_count,false} = erlang:trace_info({?MODULE,seq,3}, call_count), 199: ?line {call_count,0} = erlang:trace_info({?MODULE,seq_r,4}, call_count), 200: ?line Lr = seq_r(1, M, fun(X) -> X+1 end), 201: ?line {call_count,M} = erlang:trace_info({?MODULE,seq_r,4}, call_count), 202: ?line N = erlang:trace_pattern({?MODULE,'_','_'}, false, [call_count]), 203: ?line {call_count,false} = erlang:trace_info({?MODULE,seq_r,4}, call_count), 204: ?line Lr = seq_r(1, M, fun(X) -> X+1 end), 205: ?line {call_count,false} = erlang:trace_info({?MODULE,seq_r,4}, call_count), 206: ?line L = lists:reverse(Lr), 207: %% 208: ?line P = erlang:trace_pattern({'_','_','_'}, false, [call_count]), 209: ok. 210: 211: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 212: 213: info_test() -> 214: ?line P = erlang:trace_pattern({'_','_','_'}, false, [call_count]), 215: %% 216: ?line 1 = erlang:trace_pattern({?MODULE,seq,3}, true, [call_count]), 217: ?line {call_count,0} = erlang:trace_info({?MODULE,seq,3}, call_count), 218: ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, pause, [call_count]), 219: ?line {call_count,0} = erlang:trace_info({?MODULE,seq,3}, call_count), 220: ?line {all,[_|_]=L} = erlang:trace_info({?MODULE,seq,3}, all), 221: ?line {value,{call_count,0}} = lists:keysearch(call_count, 1, L), 222: ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, restart, [call_count]), 223: ?line {call_count,0} = erlang:trace_info({?MODULE,seq,3}, call_count), 224: ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, false, [call_count]), 225: ?line {call_count,false} = erlang:trace_info({?MODULE,seq,3}, call_count), 226: ?line {all,false} = erlang:trace_info({?MODULE,seq,3}, all), 227: %% 228: ?line P = erlang:trace_pattern({'_','_','_'}, false, [call_count]), 229: ok. 230: 231: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 232: 233: pause_and_restart_test() -> 234: ?line P = erlang:trace_pattern({'_','_','_'}, false, [call_count]), 235: ?line M = 100, 236: %% 237: ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, true, [call_count]), 238: ?line {call_count,0} = erlang:trace_info({?MODULE,seq,3}, call_count), 239: ?line L = seq(1, M, fun(X) -> X+1 end), 240: ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count), 241: ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, pause, [call_count]), 242: ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count), 243: ?line L = seq(1, M, fun(X) -> X+1 end), 244: ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count), 245: ?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, restart, [call_count]), 246: ?line {call_count,0} = erlang:trace_info({?MODULE,seq,3}, call_count), 247: ?line L = seq(1, M, fun(X) -> X+1 end), 248: ?line {call_count,M} = erlang:trace_info({?MODULE,seq,3}, call_count), 249: %% 250: ?line P = erlang:trace_pattern({'_','_','_'}, false, [call_count]), 251: ok. 252: 253: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 254: 255: combo_test() -> 256: ?line Self = self(), 257: 258: ?line MetaMatchSpec = [{'_',[],[{return_trace}]}], 259: ?line Flags = lists:sort([call, return_to]), 260: ?line LocalTracer = spawn_link(fun () -> relay_n(5, Self) end), 261: ?line MetaTracer = spawn_link(fun () -> relay_n(9, Self) end), 262: ?line 2 = erlang:trace_pattern({?MODULE,seq_r,'_'}, [], [local]), 263: ?line 2 = erlang:trace_pattern({?MODULE,seq_r,'_'}, 264: MetaMatchSpec, 265: [{meta,MetaTracer}, call_count]), 266: ?line 1 = erlang:trace(Self, true, [{tracer,LocalTracer} | Flags]), 267: %% 268: ?line {traced,local} = 269: erlang:trace_info({?MODULE,seq_r,3}, traced), 270: ?line {match_spec,[]} = 271: erlang:trace_info({?MODULE,seq_r,3}, match_spec), 272: ?line {meta,MetaTracer} = 273: erlang:trace_info({?MODULE,seq_r,3}, meta), 274: ?line {meta_match_spec,MetaMatchSpec} = 275: erlang:trace_info({?MODULE,seq_r,3}, meta_match_spec), 276: ?line {call_count,0} = 277: erlang:trace_info({?MODULE,seq_r,3}, call_count), 278: %% 279: ?line {all,[_|_]=TraceInfo} = 280: erlang:trace_info({?MODULE,seq_r,3}, all), 281: ?line {value,{traced,local}} = 282: lists:keysearch(traced, 1, TraceInfo), 283: ?line {value,{match_spec,[]}} = 284: lists:keysearch(match_spec, 1, TraceInfo), 285: ?line {value,{meta,MetaTracer}} = 286: lists:keysearch(meta, 1, TraceInfo), 287: ?line {value,{meta_match_spec,MetaMatchSpec}} = 288: lists:keysearch(meta_match_spec, 1, TraceInfo), 289: ?line {value,{call_count,0}} = 290: lists:keysearch(call_count, 1, TraceInfo), 291: %% 292: ?line [3,2,1] = seq_r(1, 3, fun(X) -> X+1 end), 293: %% 294: ?line List = collect(100), 295: ?line {MetaR, LocalR} = 296: lists:foldl( 297: fun ({P,X}, {M,L}) when P == MetaTracer -> 298: {[X|M],L}; 299: ({P,X}, {M,L}) when P == LocalTracer -> 300: {M,[X|L]} 301: end, 302: {[],[]}, 303: List), 304: ?line Meta = lists:reverse(MetaR), 305: ?line Local = lists:reverse(LocalR), 306: ?line [?CTT(Self,{?MODULE,seq_r,[1,3,_]}), 307: ?CTT(Self,{?MODULE,seq_r,[1,3,_,[]]}), 308: ?CTT(Self,{?MODULE,seq_r,[2,3,_,[1]]}), 309: ?CTT(Self,{?MODULE,seq_r,[3,3,_,[2,1]]}), 310: ?RFT(Self,{?MODULE,seq_r,4},[3,2,1]), 311: ?RFT(Self,{?MODULE,seq_r,4},[3,2,1]), 312: ?RFT(Self,{?MODULE,seq_r,4},[3,2,1]), 313: ?RFT(Self,{?MODULE,seq_r,3},[3,2,1])] = Meta, 314: ?line [?CT(Self,{?MODULE,seq_r,[1,3,_]}), 315: ?CT(Self,{?MODULE,seq_r,[1,3,_,[]]}), 316: ?CT(Self,{?MODULE,seq_r,[2,3,_,[1]]}), 317: ?CT(Self,{?MODULE,seq_r,[3,3,_,[2,1]]}), 318: ?RT(Self,{?MODULE,combo_test,0})] = Local, 319: ?line {call_count,1} = erlang:trace_info({?MODULE,seq_r,3}, call_count), 320: ?line {call_count,3} = erlang:trace_info({?MODULE,seq_r,4}, call_count), 321: %% 322: ?line erlang:trace_pattern({'_','_','_'}, false, [local,meta,call_count]), 323: ?line erlang:trace_pattern(on_load, false, [local,meta,call_count]), 324: ?line erlang:trace(all, false, [all]), 325: ok. 326: 327: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 328: %% Local helpers 329: 330: %% Stack recursive seq 331: seq(Stop, Stop, Succ) when is_function(Succ) -> 332: [Stop]; 333: seq(Start, Stop, Succ) when is_function(Succ) -> 334: [Start | seq(Succ(Start), Stop, Succ)]. 335: 336: 337: 338: %% Tail recursive seq, result list is reversed 339: seq_r(Start, Stop, Succ) when is_function(Succ) -> 340: seq_r(Start, Stop, Succ, []). 341: 342: seq_r(Stop, Stop, _, R) -> 343: [Stop | R]; 344: seq_r(Start, Stop, Succ, R) -> 345: seq_r(Succ(Start), Stop, Succ, [Start | R]). 346: 347: 348: 349: %% Message relay process 350: relay_n(0, _) -> 351: ok; 352: relay_n(N, Dest) -> 353: receive Msg -> 354: Dest ! {self(), Msg}, 355: relay_n(N-1, Dest) 356: end. 357: 358: 359: 360: %% Collect received messages 361: collect(Time) -> 362: Ref = erlang:start_timer(Time, self(), done), 363: L = lists:reverse(collect([], Ref)), 364: ?dbgformat("Got: ~p~n",[L]), 365: L. 366: 367: collect(A, 0) -> 368: receive 369: Mess -> 370: collect([Mess | A], 0) 371: after 0 -> 372: A 373: end; 374: collect(A, Ref) -> 375: receive 376: {timeout, Ref, done} -> 377: collect(A, 0); 378: Mess -> 379: collect([Mess | A], Ref) 380: end.