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