3f9ab283840a54bef1c1ae2ef70bf2e1ccc7d759
[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 finish_template() {
93 cat >>$TEMPLATE <<EOF
94 iodepth=$IODEPTH
95 EOF
96
97 if [ "$RUNTIME" != "0" ]; then
98 cat >>$TEMPLATE << EOF
99 runtime=$RUNTIME
100 time_based
101 EOF
102 fi
103
104 if [ "$CACHED_IO" = "FALSE" ]; then
105 cat >>$TEMPLATE << EOF
106 direct=1
107 EOF
108 fi
109 }
110
111 gen_template() {
112 cat >$TEMPLATE << EOF
113 [global]
114 ioengine=libaio
115 invalidate=1
116 ramp_time=5
117 EOF
118 }
119
120 gen_seq_suite() {
121 TYPE=$1
122 cat >> $OUTFILE << EOF
123 [$TYPE-$disk-$BLK_SIZE-seq]
124 stonewall
125 bs=$BLK_SIZE
126 filename=/dev/$disk
127 rw=$TYPE
128 write_bw_log=${PREFIX_FILENAME}$SHORT_HOSTNAME-$BLK_SIZE-$disk-$TYPE-seq.results
129 write_iops_log=${PREFIX_FILENAME}$SHORT_HOSTNAME-$BLK_SIZE-$disk-$TYPE-seq.results
130 EOF
131 ETA=$(($ETA + $RUNTIME))
132 }
133
134 gen_seq_fio() {
135 for disk in $(echo $DISKS | tr "," " "); do
136         for mode in $(echo $MODES | tr "," " "); do
137                 gen_seq_suite "$mode"
138         done
139 done
140 }
141
142
143 gen_para_suite() {
144 TYPE=$1
145 NEED_WALL=$2
146 D=0
147 for disk in $(echo $DISKS | tr "," " "); do
148     cat >> $OUTFILE << EOF
149 [$TYPE-$disk-$BLK_SIZE-para]
150 bs=$BLK_SIZE
151 EOF
152
153 if [ "$D" = 0 ]; then
154     echo "stonewall" >> $OUTFILE
155     D=1
156 fi
157
158 cat >> $OUTFILE << EOF
159 filename=/dev/$disk
160 rw=$TYPE
161 write_bw_log=${PREFIX_FILENAME}$SHORT_HOSTNAME-$BLK_SIZE-$disk-$TYPE-para.results
162 write_iops_log=${PREFIX_FILENAME}$SHORT_HOSTNAME-$BLK_SIZE-$disk-$TYPE-para.results
163 EOF
164 done
165
166 ETA=$(($ETA + $RUNTIME))
167 echo >> $OUTFILE
168 }
169
170 gen_para_fio() {
171 for mode in $(echo $MODES | tr "," " "); do
172         gen_para_suite "$mode"
173 done
174 }
175
176 gen_fio() {
177 case $SEQ in
178         2)
179                 gen_seq_fio
180                 gen_para_fio
181         ;;
182         1)
183                 gen_seq_fio
184         ;;
185         0)
186                 gen_para_fio
187         ;;
188 esac
189 }
190
191 parse_cmdline() {
192 while getopts "hacpsd:b:r:m:x:D:" opt; do
193   case $opt in
194     h)
195         show_help
196         exit 0
197         ;;
198     b)
199         BLOCK_SIZE=$OPTARG
200         ;;
201     c)
202         CACHED_IO="TRUE"
203         ;;
204     s)
205         if [ "$SEQ" = "-1" ]; then
206                 SEQ=1
207         fi
208       ;;
209     x)
210         PREFIX=$OPTARG
211         echo "$PREFIX" | grep -q "/"
212         if [ "$?" -eq 0 ]; then
213                 mkdir -p $PREFIX
214                 # No need to keep the prefix for the log files
215                 # we do have a directory for that
216                 PREFIX_FILENAME=""
217         else
218                 # We need to keep the prefix for the log files
219                 PREFIX_FILENAME=$PREFIX
220         fi
221         ;;
222     r)
223         RUNTIME=$OPTARG
224       ;;
225     p)
226         if [ "$SEQ" = "-1" ]; then
227                 SEQ=0
228         fi
229       ;;
230     m)
231         MODES=$OPTARG;
232       ;;
233     d)
234         DISKS=$OPTARG
235       ;;
236     D)
237         IODEPTH=$OPTARG
238       ;;
239     a)
240         SEQ=2
241       ;;
242     \?)
243       echo "Invalid option: -$OPTARG" >&2
244       ;;
245   esac
246 done
247
248 if [ "$SEQ" = "-1" ]; then
249         SEQ=0
250 fi
251
252 SHORT_HOSTNAME=$(hostname -s)
253 case $SEQ in
254         2)
255                 OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-all-$MODES-$DISKS.fio
256         ;;
257
258         1)
259                 OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-sequential-$MODES-$DISKS.fio
260         ;;
261         0)
262                 OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-parallel-$MODES-$DISKS.fio
263         ;;
264 esac
265
266 if [ -z "$DISKS" ]; then
267         echo "Missing DISKS !"
268         echo "Please read the help !"
269         show_help
270         exit 1
271 fi
272
273 }
274
275 check_mode_order() {
276 FOUND_WRITE="NO"
277 CAUSE="You are reading data before writing them          "
278
279 # If no write occurs, let's show a different message
280 echo $MODES | grep -q "write"
281 if [ "$?" -ne 0 ]; then
282         CAUSE="You are reading data while never wrote them before"
283 fi
284
285 for mode in $(echo $MODES | tr "," " "); do
286         echo $mode | grep -q write
287         if [ "$?" -eq 0 ]; then
288                 FOUND_WRITE="YES"
289         fi
290         echo $mode | grep -q "read"
291         if [ "$?" -eq 0 ]; then
292                 if [ "$FOUND_WRITE" = "NO" ]; then
293                         echo "###############################################################"
294                         echo "# Warning : $CAUSE#"
295                         echo "# On some storage devices, this could lead to invalid results #"
296                         echo "#                                                             #"
297                         echo "# Press Ctrl-C to adjust pattern order if you have doubts     #"
298                         echo "# Or Wait 5 seconds before the file will be created           #"
299                         echo "###############################################################"
300                         sleep 5
301                         # No need to try showing the message more than one time
302                         return
303                 fi
304         fi
305 done
306 }
307
308
309 ########## MAIN
310 gen_template
311 parse_cmdline $@
312 finish_template
313 check_mode_order
314
315 echo "Generating $OUTFILE"
316 cp -f $TEMPLATE $OUTFILE
317 echo >> $OUTFILE
318
319 for BLK_SIZE in $(echo $BLOCK_SIZE | tr "," " "); do
320         gen_fio
321 done
322 ETA_H=$(($ETA / 3600))
323 ETA_M=$((($ETA - ($ETA_H*3600)) / 60))
324 if [ "$ETA" = "0" ]; then
325         echo "Cannot estimate ETA as RUNTIME=0"
326 else
327         echo "Estimated Time = $ETA seconds : $ETA_H hour $ETA_M minutes"
328 fi