1: %%
    2: %% %CopyrightBegin%
    3: %% 
    4: %% Copyright Ericsson AB 2010-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: -module(trace_nif_SUITE).
   21: 
   22: -include_lib("test_server/include/test_server.hrl").
   23: 
   24: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   25: 	 init_per_group/2,end_per_group/2]).
   26: -export([trace_nif/1,
   27: 	 trace_nif_timestamp/1,
   28: 	 trace_nif_local/1,
   29: 	 trace_nif_meta/1,
   30: 	 trace_nif_timestamp_local/1,
   31: 	 trace_nif_return/1,
   32: 	 not_run/1]).
   33: 
   34: -export([nif_process/0, nif/0, nif/1]).
   35: 
   36: suite() -> [{ct_hooks,[ts_install_cth]}].
   37: 
   38: all() -> 
   39:     case test_server:is_native(trace_nif_SUITE) of
   40: 	true -> [not_run];
   41: 	false ->
   42: 	    [trace_nif, trace_nif_timestamp, trace_nif_local,
   43: 	     trace_nif_meta, trace_nif_timestamp_local,
   44: 	     trace_nif_return]
   45:     end.
   46: 
   47: groups() -> 
   48:     [].
   49: 
   50: init_per_suite(Config) ->
   51:     Config.
   52: 
   53: end_per_suite(_Config) ->
   54:     ok.
   55: 
   56: init_per_group(_GroupName, Config) ->
   57:     Config.
   58: 
   59: end_per_group(_GroupName, Config) ->
   60:     Config.
   61: 
   62: 
   63: not_run(Config) when is_list(Config) -> 
   64:     {skipped,"Native code"}.
   65: 
   66: trace_nif(doc) -> "Test tracing NIFs.";
   67: trace_nif(Config) when is_list(Config) ->
   68:     load_nif(Config),
   69:     
   70:     do_trace_nif([]).
   71: 
   72: trace_nif_local(doc) -> "Test tracing NIFs with local flag.";
   73: trace_nif_local(Config) when is_list(Config) ->
   74:     load_nif(Config),
   75:     do_trace_nif([local]).
   76: 
   77: trace_nif_meta(doc) -> "Test tracing NIFs with meta flag.";
   78: trace_nif_meta(Config) when is_list(Config) ->
   79:     load_nif(Config),
   80:     ?line Pid=spawn_link(?MODULE, nif_process, []),
   81:     ?line erlang:trace_pattern({?MODULE,nif,'_'}, [], [meta]),
   82:     
   83:     ?line Pid ! {apply_nif, nif, []},
   84:     ?line receive_trace_msg_ts({trace_ts,Pid,call,{?MODULE,nif,[]}}),
   85:     
   86:     ?line Pid ! {apply_nif, nif, ["Arg1"]},
   87:     ?line receive_trace_msg_ts({trace_ts,Pid,call,
   88: 				{?MODULE,nif, ["Arg1"]}}),
   89:     
   90:     ?line Pid ! {call_nif, nif, []},
   91:     ?line receive_trace_msg_ts({trace_ts,Pid,call,
   92: 				{?MODULE,nif, []}}),
   93:     
   94:     ?line Pid ! {call_nif, nif, ["Arg1"]},
   95:     ?line receive_trace_msg_ts({trace_ts,Pid,call,
   96: 				{?MODULE,nif, ["Arg1"]}}),
   97:     ok.
   98: do_trace_nif(Flags) ->
   99:     ?line Pid = spawn(?MODULE, nif_process, []),
  100:     ?line 1 = erlang:trace(Pid, true, [call]),
  101:     ?line erlang:trace_pattern({?MODULE,nif,'_'}, [], Flags),
  102:     ?line Pid ! {apply_nif, nif, []},
  103:     ?line receive_trace_msg({trace,Pid,call,{?MODULE,nif, []}}),
  104:     ?line Pid ! {apply_nif, nif, ["Arg1"]},
  105:     ?line receive_trace_msg({trace,Pid,call,{?MODULE,nif, ["Arg1"]}}),
  106: 
  107:     ?line Pid ! {call_nif, nif, []},
  108:     ?line receive_trace_msg({trace, Pid, call, {?MODULE,nif, []}}),
  109: 
  110:     ?line Pid ! {call_nif, nif, ["Arg1"]},
  111:     ?line receive_trace_msg({trace, Pid, call, {?MODULE,nif, ["Arg1"]}}),
  112: 
  113:     
  114:     %% Switch off
  115:     ?line 1 = erlang:trace(Pid, false, [call]),
  116: 
  117:     ?line Pid ! {apply_nif, nif, []},
  118:     receive_nothing(),
  119:     ?line Pid ! {apply_nif, nif, ["Arg1"]},
  120:     receive_nothing(),
  121:     ?line Pid ! {call_nif, nif, []},
  122:     receive_nothing(),
  123:     ?line Pid ! {call_nif, nif, ["Arg1"]},
  124:     receive_nothing(),
  125: 
  126:     %% Switch on again
  127:     ?line 1 = erlang:trace(Pid, true, [call]),
  128:     ?line erlang:trace_pattern({?MODULE,nif,'_'}, [], Flags),
  129:     ?line Pid ! {apply_nif, nif, []},
  130:     ?line receive_trace_msg({trace,Pid,call,{?MODULE,nif, []}}),
  131:     ?line Pid ! {apply_nif, nif, ["Arg1"]},
  132:     ?line receive_trace_msg({trace,Pid,call,{?MODULE,nif, ["Arg1"]}}),
  133: 
  134:     ?line Pid ! {call_nif, nif, []},
  135:     ?line receive_trace_msg({trace, Pid, call, {?MODULE,nif, []}}),
  136: 
  137:     ?line Pid ! {call_nif, nif, ["Arg1"]},
  138:     ?line receive_trace_msg({trace, Pid, call, {?MODULE,nif, ["Arg1"]}}),
  139:     
  140:     ?line 1 = erlang:trace(Pid, false, [call]),
  141:     ?line erlang:trace_pattern({?MODULE,nif,'_'}, false, Flags),
  142:     ?line exit(Pid, die),
  143:     ok.
  144: 
  145: trace_nif_timestamp(doc) -> "Test tracing NIFs with timestamps.";
  146: trace_nif_timestamp(Config) when is_list(Config) ->
  147:     load_nif(Config),
  148:     do_trace_nif_timestamp([]).
  149: 
  150: trace_nif_timestamp_local(doc) -> 
  151:     "Test tracing NIFs with timestamps and local flag.";
  152: trace_nif_timestamp_local(Config) when is_list(Config) ->
  153:     load_nif(Config),
  154:     do_trace_nif_timestamp([local]).
  155: 
  156: do_trace_nif_timestamp(Flags) ->
  157:     ?line Pid=spawn(?MODULE, nif_process, []),
  158:     ?line 1 = erlang:trace(Pid, true, [call,timestamp]),
  159:     ?line erlang:trace_pattern({?MODULE,nif,'_'}, [], Flags),
  160:     
  161:     ?line Pid ! {apply_nif, nif, []},
  162:     ?line receive_trace_msg_ts({trace_ts,Pid,call,{?MODULE,nif,[]}}),
  163:     
  164:     ?line Pid ! {apply_nif, nif, ["Arg1"]},
  165:     ?line receive_trace_msg_ts({trace_ts,Pid,call,
  166: 				{?MODULE,nif, ["Arg1"]}}),
  167:     
  168:     ?line Pid ! {call_nif, nif, []},
  169:     ?line receive_trace_msg_ts({trace_ts,Pid,call,
  170: 				{?MODULE,nif, []}}),
  171:     
  172:     ?line Pid ! {call_nif, nif, ["Arg1"]},
  173:     ?line receive_trace_msg_ts({trace_ts,Pid,call,
  174: 				{?MODULE,nif, ["Arg1"]}}),
  175:     
  176:     %% We should be able to turn off the timestamp.
  177:     ?line 1 = erlang:trace(Pid, false, [timestamp]),
  178:     
  179:     ?line Pid ! {call_nif, nif, []},
  180:     ?line receive_trace_msg({trace,Pid,call,
  181:  			     {?MODULE,nif, []}}),
  182:     
  183:     ?line Pid ! {apply_nif, nif, ["tjoho"]},
  184:     ?line receive_trace_msg({trace,Pid,call,
  185:  			     {?MODULE,nif, ["tjoho"]}}),
  186:     
  187:     ?line 1 = erlang:trace(Pid, false, [call]),
  188:     ?line erlang:trace_pattern({erlang,'_','_'}, false, Flags),
  189:     
  190:     ?line exit(Pid, die),
  191:     ok.
  192: 
  193: trace_nif_return(doc) -> 
  194:     "Test tracing NIF's with return/return_to trace.";
  195: trace_nif_return(Config) when is_list(Config) ->
  196:     load_nif(Config),
  197: 
  198:     ?line Pid=spawn(?MODULE, nif_process, []),
  199:     ?line 1 = erlang:trace(Pid, true, [call,timestamp,return_to]),
  200:     ?line erlang:trace_pattern({?MODULE,nif,'_'}, [{'_',[],[{return_trace}]}], 
  201:  			       [local]),
  202: 
  203:     ?line Pid ! {apply_nif, nif, []},
  204:     ?line receive_trace_msg_ts({trace_ts,Pid,call,{?MODULE,nif,[]}}),
  205:     ?line receive_trace_msg_ts_return_from({trace_ts,Pid,return_from,
  206:  					    {?MODULE,nif,0}}),
  207:     ?line receive_trace_msg_ts_return_to({trace_ts,Pid,return_to, 
  208:  					  {?MODULE, nif_process,0}}),
  209:         
  210:     ?line Pid ! {call_nif, nif, ["Arg1"]},
  211:     ?line receive_trace_msg_ts({trace_ts,Pid,call,
  212: 				{?MODULE,nif, ["Arg1"]}}),
  213:     ?line receive_trace_msg_ts_return_from({trace_ts,Pid,return_from,
  214: 					    {?MODULE,nif,1}}),
  215:     ?line receive_trace_msg_ts_return_to({trace_ts,Pid,return_to, 
  216:  					  {?MODULE, nif_process,0}}),
  217:     ok.
  218: 
  219: 
  220: receive_trace_msg(Mess) ->
  221:     receive
  222:  	Mess ->
  223:  	    ok;
  224:  	Other ->
  225:  	    io:format("Expected: ~p,~nGot: ~p~n", [Mess, Other]),
  226:  	    ?t:fail()
  227:     after 5000 ->
  228:  	    io:format("Expected: ~p,~nGot: timeout~n", [Mess]),
  229:  	    ?t:fail()
  230:     end.
  231: 
  232: receive_nothing() ->
  233:     ?line timeout = receive M -> M after 100 -> timeout end.
  234: 
  235: receive_trace_msg_ts({trace_ts, Pid, call, {M,F,A}}) ->
  236:     receive
  237:  	{trace_ts, Pid, call, {M, F, A}, _Ts} ->
  238:  	    ok;
  239:  	Other ->
  240:  	    io:format("Expected: {trace, ~p, call, {~p, ~p, ~p}, TimeStamp}},~n"
  241:  		      "Got: ~p~n",
  242:  		      [Pid, M, F, A, Other]),
  243:  	    ?t:fail()
  244:     after 5000 ->
  245:  	    io:format("Got timeout~n", []),
  246:  	    ?t:fail()
  247:     end.
  248: 
  249: receive_trace_msg_ts_return_from({trace_ts, Pid, return_from, {M,F,A}}) ->
  250:     receive
  251:  	{trace_ts, Pid, return_from, {M, F, A}, _Value, _Ts} ->
  252:  	    ok;
  253:  	Other ->
  254:  	    io:format("Expected: {trace_ts, ~p, return_from, {~p, ~p, ~p}, Value, TimeStamp}},~n"
  255:  		      "Got: ~p~n",
  256:  		      [Pid, M, F, A, Other]),
  257:  	    ?t:fail()
  258:     after 5000 ->
  259:  	    io:format("Got timeout~n", []),
  260:  	    ?t:fail()
  261:     end.
  262: 
  263: receive_trace_msg_ts_return_to({trace_ts, Pid, return_to, {M,F,A}}) ->
  264:     receive
  265:  	{trace_ts, Pid, return_to, {M, F, A}, _Ts} ->
  266:  	    ok;
  267:  	Other ->
  268:  	    io:format("Expected: {trace_ts, ~p, return_to, {~p, ~p, ~p}, TimeStamp}},~n"
  269:  		      "Got: ~p~n",
  270:  		      [Pid, M, F, A, Other]),
  271:  	    ?t:fail()
  272:     after 5000 ->
  273:  	    io:format("Got timeout~n", []),
  274:  	    ?t:fail()
  275:     end.
  276: 
  277: nif_process() ->
  278:     receive
  279: 	{apply_nif, Name, Args} ->
  280: 	    ?line {ok,Args} = apply(?MODULE, Name, Args);
  281: 
  282: 	{call_nif, Name, []} ->
  283: 	    ?line {ok, []} = ?MODULE:Name();
  284: 	
  285: 	{call_nif, Name, [A1]} ->
  286: 	    ?line {ok, [A1]} = ?MODULE:Name(A1);
  287: 	
  288: 	{call_nif, Name, [A1,A2]} ->
  289: 	    ?line {ok,[A1,A2]} = ?MODULE:Name(A1,A2);
  290: 	
  291: 	{call_nif, Name, [A1,A2,A3]} ->
  292: 	    ?line {ok,[A1,A2,A3]} = ?MODULE:Name(A1,A2,A3)    
  293:     end,
  294:     nif_process().    
  295: 
  296: load_nif(Config) ->    
  297:     ?line Path = ?config(data_dir, Config),
  298:     
  299:     ?line ok = erlang:load_nif(filename:join(Path,"trace_nif"), 0).
  300: 
  301: 
  302: nif() ->
  303:     {"Stub0",[]}. %exit("nif/0 stub called").
  304: 
  305: nif(A1) ->
  306:     {"Stub1",[A1]}. %exit(["nif/1 stub called",A1]).
  307: