4
%% Copyright Ericsson AB 2011. All Rights Reserved.
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/.
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
20
%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
22
%%% Define to run outside of test server
24
%%% -define(STANDALONE,1).
27
%%% Define for debug output
31
-module(trace_call_time_SUITE).
33
%% Exported end user tests
35
-export([seq/3, seq_r/3]).
36
-export([loaded/1, a_function/1, a_called_function/1, dec/1, nif_dec/1]).
38
-define(US_ERROR, 10000).
39
-define(R_ERROR, 0.8).
40
-define(SINGLE_CALL_US_TIME, 10).
42
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43
%% Result examination macros
45
-define(CT(P,MFA),{trace,P,call,MFA}).
46
-define(CTT(P, MFA),{trace_ts,P,call,MFA,{_,_,_}}).
47
-define(RF(P,MFA,V),{trace,P,return_from,MFA,V}).
48
-define(RFT(P,MFA,V),{trace_ts,P,return_from,MFA,V,{_,_,_}}).
49
-define(RT(P,MFA),{trace,P,return_to,MFA}).
50
-define(RTT(P,MFA),{trace_ts,P,return_to,MFA,{_,_,_}}).
53
-define(dbgformat(A,B),io:format(A,B)).
55
-define(dbgformat(A,B),noop).
58
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
60
-include_lib("test_server/include/test_server.hrl").
62
%% When run in test server.
63
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
64
init_per_group/2,end_per_group/2,
65
init_per_testcase/2, end_per_testcase/2, not_run/1]).
66
-export([basic/1, on_and_off/1, info/1,
67
pause_and_restart/1, scheduling/1, called_function/1, combo/1,
70
init_per_testcase(_Case, Config) ->
71
?line Dog=test_server:timetrap(test_server:seconds(400)),
72
erlang:trace_pattern({'_','_','_'}, false, [local,meta,call_time,call_count]),
73
erlang:trace_pattern(on_load, false, [local,meta,call_time,call_count]),
74
timer:now_diff(now(),now()),
75
[{watchdog, Dog}|Config].
77
end_per_testcase(_Case, Config) ->
78
erlang:trace_pattern({'_','_','_'}, false, [local,meta,call_time,call_count]),
79
erlang:trace_pattern(on_load, false, [local,meta,call_time,call_count]),
80
erlang:trace(all, false, [all]),
81
Dog=?config(watchdog, Config),
82
test_server:timetrap_cancel(Dog),
85
suite() -> [{ct_hooks,[ts_install_cth]}].
88
case test_server:is_native(trace_call_time_SUITE) of
91
[basic, on_and_off, info, pause_and_restart, scheduling,
92
combo, bif, nif, called_function]
98
init_per_suite(Config) ->
101
end_per_suite(_Config) ->
104
init_per_group(_GroupName, Config) ->
107
end_per_group(_GroupName, Config) ->
111
not_run(Config) when is_list(Config) ->
112
{skipped,"Native code"}.
117
["Tests basic call count trace"];
118
basic(Config) when is_list(Config) ->
119
?line P = erlang:trace_pattern({'_','_','_'}, false, [call_time]),
122
?line 1 = erlang:trace_pattern({?MODULE,seq, '_'}, true, [call_time]),
123
?line 2 = erlang:trace_pattern({?MODULE,seq_r,'_'}, true, [call_time]),
125
?line {L, T1} = execute(Pid, fun() -> seq(1, M, fun(X) -> (X+1) end) end),
126
?line ok = check_trace_info({?MODULE, seq, 3}, [{Pid, M, 0, 0}], T1),
127
?line ok = check_trace_info({?MODULE, seq_r, 3}, [], none),
129
?line {Lr, T2} = execute(Pid, fun() -> seq_r(1, M, fun(X) -> (X+1) end) end),
130
?line ok = check_trace_info({?MODULE, seq, 3}, [{Pid, M, 0, 0}], T1),
131
?line ok = check_trace_info({?MODULE, seq_r, 3}, [{Pid, 1, 0, 0}], T2/M),
132
?line ok = check_trace_info({?MODULE, seq_r, 4}, [{Pid, M, 0, 0}], T2),
133
?line L = lists:reverse(Lr),
136
?line P = erlang:trace_pattern({'_','_','_'}, false, [call_time]),
140
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
146
["Tests turning trace parameters on and off"];
147
on_and_off(Config) when is_list(Config) ->
148
?line P = erlang:trace_pattern({'_','_','_'}, false, [call_time]),
151
?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, true, [call_time]),
153
?line {L, T1} = execute(Pid, {?MODULE, seq, [1, M, fun(X) -> X+1 end]}),
154
?line ok = check_trace_info({?MODULE, seq, 3}, [{Pid, M, 0, 0}], T1),
156
?line N = erlang:trace_pattern({?MODULE,'_','_'}, true, [call_time]),
157
?line {L, T2} = execute(Pid, fun() -> seq(1, M, fun(X) -> X+1 end) end),
158
?line ok = check_trace_info({?MODULE, seq, 3}, [{Pid, M, 0, 0}], T2),
160
?line P = erlang:trace_pattern({'_','_','_'}, true, [call_time]),
161
?line {L, T3} = execute(Pid, fun() -> seq(1, M, fun(X) -> X+1 end) end),
162
?line ok = check_trace_info({?MODULE, seq, 3}, [{Pid, M, 0, 0}], T3),
164
?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, false, [call_time]),
165
?line ok = check_trace_info({?MODULE, seq, 3}, false, none),
166
?line {L, _T4} = execute(Pid, fun() -> seq(1, M, fun(X) -> X+1 end) end),
167
?line ok = check_trace_info({?MODULE, seq, 3}, false, none),
168
?line ok = check_trace_info({?MODULE, seq_r, 4}, [], none),
169
?line {Lr, T5} = execute(Pid, fun() -> seq_r(1, M, fun(X) -> X+1 end) end),
170
?line ok = check_trace_info({?MODULE, seq_r, 4}, [{Pid,M,0,0}], T5),
172
?line N = erlang:trace_pattern({?MODULE,'_','_'}, false, [call_time]),
173
?line ok = check_trace_info({?MODULE, seq_r, 4}, false, none),
174
?line {Lr, _T6} = execute(Pid, fun() -> seq_r(1, M, fun(X) -> X+1 end) end),
175
?line ok = check_trace_info({?MODULE, seq_r, 4}, false, none),
176
?line L = lists:reverse(Lr),
179
?line P = erlang:trace_pattern({'_','_','_'}, false, [call_time]),
182
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187
["Tests the trace_info BIF"];
188
info(Config) when is_list(Config) ->
189
?line P = erlang:trace_pattern({'_','_','_'}, false, [call_time]),
191
?line 1 = erlang:trace_pattern({?MODULE,seq,3}, true, [call_time]),
192
?line {call_time,[]} = erlang:trace_info({?MODULE,seq,3}, call_time),
193
?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, pause, [call_time]),
194
?line {call_time,[]} = erlang:trace_info({?MODULE,seq,3}, call_time),
195
?line {all,[_|_]=L} = erlang:trace_info({?MODULE,seq,3}, all),
196
?line {value,{call_time,[]}} = lists:keysearch(call_time, 1, L),
197
?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, restart, [call_time]),
198
?line {call_time,[]} = erlang:trace_info({?MODULE,seq,3}, call_time),
199
?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, false, [call_time]),
200
?line {call_time,false} = erlang:trace_info({?MODULE,seq,3}, call_time),
201
?line {all,false} = erlang:trace_info({?MODULE,seq,3}, all),
203
?line P = erlang:trace_pattern({'_','_','_'}, false, [call_time]),
206
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
208
pause_and_restart(suite) ->
210
pause_and_restart(doc) ->
211
["Tests pausing and restarting call time counters"];
212
pause_and_restart(Config) when is_list(Config) ->
213
?line P = erlang:trace_pattern({'_','_','_'}, false, [call_time]),
217
?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, true, [call_time]),
218
?line ok = check_trace_info({?MODULE, seq, 3}, [], none),
219
?line {L, T1} = execute(Pid, fun() -> seq(1, M, fun(X) -> X+1 end) end),
220
?line ok = check_trace_info({?MODULE, seq, 3}, [{Pid,M,0,0}], T1),
221
?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, pause, [call_time]),
222
?line ok = check_trace_info({?MODULE, seq, 3}, [{Pid,M,0,0}], T1),
223
?line {L, T2} = execute(Pid, fun() -> seq(1, M, fun(X) -> X+1 end) end),
224
?line ok = check_trace_info({?MODULE, seq, 3}, [{Pid,M,0,0}], T2),
225
?line 1 = erlang:trace_pattern({?MODULE,seq,'_'}, restart, [call_time]),
226
?line ok = check_trace_info({?MODULE, seq, 3}, [], none),
227
?line {L, T3} = execute(Pid, fun() -> seq(1, M, fun(X) -> X+1 end) end),
228
?line ok = check_trace_info({?MODULE, seq, 3}, [{Pid,M,0,0}], T3),
231
?line P = erlang:trace_pattern({'_','_','_'}, false, [call_time]),
234
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239
["Tests in/out scheduling of call time counters"];
240
scheduling(Config) when is_list(Config) ->
241
?line P = erlang:trace_pattern({'_','_','_'}, false, [call_time]),
243
?line Np = erlang:system_info(schedulers_online),
246
%% setup load processes
247
%% (single, no internal calls)
249
?line erlang:trace_pattern({?MODULE,loaded,1}, true, [call_time]),
251
?line Pids = [setup() || _ <- lists:seq(1, F*Np)],
252
?line {_Ls,T1} = execute(Pids, {?MODULE,loaded,[M]}),
253
?line [Pid ! quit || Pid <- Pids],
255
%% logic dictates that each process will get ~ 1/F of the schedulers time
257
?line {call_time, CT} = erlang:trace_info({?MODULE,loaded,1}, call_time),
259
?line lists:foreach(fun (Pid) ->
260
?line ok = case check_process_time(lists:keysearch(Pid, 1, CT), M, F, T1) of
261
schedule_time_error ->
262
test_server:comment("Warning: Failed time ratio"),
267
?line P = erlang:trace_pattern({'_','_','_'}, false, [call_time]),
270
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275
["Tests combining local call trace and meta trace with call time trace"];
276
combo(Config) when is_list(Config) ->
279
?line MetaMs = [{'_',[],[{return_trace}]}],
280
?line Flags = lists:sort([call, return_to]),
281
?line LocalTracer = spawn_link(fun () -> relay_n(5 + Nbc + 3, Self) end),
282
?line MetaTracer = spawn_link(fun () -> relay_n(9 + Nbc + 3, Self) end),
283
?line 2 = erlang:trace_pattern({?MODULE,seq_r,'_'}, [], [local]),
284
?line 2 = erlang:trace_pattern({?MODULE,seq_r,'_'}, true, [call_time]),
285
?line 2 = erlang:trace_pattern({?MODULE,seq_r,'_'}, MetaMs, [{meta,MetaTracer}]),
286
?line 2 = erlang:trace_pattern({?MODULE,seq_r,'_'}, true, [call_count]),
289
?line 2 = erlang:trace_pattern({erlang, term_to_binary, '_'}, [], [local]),
290
?line 2 = erlang:trace_pattern({erlang, term_to_binary, '_'}, true, [call_time]),
291
?line 2 = erlang:trace_pattern({erlang, term_to_binary, '_'}, MetaMs, [{meta,MetaTracer}]),
293
%?line 2 = erlang:trace_pattern({erlang, term_to_binary, '_'}, true, [call_count]),
295
?line 1 = erlang:trace(Self, true, [{tracer,LocalTracer} | Flags]),
297
?line {traced,local} =
298
erlang:trace_info({?MODULE,seq_r,3}, traced),
299
?line {match_spec,[]} =
300
erlang:trace_info({?MODULE,seq_r,3}, match_spec),
301
?line {meta,MetaTracer} =
302
erlang:trace_info({?MODULE,seq_r,3}, meta),
303
?line {meta_match_spec,MetaMs} =
304
erlang:trace_info({?MODULE,seq_r,3}, meta_match_spec),
305
?line ok = check_trace_info({?MODULE, seq_r, 3}, [], none),
307
%% check empty trace_info for ?MODULE:seq_r/3
308
?line {all,[_|_]=TraceInfo} = erlang:trace_info({?MODULE,seq_r,3}, all),
309
?line {value,{traced,local}} = lists:keysearch(traced, 1, TraceInfo),
310
?line {value,{match_spec,[]}} = lists:keysearch(match_spec, 1, TraceInfo),
311
?line {value,{meta,MetaTracer}} = lists:keysearch(meta, 1, TraceInfo),
312
?line {value,{meta_match_spec,MetaMs}} = lists:keysearch(meta_match_spec, 1, TraceInfo),
313
?line {value,{call_count,0}} = lists:keysearch(call_count, 1, TraceInfo),
314
?line {value,{call_time,[]}} = lists:keysearch(call_time, 1, TraceInfo),
316
%% check empty trace_info for erlang:term_to_binary/1
317
?line {all, [_|_] = TraceInfoBif} = erlang:trace_info({erlang, term_to_binary, 1}, all),
318
?line {value,{traced,local}} = lists:keysearch(traced, 1, TraceInfoBif),
319
?line {value,{match_spec,[]}} = lists:keysearch(match_spec, 1, TraceInfoBif),
320
?line {value,{meta, MetaTracer}} = lists:keysearch(meta, 1, TraceInfoBif),
321
?line {value,{meta_match_spec,MetaMs}} = lists:keysearch(meta_match_spec, 1, TraceInfoBif),
323
?line {value,{call_count,false}} = lists:keysearch(call_count, 1, TraceInfoBif),
324
%?line {value,{call_count,0}} = lists:keysearch(call_count, 1, TraceInfoBif),
325
?line {value,{call_time,[]}} = lists:keysearch(call_time, 1, TraceInfoBif),
328
?line [3,2,1] = seq_r(1, 3, fun(X) -> X+1 end),
332
?line TimeB = timer:now_diff(T1,T0),
335
?line List = collect(100),
336
?line {MetaR, LocalR} =
338
fun ({P,X}, {M,L}) when P == MetaTracer ->
340
({P,X}, {M,L}) when P == LocalTracer ->
345
?line Meta = lists:reverse(MetaR),
346
?line Local = lists:reverse(LocalR),
348
?line [?CTT(Self,{?MODULE,seq_r,[1,3,_]}),
349
?CTT(Self,{?MODULE,seq_r,[1,3,_,[]]}),
350
?CTT(Self,{?MODULE,seq_r,[2,3,_,[1]]}),
351
?CTT(Self,{?MODULE,seq_r,[3,3,_,[2,1]]}),
352
?RFT(Self,{?MODULE,seq_r,4},[3,2,1]),
353
?RFT(Self,{?MODULE,seq_r,4},[3,2,1]),
354
?RFT(Self,{?MODULE,seq_r,4},[3,2,1]),
355
?RFT(Self,{?MODULE,seq_r,3},[3,2,1]),
356
?CTT(Self,{erlang,term_to_binary,[3]}), % bif
357
?RFT(Self,{erlang,term_to_binary,1},<<131,97,3>>),
358
?CTT(Self,{erlang,term_to_binary,[2]}),
359
?RFT(Self,{erlang,term_to_binary,1},<<131,97,2>>)
362
?line [?CT(Self,{?MODULE,seq_r,[1,3,_]}),
363
?CT(Self,{?MODULE,seq_r,[1,3,_,[]]}),
364
?CT(Self,{?MODULE,seq_r,[2,3,_,[1]]}),
365
?CT(Self,{?MODULE,seq_r,[3,3,_,[2,1]]}),
366
?RT(Self,{?MODULE,combo,1}),
367
?CT(Self,{erlang,term_to_binary,[3]}), % bif
368
?RT(Self,{?MODULE,with_bif,1}),
369
?CT(Self,{erlang,term_to_binary,[2]}),
370
?RT(Self,{?MODULE,with_bif,1})
373
?line ok = check_trace_info({?MODULE, seq_r, 3}, [{Self,1,0,0}], 1),
374
?line ok = check_trace_info({?MODULE, seq_r, 4}, [{Self,3,0,0}], 1),
375
?line ok = check_trace_info({?MODULE, seq_r, 3}, [{Self,1,0,0}], 1),
376
?line ok = check_trace_info({?MODULE, seq_r, 4}, [{Self,3,0,0}], 1),
377
?line ok = check_trace_info({erlang, term_to_binary, 1}, [{self(), Nbc - 1, 0, 0}], TimeB),
379
?line erlang:trace_pattern({'_','_','_'}, false, [local,meta,call_time]),
380
?line erlang:trace_pattern(on_load, false, [local,meta,call_time]),
381
?line erlang:trace(all, false, [all]),
384
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
389
["Tests tracing of bifs"];
390
bif(Config) when is_list(Config) ->
391
?line P = erlang:trace_pattern({'_','_','_'}, false, [call_time]),
394
?line 2 = erlang:trace_pattern({erlang, binary_to_term, '_'}, true, [call_time]),
395
?line 2 = erlang:trace_pattern({erlang, term_to_binary, '_'}, true, [call_time]),
397
?line {L, T1} = execute(Pid, fun() -> with_bif(M) end),
399
?line ok = check_trace_info({erlang, binary_to_term, 1}, [{Pid, M - 1, 0, 0}], T1/2),
400
?line ok = check_trace_info({erlang, term_to_binary, 1}, [{Pid, M - 1, 0, 0}], T1/2),
402
% disable term2binary
404
?line 2 = erlang:trace_pattern({erlang, term_to_binary, '_'}, false, [call_time]),
406
?line {L, T2} = execute(Pid, fun() -> with_bif(M) end),
408
?line ok = check_trace_info({erlang, binary_to_term, 1}, [{Pid, M*2 - 2, 0, 0}], T1/2 + T2),
409
?line ok = check_trace_info({erlang, term_to_binary, 1}, false, none),
412
?line P = erlang:trace_pattern({'_','_','_'}, false, [call_time]),
416
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
421
["Tests tracing of nifs"];
422
nif(Config) when is_list(Config) ->
424
?line P = erlang:trace_pattern({'_','_','_'}, false, [call_time]),
427
?line 1 = erlang:trace_pattern({?MODULE, nif_dec, '_'}, true, [call_time]),
428
?line 1 = erlang:trace_pattern({?MODULE, with_nif, '_'}, true, [call_time]),
430
?line {_, T1} = execute(Pid, fun() -> with_nif(M) end),
432
% the nif is called M - 1 times, the last time the function with 'with_nif'
433
% returns ok and does not call the nif.
434
?line ok = check_trace_info({?MODULE, nif_dec, 1}, [{Pid, M-1, 0, 0}], T1/5*4),
435
?line ok = check_trace_info({?MODULE, with_nif, 1}, [{Pid, M, 0, 0}], T1/5),
438
?line P = erlang:trace_pattern({'_','_','_'}, false, [call_time]),
442
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
444
called_function(suite) ->
446
called_function(doc) ->
447
["Tests combining nested function calls and that the time accumulates to the right function"];
448
called_function(Config) when is_list(Config) ->
449
?line P = erlang:trace_pattern({'_','_','_'}, false, [call_time]),
453
?line 1 = erlang:trace_pattern({?MODULE,a_function,'_'}, true, [call_time]),
454
?line {L, T1} = execute(Pid, {?MODULE, a_function, [M]}),
455
?line ok = check_trace_info({?MODULE, a_function, 1}, [{Pid, M, 0, 0}], T1),
457
?line 1 = erlang:trace_pattern({?MODULE,a_called_function,'_'}, true, [call_time]),
458
?line {L, T2} = execute(Pid, {?MODULE, a_function, [M]}),
459
?line ok = check_trace_info({?MODULE, a_function, 1}, [{Pid, M+M, 0, 0}], T1 + M*?SINGLE_CALL_US_TIME),
460
?line ok = check_trace_info({?MODULE, a_called_function, 1}, [{Pid, M, 0, 0}], T2),
463
?line 1 = erlang:trace_pattern({?MODULE,dec,'_'}, true, [call_time]),
464
?line {L, T3} = execute(Pid, {?MODULE, a_function, [M]}),
465
?line ok = check_trace_info({?MODULE, a_function, 1}, [{Pid, M+M+M, 0, 0}], T1 + (M+M)*?SINGLE_CALL_US_TIME),
466
?line ok = check_trace_info({?MODULE, a_called_function, 1}, [{Pid, M+M, 0, 0}], T2 + M*?SINGLE_CALL_US_TIME ),
467
?line ok = check_trace_info({?MODULE, dec, 1}, [{Pid, M, 0, 0}], T3),
470
?line P = erlang:trace_pattern({'_','_','_'}, false, [call_time]),
473
%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
478
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
483
?line Path = ?config(data_dir, Config),
484
?line ok = erlang:load_nif(filename:join(Path,"trace_nif"), 0).
487
%% Stack recursive seq
488
seq(Stop, Stop, Succ) when is_function(Succ) ->
490
seq(Start, Stop, Succ) when is_function(Succ) ->
491
[Start | seq(Succ(Start), Stop, Succ)].
494
a_function(1) -> a_called_function(1);
495
a_function(N) when N > 1 -> a_function(a_called_function(N)).
497
a_called_function(N) -> dec(N).
501
with_bif(erlang:binary_to_term(erlang:term_to_binary(N)) - 1).
503
with_nif(0) -> error;
506
with_nif(?MODULE:nif_dec(N)).
515
loaded(N) when N > 1 -> loaded(N - 1);
519
%% Tail recursive seq, result list is reversed
520
seq_r(Start, Stop, Succ) when is_function(Succ) ->
521
seq_r(Start, Stop, Succ, []).
523
seq_r(Stop, Stop, _, R) ->
525
seq_r(Start, Stop, Succ, R) ->
526
seq_r(Succ(Start), Stop, Succ, [Start | R]).
528
% Check call time tracing data and print mismatches
529
check_trace_info(Mfa, [{Pid, C,_,_}] = Expect, Time) ->
530
case erlang:trace_info(Mfa, call_time) of
531
% Time tests are somewhat problematic. We want to know if Time (EXPECTED_TIME) and S*1000000 + Us (ACTUAL_TIME)
533
% If the ratio EXPECTED_TIME/ACTUAL_TIME is ~ 1 or if EXPECTED_TIME - ACTUAL_TIME is near zero, the test is ok.
534
{call_time,[{Pid,C,S,Us}]} when S >= 0, Us >= 0, abs(1 - Time/(S*1000000 + Us)) < ?R_ERROR; abs(Time - S*1000000 - Us) < ?US_ERROR ->
536
{call_time,[{Pid,C,S,Us}]} ->
537
Sum = S*1000000 + Us,
538
io:format("Expected ~p -> {call_time, ~p (Time ~p us)}~n - got ~w s. ~w us. = ~w us. - ~w -> delta ~w (ratio ~.2f, should be 1.0)~n",
539
[Mfa, Expect, Time, S, Us, Sum, Time, Sum - Time, Time/Sum]),
542
io:format("Expected ~p -> {call_time, ~p (Time ~p us)}~n - got ~p~n", [ Mfa, Expect, Time, Other]),
545
check_trace_info(Mfa, Expect, _) ->
546
case erlang:trace_info(Mfa, call_time) of
547
{call_time, Expect} ->
550
io:format("Expected ~p -> {call_time, ~p}~n - got ~p~n", [Mfa, Expect, Other]),
551
result_not_expected_error
556
check_process_time({value,{Pid, M, S, Us}}, M, F, Time) ->
557
?line Sum = S*1000000 + Us,
559
abs(1 - (F/(Time/Sum))) < ?R_ERROR ->
562
io:format("- Pid ~p, Got ratio ~.2f, expected ratio ~w~n", [Pid, Time/Sum,F]),
565
check_process_time(Other, M, _, _) ->
566
io:format(" - Got ~p, expected count ~w~n", [Other, M]),
571
%% Message relay process
576
Dest ! {self(), Msg},
582
%% Collect received messages
584
Ref = erlang:start_timer(Time, self(), done),
585
L = lists:reverse(collect([], Ref)),
586
?dbgformat("Got: ~p~n",[L]),
592
collect([Mess | A], 0)
598
{timeout, Ref, done} ->
601
collect([Mess | A], Ref)
605
Pid = spawn_link(fun() -> loop() end),
606
?line 1 = erlang:trace(Pid, true, [call]),
609
execute(Pids, Mfa) when is_list(Pids) ->
611
[P ! {self(), execute, Mfa} || P <- Pids],
612
As = [receive {P, answer, Answer} -> Answer end || P <- Pids],
614
{As, timer:now_diff(T1,T0)};
617
P ! {self(), execute, Mfa},
618
A = receive {P, answer, Answer} -> Answer end,
620
{A, timer:now_diff(T1,T0)}.
628
{Pid, execute, Fun } when is_function(Fun) ->
629
Pid ! {self(), answer, erlang:apply(Fun, [])},
631
{Pid, execute, {M, F, A}} ->
632
Pid ! {self(), answer, erlang:apply(M, F, A)},