tools/slabinfo-gnuplot: force to use bash shell
[muen/linux.git] / tools / vm / slabinfo-gnuplot.sh
1 #!/bin/bash
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