vmplot.sh, a useful tool for MySQL performance tuning
这个工具其实就是把vmstat的输出结果变成可视化的曲线图而已。
首先执行类似 vmstat 1 200 > vmstat.out 这样的命令,收集一段时间的vmstat统计结果,然后交给vmplot脚本来处理即可。vmplot也只是个简单的shell脚本,利用gnuplot工具,向其传递相应的参数,就能划出你想要的PNG图片(/tmp目录下)。
I don’t know if it is because of my science background, I am a physicist, I do like graphs, especially when I do performance tuning. With UNIX like operating systems, the vmstat command give you an easy way to grab many essential performance counters but, generating graphs from vmstat output with tools like OpenOffice Calc is time consuming and not very efficient. In order to solve this, I wrote a few scripts using gnuplot but they are not very easy to work with. Then, doing some benchmarks with DBT2, I found the vmplot.sh script and… I like that one. I just hacked it little bit to make it keeps the graph on screen, adding the “-persist” parameters to the gnuplot invocations. The script will produce 7 graphs that will be displayed on screen and save in png format in /tmp. The graphs it produces are the following:
■CPU: graphs idle, user, sys and wait time
■CS: graphs the context switches/s
■IN: graphs the interrupts/s
■IO: graphs the block read and written to disk per second
■Memory: graphs the memory usage (swapped, free, buffers, cache)
■Procs: graphs the number of running and blocked processes
■Swap: graphs swap in and swap out activity
For the interested ones, my version of vmplot script is available here.
#!/bin/sh # # This file is released under the terms of the Artistic License. # Please see the file LICENSE, included in this package, for details. # # Copyright (C) 2004 Mark Wong & Open Source Development Lab, Inc. # INFILE="vmstat.out" OUTDIR="/tmp" DATAFILE="vmstat.data" X_UNITS="Minutes" while getopts "i:o:x:" opt; do case $opt in i) INFILE=$OPTARG ;; o) OUTDIR=$OPTARG ;; x) X_UNITS=$OPTARG ;; esac done if [ ! -f "$INFILE" ]; then echo "$INFILE does not exist." exit 1 fi # Blindly create the output directory. mkdir -p $OUTDIR # This is based off vmstat with a header like: #procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu---- # r b swpd free buff cache si so bi bo in cs us sy id wa # Make 0 the first point for each graph # Also add another column at the end to represent total processor utilization. echo "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0" > ${OUTDIR}/vmstat.data cat ${INFILE} | grep -v '^procs ' | grep -v '^ r b ' | awk '{ print NR, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $13+$14+$16 }' >> ${OUTDIR}/${DATAFILE} # Plot the procs information. NAME="procs" INPUT_FILE="${NAME}.input" PNG_FILE="${NAME}.png" echo "plot \"${DATAFILE}\" using 1:2 title \"waiting for run time\" with lines, \\" > ${OUTDIR}/${INPUT_FILE} echo " \"${DATAFILE}\" using 1:3 title \"in uninterruptible sleep\" with lines" >> ${OUTDIR}/${INPUT_FILE} echo "set title \"Procs\"" >> ${OUTDIR}/${INPUT_FILE} echo "set grid xtics ytics" >> ${OUTDIR}/${INPUT_FILE} echo "set xlabel \"Elapsed Time (${X_UNITS})\"" >> ${OUTDIR}/${INPUT_FILE} echo "set ylabel \"Count\"" >> ${OUTDIR}/${INPUT_FILE} echo "set term png small" >> ${OUTDIR}/${INPUT_FILE} echo "set output \"${PNG_FILE}\"" >> ${OUTDIR}/${INPUT_FILE} echo "set yrange [0:]" >> ${OUTDIR}/${INPUT_FILE} echo "replot" >> ${OUTDIR}/${INPUT_FILE} (cd ${OUTDIR}; gnuplot -persist ${INPUT_FILE}) # Plot the memory information. NAME="memory" INPUT_FILE="${NAME}.input" PNG_FILE="${NAME}.png" echo "plot \"${DATAFILE}\" using 1:4 title \"Swapped\" with lines, \\" > ${OUTDIR}/${INPUT_FILE} echo " \"${DATAFILE}\" using 1:5 title \"Free\" with lines, \\" >> ${OUTDIR}/${INPUT_FILE} echo " \"${DATAFILE}\" using 1:6 title \"Buffers\" with lines, \\" >> ${OUTDIR}/${INPUT_FILE} echo " \"${DATAFILE}\" using 1:7 title \"Cache\" with lines" >> ${OUTDIR}/${INPUT_FILE} echo "set title \"Memory\"" >> ${OUTDIR}/${INPUT_FILE} echo "set grid xtics ytics" >> ${OUTDIR}/${INPUT_FILE} echo "set xlabel \"Sample\"" >> ${OUTDIR}/${INPUT_FILE} echo "set ylabel \"Kilobytes\"" >> ${OUTDIR}/${INPUT_FILE} echo "set term png small" >> ${OUTDIR}/${INPUT_FILE} echo "set output \"${PNG_FILE}\"" >> ${OUTDIR}/${INPUT_FILE} echo "set yrange [0:]" >> ${OUTDIR}/${INPUT_FILE} echo "replot" >> ${OUTDIR}/${INPUT_FILE} (cd ${OUTDIR}; gnuplot -persist ${INPUT_FILE}) # Plot the swap information. NAME="swap" INPUT_FILE="${NAME}.input" PNG_FILE="${NAME}.png" echo "plot \"${DATAFILE}\" using 1:8 title \"in from disk\" with lines, \\" > ${OUTDIR}/${INPUT_FILE} echo " \"${DATAFILE}\" using 1:9 title \"out to disk\" with lines" >> ${OUTDIR}/${INPUT_FILE} echo "set title \"Swap\"" >> ${OUTDIR}/${INPUT_FILE} echo "set grid xtics ytics" >> ${OUTDIR}/${INPUT_FILE} echo "set xlabel \"Sample\"" >> ${OUTDIR}/${INPUT_FILE} echo "set ylabel \"Kilobytes / Second\"" >> ${OUTDIR}/${INPUT_FILE} echo "set term png small" >> ${OUTDIR}/${INPUT_FILE} echo "set output \"${PNG_FILE}\"" >> ${OUTDIR}/${INPUT_FILE} echo "set yrange [0:]" >> ${OUTDIR}/${INPUT_FILE} echo "replot" >> ${OUTDIR}/${INPUT_FILE} (cd ${OUTDIR}; gnuplot -persist ${INPUT_FILE}) # Plot the i/o information. NAME="io" INPUT_FILE="${NAME}.input" PNG_FILE="${NAME}.png" echo "plot \"${DATAFILE}\" using 1:10 title \"received from device\" with lines, \\" > ${OUTDIR}/${INPUT_FILE} echo " \"${DATAFILE}\" using 1:11 title \"sent to device\" with lines" >> ${OUTDIR}/${INPUT_FILE} echo "set title \"IO\"" >> ${OUTDIR}/${INPUT_FILE} echo "set grid xtics ytics" >> ${OUTDIR}/${INPUT_FILE} echo "set xlabel \"Sample\"" >> ${OUTDIR}/${INPUT_FILE} echo "set ylabel \"Blocks per Second\"" >> ${OUTDIR}/${INPUT_FILE} echo "set term png small" >> ${OUTDIR}/${INPUT_FILE} echo "set output \"${PNG_FILE}\"" >> ${OUTDIR}/${INPUT_FILE} echo "set yrange [0:]" >> ${OUTDIR}/${INPUT_FILE} echo "replot" >> ${OUTDIR}/${INPUT_FILE} (cd ${OUTDIR}; gnuplot -persist ${INPUT_FILE}) # Plot the interrupt. NAME="in" INPUT_FILE="${NAME}.input" PNG_FILE="${NAME}.png" echo "plot \"${DATAFILE}\" using 1:12 title \"interrupts\" with lines" > ${OUTDIR}/${INPUT_FILE} echo "set title \"Interrupts\"" >> ${OUTDIR}/${INPUT_FILE} echo "set grid xtics ytics" >> ${OUTDIR}/${INPUT_FILE} echo "set xlabel \"Sample\"" >> ${OUTDIR}/${INPUT_FILE} echo "set ylabel \"# of Interrupts / Second\"" >> ${OUTDIR}/${INPUT_FILE} echo "set term png small" >> ${OUTDIR}/${INPUT_FILE} echo "set output \"${PNG_FILE}\"" >> ${OUTDIR}/${INPUT_FILE} echo "set yrange [0:]" >> ${OUTDIR}/${INPUT_FILE} echo "replot" >> ${OUTDIR}/${INPUT_FILE} (cd ${OUTDIR}; gnuplot -persist ${INPUT_FILE}) # Plot the interrupt. NAME="cs" INPUT_FILE="${NAME}.input" PNG_FILE="${NAME}.png" echo "plot \"${DATAFILE}\" using 1:13 title \"context switches\" with lines" > ${OUTDIR}/${INPUT_FILE} echo "set title \"Context Switches\"" >> ${OUTDIR}/${INPUT_FILE} echo "set grid xtics ytics" >> ${OUTDIR}/${INPUT_FILE} echo "set xlabel \"Sample\"" >> ${OUTDIR}/${INPUT_FILE} echo "set ylabel \"# of Context Switches / Second\"" >> ${OUTDIR}/${INPUT_FILE} echo "set term png small" >> ${OUTDIR}/${INPUT_FILE} echo "set output \"${PNG_FILE}\"" >> ${OUTDIR}/${INPUT_FILE} echo "set yrange [0:]" >> ${OUTDIR}/${INPUT_FILE} echo "replot" >> ${OUTDIR}/${INPUT_FILE} (cd ${OUTDIR}; gnuplot -persist ${INPUT_FILE}) # Plot the processor utilization. NAME="cpu" INPUT_FILE="${NAME}.input" PNG_FILE="${NAME}.png" echo "plot \"${DATAFILE}\" using 1:18 title \"total\" with lines, \\" > ${OUTDIR}/${INPUT_FILE} echo " \"${DATAFILE}\" using 1:14 title \"user\" with lines, \\" >> ${OUTDIR}/${INPUT_FILE} echo " \"${DATAFILE}\" using 1:15 title \"system\" with lines, \\" >> ${OUTDIR}/${INPUT_FILE} echo " \"${DATAFILE}\" using 1:16 title \"idle\" with lines, \\" >> ${OUTDIR}/${INPUT_FILE} echo " \"${DATAFILE}\" using 1:17 title \"wait\" with lines" >> ${OUTDIR}/${INPUT_FILE} echo "set title \"System Processor Utilization\"" >> ${OUTDIR}/${INPUT_FILE} echo "set grid xtics ytics" >> ${OUTDIR}/${INPUT_FILE} echo "set xlabel \"Sample\"" >> ${OUTDIR}/${INPUT_FILE} echo "set ylabel \"% Utilized\"" >> ${OUTDIR}/${INPUT_FILE} echo "set term png small" >> ${OUTDIR}/${INPUT_FILE} echo "set output \"${PNG_FILE}\"" >> ${OUTDIR}/${INPUT_FILE} echo "set yrange [0:100]" >> ${OUTDIR}/${INPUT_FILE} echo "replot" >> ${OUTDIR}/${INPUT_FILE} (cd ${OUTDIR}; gnuplot -persist ${INPUT_FILE}) exit 0