diff options
author | Sergey Senozhatsky <sergey.senozhatsky@gmail.com> | 2015-11-05 21:45:37 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-05 22:34:48 -0500 |
commit | 4a981abd115d6ade5fe8a07d5ca1d1f987a0c2f7 (patch) | |
tree | 802db5b8be603afee8ae58d0306a798c3cf747a9 /tools/vm | |
parent | 2cee611af8638d80d3abb71f878829a7e998bb44 (diff) |
tools/vm/slabinfo: gnuplot slabifo extended stat
GNUplot `slabinfo -X' stats, collected, for example, using the
following command:
while [ 1 ]; do slabinfo -X >> stats; sleep 1; done
`slabinfo-gnuplot.sh stats' pre-processes collected records
and generate graphs (totals, slabs sorted by size, slabs
sorted by size).
Graphs can be [individually] regenerate with different samples
range and graph width-heigh (-r %d,%d and -s %d,%d options).
To visually compare N `totals' graphs:
slabinfo-gnuplot.sh -t FILE1-totals FILE2-totals ... FILEN-totals
Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Cc: Christoph Lameter <cl@linux.com>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'tools/vm')
-rw-r--r-- | tools/vm/slabinfo-gnuplot.sh | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/tools/vm/slabinfo-gnuplot.sh b/tools/vm/slabinfo-gnuplot.sh new file mode 100644 index 000000000000..35b039864b77 --- /dev/null +++ b/tools/vm/slabinfo-gnuplot.sh | |||
@@ -0,0 +1,275 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | # Sergey Senozhatsky, 2015 | ||
4 | # sergey.senozhatsky.work@gmail.com | ||
5 | # | ||
6 | # This software is licensed under the terms of the GNU General Public | ||
7 | # License version 2, as published by the Free Software Foundation, and | ||
8 | # may be copied, distributed, and modified under those terms. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | |||
15 | |||
16 | # This program is intended to plot a `slabinfo -X' stats, collected, | ||
17 | # for example, using the following command: | ||
18 | # while [ 1 ]; do slabinfo -X >> stats; sleep 1; done | ||
19 | # | ||
20 | # Use `slabinfo-gnuplot.sh stats' to pre-process collected records | ||
21 | # and generate graphs (totals, slabs sorted by size, slabs sorted | ||
22 | # by size). | ||
23 | # | ||
24 | # Graphs can be [individually] regenerate with different ranges and | ||
25 | # size (-r %d,%d and -s %d,%d options). | ||
26 | # | ||
27 | # To visually compare N `totals' graphs, do | ||
28 | # slabinfo-gnuplot.sh -t FILE1-totals FILE2-totals ... FILEN-totals | ||
29 | # | ||
30 | |||
31 | min_slab_name_size=11 | ||
32 | xmin=0 | ||
33 | xmax=0 | ||
34 | width=1500 | ||
35 | height=700 | ||
36 | mode=preprocess | ||
37 | |||
38 | usage() | ||
39 | { | ||
40 | echo "Usage: [-s W,H] [-r MIN,MAX] [-t|-l] FILE1 [FILE2 ..]" | ||
41 | echo "FILEs must contain 'slabinfo -X' samples" | ||
42 | echo "-t - plot totals for FILE(s)" | ||
43 | echo "-l - plot slabs stats for FILE(s)" | ||
44 | echo "-s %d,%d - set image width and height" | ||
45 | echo "-r %d,%d - use data samples from a given range" | ||
46 | } | ||
47 | |||
48 | check_file_exist() | ||
49 | { | ||
50 | if [ ! -f "$1" ]; then | ||
51 | echo "File '$1' does not exist" | ||
52 | exit 1 | ||
53 | fi | ||
54 | } | ||
55 | |||
56 | do_slabs_plotting() | ||
57 | { | ||
58 | local file=$1 | ||
59 | local out_file | ||
60 | local range="every ::$xmin" | ||
61 | local xtic="" | ||
62 | local xtic_rotate="norotate" | ||
63 | local lines=2000000 | ||
64 | local wc_lines | ||
65 | |||
66 | check_file_exist "$file" | ||
67 | |||
68 | out_file=`basename "$file"` | ||
69 | if [ $xmax -ne 0 ]; then | ||
70 | range="$range::$xmax" | ||
71 | lines=$((xmax-xmin)) | ||
72 | fi | ||
73 | |||
74 | wc_lines=`cat "$file" | wc -l` | ||
75 | if [ $? -ne 0 ] || [ "$wc_lines" -eq 0 ] ; then | ||
76 | wc_lines=$lines | ||
77 | fi | ||
78 | |||
79 | if [ "$wc_lines" -lt "$lines" ]; then | ||
80 | lines=$wc_lines | ||
81 | fi | ||
82 | |||
83 | if [ $((width / lines)) -gt $min_slab_name_size ]; then | ||
84 | xtic=":xtic(1)" | ||
85 | xtic_rotate=90 | ||
86 | fi | ||
87 | |||
88 | gnuplot -p << EOF | ||
89 | #!/usr/bin/env gnuplot | ||
90 | |||
91 | set terminal png enhanced size $width,$height large | ||
92 | set output '$out_file.png' | ||
93 | set autoscale xy | ||
94 | set xlabel 'samples' | ||
95 | set ylabel 'bytes' | ||
96 | set style histogram columnstacked title textcolor lt -1 | ||
97 | set style fill solid 0.15 | ||
98 | set xtics rotate $xtic_rotate | ||
99 | set key left above Left title reverse | ||
100 | |||
101 | plot "$file" $range u 2$xtic title 'SIZE' with boxes,\ | ||
102 | '' $range u 3 title 'LOSS' with boxes | ||
103 | EOF | ||
104 | |||
105 | if [ $? -eq 0 ]; then | ||
106 | echo "$out_file.png" | ||
107 | fi | ||
108 | } | ||
109 | |||
110 | do_totals_plotting() | ||
111 | { | ||
112 | local gnuplot_cmd="" | ||
113 | local range="every ::$xmin" | ||
114 | local file="" | ||
115 | |||
116 | if [ $xmax -ne 0 ]; then | ||
117 | range="$range::$xmax" | ||
118 | fi | ||
119 | |||
120 | for i in "${t_files[@]}"; do | ||
121 | check_file_exist "$i" | ||
122 | |||
123 | file="$file"`basename "$i"` | ||
124 | gnuplot_cmd="$gnuplot_cmd '$i' $range using 1 title\ | ||
125 | '$i Memory usage' with lines," | ||
126 | gnuplot_cmd="$gnuplot_cmd '' $range using 2 title \ | ||
127 | '$i Loss' with lines," | ||
128 | done | ||
129 | |||
130 | gnuplot -p << EOF | ||
131 | #!/usr/bin/env gnuplot | ||
132 | |||
133 | set terminal png enhanced size $width,$height large | ||
134 | set autoscale xy | ||
135 | set output '$file.png' | ||
136 | set xlabel 'samples' | ||
137 | set ylabel 'bytes' | ||
138 | set key left above Left title reverse | ||
139 | |||
140 | plot $gnuplot_cmd | ||
141 | EOF | ||
142 | |||
143 | if [ $? -eq 0 ]; then | ||
144 | echo "$file.png" | ||
145 | fi | ||
146 | } | ||
147 | |||
148 | do_preprocess() | ||
149 | { | ||
150 | local out | ||
151 | local lines | ||
152 | local in=$1 | ||
153 | |||
154 | check_file_exist "$in" | ||
155 | |||
156 | # use only 'TOP' slab (biggest memory usage or loss) | ||
157 | let lines=3 | ||
158 | out=`basename "$in"`"-slabs-by-loss" | ||
159 | `cat "$in" | grep -A "$lines" 'Slabs sorted by loss' |\ | ||
160 | egrep -iv '\-\-|Name|Slabs'\ | ||
161 | | awk '{print $1" "$4+$2*$3" "$4}' > "$out"` | ||
162 | if [ $? -eq 0 ]; then | ||
163 | do_slabs_plotting "$out" | ||
164 | fi | ||
165 | |||
166 | let lines=3 | ||
167 | out=`basename "$in"`"-slabs-by-size" | ||
168 | `cat "$in" | grep -A "$lines" 'Slabs sorted by size' |\ | ||
169 | egrep -iv '\-\-|Name|Slabs'\ | ||
170 | | awk '{print $1" "$4" "$4-$2*$3}' > "$out"` | ||
171 | if [ $? -eq 0 ]; then | ||
172 | do_slabs_plotting "$out" | ||
173 | fi | ||
174 | |||
175 | out=`basename "$in"`"-totals" | ||
176 | `cat "$in" | grep "Memory used" |\ | ||
177 | awk '{print $3" "$7}' > "$out"` | ||
178 | if [ $? -eq 0 ]; then | ||
179 | t_files[0]=$out | ||
180 | do_totals_plotting | ||
181 | fi | ||
182 | } | ||
183 | |||
184 | parse_opts() | ||
185 | { | ||
186 | local opt | ||
187 | |||
188 | while getopts "tlr::s::h" opt; do | ||
189 | case $opt in | ||
190 | t) | ||
191 | mode=totals | ||
192 | ;; | ||
193 | l) | ||
194 | mode=slabs | ||
195 | ;; | ||
196 | s) | ||
197 | array=(${OPTARG//,/ }) | ||
198 | width=${array[0]} | ||
199 | height=${array[1]} | ||
200 | ;; | ||
201 | r) | ||
202 | array=(${OPTARG//,/ }) | ||
203 | xmin=${array[0]} | ||
204 | xmax=${array[1]} | ||
205 | ;; | ||
206 | h) | ||
207 | usage | ||
208 | exit 0 | ||
209 | ;; | ||
210 | \?) | ||
211 | echo "Invalid option: -$OPTARG" >&2 | ||
212 | exit 1 | ||
213 | ;; | ||
214 | :) | ||
215 | echo "-$OPTARG requires an argument." >&2 | ||
216 | exit 1 | ||
217 | ;; | ||
218 | esac | ||
219 | done | ||
220 | |||
221 | return $OPTIND | ||
222 | } | ||
223 | |||
224 | parse_args() | ||
225 | { | ||
226 | local idx=0 | ||
227 | local p | ||
228 | |||
229 | for p in "$@"; do | ||
230 | case $mode in | ||
231 | preprocess) | ||
232 | files[$idx]=$p | ||
233 | idx=$idx+1 | ||
234 | ;; | ||
235 | totals) | ||
236 | t_files[$idx]=$p | ||
237 | idx=$idx+1 | ||
238 | ;; | ||
239 | slabs) | ||
240 | files[$idx]=$p | ||
241 | idx=$idx+1 | ||
242 | ;; | ||
243 | esac | ||
244 | done | ||
245 | } | ||
246 | |||
247 | parse_opts "$@" | ||
248 | argstart=$? | ||
249 | parse_args "${@:$argstart}" | ||
250 | |||
251 | if [ ${#files[@]} -eq 0 ] && [ ${#t_files[@]} -eq 0 ]; then | ||
252 | usage | ||
253 | exit 1 | ||
254 | fi | ||
255 | |||
256 | case $mode in | ||
257 | preprocess) | ||
258 | for i in "${files[@]}"; do | ||
259 | do_preprocess "$i" | ||
260 | done | ||
261 | ;; | ||
262 | totals) | ||
263 | do_totals_plotting | ||
264 | ;; | ||
265 | slabs) | ||
266 | for i in "${files[@]}"; do | ||
267 | do_slabs_plotting "$i" | ||
268 | done | ||
269 | ;; | ||
270 | *) | ||
271 | echo "Unknown mode $mode" >&2 | ||
272 | usage | ||
273 | exit 1 | ||
274 | ;; | ||
275 | esac | ||