-#!/bin/bash
+#!/usr/bin/env bash
#
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
# Author: Erwan Velu <erwan@enovance.com>
TEMPLATE=/tmp/template.fio
OUTFILE=
DISKS=
+PRINTABLE_DISKS=
RUNTIME=300
ETA=0
-MODES="read,write,randread,randwrite"
+MODES="write,randwrite,read,randread"
SHORT_HOSTNAME=
CACHED_IO="FALSE"
PREFIX=""
PREFIX_FILENAME=""
+IODEPTH=1
show_help() {
PROG=$(basename $0)
-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
- Disk name shall be "sdxx", /dev/ shall NOT be used here
+-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 300 seconds
+ Default is $RUNTIME seconds
-b blocksize[,blocksize1, ...] : The blocksizes to test under fio format (4k, 1m, ...)
Separated each blocksize with a comma
- Default is 4k
+ Default is $BLOCK_SIZE
-m mode1,[mode2,mode3, ...] : Define the fio IO profile to use like read, write, randread, randwrite
- Default is "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 sdb,sdc,sdd,sde -a -b 4k,128k,1m -r 100 -a -x dellr720-day2/
+$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 read,write,randread,randwrite tests
+ - 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 read,write,randread,randwrite tests
+ - 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 read,write,randread,randwrite tests
+ - 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 read,write,randread,randwrite tests
+ - 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 read,write,randread,randwrite tests
+ - 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 read,write,randread,randwrite tests
+ - 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-read,write,randread,randwrite-sdb,sdc,sdd,sde.fio
+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
}
-gen_template() {
-cat >$TEMPLATE << EOF
-[global]
-ioengine=libaio
-invalidate=1
-ramp_time=5
-EOF
+finish_template() {
+echo "iodepth=$IODEPTH" >> $TEMPLATE
if [ "$RUNTIME" != "0" ]; then
-cat >>$TEMPLATE << EOF
-runtime=$RUNTIME
-EOF
+ echo "runtime=$RUNTIME" >> $TEMPLATE
+ echo "time_based" >> $TEMPLATE
fi
if [ "$CACHED_IO" = "FALSE" ]; then
-cat >>$TEMPLATE << EOF
-direct=1
-EOF
+ 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-$disk-$BLK_SIZE-seq]
+[$TYPE-$PRINTABLE_DISK-$BLK_SIZE-seq]
stonewall
bs=$BLK_SIZE
-filename=/dev/$disk
+filename=$disk
rw=$TYPE
-write_bw_log=${PREFIX_FILENAME}$SHORT_HOSTNAME-$BLK_SIZE-$disk-$TYPE-seq.results
-write_iops_log=${PREFIX_FILENAME}$SHORT_HOSTNAME-$BLK_SIZE-$disk-$TYPE-seq.results
+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"
+ gen_seq_suite "$mode" "$disk"
done
done
}
NEED_WALL=$2
D=0
for disk in $(echo $DISKS | tr "," " "); do
+ PRINTABLE_DISK=$(diskname_to_printable $disk)
cat >> $OUTFILE << EOF
-[$TYPE-$disk-$BLK_SIZE-para]
+[$TYPE-$PRINTABLE_DISK-$BLK_SIZE-para]
bs=$BLK_SIZE
EOF
fi
cat >> $OUTFILE << EOF
-filename=/dev/$disk
+filename=$disk
rw=$TYPE
-write_bw_log=${PREFIX_FILENAME}$SHORT_HOSTNAME-$BLK_SIZE-$disk-$TYPE-para.results
-write_iops_log=${PREFIX_FILENAME}$SHORT_HOSTNAME-$BLK_SIZE-$disk-$TYPE-para.results
+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
}
parse_cmdline() {
-while getopts "hacpsd:b:r:m:x:" opt; do
+while getopts "hacpsd:b:r:m:x:z:D:A:B:" opt; do
case $opt in
h)
show_help
;;
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
;;
SHORT_HOSTNAME=$(hostname -s)
case $SEQ in
2)
- OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-all-$MODES-$DISKS.fio
+ OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-all-$MODES-$PRINTABLE_DISKS.fio
;;
1)
- OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-sequential-$MODES-$DISKS.fio
+ OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-sequential-$MODES-$PRINTABLE_DISKS.fio
;;
0)
- OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-parallel-$MODES-$DISKS.fio
+ OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-parallel-$MODES-$PRINTABLE_DISKS.fio
;;
esac
}
+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
-parse_cmdline $@
gen_template
+parse_cmdline "$@"
+finish_template
+check_mode_order
echo "Generating $OUTFILE"
cp -f $TEMPLATE $OUTFILE