1 %%%-------------------------------------------------------------------
3 %%% Author : Mats Cronqvist <etxmacr@cbe2077>
6 %%% Created : 2 Dec 2002 by Mats Cronqvist <etxmacr@cbe2077>
7 %%%-------------------------------------------------------------------
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
]},
21 go([Msg
, Line
, Out
, initial
]) ->
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
|_
]) ->
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
};
38 io:fwrite("~p: crash on: ~p~n~p~n~p~n", [?MODULE
, Line
, Msg
, R
]),
42 handle(Msg
, State
= #state
{tab
= Tab
, in
= In
, prev
= Prev
}) ->
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
};
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
);
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
]});
89 do_stack(exit, State
= #state
{tab
= Tab
}, Pid
, _
) ->
90 ets_del(Tab
, {stack
, Pid
}),
92 do_stack(call
, State
= #state
{tab
= Tab
}, Pid
, MFA
) ->
93 case ets_lup(Tab
, {stack
, Pid
}) of
95 do_stack(in
, State
, Pid
, MFA
);
99 case lists:member(MFA
, Stack
) of
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
});
107 NS
= lists:dropwhile(fun(Mfa
) -> MFA
=/= Mfa
end, Stack
),
108 ets_ins(Tab
, {{stack
, Pid
}, NS
})
112 do_stack(return
, State
= #state
{tab
= Tab
}, Pid
, MFA
) ->
113 case ets_lup(Tab
, {stack
, Pid
}) of
115 do_stack(in
, State
, Pid
, MFA
);
117 case lists:member(MFA
, Stack
) of
119 do_stack(in
, State
, Pid
, MFA
);
121 NS
= lists:dropwhile(fun(Mfa
) -> MFA
=/= Mfa
end, Stack
),
122 ets_ins(Tab
, {{stack
, Pid
}, NS
})
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
}) ->
132 {{Pid
, _
}, no
, no
} ->
134 undefined
-> State#state
{currf
= {Pid
, Now
}};
135 X
-> State#state
{error
= {State
}}
140 leave_currf(Now
, State
= #state
{tab
= Tab
, in
= In
, gc
= GC
, currf
= Currf
}) ->
147 Tim
= ntdiff(Now
, NowIn
),
148 Stack
= ets_lup(Tab
, {stack
, Pid
}),
149 Rstack
= lists:reverse(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
}
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
});
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
).
176 catch ets:insert(Tab
, Rec
).
178 case catch ets:lookup(Tab
, Key
) of
183 catch ets:delete(Tab
, Key
).
185 ntdiff({MS
, S
, USo
}, {MS
, S
, 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.