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