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