Commit | Line | Data |
---|---|---|
4a981abd SS |
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 |