slabinfo-gnuplot.sh 4.7 KB

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