Merge branch 'pu'
[jungerl.git] / lib / pan / src / cb_prof.erl
blobfe591ae19ac3a5847e23832db65a1d0847dd1dd8
1 %%%-------------------------------------------------------------------
2 %%% File : cb_prof.erl
3 %%% Author : Mats Cronqvist <etxmacr@cbe2077>
4 %%% Description :
5 %%%
6 %%% Created : 2 Dec 2002 by Mats Cronqvist <etxmacr@cbe2077>
7 %%%-------------------------------------------------------------------
8 -module(cb_prof).
10 -author('etxmacr@avc386').
12 -export([go/1, requires/0, doc/0]).
14 -record(state, {tab, currf, in = no, gc = no, fd = no, error, prev}).
16 doc() -> "populates the prof table. "
17 "not useful on its own. run from pan:prof".
18 requires() -> [{flags, [garbage_collection,running,procs,return_to,arity]},
19 {tps, []}].
21 go([Msg, Line, Out, initial]) ->
22 ets_new(),
23 go([Msg, Line, Out, initial, ?MODULE]);
24 go([Msg, Line, Out, initial, Tab|_]) when atom(Tab) ->
25 go([Msg, Line, Out, #state{tab = Tab}]);
26 go([end_of_trace, Line, Out, State|_]) ->
27 State;
28 go([Msg, Line, Out, State|_]) ->
29 (do(Msg, Line, State))#state{prev = element(4, Msg)}.
31 do(Msg, Line, State) ->
32 case catch handle(Msg, State) of
33 NState = #state{error = undefined} -> NState;
34 NState = #state{error = Err} ->
35 io:fwrite("~p: error on: ~p~n~p~n~p~n", [?MODULE, Line, Msg, Err]),
36 NState#state{error = undefined};
37 {'EXIT', R} ->
38 io:fwrite("~p: crash on: ~p~n~p~n~p~n", [?MODULE, Line, Msg, R]),
39 exit(crashed)
40 end.
42 handle(Msg, State = #state{tab = Tab, in = In, prev = Prev}) ->
43 case Msg of
44 {out, _, 0, Now} -> %>late r7 filedriver
45 leave_currf(Now, State#state{fd = yes});
46 {out, P, _, Prev} -> %early r7b filedriver
47 handle({out, P, 0, Prev}, State);
48 {in, _, 0, Now} -> %>late r7 filedriver
49 enter_currf(Now, State#state{fd = no});
50 {in, P, _, Now} when State#state.fd /= no -> %early r7b filedriver
51 handle({in, P, 0, Now}, State);
52 {gc_start, {Pid, ID}, Info, Now} -> %gc
53 leave_currf(Now, State#state{gc = yes});
54 {gc_end, {Pid, ID}, Info, Now} -> %gc
55 enter_currf(Now, State#state{gc = no});
56 {in, {Pid, ID}, CurrF, Now} ->
57 do_stack(in, State, Pid, CurrF),
58 enter_currf(Now, State#state{in = {Pid, Now}});
59 {out, {Pid, ID}, CurrF, Now} ->
60 (leave_currf(Now, State))#state{in = no};
61 {spawn, _, {Pid, MFA}, Now} ->
62 do_stack(in, State, Pid, check_mfa(MFA));
63 {exit,{Pid, ID},Reason, Now} -> %2 cases; killed pid is in or out
64 NState = leave_currf(Now, State),
65 do_stack(exit, NState, Pid, []),
66 case NState#state.in of
67 {Pid, _} -> NState#state{in = no};
68 _ -> NState
69 end;
70 {call, {Pid, ID}, MFA, Now} ->
71 NState = leave_currf(Now, State),
72 do_stack(call, NState, Pid, check_mfa(MFA)),
73 enter_currf(Now, NState);
74 {return_to, {Pid, Id}, MFA, Now} ->
75 NState = leave_currf(Now, State),
76 do_stack(return, NState, Pid, check_mfa(MFA)),
77 enter_currf(Now, NState);
78 _ ->
79 State
80 end.
83 do_stack(in, State = #state{tab = Tab}, Pid, MFA) ->
84 case ets_lup(Tab, {stack, Pid}) of
85 undefined -> ets_ins(Tab, {{stack, Pid}, [MFA]});
86 _ -> ok
87 end,
88 State;
89 do_stack(exit, State = #state{tab = Tab}, Pid, _) ->
90 ets_del(Tab, {stack, Pid}),
91 State;
92 do_stack(call, State = #state{tab = Tab}, Pid, MFA) ->
93 case ets_lup(Tab, {stack, Pid}) of
94 undefined ->
95 do_stack(in, State, Pid, MFA);
96 [MFA|_] ->
97 ok;
98 Stack ->
99 case lists:member(MFA, Stack) of
100 false ->
101 Stakk = [MFA|Stack],
102 ets_upd(Tab, {{func, calls}, MFA}),
103 ets_upd(Tab, {{func, calls}, Pid, MFA}),
104 ets_upd(Tab, {{stack, calls}, Pid, lists:reverse(Stakk)}),
105 ets_ins(Tab, {{stack, Pid}, Stakk});
106 true ->
107 NS = lists:dropwhile(fun(Mfa) -> MFA =/= Mfa end, Stack),
108 ets_ins(Tab, {{stack, Pid}, NS})
110 end,
111 State;
112 do_stack(return, State = #state{tab = Tab}, Pid, MFA) ->
113 case ets_lup(Tab, {stack, Pid}) of
114 undefined ->
115 do_stack(in, State, Pid, MFA);
116 Stack ->
117 case lists:member(MFA, Stack) of
118 false ->
119 do_stack(in, State, Pid, MFA);
120 true ->
121 NS = lists:dropwhile(fun(Mfa) -> MFA =/= Mfa end, Stack),
122 ets_ins(Tab, {{stack, Pid}, NS})
124 end,
125 State.
127 check_mfa({M, F, As}) when list(As) -> {M, F, length(As)};
128 check_mfa(MFA) -> MFA.
130 enter_currf(Now, State = #state{in=In, gc=Gc, fd=Fd, currf=Currf}) ->
131 case {In, Gc, Fd} of
132 {{Pid, _}, no, no} ->
133 case Currf of
134 undefined -> State#state{currf = {Pid, Now}};
135 X -> State#state{error = {State}}
136 end;
137 _ -> State
138 end.
140 leave_currf(Now, State = #state{tab = Tab, in = In, gc = GC, currf = Currf}) ->
141 case In of
142 no ->
143 State;
144 _ ->
145 case Currf of
146 {Pid, NowIn} ->
147 Tim = ntdiff(Now, NowIn),
148 Stack = ets_lup(Tab, {stack, Pid}),
149 Rstack = lists:reverse(Stack),
150 Func = hd(Stack),
151 ets_upd(Tab, {total,time}, Tim),
152 ets_upd(Tab, {{pid,time}, Pid}, Tim),
153 ets_upd(Tab, {{func,time}, Func}, Tim),
154 ets_upd(Tab, {{func, time}, Pid, Func}, Tim),
155 ets_upd(Tab, {{stack, time}, Rstack}, Tim),
156 ets_upd(Tab, {{stack, time}, Pid, Rstack}, Tim),
157 State#state{currf = undefined};
158 undefined when GC == yes -> State;
159 X -> State#state{error = State}
161 end.
163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164 ets_upd(Tab, Key) -> ets_upd(Tab, Key, 1).
165 ets_upd(Tab, Key, Inc) ->
166 case catch ets:update_counter(Tab, Key, Inc) of
167 {'EXIT', _ } -> ets:insert(Tab, {Key, Inc});
168 _ -> ok
169 end.
170 ets_new() -> ets_new(?MODULE).
171 ets_new(Tab) -> ets_new(Tab, [ordered_set]).
172 ets_new(Tab, Opts) ->
173 catch ets:delete(Tab),
174 ets:new(Tab, [named_table,public]++Opts).
175 ets_ins(Tab, Rec) ->
176 catch ets:insert(Tab, Rec).
177 ets_lup(Tab, Key) ->
178 case catch ets:lookup(Tab, Key) of
179 [{Key, R}] -> R;
180 R -> undefined
181 end.
182 ets_del(Tab, Key) ->
183 catch ets:delete(Tab, Key).
185 ntdiff({MS, S, USo}, {MS, S, USi}) ->
186 (USo-USi);
187 ntdiff({MS, So, USo}, {MS, Si, USi}) ->
188 (USo-USi)+(So-Si)*1000000;
189 ntdiff({MSo, So, USo}, {MSi, Si, USi}) ->
190 (USo-USi)+(So-Si)*1000000+(MSo-MSi)*1000000000000.