diff options
| author | Sergey Senozhatsky <sergey.senozhatsky@gmail.com> | 2015-11-05 21:45:37 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-05 22:34:48 -0500 |
| commit | 4a981abd115d6ade5fe8a07d5ca1d1f987a0c2f7 (patch) | |
| tree | 802db5b8be603afee8ae58d0306a798c3cf747a9 /tools/vm | |
| parent | 2cee611af8638d80d3abb71f878829a7e998bb44 (diff) | |
tools/vm/slabinfo: gnuplot slabifo extended stat
GNUplot `slabinfo -X' stats, collected, for example, using the
following command:
while [ 1 ]; do slabinfo -X >> stats; sleep 1; done
`slabinfo-gnuplot.sh stats' pre-processes collected records
and generate graphs (totals, slabs sorted by size, slabs
sorted by size).
Graphs can be [individually] regenerate with different samples
range and graph width-heigh (-r %d,%d and -s %d,%d options).
To visually compare N `totals' graphs:
slabinfo-gnuplot.sh -t FILE1-totals FILE2-totals ... FILEN-totals
Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Cc: Christoph Lameter <cl@linux.com>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'tools/vm')
| -rw-r--r-- | tools/vm/slabinfo-gnuplot.sh | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/tools/vm/slabinfo-gnuplot.sh b/tools/vm/slabinfo-gnuplot.sh new file mode 100644 index 000000000000..35b039864b77 --- /dev/null +++ b/tools/vm/slabinfo-gnuplot.sh | |||
| @@ -0,0 +1,275 @@ | |||
| 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 | ||
