41
41
%%==========================================================================
43
-type(activity_option() ::
44
{'ts_min', timestamp()} |
45
{'ts_max', timestamp()} |
46
{'ts_exact', bool()} |
49
{'id', 'all' | 'procs' | 'ports' | pid() | port()}).
51
-type(scheduler_option() ::
52
{'ts_min', timestamp()} |
53
{'ts_max', timestamp()} |
54
{'ts_exact', bool()} |
55
{'id', scheduler_id()}).
57
-type(system_option() ::
58
'start_ts' | 'stop_ts').
60
-type(information_option() ::
61
'all' | 'procs' | 'ports' |
64
43
%% @type activity_option() =
65
44
%% {ts_min, timestamp()} |
66
45
%% {ts_max, timestamp()} |
225
205
%%==========================================================================
207
%% cleans trace messages from external pids
209
clean_trace(Trace) when is_tuple(Trace) -> list_to_tuple(clean_trace(tuple_to_list(Trace)));
210
clean_trace(Trace) when is_list(Trace) -> clean_list(Trace, []);
211
clean_trace(Trace) when is_pid(Trace) ->
212
PidStr = pid_to_list(Trace),
213
[_,P2,P3p] = string:tokens(PidStr,"."),
214
P3 = lists:sublist(P3p, 1, length(P3p) - 1),
215
erlang:list_to_pid("<0." ++ P2 ++ "." ++ P3 ++ ">");
216
clean_trace(Trace) -> Trace.
218
clean_list([], Out) -> lists:reverse(Out);
219
clean_list([Element|Trace], Out) ->
220
clean_list(Trace, [clean_trace(Element)|Out]).
227
223
insert_trace(Trace) ->
229
225
{profile_start, Ts} ->
288
282
%%% erlang:trace, option: procs
289
283
%%% ---------------------------
290
284
{trace_ts, Parent, spawn, Pid, Mfa, TS} ->
291
% Update registered procs
285
InformativeMfa = mfa2informative(Mfa),
293
286
% Update id_information
294
update_information(#information{id = Pid, start = TS, parent = Parent, entry = Mfa}),
287
update_information(#information{id = Pid, start = TS, parent = Parent, entry = InformativeMfa}),
295
288
update_information_child(Parent, Pid),
298
290
{trace_ts, Pid, exit, _Reason, TS} ->
299
291
% Update registered procs
339
334
io:format("insert_trace, unhandled: ~p~n", [Unhandled])
337
mfa2informative({erlang, apply, [M, F, Args]}) -> mfa2informative({M, F,Args});
338
mfa2informative({erlang, apply, [Fun, Args]}) ->
339
FunInfo = erlang:fun_info(Fun),
340
M = case proplists:get_value(module, FunInfo, undefined) of
341
[] -> undefined_fun_module;
342
undefined -> undefined_fun_module;
345
F = case proplists:get_value(name, FunInfo, undefined) of
346
[] -> undefined_fun_function;
347
undefined -> undefined_fun_function;
350
mfa2informative({M, F, Args});
351
mfa2informative(Mfa) -> Mfa.
342
353
%% consolidate_db() -> bool()
344
355
%% Check start/stop time
345
356
%% Activity consistency
347
358
consolidate_db() ->
359
io:format("Consolidating...~n"),
348
360
% Check start/stop timestamps
349
361
case select_query({system, start_ts}) of
358
370
update_system_stop_ts(Max);
373
consolidate_runnability(),
376
consolidate_runnability() ->
377
put({runnable, procs}, undefined),
378
put({runnable, ports}, undefined),
379
consolidate_runnability_loop(ets:first(pdb_activity)).
381
consolidate_runnability_loop('$end_of_table') -> ok;
382
consolidate_runnability_loop(Key) ->
383
case ets:lookup(pdb_activity, Key) of
384
[#activity{id = Id, state = State } = A] when is_pid(Id) ->
385
Rc = get_runnable_count(procs, State),
386
ets:insert(pdb_activity, A#activity{ runnable_count = Rc});
387
[#activity{id = Id, state = State } = A] when is_port(Id) ->
388
Rc = get_runnable_count(ports, State),
389
ets:insert(pdb_activity, A#activity{ runnable_count = Rc});
390
_ -> throw(consolidate)
392
consolidate_runnability_loop(ets:next(pdb_activity, Key)).
364
395
ATs = [ Act#activity.timestamp ||
365
396
Act <- select_query({activity, []})],
390
421
%% during the profile duration.
392
423
get_runnable_count(Type, State) ->
393
case get({runnable, Type}) of
394
undefined when State == active ->
424
case {get({runnable, Type}), State} of
425
{undefined, active} ->
395
426
put({runnable, Type}, 1),
397
N when State == active ->
398
429
put({runnable, Type}, N + 1),
400
N when State == inactive ->
401
432
put({runnable, Type}, N - 1),
543
573
select_query_activity_exact_ts(Options) ->
544
TsMinMember = lists:keymember(ts_min, 1, Options),
545
TsMaxMember = lists:keymember(ts_max, 1, Options),
547
TsMinMember == true , TsMaxMember == true ->
549
{value, {ts_min, TsMin}} = lists:keysearch(ts_min, 1, Options),
550
{value, {ts_max, TsMax}} = lists:keysearch(ts_max, 1, Options),
574
case { proplists:get_value(ts_min, Options, undefined), proplists:get_value(ts_max, Options, undefined) } of
575
{undefined, undefined} -> [];
576
{undefined, _ } -> [];
577
{_ , undefined} -> [];
552
579
% Remove unwanted options
556
{ts_min, _ } -> false;
557
{ts_max, _ } -> false;
558
{ts_exact, _ } -> false;
580
Opts = lists_filter([ts_exact], Options),
562
581
Ms = activity_ms(Opts),
563
Activities = ets:select(pdb_activity, Ms),
564
filter_activities_exact_ts(Activities, TsMin,TsMax);
566
io:format("select_query_activity, error: exact needs ts_min and ts_max~n"),
570
filter_activities_exact_ts(Activities, TsMin, TsMax) ->
571
filter_activities_exact_ts_pre(Activities, {undefined, TsMin, TsMax}, []).
573
filter_activities_exact_ts_pre([], _, Out) ->
575
filter_activities_exact_ts_pre([A | As], {PreA, TsMin, TsMax}, Out) ->
577
A#activity.timestamp < TsMin ->
578
filter_activities_exact_ts_pre(As, {A,TsMin, TsMax}, Out);
580
filter_activities_exact_ts_end(As, {A,TsMin, TsMax}, [ A | Out]);
582
B = PreA#activity{timestamp = TsMin},
583
filter_activities_exact_ts_end(As, {A,TsMin, TsMax}, [A,B])
585
filter_activities_exact_ts_end([],_, Out) ->
587
filter_activities_exact_ts_end([A | As], {_PreA, TsMin, TsMax}, Out) ->
589
A#activity.timestamp > TsMin , A#activity.timestamp < TsMax ->
590
filter_activities_exact_ts_end(As, {A,TsMin, TsMax}, [A | Out]);
591
A#activity.timestamp >= TsMax ->
592
B = A#activity{timestamp = TsMax},
593
filter_activities_exact_ts_end([], {A,TsMin, TsMax}, [B | Out]);
595
io:format("filter_activities_exact_ts_pro, error: range problems~n"),
582
case ets:select(pdb_activity, Ms) of
583
% no entries within interval
585
Opts2 = lists_filter([ts_max, ts_min], Opts) ++ [{ts_min, TsMax}],
586
Ms2 = activity_ms(Opts2),
587
case ets:select(pdb_activity, Ms2, 1) of
588
'$end_of_table' -> [];
590
[PrevAct] = ets:lookup(pdb_activity, ets:prev(pdb_activity, E#activity.timestamp)),
591
[PrevAct#activity{ timestamp = TsMin} , E]
596
Head#activity.timestamp == TsMin -> Acts;
598
PrevTs = ets:prev(pdb_activity, Head#activity.timestamp),
599
case ets:lookup(pdb_activity, PrevTs) of
601
[PrevAct] -> [PrevAct#activity{timestamp = TsMin}|Acts]
607
lists_filter([], Options) -> Options;
608
lists_filter([D|Ds], Options) ->
609
lists_filter(Ds, lists:filter(
600
618
% {ts_min, timestamp()}