bbf88337ebbedba7657f09b45e42d66bff70a83c
[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 $IODEPTH
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 $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
71 Example:
72
73 $PROG -d sdb,sdc,sdd,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
89 Generating dellr720-day2/localhost-4k,128k,1m-all-write,randwrite,read,randread-sdb,sdc,sdd,sde.fio
90 Estimated Time = 6000 seconds : 1 hour 40 minutes
91 EOF
92 }
93
94 finish_template() {
95 echo "iodepth=$IODEPTH" >> $TEMPLATE
96
97 if [ "$RUNTIME" != "0" ]; then
98         echo "runtime=$RUNTIME" >> $TEMPLATE
99         echo "time_based" >> $TEMPLATE
100 fi
101
102 if [ "$CACHED_IO" = "FALSE" ]; then
103         echo "direct=1" >> $TEMPLATE
104 fi
105 }
106
107 gen_template() {
108 cat >$TEMPLATE << EOF
109 [global]
110 ioengine=libaio
111 invalidate=1
112 ramp_time=5
113 EOF
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:A:B:" 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     B)
239         echo "exec_prerun=$OPTARG" >> $TEMPLATE
240       ;;
241     A)
242         echo "exec_postrun=$OPTARG" >> $TEMPLATE
243       ;;
244     \?)
245       echo "Invalid option: -$OPTARG" >&2
246       ;;
247   esac
248 done
249
250 if [ "$SEQ" = "-1" ]; then
251         SEQ=0
252 fi
253
254 SHORT_HOSTNAME=$(hostname -s)
255 case $SEQ in
256         2)
257                 OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-all-$MODES-$DISKS.fio
258         ;;
259
260         1)
261                 OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-sequential-$MODES-$DISKS.fio
262         ;;
263         0)
264                 OUTFILE=${PREFIX}$SHORT_HOSTNAME-$BLOCK_SIZE-parallel-$MODES-$DISKS.fio
265         ;;
266 esac
267
268 if [ -z "$DISKS" ]; then
269         echo "Missing DISKS !"
270         echo "Please read the help !"
271         show_help
272         exit 1
273 fi
274
275 }
276
277 check_mode_order() {
278 FOUND_WRITE="NO"
279 CAUSE="You are reading data before writing them          "
280
281 # If no write occurs, let's show a different message
282 echo $MODES | grep -q "write"
283 if [ "$?" -ne 0 ]; then
284         CAUSE="You are reading data while never wrote them before"
285 fi
286
287 for mode in $(echo $MODES | tr "," " "); do
288         echo $mode | grep -q write
289         if [ "$?" -eq 0 ]; then
290                 FOUND_WRITE="YES"
291         fi
292         echo $mode | grep -q "read"
293         if [ "$?" -eq 0 ]; then
294                 if [ "$FOUND_WRITE" = "NO" ]; then
295                         echo "###############################################################"
296                         echo "# Warning : $CAUSE#"
297                         echo "# On some storage devices, this could lead to invalid results #"
298                         echo "#                                                             #"
299                         echo "# Press Ctrl-C to adjust pattern order if you have doubts     #"
300                         echo "# Or Wait 5 seconds before the file will be created           #"
301                         echo "###############################################################"
302                         sleep 5
303                         # No need to try showing the message more than one time
304                         return
305                 fi
306         fi
307 done
308 }
309
310
311 ########## MAIN
312 gen_template
313 parse_cmdline "$@"
314 finish_template
315 check_mode_order
316
317 echo "Generating $OUTFILE"
318 cp -f $TEMPLATE $OUTFILE
319 echo >> $OUTFILE
320
321 for BLK_SIZE in $(echo $BLOCK_SIZE | tr "," " "); do
322         gen_fio
323 done
324 ETA_H=$(($ETA / 3600))
325 ETA_M=$((($ETA - ($ETA_H*3600)) / 60))
326 if [ "$ETA" = "0" ]; then
327         echo "Cannot estimate ETA as RUNTIME=0"
328 else
329         echo "Estimated Time = $ETA seconds : $ETA_H hour $ETA_M minutes"
330 fi