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