Linux 4.19-rc7
[linux-2.6/btrfs-unstable.git] / tools / vm / slabinfo-gnuplot.sh
blob0cf28aa6f21c3b392b8a90b4aa9e9087f6807b3e
1 #!/bin/bash
3 # Sergey Senozhatsky, 2015
4 # sergey.senozhatsky.work@gmail.com
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.
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.
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
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).
24 # Graphs can be [individually] regenerate with different ranges and
25 # size (-r %d,%d and -s %d,%d options).
27 # To visually compare N `totals' graphs, do
28 # slabinfo-gnuplot.sh -t FILE1-totals FILE2-totals ... FILEN-totals
31 min_slab_name_size=11
32 xmin=0
33 xmax=0
34 width=1500
35 height=700
36 mode=preprocess
38 usage()
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"
48 check_file_exist()
50 if [ ! -f "$1" ]; then
51 echo "File '$1' does not exist"
52 exit 1
56 do_slabs_plotting()
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
66 check_file_exist "$file"
68 out_file=`basename "$file"`
69 if [ $xmax -ne 0 ]; then
70 range="$range::$xmax"
71 lines=$((xmax-xmin))
74 wc_lines=`cat "$file" | wc -l`
75 if [ $? -ne 0 ] || [ "$wc_lines" -eq 0 ] ; then
76 wc_lines=$lines
79 if [ "$wc_lines" -lt "$lines" ]; then
80 lines=$wc_lines
83 if [ $((width / lines)) -gt $min_slab_name_size ]; then
84 xtic=":xtic(1)"
85 xtic_rotate=90
88 gnuplot -p << EOF
89 #!/usr/bin/env gnuplot
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
101 plot "$file" $range u 2$xtic title 'SIZE' with boxes,\
102 '' $range u 3 title 'LOSS' with boxes
105 if [ $? -eq 0 ]; then
106 echo "$out_file.png"
110 do_totals_plotting()
112 local gnuplot_cmd=""
113 local range="every ::$xmin"
114 local file=""
116 if [ $xmax -ne 0 ]; then
117 range="$range::$xmax"
120 for i in "${t_files[@]}"; do
121 check_file_exist "$i"
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
130 gnuplot -p << EOF
131 #!/usr/bin/env gnuplot
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
140 plot $gnuplot_cmd
143 if [ $? -eq 0 ]; then
144 echo "$file.png"
148 do_preprocess()
150 local out
151 local lines
152 local in=$1
154 check_file_exist "$in"
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"
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"
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
184 parse_opts()
186 local opt
188 while getopts "tlr::s::h" opt; do
189 case $opt in
191 mode=totals
194 mode=slabs
197 array=(${OPTARG//,/ })
198 width=${array[0]}
199 height=${array[1]}
202 array=(${OPTARG//,/ })
203 xmin=${array[0]}
204 xmax=${array[1]}
207 usage
208 exit 0
211 echo "Invalid option: -$OPTARG" >&2
212 exit 1
215 echo "-$OPTARG requires an argument." >&2
216 exit 1
218 esac
219 done
221 return $OPTIND
224 parse_args()
226 local idx=0
227 local p
229 for p in "$@"; do
230 case $mode in
231 preprocess)
232 files[$idx]=$p
233 idx=$idx+1
235 totals)
236 t_files[$idx]=$p
237 idx=$idx+1
239 slabs)
240 files[$idx]=$p
241 idx=$idx+1
243 esac
244 done
247 parse_opts "$@"
248 argstart=$?
249 parse_args "${@:$argstart}"
251 if [ ${#files[@]} -eq 0 ] && [ ${#t_files[@]} -eq 0 ]; then
252 usage
253 exit 1
256 case $mode in
257 preprocess)
258 for i in "${files[@]}"; do
259 do_preprocess "$i"
260 done
262 totals)
263 do_totals_plotting
265 slabs)
266 for i in "${files[@]}"; do
267 do_slabs_plotting "$i"
268 done
271 echo "Unknown mode $mode" >&2
272 usage
273 exit 1
275 esac