mirror of
https://github.com/brendangregg/perf-tools.git
synced 2025-11-30 23:16:03 +07:00
This patch tries to fix following bitesize issues, 1. Error flooding messages when array index value is negative. 2. the smax in gawk was treated as string, that cause bug when perf return zero IO count. Signed-off-by: Yong Yang <yangoliver@gmail.com>
176 lines
4.9 KiB
Bash
Executable File
176 lines
4.9 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# bitesize - show disk I/O size as a histogram.
|
|
# Written using Linux perf_events (aka "perf").
|
|
#
|
|
# This can be used to characterize the distribution of block device I/O
|
|
# sizes. To study I/O in more detail, see iosnoop(8).
|
|
#
|
|
# USAGE: bitesize [-h] [-b buckets] [seconds]
|
|
# eg,
|
|
# ./bitesize 10
|
|
#
|
|
# Run "bitesize -h" for full usage.
|
|
#
|
|
# REQUIREMENTS: perf_events and block:block_rq_issue tracepoint, which you may
|
|
# already have on recent kernels.
|
|
#
|
|
# This uses multiple counting tracepoints with different filters, one for each
|
|
# histogram bucket. While this is summarized in-kernel, the use of multiple
|
|
# tracepoints does add addiitonal overhead, which is more evident if you add
|
|
# more buckets. In the future this functionality will be available in an
|
|
# efficient way in the kernel, and this tool can be rewritten.
|
|
#
|
|
# From perf-tools: https://github.com/brendangregg/perf-tools
|
|
#
|
|
# COPYRIGHT: Copyright (c) 2014 Brendan Gregg.
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software Foundation,
|
|
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
#
|
|
# (http://www.gnu.org/copyleft/gpl.html)
|
|
#
|
|
# 22-Jul-2014 Brendan Gregg Created this.
|
|
|
|
duration=0
|
|
buckets=(1 8 64 128)
|
|
secsz=512
|
|
trap ':' INT QUIT TERM PIPE HUP
|
|
|
|
function usage {
|
|
cat <<-END >&2
|
|
USAGE: bitesize [-h] [-b buckets] [seconds]
|
|
-b buckets # specify histogram buckets (Kbytes)
|
|
-h # this usage message
|
|
eg,
|
|
bitesize # trace I/O size until Ctrl-C
|
|
bitesize 10 # trace I/O size for 10 seconds
|
|
bitesize -b "8 16 32" # specify custom bucket points
|
|
END
|
|
exit
|
|
}
|
|
|
|
function die {
|
|
echo >&2 "$@"
|
|
exit 1
|
|
}
|
|
|
|
### process options
|
|
while getopts b:h opt
|
|
do
|
|
case $opt in
|
|
b) buckets=($OPTARG) ;;
|
|
h|?) usage ;;
|
|
esac
|
|
done
|
|
shift $(( $OPTIND - 1 ))
|
|
tpoint=block:block_rq_issue
|
|
var=nr_sector
|
|
duration=$1
|
|
|
|
### convert buckets (Kbytes) to disk sectors
|
|
i=0
|
|
sectors=(${buckets[*]})
|
|
((max_i = ${#buckets[*]} - 1))
|
|
while (( i <= max_i )); do
|
|
(( sectors[$i] = ${sectors[$i]} * 1024 / $secsz ))
|
|
# avoid negative array index errors for old version bash
|
|
if (( i > 0 ));then
|
|
if (( ${sectors[$i]} <= ${sectors[$i - 1]} )); then
|
|
die "ERROR: bucket list must increase in size."
|
|
fi
|
|
fi
|
|
(( i++ ))
|
|
done
|
|
|
|
### build list of tracepoints and filters for each histogram bucket
|
|
max_b=${buckets[$max_i]}
|
|
max_s=${sectors[$max_i]}
|
|
tpoints="-e $tpoint --filter \"$var < ${sectors[0]}\""
|
|
awkarray=
|
|
i=0
|
|
while (( i < max_i )); do
|
|
tpoints="$tpoints -e $tpoint --filter \"$var >= ${sectors[$i]} && "
|
|
tpoints="$tpoints $var < ${sectors[$i + 1]}\""
|
|
awkarray="$awkarray buckets[$i]=${buckets[$i]};"
|
|
(( i++ ))
|
|
done
|
|
awkarray="$awkarray buckets[$max_i]=${buckets[$max_i]};"
|
|
tpoints="$tpoints -e $tpoint --filter \"$var >= ${sectors[$max_i]}\""
|
|
|
|
### prepare to run
|
|
if (( duration )); then
|
|
etext="for $duration seconds"
|
|
cmd="sleep $duration"
|
|
else
|
|
etext="until Ctrl-C"
|
|
cmd="sleep 999999"
|
|
fi
|
|
echo "Tracing block I/O size (bytes), $etext..."
|
|
|
|
### run perf
|
|
out="-o /dev/stdout" # a workaround needed in linux 3.2; not by 3.4.15
|
|
stat=$(eval perf stat $tpoints -a $out $cmd 2>&1)
|
|
if (( $? != 0 )); then
|
|
echo >&2 "ERROR running perf:"
|
|
echo >&2 "$stat"
|
|
exit
|
|
fi
|
|
|
|
### find max value for ASCII histogram
|
|
most=$(echo "$stat" | awk -v tpoint=$tpoint '
|
|
$2 == tpoint { gsub(/,/, ""); if ($1 > m) { m = $1 } }
|
|
END { print m }'
|
|
)
|
|
|
|
### process output
|
|
echo
|
|
echo "$stat" | awk -v tpoint=$tpoint -v max_i=$max_i -v most=$most '
|
|
function star(sval, smax, swidth) {
|
|
stars = ""
|
|
# using int could avoid error on gawk
|
|
if (int(smax) == 0) return ""
|
|
for (si = 0; si < (swidth * sval / smax); si++) {
|
|
stars = stars "#"
|
|
}
|
|
return stars
|
|
}
|
|
BEGIN {
|
|
'"$awkarray"'
|
|
printf(" %-15s: %-8s %s\n", "Kbytes", "I/O",
|
|
"Distribution")
|
|
}
|
|
/Performance counter stats/ { i = -1 }
|
|
# reverse order of rule set is important
|
|
{ ok = 0 }
|
|
$2 == tpoint { num = $1; gsub(/,/, "", num); ok = 1 }
|
|
ok && i >= max_i {
|
|
printf(" %10.1f -> %-10s: %-8s |%-38s|\n",
|
|
buckets[i], "", num, star(num, most, 38))
|
|
next
|
|
}
|
|
ok && i >= 0 && i < max_i {
|
|
printf(" %10.1f -> %-10.1f: %-8s |%-38s|\n",
|
|
buckets[i], buckets[i+1] - 0.1, num,
|
|
star(num, most, 38))
|
|
i++
|
|
next
|
|
}
|
|
ok && i == -1 {
|
|
printf(" %10s -> %-10.1f: %-8s |%-38s|\n", "",
|
|
buckets[0] - 0.1, num, star(num, most, 38))
|
|
i++
|
|
}
|
|
'
|