Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/env bash
      2 #
      3 #  Copyright (C) 2013 eNovance SAS <licensing (at] enovance.com>
      4 #  Author: Erwan Velu  <erwan (at] enovance.com>
      5 #
      6 #  The license below covers all files distributed with fio unless otherwise
      7 #  noted in the file itself.
      8 #
      9 #  This program is free software; you can redistribute it and/or modify
     10 #  it under the terms of the GNU General Public License version 2 as
     11 #  published by the Free Software Foundation.
     12 #
     13 #  This program is distributed in the hope that it will be useful,
     14 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
     15 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16 #  GNU General Public License for more details.
     17 #
     18 #  You should have received a copy of the GNU General Public License
     19 #  along with this program; if not, write to the Free Software
     20 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     21 
     22 BLK_SIZE=
     23 BLOCK_SIZE=4k
     24 SEQ=-1
     25 TEMPLATE=/tmp/template.fio
     26 OUTFILE=
     27 DISKS=
     28 PRINTABLE_DISKS=
     29 RUNTIME=300
     30 ETA=0
     31 MODES="write,randwrite,read,randread"
     32 SHORT_HOSTNAME=
     33 CACHED_IO="FALSE"
     34 PREFIX=""
     35 PREFIX_FILENAME=""
     36 IODEPTH=1
     37 
     38 show_help() {
     39 	PROG=$(basename $0)
     40 	echo "usage of $PROG:"
     41 	cat << EOF
     42 -h				: Show this help & exit
     43 -c				: Enable cached-based IOs
     44 					Disabled by default
     45 -a				: Run sequential test then parallel one
     46 					Disabled by default
     47 -s				: Run sequential test (default value)
     48 					one test after another then one disk after another
     49 					Disabled by default
     50 -p				: Run parallel test
     51 					one test after anoter but all disks at the same time
     52 					Enabled by default
     53 -D iodepth			: Run with the specified iodepth
     54 					Default is $IODEPTH
     55 -d disk1[,disk2,disk3,..]	: Run the tests on the selected disks
     56 					Separated each disk with a comma
     57 -z filesize                     : Specify the working file size, if you are passing filepaths to -d
     58                                         Disabled by default
     59 -r seconds			: Time in seconds per benchmark
     60 					0 means till the end of the device
     61 					Default is $RUNTIME seconds
     62 -b blocksize[,blocksize1, ...]  : The blocksizes to test under fio format (4k, 1m, ...)
     63 					Separated each blocksize with a comma
     64 					Default is $BLOCK_SIZE
     65 -m mode1,[mode2,mode3, ...]     : Define the fio IO profile to use like read, write, randread, randwrite
     66 					Default is "$MODES"
     67 -x prefix			: Add a prefix to the fio filename
     68 					Useful to let a context associated with the file
     69 					If the prefix features a / (slash), prefix will be considered as a directory
     70 -A cmd_to_run			: System command to run after each job (exec_postrun in fio)
     71 -B cmd_to_run			: System command to run before each job (exec_prerun in fio)
     72 
     73 Example:
     74 
     75 $PROG -d /dev/sdb,/dev/sdc,/dev/sdd,/dev/sde -a -b 4k,128k,1m -r 100 -a -x dellr720-day2/
     76 
     77 	Will generate an fio file that will run
     78 		- a sequential bench on /dev/sdb /dev/sdc /dev/sdd /dev/sde for block size = 4k with write,randwrite,read,randread tests
     79 			ETA ~ 4 tests * 4 disks * 100 seconds
     80 		- a sequential bench on /dev/sdb /dev/sdc /dev/sdd /dev/sde for block size = 128k with write,randwrite,read,randread tests
     81 			ETA ~ 4 tests * 4 disks * 100 seconds
     82 		- a sequential bench on /dev/sdb /dev/sdc /dev/sdd /dev/sde for block size = 1m with write,randwrite,read,randread tests
     83 			ETA ~ 4 tests * 4 disks * 100 seconds
     84 		- a parallel bench on /dev/sdb /dev/sdc /dev/sdd /dev/sde for block size = 4k with write,randwrite,read,randread tests
     85 			ETA ~ 4 tests * 100 seconds
     86 		- a parallel bench on /dev/sdb /dev/sdc /dev/sdd /dev/sde for block size = 128k with write,randwrite,read,randread tests
     87 			ETA ~ 4 tests * 100 seconds
     88 		- a parallel bench on /dev/sdb /dev/sdc /dev/sdd /dev/sde for block size = 1m with write,randwrite,read,randread tests
     89 			ETA ~ 4 tests * 100 seconds
     90 
     91 Generating dellr720-day2/localhost-4k,128k,1m-all-write,randwrite,read,randread-sdb,sdc,sdd,sde.fio
     92 Estimated Time = 6000 seconds : 1 hour 40 minutes
     93 EOF
     94 }
     95 
     96 finish_template() {
     97 echo "iodepth=$IODEPTH" >> $TEMPLATE
     98 
     99 if [ "$RUNTIME" != "0" ]; then
    100 	echo "runtime=$RUNTIME" >> $TEMPLATE
    101 	echo "time_based" >> $TEMPLATE
    102 fi
    103 
    104 if [ "$CACHED_IO" = "FALSE" ]; then
    105 	echo "direct=1" >> $TEMPLATE
    106 fi
    107 }
    108 
    109 
    110 diskname_to_printable() {
    111 COUNT=0
    112 for disk in $(echo $@ | tr "," " "); do
    113 	R=$(basename $disk | sed 's|/|_|g')
    114 	COUNT=$(($COUNT + 1))
    115 	if [ $COUNT -eq 1 ]; then
    116 		P="$R"
    117 	else
    118 		P="$P,$R"
    119 	fi
    120 done
    121 echo $P
    122 }
    123 
    124 gen_template() {
    125 cat >$TEMPLATE << EOF
    126 [global]
    127 ioengine=libaio
    128 invalidate=1
    129 ramp_time=5
    130 EOF
    131 }
    132 
    133 gen_seq_suite() {
    134 TYPE=$1
    135 disk=$2
    136 PRINTABLE_DISK=$(diskname_to_printable $disk)
    137 cat >> $OUTFILE << EOF
    138 [$TYPE-$PRINTABLE_DISK-$BLK_SIZE-seq]
    139 stonewall
    140 bs=$BLK_SIZE
    141 filename=$disk
    142 rw=$TYPE
    143 write_bw_log=${PREFIX_FILENAME}$SHORT_HOSTNAME-$BLK_SIZE-$PRINTABLE_DISK-$TYPE-seq.results
    144 write_iops_log=${PREFIX_FILENAME}$SHORT_HOSTNAME-$BLK_SIZE-$PRINTABLE_DISK-$TYPE-seq.results
    145 EOF
    146 ETA=$(($ETA + $RUNTIME))
    147 }
    148 
    149 gen_seq_fio() {
    150 for disk in $(echo $DISKS | tr "," " "); do
    151 	for mode in $(echo $MODES | tr "," " "); do
    152 		gen_seq_suite "$mode" "$disk"
    153 	done
    154 done
    155 }
    156 
    157 
    158 gen_para_suite() {
    159 TYPE=$1
    160 NEED_WALL=$2
    161 D=0
    162 for disk in $(echo $DISKS | tr "," " "); do
    163     PRINTABLE_DISK=$(diskname_to_printable $disk)
    164     cat >> $OUTFILE << EOF
    165 [$TYPE-$PRINTABLE_DISK-$BLK_SIZE-para]
    166 bs=$BLK_SIZE
    167 EOF
    168 
    169 if [ "$D" = 0 ]; then
    170     echo "stonewall" >> $OUTFILE
    171     D=1
    172 fi
    173 
    174 cat >> $OUTFILE << EOF
    175 filename=$disk
    176 rw=$TYPE
    177 write_bw_log=${PREFIX_FILENAME}$SHORT_HOSTNAME-$BLK_SIZE-$PRINTABLE_DISK-$TYPE-para.results
    178 write_iops_log=${PREFIX_FILENAME}$SHORT_HOSTNAME-$BLK_SIZE-$PRINTABLE_DISK-$TYPE-para.results
    179 EOF
    180 done
    181 
    182 ETA=$(($ETA + $RUNTIME))
    183 echo >> $OUTFILE
    184 }
    185 
    186 gen_para_fio() {
    187 for mode in $(echo $MODES | tr "," " "); do
    188 	gen_para_suite "$mode"
    189 done
    190 }
    191 
    192 gen_fio() {
    193 case $SEQ in
    194 	2)
    195 		gen_seq_fio
    196 		gen_para_fio
    197 	;;
    198 	1)
    199 		gen_seq_fio
    200 	;;
    201 	0)
    202 		gen_para_fio
    203 	;;
    204 esac
    205 }
    206 
    207 parse_cmdline() {
    208 while getopts "hacpsd:b:r:m:x:z:D:A:B:" opt; do
    209   case $opt in
    210     h)
    211 	show_help
    212 	exit 0
    213 	;;
    214     b)
    215 	BLOCK_SIZE=$OPTARG
    216 	;;
    217     c)
    218 	CACHED_IO="TRUE"
    219 	;;
    220     s)
    221 	if [ "$SEQ" = "-1" ]; then
    222 		SEQ=1
    223 	fi
    224       ;;
    225     x)
    226 	PREFIX=$OPTARG
    227 	echo "$PREFIX" | grep -q "/"
    228 	if [ "$?" -eq 0 ]; then
    229 		mkdir -p $PREFIX
    230 		# No need to keep the prefix for the log files
    231 		# we do have a directory for that
    232 		PREFIX_FILENAME=""
    233 	else
    234 		# We need to keep the prefix for the log files
    235 		PREFIX_FILENAME=$PREFIX
    236 	fi
    237 	;;
    238     r)
    239 	RUNTIME=$OPTARG
    240       ;;
    241     p)
    242 	if [ "$SEQ" = "-1" ]; then
    243 		SEQ=0
    244 	fi
    245       ;;
    246     m)
    247         MODES=$OPTARG;
    248       ;;
    249     d)
    250  	DISKS=$OPTARG
    251 	PRINTABLE_DISKS=$(diskname_to_printable "$DISKS")
    252       ;;
    253     D)
    254 	IODEPTH=$OPTARG
    255       ;;
    256     a)
    257 	SEQ=2
    258       ;;
    259     B)
    260 	echo "exec_prerun=$OPTARG" >> $TEMPLATE
    261       ;;
    262     A)
    263 	echo "exec_postrun=$OPTARG" >> $TEMPLATE
    264       ;;
    265     z)
    266 	FSIZE=$OPTARG
    267 	echo "size=$FSIZE" >> $TEMPLATE
    268       ;;
    269     \?)
    270       echo "Invalid option: -$OPTARG" >&2
    271       ;;
    272   esac
    273 done
    274 
    275 if [ "$SEQ" = "-1" ]; then
    276 	SEQ=0
    277 fi
    278 
    279 SHORT_HOSTNAME=$(hostname -s)
    280 case $SEQ in
    281 	2)
    282 		OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-all-$MODES-$PRINTABLE_DISKS.fio
    283 	;;
    284 
    285 	1)
    286 		OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-sequential-$MODES-$PRINTABLE_DISKS.fio
    287 	;;
    288 	0)
    289 		OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-parallel-$MODES-$PRINTABLE_DISKS.fio
    290 	;;
    291 esac
    292 
    293 if [ -z "$DISKS" ]; then
    294 	echo "Missing DISKS !"
    295 	echo "Please read the help !"
    296 	show_help
    297 	exit 1
    298 fi
    299 
    300 }
    301 
    302 check_mode_order() {
    303 FOUND_WRITE="NO"
    304 CAUSE="You are reading data before writing them          "
    305 
    306 # If no write occurs, let's show a different message
    307 echo $MODES | grep -q "write"
    308 if [ "$?" -ne 0 ]; then
    309 	CAUSE="You are reading data while never wrote them before"
    310 fi
    311 
    312 for mode in $(echo $MODES | tr "," " "); do
    313 	echo $mode | grep -q write
    314 	if [ "$?" -eq 0 ]; then
    315 		FOUND_WRITE="YES"
    316 	fi
    317 	echo $mode | grep -q "read"
    318 	if [ "$?" -eq 0 ]; then
    319 		if [ "$FOUND_WRITE" = "NO" ]; then
    320 			echo "###############################################################"
    321 			echo "# Warning : $CAUSE#"
    322 			echo "# On some storage devices, this could lead to invalid results #"
    323 			echo "#                                                             #"
    324 			echo "# Press Ctrl-C to adjust pattern order if you have doubts     #"
    325 			echo "# Or Wait 5 seconds before the file will be created           #"
    326 			echo "###############################################################"
    327 			sleep 5
    328 			# No need to try showing the message more than one time
    329 			return
    330 		fi
    331 	fi
    332 done
    333 }
    334 
    335 
    336 ########## MAIN
    337 gen_template
    338 parse_cmdline "$@"
    339 finish_template
    340 check_mode_order
    341 
    342 echo "Generating $OUTFILE"
    343 cp -f $TEMPLATE $OUTFILE
    344 echo >> $OUTFILE
    345 
    346 for BLK_SIZE in $(echo $BLOCK_SIZE | tr "," " "); do
    347 	gen_fio
    348 done
    349 ETA_H=$(($ETA / 3600))
    350 ETA_M=$((($ETA - ($ETA_H*3600)) / 60))
    351 if [ "$ETA" = "0" ]; then
    352 	echo "Cannot estimate ETA as RUNTIME=0"
    353 else
    354 	echo "Estimated Time = $ETA seconds : $ETA_H hour $ETA_M minutes"
    355 fi
    356