Skip to content

Commit e537d8a

Browse files
committed
Adding scripts
- app_deps for application dependencies - erl_crashdump_analyzer.sh for quick crashdump diagnostics
1 parent 892cc38 commit e537d8a

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed

script/app_deps.erl

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
%%% Run with 'escript app_deps.erl'
2+
%%% Change the path in filelib:wildcard/1 as required to capture
3+
%%% all your dependencies.
4+
%%%
5+
%%% Rectangular nodes will represent library apps (no processes
6+
%%% involved) and the circular nodes will represent regular apps.
7+
%%% An arrow going from 'A -> B' means 'A depends on B'.
8+
%%%
9+
%%% This script depends on graphviz being present on the system.
10+
-module(app_deps).
11+
-export([main/1]).
12+
13+
main(_) ->
14+
AppFiles = filelib:wildcard("deps/*/ebin/*.app")
15+
++
16+
filelib:wildcard("ebin/*.app"),
17+
to_graphviz(read_deps(AppFiles)).
18+
19+
read_deps(AppFiles) ->
20+
[{App,
21+
proplists:get_value(applications, Props, []),
22+
apptype(Props)}
23+
|| {ok, [{_,App,Props}]} <-
24+
[file:consult(AppFile) || AppFile <- AppFiles]].
25+
26+
apptype(Props) ->
27+
case proplists:get_value(mod, Props) of
28+
undefined -> library;
29+
_ -> regular
30+
end.
31+
32+
to_graphviz(Deps) ->
33+
AllApps = lists:usort(lists:flatten(
34+
[[{App,Type},DepList] || {App,DepList,Type} <- Deps]
35+
)),
36+
Bytes = ["digraph G { ",
37+
"K=0.25; ratio=0.75; overlap=\"9:prism\"; ",
38+
[io_lib:format("~p [shape=box] ", [App])
39+
|| App <- libapps(AllApps -- [kernel,stdlib])],
40+
[[io_lib:format("~p->~p ", [App,Dep])
41+
|| Dep <- DepList -- [kernel, stdlib]]
42+
|| {App, DepList, _} <- Deps],
43+
"}"],
44+
file:write_file("app-deps.dot", Bytes),
45+
os:cmd("dot app-deps.dot -Tpng -o app-deps.png").
46+
47+
libapps([]) -> [];
48+
libapps([{App,library}|Apps]) -> [App|libapps(Apps)];
49+
libapps([{_,_}|Apps]) -> libapps(Apps);
50+
libapps([App|Apps]) ->
51+
Dir = case code:lib_dir(App) of
52+
{error, _} -> ""; % not an OTP app
53+
DirPath -> DirPath
54+
end,
55+
Path = filename:join([Dir, "ebin", atom_to_list(App)++".app"]),
56+
case lists:prefix(code:lib_dir(), Path) of
57+
false ->
58+
[App|libapps(Apps)]; % not OTP app, we don't care
59+
true -> % deps of OTP deps: we don't care either.
60+
{ok, [{_,App,Props}]} = file:consult(Path),
61+
case apptype(Props) of
62+
library -> [App | libapps(Apps)];
63+
regular -> libapps(Apps)
64+
end
65+
end.

script/erl_crashdump_analyzer.sh

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env bash
2+
DUMP=$1
3+
4+
echo -e "analyzing $DUMP, generated on: " `head -2 $DUMP | tail -1` "\n"
5+
6+
### SLOGAN ###
7+
grep Slogan: $DUMP -m 1
8+
9+
### MEMORY ###
10+
echo -e "\nMemory:\n==="
11+
M=`grep -m 1 'processes' $DUMP | sed "s/processes: //"`
12+
let "m=$M/(1024*1024)"
13+
echo " processes: $m Mb"
14+
M=`grep -m 1 'processes_used' $DUMP | sed "s/processes_used: //"`
15+
let "m=$M/(1024*1024)"
16+
echo " processes_used: $m Mb"
17+
M=`grep -m 1 'system' $DUMP | sed "s/system: //"`
18+
let "m=$M/(1024*1024)"
19+
echo " system: $m Mb"
20+
M=`grep -m 1 'atom' $DUMP | sed "s/atom: //"`
21+
let "m=$M/(1024*1024)"
22+
echo " atom: $m Mb"
23+
M=`grep -m 1 'atom_used' $DUMP | sed "s/atom_used: //"`
24+
let "m=$M/(1024*1024)"
25+
echo " atom_used: $m Mb"
26+
M=`grep -m 1 'binary' $DUMP | sed "s/binary: //"`
27+
let "m=$M/(1024*1024)"
28+
echo " binary: $m Mb"
29+
M=`grep -m 1 'code' $DUMP | sed "s/code: //"`
30+
let "m=$M/(1024*1024)"
31+
echo " code: $m Mb"
32+
M=`grep -m 1 'ets' $DUMP | sed "s/ets: //"`
33+
let "m=$M/(1024*1024)"
34+
echo " ets: $m Mb"
35+
M=`grep -m 1 'total' $DUMP | sed "s/total: //"`
36+
let "m=$M/(1024*1024)"
37+
echo -e " ---\n total: $m Mb"
38+
39+
### PROCESS MESSAGE QUEUES LENGTHS ###
40+
echo -e "\nDifferent message queue lengths (5 largest different):\n==="
41+
grep 'Message queue len' $DUMP | sed 's/Message queue length: //g' | sort -n -r | uniq -c | head -5
42+
43+
### ERROR LOGGER QUEUE LENGTH ###
44+
echo -e "\nError logger queue length:\n==="
45+
grep -C 10 'Name: error_logger' $DUMP -m 1| grep 'Message queue length' | sed 's/Message queue length: //g'
46+
47+
48+
### PORT/FILE DESCRIPTOR INFO ###
49+
echo -e "\nFile descriptors open:\n==="
50+
echo -e " UDP: " `grep 'Port controls linked-in driver:' $DUMP | grep 'udp_inet' | wc -l`
51+
echo -e " TCP: " `grep 'Port controls linked-in driver:' $DUMP | grep 'tcp_inet' | wc -l`
52+
echo -e " Files: " `grep 'Port controls linked-in driver:' $DUMP | grep -vi 'udp_inet' | grep -vi 'tcp_inet' | wc -l`
53+
echo -e " ---\n Total: " `grep 'Port controls linked-in driver:' $DUMP | wc -l`
54+
55+
### NUMBER OF PROCESSES ###
56+
echo -e "\nNumber of processes:\n==="
57+
grep '=proc:' $DUMP | wc -l
58+
59+
### PROC HEAPS+STACK ###
60+
echo -e "\nProcesses Heap+Stack memory sizes (words) used in the VM (5 largest different):\n==="
61+
grep 'Stack+heap' $DUMP | sed "s/Stack+heap: //g" | sort -n -r | uniq -c | head -5
62+
63+
### PROC OLDHEAP ###
64+
echo -e "\nProcesses OldHeap memory sizes (words) used in the VM (5 largest different):\n==="
65+
grep 'OldHeap' $DUMP | sed "s/OldHeap: //g" | sort -n -r | uniq -c | head -5
66+
67+
### PROC STATES ###
68+
echo -e "\nProcess States when crashing (sum): \n==="
69+
grep 'State: ' $DUMP | sed "s/State: //g" | sort | uniq -c

0 commit comments

Comments
 (0)