aboutsummaryrefslogtreecommitdiffstats
path: root/erts/etc/unix/etp_commands.erl
diff options
context:
space:
mode:
Diffstat (limited to 'erts/etc/unix/etp_commands.erl')
-rw-r--r--erts/etc/unix/etp_commands.erl173
1 files changed, 173 insertions, 0 deletions
diff --git a/erts/etc/unix/etp_commands.erl b/erts/etc/unix/etp_commands.erl
new file mode 100644
index 0000000000..66cb76edbc
--- /dev/null
+++ b/erts/etc/unix/etp_commands.erl
@@ -0,0 +1,173 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(etp_commands).
+
+-export([file/1]).
+
+file([Fname]) ->
+ Result = (catch file_1(Fname)),
+ io:format("% ~p~n", [Result]),
+ init:stop().
+
+file_1(Fname) ->
+ io:format("% Reading ~p...~n", [Fname]),
+ {ok,Fd} = file:open(Fname, [read,binary]),
+ case read_op(Fd, 128) of
+ "chart" ->
+ io:format("% Reading heap chart data...~n"),
+ chart_scan(Fd);
+ "overlapped-heaps" ->
+ io:format("% Reading overlapped-heaps data...~n"),
+ overlapped_scan(Fd)
+ end.
+
+read_op(_Fd, 0) ->
+ [];
+read_op(Fd, N) ->
+ case file:read(Fd, 1) of
+ {ok,<<0>>} -> [];
+ {ok,<<C>>} -> [C|read_op(Fd, N-1)]
+ end.
+
+
+
+overlapped_scan(Fd) ->
+ overlapped_scan_1(Fd, []).
+
+overlapped_scan_1(Fd, R) ->
+ case file:read(Fd, 4*5) of
+ eof ->
+ io:format("% Analyzing overlaps...~n"),
+ overlapped_analyze(lists:sort(R));
+ {ok,<<Id:32/native,Heap:32/native,Hend:32/native,
+ 0:32/native,0:32/native>>}
+ when Heap < Hend ->
+ overlapped_scan_to_0(Fd, [{{Heap,Hend},{Id,heap}}|R], Id, 1);
+ {ok,<<Id:32/native,Heap:32/native,Hend:32/native,
+ OldHeap:32/native,OldHend:32/native>>}
+ when Heap < Hend, OldHeap < OldHend->
+ overlapped_scan_to_0(Fd, [{{Heap,Hend},{Id,heap}},
+ {{OldHeap,OldHend},{Id,old_heap}}|R],
+ Id, 1)
+ end.
+
+overlapped_scan_to_0(Fd, R, Id, Cnt) ->
+ case file:read(Fd, 4*2) of
+ {ok,<<0:32/native,0:32/native>>} ->
+ overlapped_scan_1(Fd, R);
+ {ok,<<Heap:32/native,Hend:32/native>>}
+ when Heap < Hend ->
+ overlapped_scan_to_0(Fd,
+ [{{Heap,Hend},{Id,{heap_fragment,Cnt}}}|R],
+ Id, Cnt+1);
+ eof ->
+ io:format("% Premature end of dump: ~p~n", [Id,Cnt|R])
+ end.
+
+overlapped_analyze([]) ->
+ io:format("% Oops! was that file empty?~n");
+overlapped_analyze([{{_,Hend1},_}|[{{Heap2,_},_}|_]=R])
+ when Hend1 =< Heap2 ->
+ overlapped_analyze(R);
+overlapped_analyze([{Addrs1,Tag1}|[{Addrs2,Tag2}|_]=R]) ->
+ io:format("% ~p overlaps ~p (~p,~p)~n", [Tag1,Tag2,Addrs1,Addrs2]),
+ overlapped_analyze(R);
+overlapped_analyze([_]) ->
+ io:format("% End of overlaps~n").
+
+
+chart_scan(Fd) ->
+ {ok,<<Heap:32/native,HighWater:32/native,Hend:32/native,
+ OldHeap:32/native,OldHend:32/native>>} = file:read(Fd, 4*5),
+ chart_scan_1(Fd,
+ [{Heap,Heap,heap,0},
+ {HighWater,HighWater,high_water,0},
+ {Hend,Hend,hend,0},
+ {OldHeap,OldHeap,old_heap,0},
+ {OldHend,OldHend,old_hend,0}|chart_scan_hdr(Fd)]).
+
+chart_scan_hdr(Fd) ->
+ chart_scan_hdr_2(0, chart_scan_hdr_1(Fd)).
+
+chart_scan_hdr_1(Fd) ->
+ case file:read(Fd, 4*2) of
+ eof -> [];
+ {ok,<<0:32/native,0:32/native>>} -> [];
+ {ok,<<Start:32/native,Size:32/native>>} ->
+ [{Start,Size}|chart_scan_hdr_1(Fd)]
+ end.
+
+chart_scan_hdr_2(_N, []) -> [];
+chart_scan_hdr_2(N, [{Start,End}|T]) when Start =< End ->
+ [{Start,Start,{heap_frag,N},0},{End,End,{heap_frag_end,N},0}
+ |chart_scan_hdr_2(N+1, T)].
+
+chart_scan_1(Fd, R) ->
+ case file:read(Fd, 4*4) of
+ eof ->
+ io:format("% Analyzing heap chart...~n"),
+ chart_analyze(lists:sort(R));
+ {ok,
+ <<Addr:32/native,Size:32/native,Id:32/native,Depth:32/native>>} ->
+ chart_scan_1(Fd, [{Addr,Addr+Size,Id,Depth}|R])
+ end.
+
+%-define(raw_chart_dump, 1).
+-ifdef(raw_chart_dump).
+
+chart_analyze([]) ->
+ io:format("% End of chart~n");
+chart_analyze([{S,E,Id,D}|R]) ->
+ io:format("% ~.16x-~.16x: ~w[~w]~n",
+ [S,"0x",E,"0x",Id,D]),
+ chart_analyze(R).
+
+-else.
+
+chart_analyze([]) ->
+ io:format("% ***Oops, was chart empty?***~n");
+chart_analyze([{S,_,Id,D}=X|R]) ->
+ io:format("% ~.16x: ~w[~w", [S,"0x",Id,D]),
+ chart_analyze_1(R, X).
+
+chart_analyze_1([{S,E,Id,D}=X|R], {S,E,Id,_}) ->
+ io:format(",~w", [D]),
+ chart_analyze_1(R, X);
+chart_analyze_1([{S,E,Id,D}=X|R], {S,E,_,_}) ->
+ io:format("],~w[~w", [Id,D]),
+ chart_analyze_1(R, X);
+chart_analyze_1(R, X) ->
+ io:format("]~n"),
+ chart_analyze_2(R, X).
+
+chart_analyze_2([], {_,E,_,_}) ->
+ io:format("% ~.16x: End of chart~n", [E,"0x"]);
+chart_analyze_2([{S,_,_,_}|_]=R, {_,E,_,_}) ->
+ if E == S ->
+ chart_analyze(R);
+ E < S ->
+ io:format("% ~.16x:~n", [E,"0x"]),
+ chart_analyze(R);
+ true ->
+ io:format("% ~.16x: ***Overlap***~n", [E,"0x"]),
+ chart_analyze(R)
+ end.
+
+-endif.