Merge branch 'pu'
[jungerl.git] / lib / pan / src / cb_zpu.erl
blob15d3fffb92517abc8897d2ad3dfea884a4810aa3
1 %%%----------------------------------------------------------------------
2 %%% File : cb_zpu.erl
3 %%% Author : Mats Cronqvist <etxmacr@avc386>
4 %%% Purpose : cpu time per pid
5 %%% Created : 28 Feb 2000 by Mats Cronqvist <etxmacr@avc386>
6 %%%----------------------------------------------------------------------
8 -module(cb_zpu).
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),
23 Tab = ets_new(),
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),
30 State.
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),
36 case Msg of
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
46 _ -> %raimo
47 ets_upd(Tab, {PI, in}, 1),
48 doOne(in, Tab, PI, Now, Line)
49 end; %raimo
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
55 _ -> %raimo
56 doOne(out, Tab, PI, Now, Line)
57 end; %raimo
58 {exit, PI, Reason, Now} ->
59 doOne(out, Tab, PI, Now, Line);
60 _ -> ok
61 end.
63 doOne(out, Tab, {PID, _} = PI, {_, S, _} = Now, Line) ->
64 case get(cb_cpu_now) of
65 {PID, Now0} ->
66 erase(cb_cpu_now),
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));
71 initial -> ok;
72 Err -> ok %%io:fwrite("~p:out_error: ~p~n ~p~n ~p~n", [?MODULE, Line, PID, Err])
73 end;
74 doOne(in, Tab, {PID, _}, Now, Line) ->
75 case get(cb_cpu_now) of
76 undefined -> ok;
77 initial -> ok;
78 Err -> ok %%io:fwrite("~p:in_error: ~p~n ~p~n ~p~n", [?MODULE, Line, PID, Err])
79 end,
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}})
86 end.
88 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
89 outro(_, Out, #state{tab = Tab, quiet = Qt}) ->
90 Secs = ets_mch(Tab, {{total, '$1'}, '_'}),
91 [S0] = hd(Secs),
92 lists:foreach(fun([S]) -> dout(Tab, S, S0) end, Secs).
93 dout(Tab, N, N0) ->
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
97 [] -> ok;
98 Apps ->
99 io:fwrite("####################~n", []),
100 lists:foreach(fun(A) -> io:fwrite("started ~p~n", A) end, Apps)
101 end,
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)]).
104 head(L, N, Tot) ->
105 [{trunc(100*I/Tot), P} || [I, P] <- lists_top(L, N)].
106 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).
114 ets_ins(Tab, Rec) ->
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});
119 _ -> ok
120 end.
121 ets_lup(Tab, Key) ->
122 case catch ets:lookup(Tab, Key) of
123 {'EXIT', _} ->[];
124 [{Key, R}] -> R;
125 R -> R
126 end.
127 ets_mch(Tab, Pat) ->
128 case catch ets:match(Tab, Pat) of
129 {'EXIT', _} -> [];
130 L -> L
131 end.
133 ntdiff({MS, S, USo}, {MS, S, USi}) ->
134 (USo-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.