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_meta_SUITE). 32: 33: %% Exported end user tests 34: -export([basic_test/0, return_test/0, on_and_off_test/0, stack_grow_test/0, 35: info_test/0, tracer_test/0, combo_test/0, nosilent_test/0]). 36: 37: %% Internal exports 38: -export([exported/1, exported_wrap/1, loop/4, id/1, receiver/1]). 39: 40: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 41: %% Test server related stuff 42: %% 43: 44: -ifdef(STANDALONE). 45: -define(config(A,B),config(A,B)). 46: -export([config/2]). 47: -else. 48: -include_lib("test_server/include/test_server.hrl"). 49: -endif. 50: 51: -ifdef(debug). 52: -ifdef(STANDALONE). 53: -define(line, erlang:display({?MODULE,?LINE}), ). 54: -endif. 55: -define(dbgformat(A,B),io:format(A,B)). 56: -else. 57: -ifdef(STANDALONE). 58: -define(line, noop, ). 59: -endif. 60: -define(dbgformat(A,B),noop). 61: -endif. 62: 63: -ifdef(STANDALONE). 64: config(priv_dir,_) -> 65: ".". 66: -else. 67: %% When run in test server. 68: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 69: init_per_group/2,end_per_group/2, 70: init_per_testcase/2, end_per_testcase/2, not_run/1]). 71: -export([basic/1, return/1, on_and_off/1, stack_grow/1, 72: info/1, tracer/1, combo/1, nosilent/1]). 73: 74: init_per_testcase(_Case, Config) -> 75: ?line Dog=test_server:timetrap(test_server:minutes(5)), 76: [{watchdog, Dog}|Config]. 77: 78: end_per_testcase(_Case, Config) -> 79: shutdown(), 80: Dog=?config(watchdog, Config), 81: test_server:timetrap_cancel(Dog), 82: ok. 83: suite() -> [{ct_hooks,[ts_install_cth]}]. 84: 85: all() -> 86: case test_server:is_native(trace_meta_SUITE) of 87: true -> [not_run]; 88: false -> 89: [basic, return, on_and_off, stack_grow, info, tracer, 90: combo, nosilent] 91: end. 92: 93: groups() -> 94: []. 95: 96: init_per_suite(Config) -> 97: Config. 98: 99: end_per_suite(_Config) -> 100: ok. 101: 102: init_per_group(_GroupName, Config) -> 103: Config. 104: 105: end_per_group(_GroupName, Config) -> 106: Config. 107: 108: 109: not_run(Config) when is_list(Config) -> 110: {skipped,"Native code"}. 111: 112: basic(suite) -> 113: []; 114: basic(doc) -> 115: ["Tests basic meta trace"]; 116: basic(Config) when is_list(Config) -> 117: basic_test(). 118: 119: return(suite) -> 120: []; 121: return(doc) -> 122: ["Tests return trace"]; 123: return(Config) when is_list(Config) -> 124: return_test(). 125: 126: on_and_off(suite) -> 127: []; 128: on_and_off(doc) -> 129: ["Tests turning trace parameters on and off"]; 130: on_and_off(Config) when is_list(Config) -> 131: on_and_off_test(). 132: 133: stack_grow(doc) -> 134: ["Tests the stack growth during return traces"]; 135: stack_grow(Config) when is_list(Config) -> 136: stack_grow_test(). 137: 138: info(doc) -> 139: ["Tests the trace_info BIF"]; 140: info(Config) when is_list(Config) -> 141: info_test(). 142: 143: tracer(suite) -> 144: []; 145: tracer(doc) -> 146: ["Tests stopping and changing tracer process"]; 147: tracer(Config) when is_list(Config) -> 148: tracer_test(). 149: 150: combo(suite) -> 151: []; 152: combo(doc) -> 153: ["Tests combining local call trace with meta trace"]; 154: combo(Config) when is_list(Config) -> 155: combo_test(). 156: 157: nosilent(suite) -> 158: []; 159: nosilent(doc) -> 160: ["Tests that meta trace is not silenced by the silent process flag"]; 161: nosilent(Config) when is_list(Config) -> 162: nosilent_test(). 163: 164: -endif. 165: 166: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 167: %% Result examination macros 168: 169: -define(CT(P,MFA),{trace,P,call,MFA}). 170: -define(CTT(P, MFA),{trace_ts,P,call,MFA,{_,_,_}}). 171: -define(RF(P,MFA,V),{trace,P,return_from,MFA,V}). 172: -define(RFT(P,MFA,V),{trace_ts,P,return_from,MFA,V,{_,_,_}}). 173: -define(RT(P,MFA),{trace,P,return_to,MFA}). 174: -define(RTT(P,MFA),{trace_ts,P,return_to,MFA,{_,_,_}}). 175: -define(NM, receive_no_next(100)). 176: 177: %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 178: %%% The Tests 179: %%% 180: 181: basic_test() -> 182: ?line Pid = setup(), 183: ?line erlang:trace_pattern({?MODULE,'_','_'},[],[meta]), 184: ?line [1,1,1,0] = apply_slave(?MODULE,exported_wrap,[1]), 185: ?line ?CTT(Pid,{?MODULE,exported_wrap,[1]}) = receive_next(), 186: ?line ?CTT(Pid,{?MODULE,exported,[1]}) = receive_next(), 187: ?line ?CTT(Pid,{?MODULE,local,[1]}) = receive_next(), 188: ?line ?CTT(Pid,{?MODULE,local2,[1]}) = receive_next(), 189: ?line ?CTT(Pid,{?MODULE,local_tail,[1]}) = receive_next(), 190: ?line erlang:trace_pattern({?MODULE,'_','_'},false,[meta]), 191: ?line [1,1,1,0] = apply_slave(?MODULE,exported_wrap,[1]), 192: ?line ?NM, 193: ?line [1,1,1,0] = lambda_slave(fun() -> 194: exported_wrap(1) 195: end), 196: ?line ?NM, 197: ?line erlang:trace_pattern({?MODULE,'_','_'},[],[meta]), 198: ?line [1,1,1,0] = lambda_slave(fun() -> 199: exported_wrap(1) 200: end), 201: ?line ?CTT(Pid,{?MODULE,_,_}) = receive_next(), %% The fun 202: ?line ?CTT(Pid,{?MODULE,exported_wrap,[1]}) = receive_next(), 203: ?line ?CTT(Pid,{?MODULE,exported,[1]}) = receive_next(), 204: ?line ?CTT(Pid,{?MODULE,local,[1]}) = receive_next(), 205: ?line ?CTT(Pid,{?MODULE,local2,[1]}) = receive_next(), 206: ?line ?CTT(Pid,{?MODULE,local_tail,[1]}) = receive_next(), 207: ?line erlang:trace_pattern({?MODULE,'_','_'},false,[meta]), 208: ?line shutdown(), 209: ?line ?NM, 210: ok. 211: 212: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 213: 214: return_test() -> 215: ?line Pid = setup(), 216: ?line erlang:trace_pattern({?MODULE,'_','_'},[{'_',[],[{return_trace}]}], 217: [meta]), 218: ?line erlang:trace_pattern({erlang,phash2,'_'},[{'_',[],[{return_trace}]}], 219: [meta]), 220: ?line [1,1,1,0] = apply_slave(?MODULE,exported_wrap,[1]), 221: ?line ?CTT(Pid,{?MODULE,exported_wrap,[1]}) = receive_next(), 222: ?line ?CTT(Pid,{?MODULE,exported,[1]}) = receive_next(), 223: ?line ?CTT(Pid,{?MODULE,local,[1]}) = receive_next(), 224: ?line ?CTT(Pid,{?MODULE,local2,[1]}) = receive_next(), 225: ?line ?CTT(Pid,{?MODULE,local_tail,[1]}) = receive_next(), 226: ?line ?CTT(Pid,{erlang,phash2,[1,1]}) = receive_next(), 227: ?line ?RFT(Pid,{erlang,phash2,2},0) = receive_next(), 228: ?line ?RFT(Pid,{?MODULE,local_tail,1},[1,0]) = receive_next(), 229: ?line ?RFT(Pid,{?MODULE,local2,1},[1,0]) = receive_next(), 230: ?line ?RFT(Pid,{?MODULE,local,1},[1,1,0]) = receive_next(), 231: ?line ?RFT(Pid,{?MODULE,exported,1},[1,1,1,0]) = receive_next(), 232: ?line ?RFT(Pid,{?MODULE,exported_wrap,1},[1,1,1,0]) = receive_next(), 233: ?line shutdown(), 234: ?line ?NM, 235: ok. 236: 237: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 238: 239: on_and_off_test() -> 240: ?line Pid = setup(), 241: ?line 1 = erlang:trace_pattern({?MODULE,local_tail,1},[],[meta]), 242: ?line LocalTail = fun() -> 243: local_tail(1) 244: end, 245: ?line [1,0] = lambda_slave(LocalTail), 246: ?line ?CTT(Pid,{?MODULE,local_tail,[1]}) = receive_next(), 247: ?line 0 = erlang:trace_pattern({?MODULE,local_tail,1},[],[global]), 248: ?line [1,0] = lambda_slave(LocalTail), 249: ?line ?NM, 250: ?line 1 = erlang:trace_pattern({?MODULE,exported_wrap,1},[],[meta]), 251: ?line [1,1,1,0] = apply_slave(?MODULE,exported_wrap,[1]), 252: ?line ?CTT(Pid,{?MODULE,exported_wrap,[1]}) = receive_next(), 253: ?line 1 = erlang:trace_pattern({erlang,phash2,2},[],[meta]), 254: ?line [1,1,1,0] = apply_slave(?MODULE,exported_wrap,[1]), 255: ?line ?CTT(Pid,{?MODULE,exported_wrap,[1]}) = receive_next(), 256: ?line ?CTT(Pid,{erlang,phash2,[1,1]}) = receive_next(), 257: ?line shutdown(), 258: ?line erlang:trace_pattern({'_','_','_'},false,[meta]), 259: ?line N = erlang:trace_pattern({erlang,'_','_'},true,[meta]), 260: ?line case erlang:trace_pattern({erlang,'_','_'},false,[meta]) of 261: N -> 262: ok; 263: Else -> 264: exit({number_mismatch, {expected, N}, {got, Else}}) 265: end, 266: ?line case erlang:trace_pattern({erlang,'_','_'},false,[meta]) of 267: N -> 268: ok; 269: Else2 -> 270: exit({number_mismatch, {expected, N}, {got, Else2}}) 271: end, 272: ?line ?NM, 273: ok. 274: 275: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 276: 277: stack_grow_test() -> 278: ?line Pid = setup(), 279: ?line 1 = erlang:trace_pattern({?MODULE,loop,4}, 280: [{'_',[],[{return_trace}]}],[meta]), 281: ?line Num = 1 bsl 15, 282: ?line Surface = 283: fun (This, ?RFT(P,{?MODULE,loop,4},N), N) when P == Pid-> 284: if N == Num -> 285: ?NM, 286: ok; 287: true -> 288: This(This, receive_next(), N+1) 289: end 290: end, 291: ?line Dive = 292: fun (This, ?CTT(P,{?MODULE,loop,[{hej,hopp},[a,b,c],4.5,N]}), N) 293: when P == Pid-> 294: if N == 0 -> 295: Surface(Surface, receive_next(), 0); 296: true -> 297: This(This, receive_next(), N-1) 298: end 299: end, 300: ?line apply_slave(?MODULE,loop,[{hej,hopp},[a,b,c],4.5,Num]), 301: % ?line apply_slave_async(?MODULE,loop,[{hej,hopp},[a,b,c],4.5,Num]), 302: % ?line List = collect(test_server:seconds(5)), 303: ?line ok = Dive(Dive, receive_next(), Num), 304: ?line ?NM, 305: ok. 306: 307: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 308: 309: info_test() -> 310: ?line setup(), 311: ?line Prog = [{['$1'],[{is_integer,'$1'}],[{message, false}]}, 312: {'_',[],[]}], 313: ?line Self = self(), 314: ?line GoOn = make_ref(), 315: 316: ?line Pid = 317: spawn_link( 318: fun () -> 319: erlang:trace_pattern({?MODULE,exported_wrap,1}, 320: Prog, [{meta, Self}]), 321: Self ! {self(), GoOn} 322: end), 323: ?line receive {Pid, GoOn} -> ok end, 324: ?line {traced,false} = erlang:trace_info({?MODULE,exported_wrap,1}, traced), 325: ?line {match_spec, false} = 326: erlang:trace_info({?MODULE,exported_wrap,1}, match_spec), 327: ?line {meta, Self} = erlang:trace_info({?MODULE,exported_wrap,1}, meta), 328: ?line {meta_match_spec, MMS} = 329: erlang:trace_info({?MODULE,exported_wrap,1}, meta_match_spec), 330: ?line case MMS of 331: Prog -> 332: ok; 333: Wrong -> 334: exit({bad_result, {erlang,trace_info, 335: [{?MODULE,exported_wrap,1}, 336: meta_match_spec]}, 337: {expected, Prog}, {got, Wrong}}) 338: end, 339: ?line erlang:garbage_collect(self()), 340: ?line receive 341: after 1 -> 342: ok 343: end, 344: ?line io:format("~p~n",[MMS]), 345: ?line {meta_match_spec,MMS2} = 346: erlang:trace_info({?MODULE,exported_wrap,1}, meta_match_spec), 347: ?line io:format("~p~n",[MMS2]), 348: ?line case MMS2 of 349: Prog -> 350: ok; 351: Wrong2 -> 352: exit({bad_result, {erlang,trace_info, 353: [{?MODULE,exported_wrap,1}, 354: meta_match_spec]}, 355: {expected, Prog}, {got, Wrong2}}) 356: end, 357: ?line {all, [_|_]=L} = erlang:trace_info({?MODULE,exported_wrap,1}, all), 358: ?line {value, {meta, Self}} = 359: lists:keysearch(meta, 1, L), 360: ?line {value, {meta_match_spec, MMS}} = 361: lists:keysearch(meta_match_spec, 1, L), 362: 363: ?line erlang:trace_pattern({?MODULE,exported_wrap,1}, true, [meta]), 364: ?line {meta_match_spec, []} = 365: erlang:trace_info({?MODULE,exported_wrap,1}, meta_match_spec), 366: 367: ?line erlang:trace_pattern({?MODULE,exported_wrap,1}, false, [meta]), 368: ?line {meta, false} = erlang:trace_info({?MODULE,exported_wrap,1}, meta), 369: ?line {meta_match_spec, false} = 370: erlang:trace_info({?MODULE,exported_wrap,1}, meta_match_spec), 371: ?line {all, false} = erlang:trace_info({?MODULE,exported_wrap,1}, all), 372: 373: ?line shutdown(), 374: ?line ?NM, 375: ok. 376: 377: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 378: 379: tracer_test() -> 380: ?line Slave = setup(), 381: ?line Self = self(), 382: 383: ?line MatchSpec = [{'_',[],[{return_trace}]}], 384: ?line Tracer1 = spawn_link(fun () -> relay_n(3, Self) end), 385: ?line Setter = 386: spawn_link( 387: fun () -> 388: erlang:trace_pattern({?MODULE,receiver,1}, 389: MatchSpec, 390: [{meta,Tracer1}]), 391: erlang:trace_pattern({erlang,phash2,2}, 392: MatchSpec, 393: [{meta,Tracer1}]), 394: Self ! {self(), done} 395: end), 396: ?line receive {Setter, done} -> ok end, 397: ?line Ref = make_ref(), 398: ?line apply_slave_async(?MODULE, receiver, [Ref]), 399: ?line {Tracer1,?CTT(Slave,{?MODULE,receiver,[Ref]})} = receive_next(100), 400: ?line {Tracer1,?CTT(Slave,{erlang,phash2,[1,1]})} = receive_next(100), 401: ?line {Tracer1,?RFT(Slave,{erlang,phash2,2},0)} = receive_next(100), 402: %% Initiate a return_trace that will fail since the tracer just stopped 403: ?line Slave ! Ref, 404: ?line receive_no_next(100), 405: %% The breakpoint has not been hit since the tracer stopped 406: ?line {meta,Tracer1} = 407: erlang:trace_info({?MODULE,receiver,1}, meta), 408: ?line {meta_match_spec, MatchSpec} = 409: erlang:trace_info({?MODULE,receiver,1}, meta_match_spec), 410: ?line {meta,Tracer1} = 411: erlang:trace_info({erlang,phash2,2}, meta), 412: ?line {meta_match_spec, MatchSpec} = 413: erlang:trace_info({erlang,phash2,2}, meta_match_spec), 414: %% Initiate trace messages that will fail 415: ?line Ref2 = make_ref(), 416: ?line apply_slave_async(?MODULE, receiver, [Ref2]), 417: ?line Slave ! Ref2, 418: ?line receive_no_next(100), 419: ?line {meta,[]} = 420: erlang:trace_info({?MODULE,receiver,1}, meta), 421: ?line {meta_match_spec, MatchSpec} = 422: erlang:trace_info({?MODULE,receiver,1}, meta_match_spec), 423: ?line {meta,[]} = 424: erlang:trace_info({erlang,phash2,2}, meta), 425: ?line {meta_match_spec, MatchSpec} = 426: erlang:trace_info({erlang,phash2,2}, meta_match_spec), 427: %% Change tracer 428: ?line Tracer2 = spawn_link(fun () -> relay_n(4, Self) end), 429: ?line erlang:trace_pattern({?MODULE,receiver,1}, 430: MatchSpec, 431: [{meta,Tracer2}]), 432: ?line erlang:trace_pattern({erlang,phash2,2}, 433: MatchSpec, 434: [{meta,Tracer2}]), 435: ?line Ref3 = make_ref(), 436: ?line apply_slave_async(?MODULE, receiver, [Ref3]), 437: ?line {Tracer2,?CTT(Slave,{?MODULE,receiver,[Ref3]})} = receive_next(), 438: ?line {Tracer2,?CTT(Slave,{erlang,phash2,[1,1]})} = receive_next(), 439: ?line {Tracer2,?RFT(Slave,{erlang,phash2,2},0)} = receive_next(), 440: %% Change tracer between call trace and return trace 441: ?line Tracer3 = spawn_link(fun () -> relay_n(4, Self) end), 442: ?line erlang:trace_pattern({?MODULE,receiver,1}, 443: MatchSpec, 444: [{meta,Tracer3}]), 445: ?line erlang:trace_pattern({erlang,phash2,2}, 446: MatchSpec, 447: [{meta,Tracer3}]), 448: ?line Slave ! Ref3, 449: %% The return trace should still come from Tracer2 450: ?line {Tracer2,?RFT(Slave,{?MODULE,receiver,1},Ref3)} = receive_next(), 451: ?line Ref4 = make_ref(), 452: %% Now should Tracer3 be used 453: ?line apply_slave_async(?MODULE, receiver, [Ref4]), 454: ?line Slave ! Ref4, 455: ?line {Tracer3,?CTT(Slave,{?MODULE,receiver,[Ref4]})} = receive_next(), 456: ?line {Tracer3,?CTT(Slave,{erlang,phash2,[1,1]})} = receive_next(), 457: ?line {Tracer3,?RFT(Slave,{erlang,phash2,2},0)} = receive_next(), 458: ?line {Tracer3,?RFT(Slave,{?MODULE,receiver,1},Ref4)} = receive_next(), 459: %% The breakpoint has not been hit since the tracer stopped 460: ?line {meta,Tracer3} = 461: erlang:trace_info({?MODULE,receiver,1}, meta), 462: ?line {meta_match_spec, MatchSpec} = 463: erlang:trace_info({?MODULE,receiver,1}, meta_match_spec), 464: ?line {meta,Tracer3} = 465: erlang:trace_info({erlang,phash2,2}, meta), 466: ?line {meta_match_spec, MatchSpec} = 467: erlang:trace_info({erlang,phash2,2}, meta_match_spec), 468: 469: ?line shutdown(), 470: ?line ?NM, 471: ok. 472: 473: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 474: 475: combo_test() -> 476: ?line Slave = setup(), 477: ?line Self = self(), 478: 479: ?line MatchSpec = [{'_',[],[{return_trace}]}], 480: ?line Flags = lists:sort([call, return_to]), 481: ?line LocalTracer = spawn_link(fun () -> relay_n(6, Self) end), 482: ?line MetaTracer = spawn_link(fun () -> relay_n(4, Self) end), 483: ?line 1 = erlang:trace_pattern({?MODULE,receiver,1}, 484: MatchSpec, 485: [local,{meta,MetaTracer}]), 486: ?line 1 = erlang:trace_pattern({erlang,phash2,2}, 487: MatchSpec, 488: [local,{meta,MetaTracer}]), 489: ?line 1 = erlang:trace(Slave, true, 490: [{tracer,LocalTracer} | Flags]), 491: %% 492: ?line {all, TraceInfo1} = 493: erlang:trace_info({?MODULE,receiver,1}, all), 494: ?line {meta,MetaTracer} = 495: erlang:trace_info({?MODULE,receiver,1}, meta), 496: ?line {value,{meta,MetaTracer}} = 497: lists:keysearch(meta, 1, TraceInfo1), 498: ?line {meta_match_spec,MatchSpec} = 499: erlang:trace_info({?MODULE,receiver,1}, meta_match_spec), 500: ?line {value,{meta_match_spec,MatchSpec}} = 501: lists:keysearch(meta_match_spec, 1, TraceInfo1), 502: ?line {traced,local} = 503: erlang:trace_info({?MODULE,receiver,1}, traced), 504: ?line {value,{traced,local}} = 505: lists:keysearch(traced, 1, TraceInfo1), 506: ?line {match_spec,MatchSpec} = 507: erlang:trace_info({?MODULE,receiver,1}, match_spec), 508: ?line {value,{match_spec,MatchSpec}} = 509: lists:keysearch(match_spec, 1, TraceInfo1), 510: %% 511: ?line {all, TraceInfo2} = 512: erlang:trace_info({erlang,phash2,2}, all), 513: ?line {meta,MetaTracer} = 514: erlang:trace_info({erlang,phash2,2}, meta), 515: ?line {value,{meta,MetaTracer}} = 516: lists:keysearch(meta, 1, TraceInfo2), 517: ?line {meta_match_spec,MatchSpec} = 518: erlang:trace_info({erlang,phash2,2}, meta_match_spec), 519: ?line {value,{meta_match_spec,MatchSpec}} = 520: lists:keysearch(meta_match_spec, 1, TraceInfo2), 521: ?line {traced,local} = 522: erlang:trace_info({erlang,phash2,2}, traced), 523: ?line {value,{traced,local}} = 524: lists:keysearch(traced, 1, TraceInfo2), 525: ?line {match_spec,MatchSpec} = 526: erlang:trace_info({erlang,phash2,2}, match_spec), 527: ?line {value,{match_spec,MatchSpec}} = 528: lists:keysearch(match_spec, 1, TraceInfo2), 529: %% 530: ?line {flags,Flags1} = erlang:trace_info(Slave, flags), 531: ?line Flags = lists:sort(Flags1), 532: ?line {tracer,LocalTracer} = erlang:trace_info(Slave, tracer), 533: %% 534: ?line Ref = make_ref(), 535: ?line apply_slave_async(?MODULE, receiver, [Ref]), 536: ?line Slave ! Ref, 537: ?line ?CTT(Slave,{?MODULE,receiver,[Ref]}) = receive_next_bytag(MetaTracer), 538: ?line ?CTT(Slave,{erlang,phash2,[1,1]}) = receive_next_bytag(MetaTracer), 539: ?line ?RFT(Slave,{erlang,phash2,2},0) = receive_next_bytag(MetaTracer), 540: ?line ?RFT(Slave,{?MODULE,receiver,1},Ref) = receive_next_bytag(MetaTracer), 541: ?line ?CT(Slave,{?MODULE,receiver,[Ref]}) = receive_next_bytag(LocalTracer), 542: ?line ?CT(Slave,{erlang,phash2,[1,1]}) = receive_next_bytag(LocalTracer), 543: ?line case {receive_next_bytag(LocalTracer), 544: receive_next_bytag(LocalTracer)} of 545: {?RF(Slave,{erlang,phash2,2},0), 546: ?RT(Slave,{?MODULE,receiver,1})} -> 547: ?line ok; 548: {?RT(Slave,{?MODULE,receiver,1}), 549: ?RF(Slave,{erlang,phash2,2},0)} -> 550: ?line ok; 551: Error1 -> ?t:fail({unexpected_message, Error1}) 552: end, 553: ?line case {receive_next_bytag(LocalTracer), 554: receive_next_bytag(LocalTracer)} of 555: {?RF(Slave,{?MODULE,receiver,1},Ref), 556: ?RT(Slave,{?MODULE,slave,1})} -> 557: ?line ok; 558: {?RT(Slave,{?MODULE,slave,1}), 559: ?RF(Slave,{?MODULE,receiver,1},Ref)} -> 560: ?line ok; 561: Error2 -> ?t:fail({unexpected_message, Error2}) 562: end, 563: 564: ?line shutdown(), 565: ?line ?NM, 566: ok. 567: 568: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 569: %% Use case for Inviso meta tracing: 570: %% Setup silent local call tracing, and start it using meta trace. 571: 572: nosilent_test() -> 573: ?line Pid = setup(), 574: ?line Trigger = {?MODULE,id,1}, 575: ?line TriggerMS = [{[start],[],[{silent,false}]}, 576: {[stop],[],[{silent,true},{return_trace}]}], 577: ?line 1 = erlang:trace(Pid, true, [call,silent,return_to]), 578: ?line erlang:trace_pattern({?MODULE,'_','_'},[],[local]), 579: ?line 1 = erlang:trace_pattern({?MODULE,local2,1}, 580: [{'_',[],[{return_trace}]}], 581: [local]), 582: ?line 1 = erlang:trace_pattern({?MODULE,slave,1},false,[local]), 583: ?line 1 = erlang:trace_pattern(Trigger,false,[local]), 584: ?line 1 = erlang:trace_pattern(Trigger,TriggerMS,[meta]), 585: ?line [1,1,1,0] = apply_slave(?MODULE,exported_wrap,[1]), 586: ?line receive_no_next(17), 587: ?line start = apply_slave(?MODULE, id, [start]), 588: ?line ?CTT(Pid,{?MODULE,id,[start]}) = receive_next(), 589: ?line [2,2,2,0] = apply_slave(?MODULE,exported_wrap,[2]), 590: ?line ?CT(Pid,{?MODULE,exported_wrap,[2]}) = receive_next(), 591: ?line ?CT(Pid,{?MODULE,exported,[2]}) = receive_next(), 592: ?line ?CT(Pid,{?MODULE,local,[2]}) = receive_next(), 593: ?line ?CT(Pid,{?MODULE,local2,[2]}) = receive_next(), 594: ?line ?CT(Pid,{?MODULE,local_tail,[2]}) = receive_next(), 595: ?line ?RF(Pid,{?MODULE,local2,1}, [2,0]) = receive_next(), 596: ?line ?RT(Pid,{?MODULE,local,1}) = receive_next(), 597: ?line ?RT(Pid,{?MODULE,exported,1}) = receive_next(), 598: ?line ?RT(Pid,{?MODULE,slave,1}) = receive_next(), 599: ?line stop = apply_slave(?MODULE, id, [stop]), 600: ?line ?CTT(Pid,{?MODULE,id,[stop]}) = receive_next(), 601: ?line ?RFT(Pid,{?MODULE,id,1}, stop) = receive_next(), 602: ?line [3,3,3,0] = apply_slave(?MODULE,exported_wrap,[3]), 603: ?line receive_no_next(17), 604: ?line shutdown(), 605: ok. 606: 607: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 608: %% Trace target functions 609: 610: loop(D1,D2,D3,0) -> 611: io:format("~p~n",[[D1,D2,D3]]), 612: 0; 613: loop(D1,D2,D3,N) -> 614: max(N,loop(D1,D2,D3,N-1)). 615: 616: id(X) -> 617: X. 618: 619: 620: exported_wrap(Val) -> 621: exported(Val). 622: 623: exported(Val) -> 624: [Val | local(Val)]. %% Non tail recursive local call 625: 626: local(Val) -> 627: [Val | local2(Val)]. %% Non tail recursive local call 628: 629: local2(Val) -> 630: local_tail(Val). %% Tail recursive call 631: 632: local_tail(Val) -> 633: [Val , erlang:phash2(1,1)]. 634: 635: 636: 637: receiver(Msg) -> 638: erlang:phash2(1,1), 639: receive Msg -> Msg end. 640: 641: %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 642: %% Trace target process and utilities 643: 644: slave(Sync) -> 645: Sync ! sync, 646: receive 647: {From,apply, M, F, A} -> 648: ?line ?dbgformat("Apply: ~p:~p/~p (~p)~n",[M,F,length(A),A]), 649: ?line Res = apply(M,F,A), 650: ?line ?dbgformat("done Apply: ~p:~p/~p (~p)~n",[M,F,length(A),A]), 651: From ! {apply, Res}, 652: erlang:trace_pattern({?MODULE,slave,1},false,[meta]), 653: slave(From); 654: {From, lambda, Fun} -> 655: Res = Fun(), 656: From ! {lambda, Res}, 657: erlang:trace_pattern({?MODULE,slave,1},false,[meta]), 658: slave(From); 659: die -> 660: exit(normal) 661: end. 662: 663: setup() -> 664: trace_off(), 665: Self = self(), 666: Pid = spawn(fun () -> slave(Self) end), 667: receive sync -> ok end, 668: put(slave,Pid), 669: Pid. 670: 671: shutdown() -> 672: trace_off(), 673: Pid = get(slave), 674: case (catch is_process_alive(Pid)) of 675: true -> 676: Ref = erlang:monitor(process,Pid), 677: Pid ! die, 678: receive 679: {'DOWN',Ref,process,Pid,_} -> 680: ok 681: end; 682: _ -> 683: ok 684: end. 685: 686: trace_off() -> 687: erlang:trace(all, false, [all]), 688: erlang:trace_pattern({'_','_','_'},false,[]), 689: erlang:trace_pattern({'_','_','_'},false,[local]), 690: erlang:trace_pattern({'_','_','_'},false,[meta]), 691: erlang:trace_pattern(on_load,false,[]), 692: erlang:trace_pattern(on_load,false,[local]), 693: erlang:trace_pattern(on_load,false,[meta]), 694: ok. 695: 696: apply_slave_async(M,F,A) -> 697: Slave = get(slave), 698: Pid = 699: spawn( 700: fun () -> 701: Slave ! {self(),apply, M, F, A}, 702: receive 703: {apply, _} -> 704: receive 705: sync -> 706: ok 707: end 708: end 709: end), 710: Pid. 711: 712: apply_slave(M,F,A) -> 713: Pid = get(slave), 714: Pid ! {self(),apply, M, F, A}, 715: receive 716: {apply, Res} -> 717: receive 718: sync -> 719: Res 720: end 721: end. 722: 723: lambda_slave(Fun) -> 724: Pid = get(slave), 725: Pid ! {self(), lambda, Fun}, 726: receive 727: {lambda, Res} -> 728: receive 729: sync -> 730: Res 731: end 732: end. 733: 734: relay_n(0, _) -> 735: ok; 736: relay_n(N, Dest) -> 737: receive Msg -> 738: Dest ! {self(), Msg}, 739: relay_n(N-1, Dest) 740: end. 741: 742: 743: receive_next() -> 744: receive_next(infinity). 745: 746: receive_next(TO) -> 747: receive 748: M -> 749: M 750: after TO -> 751: ?t:fail(timeout) 752: end. 753: 754: receive_no_next(TO) -> 755: receive 756: M -> 757: ?t:fail({unexpected_message, M}) 758: after 759: TO -> 760: ok 761: end. 762: 763: receive_next_bytag(Tag) -> 764: receive_next_bytag(Tag, infinity). 765: receive_next_bytag(Tag, TO) -> 766: receive 767: {Tag, Msg} -> 768: Msg 769: after 770: TO -> 771: timeout 772: end.