Commit | Line | Data |
---|---|---|
77bd540c SK |
1 | #! /bin/sh |
2 | ||
059851a9 SK |
3 | set -e |
4 | ||
77bd540c SK |
5 | usage() { |
6 | echo "EXAMPLE (whole tree) : $0 | neato -T png > ps.png && open ps.png" | |
7 | echo "EXAMPLE (user clusters): $0 | sdp -T png > ps.png && open ps.png" | |
8 | } | |
9 | ||
10 | ||
059851a9 | 11 | ps2dot() { |
77bd540c SK |
12 | awk -v kernel="$(uname -v)" -v whoami="$(whoami)" \ |
13 | ' | |
4a01bf49 SK |
14 | function num_scale(src_cur, src_max, dst_min, dst_max) { |
15 | return dst_min + ((src_cur * (dst_max - dst_min)) / src_max) | |
16 | } | |
17 | ||
2940f645 | 18 | function vert_print(v, _color, _fontcolor, _shape, _state, _size, _height, _label, _label_base, _label_ext) { |
43061022 | 19 | _state = child2state[v] |
182bd2be SK |
20 | _style = "filled,solid" |
21 | ||
22 | # ----------------------------------------------------------------- | |
23 | # Sleeping/idling | |
24 | # ----------------------------------------------------------------- | |
25 | # D uninterruptible sleep (usually IO) | |
43061022 SK |
26 | if (_state == "D") { |
27 | _shape = "circle" | |
182bd2be | 28 | # I Idle kernel thread |
43061022 | 29 | } else if (_state == "I") { |
182bd2be SK |
30 | _shape = "circle" |
31 | # S interruptible sleep (waiting for an event to complete) | |
43061022 | 32 | } else if (_state == "S") { |
182bd2be SK |
33 | _shape = "circle" |
34 | # ----------------------------------------------------------------- | |
35 | # Running | |
36 | # ----------------------------------------------------------------- | |
37 | # R running or runnable (on run queue) | |
38 | } else if (_state == "R") { | |
39 | _shape = "rarrow" | |
40 | # ----------------------------------------------------------------- | |
41 | # Stopped | |
42 | # ----------------------------------------------------------------- | |
43 | # T stopped by job control signal | |
43061022 SK |
44 | } else if (_state == "T") { |
45 | _shape = "square" | |
182bd2be | 46 | # t stopped by debugger during the tracing |
43061022 | 47 | } else if (_state == "t") { |
182bd2be SK |
48 | _shape = "square" |
49 | # ----------------------------------------------------------------- | |
50 | # Dead | |
51 | # ----------------------------------------------------------------- | |
52 | # Z defunct ("zombie") process, terminated but not reaped by its parent | |
43061022 | 53 | } else if (_state == "Z") { |
182bd2be SK |
54 | _shape = "Msquare" |
55 | _style = "solid" | |
56 | # ----------------------------------------------------------------- | |
57 | # UNKNOWN STATE | |
58 | # ----------------------------------------------------------------- | |
59 | } else { | |
60 | _shape = "doublecircle" | |
43061022 | 61 | } |
182bd2be | 62 | |
4a01bf49 SK |
63 | _color =\ |
64 | num_scale(\ | |
2940f645 SK |
65 | child2cpu[v], |
66 | max_cpu, | |
67 | VERT_COLORSCHEME_MAX, | |
68 | VERT_COLORSCHEME_MIN\ | |
4a01bf49 | 69 | ) |
2940f645 SK |
70 | _size =\ |
71 | num_scale(\ | |
72 | child2mem[v], | |
73 | max_mem, | |
74 | 1, | |
182bd2be SK |
75 | 4\ |
76 | ) / 4 | |
2940f645 | 77 | _height = _size |
182bd2be | 78 | _width = _size |
5259a527 | 79 | _fontcolor = \ |
2940f645 SK |
80 | _color == VERT_COLORSCHEME_MAX || _color == VERT_COLORSCHEME_MIN \ |
81 | ? sprintf("/%s/%d", VERT_COLORSCHEME, VERT_COLORSCHEME_MID) \ | |
5259a527 | 82 | : sprintf("/%s/%d", "greys9", 9) |
2940f645 SK |
83 | _fontcolor = \ |
84 | _size < 0.5 \ | |
85 | ? sprintf("/%s/%d", "greys9", 9) \ | |
86 | : _fontcolor | |
87 | _label_base = \ | |
88 | sprintf("%s\n%d", child2comm[v], v) | |
89 | _label_ext = \ | |
90 | _size >= 0.5 \ | |
91 | ? sprintf("\ncpu: %.1f%%\nmem: %.1f%%", child2cpu[v], child2mem[v]) \ | |
92 | : "" | |
93 | _label = _label_base _label_ext | |
4a01bf49 SK |
94 | printf(\ |
95 | "\"%d\"\ | |
96 | [ fontsize=8 \ | |
2940f645 SK |
97 | , fixedsize=true \ |
98 | , height=%f \ | |
182bd2be | 99 | , width=%f \ |
43061022 | 100 | , border=1 \ |
182bd2be | 101 | , style=\"%s\" \ |
4a01bf49 | 102 | , fontname=Helvetica \ |
2940f645 | 103 | , label=\"%s\" \ |
43061022 SK |
104 | , shape=\"%s\" \ |
105 | , fillcolor=\"/%s/%d\" \ | |
5259a527 | 106 | , fontcolor=\"%s\" \ |
4a01bf49 SK |
107 | ];", |
108 | v, | |
2940f645 | 109 | _height, |
182bd2be SK |
110 | _width, |
111 | _style, | |
2940f645 | 112 | _label, |
43061022 | 113 | _shape, |
2940f645 | 114 | VERT_COLORSCHEME, |
4a01bf49 | 115 | _color, |
5259a527 | 116 | _fontcolor\ |
4a01bf49 SK |
117 | ) |
118 | } | |
119 | ||
2940f645 | 120 | function edge_print(child, _parent) { |
4a01bf49 | 121 | _parent = child2parent[child] |
4a01bf49 SK |
122 | printf(\ |
123 | "\"%s\" -> \"%s\"\ | |
124 | [ fontsize=8 \ | |
125 | , fontname=Helvetica \ | |
126 | , len=2.0 \ | |
2940f645 | 127 | , color=\"%s\" \ |
4a01bf49 SK |
128 | ];\n", |
129 | _parent, | |
130 | child, | |
2940f645 | 131 | EDGE_COLOR\ |
4a01bf49 SK |
132 | ) |
133 | } | |
134 | ||
77bd540c | 135 | BEGIN { |
5259a527 SK |
136 | # Hot->Cold gradual colorschemes: |
137 | # - rdbu11 | |
138 | # - rdbu9 | |
139 | # - rdbu8 | |
2940f645 | 140 | # - rdylgn10 # 3 - 11 |
5259a527 SK |
141 | |
142 | # Light->Dark gradual colorschemes: | |
143 | # - reds9 | |
144 | # - blues9 | |
145 | # - orrd9 | |
146 | # - oranges9 | |
147 | # - bupu9 | |
148 | # - greys9 | |
149 | ||
2940f645 SK |
150 | VERT_COLORSCHEME_MIN = 1 |
151 | VERT_COLORSCHEME_MID = 4 | |
152 | VERT_COLORSCHEME_MAX = 8 | |
153 | VERT_COLORSCHEME = "rdylgn10" | |
154 | ||
155 | EDGE_COLOR = "/ylorbr9/3" | |
5259a527 | 156 | |
43061022 | 157 | child2comm[0] = "swapper/sched" |
77bd540c SK |
158 | } |
159 | ||
160 | NR > 1 { | |
4a01bf49 SK |
161 | parent2child_count[$2]++ |
162 | max_children = \ | |
163 | parent2child_count[$2] > max_children\ | |
164 | ? parent2child_count[$2]\ | |
165 | : max_children | |
166 | child2parent[$1] = $2 | |
167 | child2user_id[$1] = $3 | |
168 | child2user_name[$1] = $4 | |
5259a527 | 169 | child2nice[$1] = $5 |
43061022 | 170 | child2state[$1] = $6 |
2940f645 SK |
171 | child2cpu[$1] = $7 |
172 | child2mem[$1] = $8 | |
173 | child2comm[$1] = $9 | |
4a01bf49 | 174 | user_names[$4] = 1 |
2940f645 SK |
175 | max_cpu = $7 > max_cpu ? $7 : max_cpu |
176 | max_mem = $8 > max_mem ? $8 : max_mem | |
77bd540c SK |
177 | } |
178 | ||
179 | END { | |
180 | print "strict digraph G {"; | |
181 | ||
182 | print "start=0;"; | |
77bd540c SK |
183 | print "fontsize=8;"; |
184 | print "fontname=Helvetica;"; | |
185 | print "label=\"" kernel "\";"; | |
af6e57a2 | 186 | print "fontcolor=\"/greys9/9\";" |
77bd540c SK |
187 | |
188 | ##### Vertices (clustered by user) | |
4a01bf49 SK |
189 | for (user_name in user_names) { |
190 | printf "subgraph \"cluster_%s\" {\n", user_name | |
191 | printf "label=\"%s\"\n", user_name | |
192 | for (c in child2parent) | |
193 | if (child2user_name[c] == user_name) | |
194 | vert_print(c) | |
77bd540c SK |
195 | print "}" |
196 | } | |
197 | ||
198 | ##### Vertices (without a user) | |
43061022 | 199 | for (c in child2comm) |
4a01bf49 SK |
200 | if (!child2user_name[c]) |
201 | vert_print(c) | |
77bd540c SK |
202 | |
203 | ##### Edges (across clusters) | |
4a01bf49 SK |
204 | for (c in child2parent) |
205 | edge_print(c) | |
77bd540c SK |
206 | |
207 | print "}"; | |
208 | } | |
209 | ' | |
210 | } | |
211 | ||
212 | ||
213 | procs() { | |
214 | if [ "$(uname)" = 'Linux' ]; then | |
2940f645 | 215 | ps -eo 'pid,ppid,euid,euser,nice,s,%cpu,%mem,comm' |
77bd540c | 216 | else |
2940f645 | 217 | ps -eco 'pid,ppid,euid,euser,nice,s,%cpu,%mem,comm' |
77bd540c SK |
218 | fi |
219 | } | |
220 | ||
221 | ||
222 | main() { | |
223 | case "$1" in | |
059851a9 SK |
224 | '--help') |
225 | usage | |
77bd540c | 226 | ;; |
059851a9 SK |
227 | *) |
228 | timestamp="$(date +'%Y-%m-%d_%H:%M:%S%z')" | |
229 | host="$(hostname)" | |
230 | kernel="$(uname -s | awk '{print tolower($0)}')" | |
231 | filename_base=$(mktemp "ps.$host.$kernel.$timestamp.XXXXX") | |
232 | file_log="$filename_base.log" | |
233 | file_dot="$filename_base.dot" | |
234 | mv "$filename_base" "$file_log" | |
235 | procs | grep "$1" | ps2dot 2> "$file_log" > "$file_dot" | |
236 | time neato -T png "$file_dot" 2> "$file_log" > "$filename_base.neato.png" | |
237 | time fdp -T png "$file_dot" 2> "$file_log" > "$filename_base.fdp.png" | |
238 | time dot -T png "$file_dot" 2> "$file_log" > "$filename_base.dot.png" | |
239 | ls -1 "$filename_base"* | |
77bd540c SK |
240 | ;; |
241 | esac | |
242 | } | |
243 | ||
244 | ||
245 | main "$1" |