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