-
-
Save jtuple/161ad7c8c278b45729df to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(ktrace). | |
-compile(export_all). | |
-record(ps, {stack = [], | |
trace = array:new(), | |
depth = 0}). | |
-record(state, {pinfo = dict:new(), | |
ts}). | |
c() -> | |
State = #state{}, | |
dbg:trace_client(ip, {"localhost", 4711}, {fun ?MODULE:t/2, State}). | |
s() -> | |
%% s(all). | |
s(vnodes). | |
s(vnodes) -> | |
VNs = [Pid || {_,_,Pid} <- riak_core_vnode_manager:all_vnodes(riak_kv_vnode)], | |
dbg:tracer(port, dbg:trace_port(ip,{4711,10000000})), | |
[dbg:p(VN, [call, arity, return_to, timestamp]) || VN <- VNs], | |
dbg:tpl('_', '_', []), | |
erlang:trace_pattern({riak_kv_vnode, do_get, 4}, | |
[{['_',{'$1','$2'},'_','_'], | |
[], | |
[{message,{{'$1','$2'}}}]}], | |
[local]), | |
ok; | |
s(Who) -> | |
dbg:tracer(port, dbg:trace_port(ip,4711)), | |
dbg:p(Who, [call, arity, return_to, timestamp]), | |
dbg:tpl('_', '_', []). | |
ss() -> | |
dbg:stop_clear(). | |
t({trace_ts, Pid, Type, Args, TS}, State) -> | |
t({trace, Pid, Type, Args}, State#state{ts=TS}); | |
t({trace_ts, Pid, Type, Args1, Args2, TS}, State) -> | |
t({trace, Pid, Type, Args1, Args2}, State#state{ts=TS}); | |
t({trace, Pid, Type, Args}, State) -> | |
tt(Type, Pid, Args, State); | |
t({trace, Pid, Type, Args1, Args2}, State) -> | |
tt(Type, Pid, {Args1, Args2}, State); | |
t({trace, Pid, Type, Args1, Args2, Args3}, State) -> | |
tt(Type, Pid, {Args1, Args2, Args3}, State); | |
t({drop, Num}, State) -> | |
io:format("dropped: ~p~n", [Num]), | |
State; | |
t(end_of_trace, State) -> | |
State. | |
tt(call, Pid, MFA={_M,_F,_A}, State) -> | |
%% State = maybe_reset_stack(Pid, MFA, State0), | |
{Pos, State1} = add_trace(Pid, MFA, undefined, State), | |
State2 = push_stack(Pid, MFA, Pos, State1), | |
State2; | |
tt(call, Pid, {MFA={_M,_F,_A}, Extra}, State0) -> | |
State = maybe_reset_stack(Pid, MFA, State0), | |
{Pos, State1} = add_trace(Pid, MFA, Extra, State), | |
State2 = push_stack(Pid, MFA, Pos, State1), | |
State2; | |
tt(return_to, Pid, MFA, State0) -> | |
State = maybe_reset_stack(Pid, MFA, State0), | |
{Fun, State2} = pop_stack_until(Pid, MFA, State), | |
State3 = rrr(Pid, Fun, State2), | |
State3; | |
tt(_, _Pid, _, State) -> | |
State. | |
rrr(_, undefined, State) -> | |
State; | |
rrr(Pid, {_MFA={_M,_F,_}, _Then, Pos, _Depth}, State) -> | |
State2 = update_trace(Pid, Pos, State), | |
State2; | |
rrr(_Pid, {_MFA, _TS, _, _}, State) -> | |
State. | |
update_trace(Pid, Pos, State) -> | |
PS = pinfo(Pid, State), | |
T1 = PS#ps.trace, | |
{MFA, Then, _, _, Depth, Extra} = array:get(Pos, T1), | |
Diff = timer:now_diff(State#state.ts, Then), | |
T2 = array:set(Pos, {MFA, Then, State#state.ts, Diff, Depth, Extra}, T1), | |
PS2 = PS#ps{trace=T2}, | |
PI = dict:store(Pid, PS2, State#state.pinfo), | |
State#state{pinfo=PI}. | |
add_trace(Pid, MFA, Extra, State=#state{pinfo=SS,ts=TS}) -> | |
DT = array_append({MFA,TS,TS,unknown,0,Extra}, array:new()), | |
SS2 = dict:update(Pid, | |
fun(PS=#ps{trace=T,depth=Depth}) -> | |
T2 = array_append({MFA,TS,TS,unknown,Depth,Extra},T), | |
PS#ps{trace=T2} | |
end, | |
#ps{trace=DT}, SS), | |
State2 = State#state{pinfo=SS2}, | |
PS = pinfo(Pid, State2), | |
Pos = array:size(PS#ps.trace) - 1, | |
{Pos, State2}. | |
push_stack(Pid, MFA, Pos, State=#state{pinfo=SS,ts=TS}) -> | |
SS2 = dict:update(Pid, | |
fun(PS=#ps{stack=S,depth=Depth}) -> | |
S2=[{MFA,TS,Pos,Depth}|S], | |
PS#ps{stack=S2,depth=Depth+1} | |
end, | |
#ps{stack=[{MFA,TS,Pos,0}]}, SS), | |
State#state{pinfo=SS2}. | |
pop_stack_until(Pid, MFA, State=#state{pinfo=SS}) -> | |
PS = pinfo(Pid, State), | |
case PS#ps.stack of | |
[] -> | |
Stack = [], | |
Top = undefined; | |
[H|T] -> | |
Stack = T, | |
Top = H | |
end, | |
Stack2 = lists:dropwhile(fun({MFA2,_,_,_}) -> | |
MFA2 /= MFA | |
end, Stack), | |
Depth = case Stack2 of | |
[] -> | |
0; | |
[{_,_,_,D}|_] -> | |
D | |
end, | |
PS2 = PS#ps{stack=Stack2, depth=Depth+1}, | |
SS2 = dict:store(Pid, PS2, SS), | |
State2 = State#state{pinfo=SS2}, | |
{Top, State2}. | |
maybe_reset_stack(Pid, {gen_fsm, handle_msg,_}, State=#state{pinfo=SS}) -> | |
PI = pinfo(Pid, State), | |
Trace = PI#ps.trace, | |
Size = array:size(Trace), | |
case Size > 1 of | |
true -> | |
{_, Start, _, _, _, _} = array:get(1, Trace), | |
End = State#state.ts; | |
false -> | |
Start = {0,0,0}, | |
End = {0,0,0} | |
end, | |
Diff = timer:now_diff(End, Start), | |
if Diff > 5000 -> | |
%% if Diff > 1 -> | |
io:format("*** ~p :: ~p :: ~p~n", [Diff, Pid, node(Pid)]), | |
print_trace(PI#ps.trace); | |
true -> | |
ok | |
end, | |
PI2 = PI#ps{stack=[], trace=array:new(), depth=0}, | |
SS2 = dict:store(Pid, PI2, SS), | |
State#state{pinfo=SS2}; | |
maybe_reset_stack(_Pid, _MFA, State) -> | |
State. | |
print_trace(Trace) -> | |
array:foldl(fun(_, {MFA,_,_,Time,Depth, Extra}, _) -> | |
ExtraOut = case Extra of | |
undefined -> | |
""; | |
_ -> | |
io_lib:format(" :: ~p", [Extra]) | |
end, | |
case Time of | |
unknown -> | |
io:format("~10s | ~*s~p~s~n", ["", Depth, "", MFA, ExtraOut]); | |
_ -> | |
io:format("~10s | ~*s~p~s~n", [integer_to_list(Time), Depth, "", MFA, ExtraOut]) | |
end | |
end, ok, Trace). | |
get_stack(Pid, State) -> | |
PS = pinfo(Pid, State), | |
[MFA || {MFA, _TS, _, _} <- PS#ps.stack]. | |
get_stack2(Pid, State) -> | |
PS = pinfo(Pid, State), | |
PS#ps.stack. | |
dict_find(Key, Default, Dict) -> | |
case dict:find(Key, Dict) of | |
{ok, Value} -> | |
Value; | |
_ -> | |
Default | |
end. | |
pinfo(Pid, #state{pinfo=PI}) -> | |
dict_find(Pid, #ps{}, PI). | |
array_append(Item, A) -> | |
array:set(array:size(A), Item, A). |
Author
jtuple
commented
Jun 11, 2013
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment