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 24 min_slab_name_size=11 25 xmin=0 26 xmax=0 27 width=1500 28 height=700 29 mode=preprocess 30 31 usage() 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 41 check_file_exist() 42 { 43 if [ ! -f "$1" ]; then 44 echo "File '$1' does not exist" 45 exit 1 46 fi 47 } 48 49 do_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 81 gnuplot -p << EOF 82 #!/usr/bin/env gnuplot 83 84 set terminal png enhanced size $width,$height large 85 set output '$out_file.png' 86 set autoscale xy 87 set xlabel 'samples' 88 set ylabel 'bytes' 89 set style histogram columnstacked title textcolor lt -1 90 set style fill solid 0.15 91 set xtics rotate $xtic_rotate 92 set key left above Left title reverse 93 94 plot "$file" $range u 2$xtic title 'SIZE' with boxes,\ 95 '' $range u 3 title 'LOSS' with boxes 96 EOF 97 98 if [ $? -eq 0 ]; then 99 echo "$out_file.png" 100 fi 101 } 102 103 do_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 123 gnuplot -p << EOF 124 #!/usr/bin/env gnuplot 125 126 set terminal png enhanced size $width,$height large 127 set autoscale xy 128 set output '$file.png' 129 set xlabel 'samples' 130 set ylabel 'bytes' 131 set key left above Left title reverse 132 133 plot $gnuplot_cmd 134 EOF 135 136 if [ $? -eq 0 ]; then 137 echo "$file.png" 138 fi 139 } 140 141 do_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 grep -E -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 grep -E -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 177 parse_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 217 parse_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 240 parse_opts "$@" 241 argstart=$? 242 parse_args "${@:$argstart}" 243 244 if [ ${#files[@]} -eq 0 ] && [ ${#t_files[@]} -eq 0 ]; then 245 usage 246 exit 1 247 fi 248 249 case $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 ;; 268 esac
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.