355 lines
8.6 KiB
Bash
Executable file
355 lines
8.6 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
#
|
|
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
|
|
# Author: Erwan Velu <erwan@enovance.com>
|
|
#
|
|
# The license below covers all files distributed with fio unless otherwise
|
|
# noted in the file itself.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License version 2 as
|
|
# published by the Free Software Foundation.
|
|
#
|
|
# 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
|
|
|
|
BLK_SIZE=
|
|
BLOCK_SIZE=4k
|
|
SEQ=-1
|
|
TEMPLATE=/tmp/template.fio
|
|
OUTFILE=
|
|
DISKS=
|
|
PRINTABLE_DISKS=
|
|
RUNTIME=300
|
|
ETA=0
|
|
MODES="write,randwrite,read,randread"
|
|
SHORT_HOSTNAME=
|
|
CACHED_IO="FALSE"
|
|
PREFIX=""
|
|
PREFIX_FILENAME=""
|
|
IODEPTH=1
|
|
|
|
show_help() {
|
|
PROG=$(basename $0)
|
|
echo "usage of $PROG:"
|
|
cat << EOF
|
|
-h : Show this help & exit
|
|
-c : Enable cached-based IOs
|
|
Disabled by default
|
|
-a : Run sequential test then parallel one
|
|
Disabled by default
|
|
-s : Run sequential test (default value)
|
|
one test after another then one disk after another
|
|
Disabled by default
|
|
-p : Run parallel test
|
|
one test after anoter but all disks at the same time
|
|
Enabled by default
|
|
-D iodepth : Run with the specified iodepth
|
|
Default is $IODEPTH
|
|
-d disk1[,disk2,disk3,..] : Run the tests on the selected disks
|
|
Separated each disk with a comma
|
|
-z filesize : Specify the working file size, if you are passing filepaths to -d
|
|
Disabled by default
|
|
-r seconds : Time in seconds per benchmark
|
|
0 means till the end of the device
|
|
Default is $RUNTIME seconds
|
|
-b blocksize[,blocksize1, ...] : The blocksizes to test under fio format (4k, 1m, ...)
|
|
Separated each blocksize with a comma
|
|
Default is $BLOCK_SIZE
|
|
-m mode1,[mode2,mode3, ...] : Define the fio IO profile to use like read, write, randread, randwrite
|
|
Default is "$MODES"
|
|
-x prefix : Add a prefix to the fio filename
|
|
Useful to let a context associated with the file
|
|
If the prefix features a / (slash), prefix will be considered as a directory
|
|
-A cmd_to_run : System command to run after each job (exec_postrun in fio)
|
|
-B cmd_to_run : System command to run before each job (exec_prerun in fio)
|
|
|
|
Example:
|
|
|
|
$PROG -d /dev/sdb,/dev/sdc,/dev/sdd,/dev/sde -a -b 4k,128k,1m -r 100 -a -x dellr720-day2/
|
|
|
|
Will generate an fio file that will run
|
|
- a sequential bench on /dev/sdb /dev/sdc /dev/sdd /dev/sde for block size = 4k with write,randwrite,read,randread tests
|
|
ETA ~ 4 tests * 4 disks * 100 seconds
|
|
- a sequential bench on /dev/sdb /dev/sdc /dev/sdd /dev/sde for block size = 128k with write,randwrite,read,randread tests
|
|
ETA ~ 4 tests * 4 disks * 100 seconds
|
|
- a sequential bench on /dev/sdb /dev/sdc /dev/sdd /dev/sde for block size = 1m with write,randwrite,read,randread tests
|
|
ETA ~ 4 tests * 4 disks * 100 seconds
|
|
- a parallel bench on /dev/sdb /dev/sdc /dev/sdd /dev/sde for block size = 4k with write,randwrite,read,randread tests
|
|
ETA ~ 4 tests * 100 seconds
|
|
- a parallel bench on /dev/sdb /dev/sdc /dev/sdd /dev/sde for block size = 128k with write,randwrite,read,randread tests
|
|
ETA ~ 4 tests * 100 seconds
|
|
- a parallel bench on /dev/sdb /dev/sdc /dev/sdd /dev/sde for block size = 1m with write,randwrite,read,randread tests
|
|
ETA ~ 4 tests * 100 seconds
|
|
|
|
Generating dellr720-day2/localhost-4k,128k,1m-all-write,randwrite,read,randread-sdb,sdc,sdd,sde.fio
|
|
Estimated Time = 6000 seconds : 1 hour 40 minutes
|
|
EOF
|
|
}
|
|
|
|
finish_template() {
|
|
echo "iodepth=$IODEPTH" >> $TEMPLATE
|
|
|
|
if [ "$RUNTIME" != "0" ]; then
|
|
echo "runtime=$RUNTIME" >> $TEMPLATE
|
|
echo "time_based" >> $TEMPLATE
|
|
fi
|
|
|
|
if [ "$CACHED_IO" = "FALSE" ]; then
|
|
echo "direct=1" >> $TEMPLATE
|
|
fi
|
|
}
|
|
|
|
|
|
diskname_to_printable() {
|
|
COUNT=0
|
|
for disk in $(echo $@ | tr "," " "); do
|
|
R=$(basename $disk | sed 's|/|_|g')
|
|
COUNT=$(($COUNT + 1))
|
|
if [ $COUNT -eq 1 ]; then
|
|
P="$R"
|
|
else
|
|
P="$P,$R"
|
|
fi
|
|
done
|
|
echo $P
|
|
}
|
|
|
|
gen_template() {
|
|
cat >$TEMPLATE << EOF
|
|
[global]
|
|
ioengine=libaio
|
|
invalidate=1
|
|
ramp_time=5
|
|
EOF
|
|
}
|
|
|
|
gen_seq_suite() {
|
|
TYPE=$1
|
|
disk=$2
|
|
PRINTABLE_DISK=$(diskname_to_printable $disk)
|
|
cat >> $OUTFILE << EOF
|
|
[$TYPE-$PRINTABLE_DISK-$BLK_SIZE-seq]
|
|
stonewall
|
|
bs=$BLK_SIZE
|
|
filename=$disk
|
|
rw=$TYPE
|
|
write_bw_log=${PREFIX_FILENAME}$SHORT_HOSTNAME-$BLK_SIZE-$PRINTABLE_DISK-$TYPE-seq.results
|
|
write_iops_log=${PREFIX_FILENAME}$SHORT_HOSTNAME-$BLK_SIZE-$PRINTABLE_DISK-$TYPE-seq.results
|
|
EOF
|
|
ETA=$(($ETA + $RUNTIME))
|
|
}
|
|
|
|
gen_seq_fio() {
|
|
for disk in $(echo $DISKS | tr "," " "); do
|
|
for mode in $(echo $MODES | tr "," " "); do
|
|
gen_seq_suite "$mode" "$disk"
|
|
done
|
|
done
|
|
}
|
|
|
|
|
|
gen_para_suite() {
|
|
TYPE=$1
|
|
NEED_WALL=$2
|
|
D=0
|
|
for disk in $(echo $DISKS | tr "," " "); do
|
|
PRINTABLE_DISK=$(diskname_to_printable $disk)
|
|
cat >> $OUTFILE << EOF
|
|
[$TYPE-$PRINTABLE_DISK-$BLK_SIZE-para]
|
|
bs=$BLK_SIZE
|
|
EOF
|
|
|
|
if [ "$D" = 0 ]; then
|
|
echo "stonewall" >> $OUTFILE
|
|
D=1
|
|
fi
|
|
|
|
cat >> $OUTFILE << EOF
|
|
filename=$disk
|
|
rw=$TYPE
|
|
write_bw_log=${PREFIX_FILENAME}$SHORT_HOSTNAME-$BLK_SIZE-$PRINTABLE_DISK-$TYPE-para.results
|
|
write_iops_log=${PREFIX_FILENAME}$SHORT_HOSTNAME-$BLK_SIZE-$PRINTABLE_DISK-$TYPE-para.results
|
|
EOF
|
|
done
|
|
|
|
ETA=$(($ETA + $RUNTIME))
|
|
echo >> $OUTFILE
|
|
}
|
|
|
|
gen_para_fio() {
|
|
for mode in $(echo $MODES | tr "," " "); do
|
|
gen_para_suite "$mode"
|
|
done
|
|
}
|
|
|
|
gen_fio() {
|
|
case $SEQ in
|
|
2)
|
|
gen_seq_fio
|
|
gen_para_fio
|
|
;;
|
|
1)
|
|
gen_seq_fio
|
|
;;
|
|
0)
|
|
gen_para_fio
|
|
;;
|
|
esac
|
|
}
|
|
|
|
parse_cmdline() {
|
|
while getopts "hacpsd:b:r:m:x:z:D:A:B:" opt; do
|
|
case $opt in
|
|
h)
|
|
show_help
|
|
exit 0
|
|
;;
|
|
b)
|
|
BLOCK_SIZE=$OPTARG
|
|
;;
|
|
c)
|
|
CACHED_IO="TRUE"
|
|
;;
|
|
s)
|
|
if [ "$SEQ" = "-1" ]; then
|
|
SEQ=1
|
|
fi
|
|
;;
|
|
x)
|
|
PREFIX=$OPTARG
|
|
echo "$PREFIX" | grep -q "/"
|
|
if [ "$?" -eq 0 ]; then
|
|
mkdir -p $PREFIX
|
|
# No need to keep the prefix for the log files
|
|
# we do have a directory for that
|
|
PREFIX_FILENAME=""
|
|
else
|
|
# We need to keep the prefix for the log files
|
|
PREFIX_FILENAME=$PREFIX
|
|
fi
|
|
;;
|
|
r)
|
|
RUNTIME=$OPTARG
|
|
;;
|
|
p)
|
|
if [ "$SEQ" = "-1" ]; then
|
|
SEQ=0
|
|
fi
|
|
;;
|
|
m)
|
|
MODES=$OPTARG;
|
|
;;
|
|
d)
|
|
DISKS=$OPTARG
|
|
PRINTABLE_DISKS=$(diskname_to_printable "$DISKS")
|
|
;;
|
|
D)
|
|
IODEPTH=$OPTARG
|
|
;;
|
|
a)
|
|
SEQ=2
|
|
;;
|
|
B)
|
|
echo "exec_prerun=$OPTARG" >> $TEMPLATE
|
|
;;
|
|
A)
|
|
echo "exec_postrun=$OPTARG" >> $TEMPLATE
|
|
;;
|
|
z)
|
|
FSIZE=$OPTARG
|
|
echo "size=$FSIZE" >> $TEMPLATE
|
|
;;
|
|
\?)
|
|
echo "Invalid option: -$OPTARG" >&2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ "$SEQ" = "-1" ]; then
|
|
SEQ=0
|
|
fi
|
|
|
|
SHORT_HOSTNAME=$(hostname -s)
|
|
case $SEQ in
|
|
2)
|
|
OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-all-$MODES-$PRINTABLE_DISKS.fio
|
|
;;
|
|
|
|
1)
|
|
OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-sequential-$MODES-$PRINTABLE_DISKS.fio
|
|
;;
|
|
0)
|
|
OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-parallel-$MODES-$PRINTABLE_DISKS.fio
|
|
;;
|
|
esac
|
|
|
|
if [ -z "$DISKS" ]; then
|
|
echo "Missing DISKS !"
|
|
echo "Please read the help !"
|
|
show_help
|
|
exit 1
|
|
fi
|
|
|
|
}
|
|
|
|
check_mode_order() {
|
|
FOUND_WRITE="NO"
|
|
CAUSE="You are reading data before writing them "
|
|
|
|
# If no write occurs, let's show a different message
|
|
echo $MODES | grep -q "write"
|
|
if [ "$?" -ne 0 ]; then
|
|
CAUSE="You are reading data while never wrote them before"
|
|
fi
|
|
|
|
for mode in $(echo $MODES | tr "," " "); do
|
|
echo $mode | grep -q write
|
|
if [ "$?" -eq 0 ]; then
|
|
FOUND_WRITE="YES"
|
|
fi
|
|
echo $mode | grep -q "read"
|
|
if [ "$?" -eq 0 ]; then
|
|
if [ "$FOUND_WRITE" = "NO" ]; then
|
|
echo "###############################################################"
|
|
echo "# Warning : $CAUSE#"
|
|
echo "# On some storage devices, this could lead to invalid results #"
|
|
echo "# #"
|
|
echo "# Press Ctrl-C to adjust pattern order if you have doubts #"
|
|
echo "# Or Wait 5 seconds before the file will be created #"
|
|
echo "###############################################################"
|
|
sleep 5
|
|
# No need to try showing the message more than one time
|
|
return
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
|
|
########## MAIN
|
|
gen_template
|
|
parse_cmdline "$@"
|
|
finish_template
|
|
check_mode_order
|
|
|
|
echo "Generating $OUTFILE"
|
|
cp -f $TEMPLATE $OUTFILE
|
|
echo >> $OUTFILE
|
|
|
|
for BLK_SIZE in $(echo $BLOCK_SIZE | tr "," " "); do
|
|
gen_fio
|
|
done
|
|
ETA_H=$(($ETA / 3600))
|
|
ETA_M=$((($ETA - ($ETA_H*3600)) / 60))
|
|
if [ "$ETA" = "0" ]; then
|
|
echo "Cannot estimate ETA as RUNTIME=0"
|
|
else
|
|
echo "Estimated Time = $ETA seconds : $ETA_H hour $ETA_M minutes"
|
|
fi
|