1 %%%----------------------------------------------------------------------
3 %%% Author : Mats Cronqvist <etxmacr@avc386>
4 %%% Purpose : cpu time per pid
5 %%% Created : 28 Feb 2000 by Mats Cronqvist <etxmacr@avc386>
6 %%%----------------------------------------------------------------------
9 -author('etxmacr@avc386').
11 -export([go
/1, requires
/0, doc
/0]).
13 -record(state
, {tab
, quiet
}).
15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16 requires() -> [{flags
, [procs
,running
]}, {tps
, []}].
17 doc() -> "for each second, prints the 5 processes that uses the most CPU time."
18 "also prints the total CPU time used in that second, and the"
19 "first and last line number in the trace file".
21 go([Msg
, Line
, Out
, initial
]) ->
22 put(cb_cpu_now
, initial
),
24 io:fwrite("~p: initializing - created table ~w~n", [?MODULE
, Tab
]),
25 go([Msg
, Line
, Out
, #state
{tab
= Tab
, quiet
= no
}]);
26 go([end_of_trace
, Line
, Out
, State
|_
]) ->
27 outro(Line
, Out
, State
);
28 go([Msg
, Line
, Out
, State
|_
]) ->
29 handle(Msg
, State#state
.tab
, Line
),
32 %%% "raimo" refers to a bug in the R7B(up to 3) emulator
33 %%% getting_linked & getting_unlinked can mangle the following in/out msgs
34 handle(Msg
, Tab
, Line
) ->
35 liner(Tab
, Msg
, Line
),
37 {spawn,_
,{{_
,{application_master
,{App
}}},_
},{_
,Sec
,_
}} ->
38 ets_ins(Tab
, {{appl
, Sec
, App
}});
39 {T
, _
, PI
, Now
} when T
== getting_linked
; T
== getting_unlinked
-> %raimo
40 put(cb_cpu_hack
, {fix_out
, Now
, PI
}); %raimo
41 {in
, PI
, CurrF
, Now
} ->
42 case get(cb_cpu_hack
) of %raimo
43 {fix_in
, PI0
} -> %raimo
44 erase(cb_cpu_hack
), %raimo
45 handle({in
, PI0
, CurrF
, Now
}, Tab
, Line
); %raimo
47 ets_upd(Tab
, {PI
, in
}, 1),
48 doOne(in
, Tab
, PI
, Now
, Line
)
50 {out
, PI
, CurrF
, Now
} ->
51 case get(cb_cpu_hack
) of %raimo
52 {fix_out
, Now
, PI0
} -> %raimo
53 put(cb_cpu_hack
, {fix_in
, PI0
}), %raimo
54 handle({out
, PI0
, CurrF
, Now
}, Tab
, Line
);%raimo
56 doOne(out
, Tab
, PI
, Now
, Line
)
58 {exit, PI
, Reason
, Now
} ->
59 doOne(out
, Tab
, PI
, Now
, Line
);
63 doOne(out
, Tab
, {PID
, _
} = PI
, {_
, S
, _
} = Now
, Line
) ->
64 case get(cb_cpu_now
) of
67 ets_upd(Tab
, total
, ntdiff(Now
, Now0
)),
68 ets_upd(Tab
, {total
, S
}, ntdiff(Now
, Now0
)),
69 ets_upd(Tab
, {PI
, cpu
}, ntdiff(Now
, Now0
)),
70 ets_upd(Tab
, {PI
, S
, cpu
}, ntdiff(Now
, Now0
));
72 Err
-> ok
%%io:fwrite("~p:out_error: ~p~n ~p~n ~p~n", [?MODULE, Line, PID, Err])
74 doOne(in
, Tab
, {PID
, _
}, Now
, Line
) ->
75 case get(cb_cpu_now
) of
78 Err
-> ok
%%io:fwrite("~p:in_error: ~p~n ~p~n ~p~n", [?MODULE, Line, PID, Err])
80 put(cb_cpu_now
, {PID
, Now
}).
82 liner(Tab
, {_
, _
,_
, {_
, Sec
, _
}}, Line
) ->
83 case ets_lup(Tab
, {sec
, Sec
}) of
84 [] -> ets_ins(Tab
, {{sec
, Sec
}, {Line
, 0}});
85 {FLine
, _
} -> ets_ins(Tab
, {{sec
, Sec
}, {FLine
, Line
}})
88 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
89 outro(_
, Out
, #state
{tab
= Tab
, quiet
= Qt
}) ->
90 Secs
= ets_mch(Tab
, {{total
, '$1'}, '_'}),
92 lists:foreach(fun([S
]) -> dout(Tab
, S
, S0
) end, Secs
).
94 [[Tot
]] = ets_mch(Tab
, {{total
, N
}, '$1'}),
95 {FL
, LL
} = ets_lup(Tab
, {sec
, N
}),
96 case ets_mch(Tab
, {{appl
, N
, '$1'}}) of
99 io:fwrite("####################~n", []),
100 lists:foreach(fun(A
) -> io:fwrite("started ~p~n", A
) end, Apps
)
102 io:fwrite("####~n~p - ~p ms (~p,~p)~n", [N
-N0
, trunc(Tot
/1000), FL
, LL
]),
103 io:fwrite("~p~n", [head(ets_mch(Tab
, {{'$2', N
, cpu
}, '$1'}), 5, Tot
)]).
105 [{trunc(100*I
/Tot
), P
} || [I
, P
] <- lists_top(L
, N
)].
107 lists:sublist(lists:reverse(lists:sort(L
)), N
).
108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109 ets_new() -> ets_new(?MODULE
).
110 ets_new(Tab
) -> ets_new(Tab
, [ordered_set
]).
111 ets_new(Tab
, Opts
) ->
112 catch ets:delete(Tab
),
113 ets:new(Tab
, [named_table
,public
]++Opts
).
115 catch ets:insert(Tab
, Rec
).
116 ets_upd(Tab
, Key
, Inc
) ->
117 case catch ets:update_counter(Tab
, Key
, Inc
) of
118 {'EXIT', _
} -> ets:insert(Tab
, {Key
, Inc
});
122 case catch ets:lookup(Tab
, Key
) of
128 case catch ets:match(Tab
, Pat
) of
133 ntdiff({MS
, S
, USo
}, {MS
, S
, USi
}) ->
135 ntdiff({MS
, So
, USo
}, {MS
, Si
, USi
}) ->
136 (USo
-USi
)+(So
-Si
)*1000000;
137 ntdiff({MSo
, So
, USo
}, {MSi
, Si
, USi
}) ->
138 (USo
-USi
)+(So
-Si
)*1000000+(MSo
-MSi
)*1000000000000.