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