OSDN Git Service

mkuserimg_mke2fs: Support passing reserved block percent
[android-x86/system-extras.git] / tools / graph_lockdep_chains
1 #! /bin/sh
2 progname="${0##*/}"
3 progname="${progname%.sh}"
4
5 usage() {
6   echo "Host side filter pipeline tool to convert kernel /proc/lockdep_chains via"
7   echo "graphviz into dependency chart for visualization. Watch out for any up-arrows"
8   echo "as they signify a circular dependency."
9   echo
10   echo "Usage: ${progname} [flags...] [regex...] < input-file > output-file"
11   echo
12   echo "flags:"
13   echo "       --format={png|ps|svg|fig|imap|cmapx} | -T<format>"
14   echo "           Output format, default png"
15   echo "       --debug | -d"
16   echo "           Leave intermediate files /tmp/${progname}.*"
17   echo "       --verbose | -v"
18   echo "           Do not strip address from lockname"
19   echo "       --focus | -f"
20   echo "           Show only primary references for regex matches"
21   echo "       --cluster"
22   echo "           Cluster the primary references for regex matches"
23   echo "       --serial=<serial> | -s <serial>"
24   echo "           Input from 'adb -s <serial> shell su 0 cat /proc/lockdep_chains'"
25   echo "       --input=<filename> | -i <filename>"
26   echo "           Input lockdeps from filename, otherwise from standard in"
27   echo "       --output=<filename> | -o <filename>"
28   echo "           Output formatted graph to filename, otherwise to standard out"
29   echo
30   echo "Chart is best viewed in portrait. ps or pdf formats tend to pixelate. png tends"
31   echo "to hit a bug in cairo rendering at scale. Not having a set of regex matches for"
32   echo "locknames will probably give you what you deserve ..."
33   echo
34   echo "Kernel Prerequisite to get /proc/lockdep_chains:"
35   echo "       CONFIG_PROVE_LOCKING=y"
36   echo "       CONFIG_LOCK_STAT=y"
37   echo "       CONFIG_DEBUG_LOCKDEP=y"
38 }
39
40 rm -f /tmp/${progname}.*
41
42 # Indent rules and strip out address (may be overridden below)
43 beautify() {
44   sed 's/^./    &/
45        s/"[[][0-9a-f]*[]] /"/g'
46 }
47
48 input="cat -"
49 output="cat -"
50
51 dot_format="-Tpng"
52 filter=
53 debug=
54 focus=
55 cluster=
56
57 while [ ${#} -gt 0 ]; do
58   case ${1} in
59
60     -T | --format)
61       dot_format="-T${2}"
62       shift
63       ;;
64
65     -T*)
66       dot_format="${1}"
67       ;;
68
69     --format=*)
70       dot_format="-T${1#--format=}"
71       ;;
72
73     --debug | -d)
74       debug=1
75       ;;
76
77     --verbose | -v)
78       # indent, but do _not_ strip out addresses
79       beautify() {
80         sed 's/^./    &/'
81       }
82       ;;
83
84     --focus | -f | --primary) # reserving --primary
85       focus=1
86       ;;
87
88     --secondary) # reserving --secondary
89       focus=
90       ;;
91
92     --cluster) # reserve -c for dot (configure plugins)
93       cluster=1
94       ;;
95
96     --serial | -s)
97       if [ "${input}" != "cat -" ]; then
98         usage >&2
99         echo "ERROR: --input or --serial can only be specified once" >&2
100         exit 1
101       fi
102       input="adb -s ${2} shell su 0 cat /proc/lockdep_chains"
103       shift
104       ;;
105
106     --serial=*)
107       input="adb -s ${1#--serial=} shell su 0 cat /proc/lockdep_chains"
108       ;;
109
110     --input | -i)
111       if [ "${input}" != "cat -" ]; then
112         usage >&2
113         echo "ERROR: --input or --serial can only be specified once" >&2
114         exit 1
115       fi
116       input="cat ${2}"
117       shift
118       ;;
119
120     --input=*)
121       if [ "${input}" != "cat -" ]; then
122         usage >&2
123         echo "ERROR: --input or --serial can only be specified once" >&2
124         exit 1
125       fi
126       input="cat ${1#--input=}"
127       ;;
128
129     --output | -o)
130       if [ "${output}" != "cat -" ]; then
131         usage >&2
132         echo "ERROR: --output can only be specified once" >&2
133         exit 1
134       fi
135       output="cat - > ${2}" # run through eval
136       shift
137       ;;
138
139     --output=*)
140       if [ "${output}" != "cat -" ]; then
141         usage >&2
142         echo "ERROR: --output can only be specified once" >&2
143         exit 1
144       fi
145       output="cat - > ${1#--output=}" # run through eval
146       ;;
147
148     --help | -h | -\?)
149       usage
150       exit
151       ;;
152
153     *)
154       # Everything else is a filter, which will also hide bad option flags,
155       # which is an as-designed price we pay to allow "->rwlock" for instance.
156       if [ X"${1}" = X"${1#* }" ]; then
157         if [ -z "${filter}" ]; then
158           filter="${1}"
159         else
160           filter="${filter}|${1}"
161         fi
162       else
163         if [ -z "${filter}" ]; then
164           filter=" ${1}"
165         else
166           filter="${filter}| ${1}"
167         fi
168       fi
169       ;;
170
171   esac
172   shift
173 done
174
175 if [ -z "${filter}" ]; then
176   echo "WARNING: no regex specified will give you what you deserve!" >&2
177 fi
178 if [ -n "${focus}" -a -z "${filter}" ]; then
179   echo "WARNING: --focus without regex, ignored" >&2
180 fi
181 if [ -n "${cluster}" -a -z "${filter}" ]; then
182   echo "WARNING: --cluster without regex, ignored" >&2
183 fi
184 if [ -n "${cluster}" -a -n "${focus}" -a -n "${filter}" ]; then
185   echo "WARNING: orthogonal options --cluster & --focus, ignoring --cluster" >&2
186   cluster=
187 fi
188
189 # convert to dot digraph series
190 ${input} |
191   sed '/^all lock chains:$/d
192        / [&]__lockdep_no_validate__$/d
193        /irq_context: 0/d
194        s/irq_context: [1-9]/irq_context/
195        s/..*/"&" ->/
196        s/^$/;/' |
197     sed ': loop
198          N
199          s/ ->\n;$/ ;/
200          t
201          s/ ->\n/ -> /
202          b loop' > /tmp/${progname}.formed
203
204 if [ ! -s /tmp/${progname}.formed ]; then
205   echo "ERROR: no input" >&2
206   if [ -z "${debug}" ]; then
207     rm -f /tmp/${progname}.*
208   fi
209   exit 2
210 fi
211
212 if [ -n "${filter}" ]; then
213   grep "${filter}" /tmp/${progname}.formed |
214     sed 's/ ;//
215          s/ -> /|/g' |
216       tr '|' '\n' |
217         sort -u > /tmp/${progname}.symbols
218 fi
219
220 (
221   echo 'digraph G {'
222   (
223     echo 'remincross="true";'
224     echo 'concentrate="true";'
225     echo
226
227     if [ -s /tmp/${progname}.symbols ]; then
228       if [ -n "${cluster}" ]; then
229         echo 'subgraph cluster_symbols {'
230         (
231           grep "${filter}" /tmp/${progname}.symbols |
232             sed 's/.*/& [shape=box] ;/'
233           grep -v "${filter}" /tmp/${progname}.symbols |
234             sed 's/.*/& [shape=diamond] ;/'
235         ) | beautify
236         echo '}'
237       else
238         grep "${filter}" /tmp/${progname}.symbols |
239           sed 's/.*/& [shape=box] ;/'
240         grep -v "${filter}" /tmp/${progname}.symbols |
241           sed 's/.*/& [shape=diamond] ;/'
242       fi
243
244       echo
245     fi
246   ) | beautify
247
248   if [ -s /tmp/${progname}.symbols ]; then
249     if [ -z "${focus}" ]; then
250       # Secondary relationships
251       fgrep -f /tmp/${progname}.symbols /tmp/${progname}.formed
252     else
253       # Focus only on primary relationships
254       grep "${filter}" /tmp/${progname}.formed
255     fi
256   else
257     cat /tmp/${progname}.formed
258   fi |
259     # optimize int A -> B ; single references
260     sed 's/\("[^"]*"\) -> \("[^"]*"\) ->/\1 -> \2 ;|\2 ->/g' |
261       sed 's/\("[^"]*"\) -> \("[^"]*"\) ->/\1 -> \2 ;|\2 ->/g' |
262         tr '|' '\n' |
263           beautify |
264             grep ' -> ' |
265               sort -u |
266                 if [ -s /tmp/${progname}.symbols ]; then
267                   beautify < /tmp/${progname}.symbols |
268                     sed 's/^  */ /' > /tmp/${progname}.short
269                   tee /tmp/${progname}.split |
270                     fgrep -f /tmp/${progname}.short |
271                       sed 's/ ;$/ [color=red] ;/'
272                   fgrep -v -f /tmp/${progname}.short /tmp/${progname}.split
273                   rm -f /tmp/${progname}.short /tmp/${progname}.split
274                 else
275                   cat -
276                 fi
277
278   echo '}'
279 ) |
280   tee /tmp/${progname}.input |
281     if dot ${dot_format} && [ -z "${debug}" ]; then
282       rm -f /tmp/${progname}.*
283     fi |
284       eval ${output}