blktrace support: support for looking up a device
[fio.git] / options.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <ctype.h>
5 #include <string.h>
6 #include <getopt.h>
7 #include <assert.h>
8
9 #include "fio.h"
10 #include "parse.h"
11
12 #define td_var_offset(var)      ((size_t) &((struct thread_options *)0)->var)
13
14 /*
15  * Check if mmap/mmaphuge has a :/foo/bar/file at the end. If so, return that.
16  */
17 static char *get_opt_postfix(const char *str)
18 {
19         char *p = strstr(str, ":");
20
21         if (!p)
22                 return NULL;
23
24         p++;
25         strip_blank_front(&p);
26         strip_blank_end(p);
27         return strdup(p);
28 }
29
30 static int str_rw_cb(void *data, const char *str)
31 {
32         struct thread_data *td = data;
33         char *nr = get_opt_postfix(str);
34
35         td->o.ddir_nr = 1;
36         if (nr)
37                 td->o.ddir_nr = atoi(nr);
38
39         return 0;
40 }
41
42 static int str_mem_cb(void *data, const char *mem)
43 {
44         struct thread_data *td = data;
45
46         if (td->o.mem_type == MEM_MMAPHUGE || td->o.mem_type == MEM_MMAP) {
47                 td->mmapfile = get_opt_postfix(mem);
48                 if (td->o.mem_type == MEM_MMAPHUGE && !td->mmapfile) {
49                         log_err("fio: mmaphuge:/path/to/file\n");
50                         return 1;
51                 }
52         }
53
54         return 0;
55 }
56
57 static int str_lockmem_cb(void fio_unused *data, unsigned long *val)
58 {
59         mlock_size = *val;
60         return 0;
61 }
62
63 #ifdef FIO_HAVE_IOPRIO
64 static int str_prioclass_cb(void *data, unsigned int *val)
65 {
66         struct thread_data *td = data;
67         unsigned short mask;
68
69         /*
70          * mask off old class bits, str_prio_cb() may have set a default class
71          */
72         mask = (1 << IOPRIO_CLASS_SHIFT) - 1;
73         td->ioprio &= mask;
74
75         td->ioprio |= *val << IOPRIO_CLASS_SHIFT;
76         return 0;
77 }
78
79 static int str_prio_cb(void *data, unsigned int *val)
80 {
81         struct thread_data *td = data;
82
83         td->ioprio |= *val;
84
85         /*
86          * If no class is set, assume BE
87          */
88         if ((td->ioprio >> IOPRIO_CLASS_SHIFT) == 0)
89                 td->ioprio |= IOPRIO_CLASS_BE << IOPRIO_CLASS_SHIFT;
90
91         return 0;
92 }
93 #endif
94
95 static int str_exitall_cb(void)
96 {
97         exitall_on_terminate = 1;
98         return 0;
99 }
100
101 static void fill_cpu_mask(os_cpu_mask_t cpumask, int cpu)
102 {
103 #ifdef FIO_HAVE_CPU_AFFINITY
104         unsigned int i;
105
106         CPU_ZERO(&cpumask);
107
108         for (i = 0; i < sizeof(int) * 8; i++) {
109                 if ((1 << i) & cpu)
110                         CPU_SET(i, &cpumask);
111         }
112 #endif
113 }
114
115 static int str_cpumask_cb(void *data, unsigned int *val)
116 {
117         struct thread_data *td = data;
118
119         fill_cpu_mask(td->o.cpumask, *val);
120         return 0;
121 }
122
123 static int str_fst_cb(void *data, const char *str)
124 {
125         struct thread_data *td = data;
126         char *nr = get_opt_postfix(str);
127
128         td->file_service_nr = 1;
129         if (nr)
130                 td->file_service_nr = atoi(nr);
131
132         return 0;
133 }
134
135 static int str_filename_cb(void *data, const char *input)
136 {
137         struct thread_data *td = data;
138         char *fname, *str, *p;
139
140         p = str = strdup(input);
141
142         strip_blank_front(&str);
143         strip_blank_end(str);
144
145         if (!td->files_index)
146                 td->o.nr_files = 0;
147
148         while ((fname = strsep(&str, ":")) != NULL) {
149                 if (!strlen(fname))
150                         break;
151                 add_file(td, fname);
152                 td->o.nr_files++;
153         }
154
155         free(p);
156         return 0;
157 }
158
159 static int str_directory_cb(void *data, const char fio_unused *str)
160 {
161         struct thread_data *td = data;
162         struct stat sb;
163
164         if (lstat(td->o.directory, &sb) < 0) {
165                 log_err("fio: %s is not a directory\n", td->o.directory);
166                 td_verror(td, errno, "lstat");
167                 return 1;
168         }
169         if (!S_ISDIR(sb.st_mode)) {
170                 log_err("fio: %s is not a directory\n", td->o.directory);
171                 return 1;
172         }
173
174         return 0;
175 }
176
177 static int str_opendir_cb(void *data, const char fio_unused *str)
178 {
179         struct thread_data *td = data;
180
181         if (!td->files_index)
182                 td->o.nr_files = 0;
183
184         return add_dir_files(td, td->o.opendir);
185 }
186
187
188 #define __stringify_1(x)        #x
189 #define __stringify(x)          __stringify_1(x)
190
191 /*
192  * Map of job/command line options
193  */
194 static struct fio_option options[] = {
195         {
196                 .name   = "description",
197                 .type   = FIO_OPT_STR_STORE,
198                 .off1   = td_var_offset(description),
199                 .help   = "Text job description",
200         },
201         {
202                 .name   = "name",
203                 .type   = FIO_OPT_STR_STORE,
204                 .off1   = td_var_offset(name),
205                 .help   = "Name of this job",
206         },
207         {
208                 .name   = "directory",
209                 .type   = FIO_OPT_STR_STORE,
210                 .off1   = td_var_offset(directory),
211                 .cb     = str_directory_cb,
212                 .help   = "Directory to store files in",
213         },
214         {
215                 .name   = "filename",
216                 .type   = FIO_OPT_STR_STORE,
217                 .off1   = td_var_offset(filename),
218                 .cb     = str_filename_cb,
219                 .help   = "File(s) to use for the workload",
220         },
221         {
222                 .name   = "opendir",
223                 .type   = FIO_OPT_STR_STORE,
224                 .off1   = td_var_offset(opendir),
225                 .cb     = str_opendir_cb,
226                 .help   = "Recursively add files from this directory and down",
227         },
228         {
229                 .name   = "rw",
230                 .alias  = "readwrite",
231                 .type   = FIO_OPT_STR,
232                 .cb     = str_rw_cb,
233                 .off1   = td_var_offset(td_ddir),
234                 .help   = "IO direction",
235                 .def    = "read",
236                 .posval = {
237                           { .ival = "read",
238                             .oval = TD_DDIR_READ,
239                             .help = "Sequential read",
240                           },
241                           { .ival = "write",
242                             .oval = TD_DDIR_WRITE,
243                             .help = "Sequential write",
244                           },
245                           { .ival = "randread",
246                             .oval = TD_DDIR_RANDREAD,
247                             .help = "Random read",
248                           },
249                           { .ival = "randwrite",
250                             .oval = TD_DDIR_RANDWRITE,
251                             .help = "Random write",
252                           },
253                           { .ival = "rw",
254                             .oval = TD_DDIR_RW,
255                             .help = "Sequential read and write mix",
256                           },
257                           { .ival = "randrw",
258                             .oval = TD_DDIR_RANDRW,
259                             .help = "Random read and write mix"
260                           },
261                 },
262         },
263         {
264                 .name   = "fadvise_hint",
265                 .type   = FIO_OPT_BOOL,
266                 .off1   = td_var_offset(fadvise_hint),
267                 .help   = "Use fadvise() to advise the kernel on IO pattern",
268                 .def    = "1",
269         },
270         {
271                 .name   = "ioengine",
272                 .type   = FIO_OPT_STR_STORE,
273                 .off1   = td_var_offset(ioengine),
274                 .help   = "IO engine to use",
275                 .def    = "sync",
276                 .posval = {
277                           { .ival = "sync",
278                             .help = "Use read/write",
279                           },
280 #ifdef FIO_HAVE_LIBAIO
281                           { .ival = "libaio",
282                             .help = "Linux native asynchronous IO",
283                           },
284 #endif
285 #ifdef FIO_HAVE_POSIXAIO
286                           { .ival = "posixaio",
287                             .help = "POSIX asynchronous IO",
288                           },
289 #endif
290                           { .ival = "mmap",
291                             .help = "Memory mapped IO",
292                           },
293 #ifdef FIO_HAVE_SPLICE
294                           { .ival = "splice",
295                             .help = "splice/vmsplice based IO",
296                           },
297 #endif
298 #ifdef FIO_HAVE_SGIO
299                           { .ival = "sg",
300                             .help = "SCSI generic v3 IO",
301                           },
302 #endif
303                           { .ival = "null",
304                             .help = "Testing engine (no data transfer)",
305                           },
306                           { .ival = "net",
307                             .help = "Network IO",
308                           },
309 #ifdef FIO_HAVE_SYSLET
310                           { .ival = "syslet-rw",
311                             .help = "syslet enabled async pread/pwrite IO",
312                           },
313 #endif
314                           { .ival = "cpuio",
315                             .help = "CPU cycler burner engine",
316                           },
317 #ifdef FIO_HAVE_GUASI
318                           { .ival = "guasi",
319                             .help = "GUASI IO engine",
320                           },
321 #endif
322                           { .ival = "external",
323                             .help = "Load external engine (append name)",
324                           },
325                 },
326         },
327         {
328                 .name   = "iodepth",
329                 .type   = FIO_OPT_INT,
330                 .off1   = td_var_offset(iodepth),
331                 .help   = "Amount of IO buffers to keep in flight",
332                 .def    = "1",
333         },
334         {
335                 .name   = "iodepth_batch",
336                 .type   = FIO_OPT_INT,
337                 .off1   = td_var_offset(iodepth_batch),
338                 .help   = "Number of IO to submit in one go",
339         },
340         {
341                 .name   = "iodepth_low",
342                 .type   = FIO_OPT_INT,
343                 .off1   = td_var_offset(iodepth_low),
344                 .help   = "Low water mark for queuing depth",
345         },
346         {
347                 .name   = "size",
348                 .type   = FIO_OPT_STR_VAL,
349                 .off1   = td_var_offset(size),
350                 .help   = "Total size of device or files",
351         },
352         {
353                 .name   = "filesize",
354                 .type   = FIO_OPT_STR_VAL,
355                 .off1   = td_var_offset(file_size_low),
356                 .off2   = td_var_offset(file_size_high),
357                 .help   = "Size of individual files",
358         },
359         {
360                 .name   = "bs",
361                 .alias  = "blocksize",
362                 .type   = FIO_OPT_STR_VAL_INT,
363                 .off1   = td_var_offset(bs[DDIR_READ]),
364                 .off2   = td_var_offset(bs[DDIR_WRITE]),
365                 .help   = "Block size unit",
366                 .def    = "4k",
367         },
368         {
369                 .name   = "bsrange",
370                 .alias  = "blocksize_range",
371                 .type   = FIO_OPT_RANGE,
372                 .off1   = td_var_offset(min_bs[DDIR_READ]),
373                 .off2   = td_var_offset(max_bs[DDIR_READ]),
374                 .off3   = td_var_offset(min_bs[DDIR_WRITE]),
375                 .off4   = td_var_offset(max_bs[DDIR_WRITE]),
376                 .help   = "Set block size range (in more detail than bs)",
377         },
378         {
379                 .name   = "bs_unaligned",
380                 .alias  = "blocksize_unaligned",
381                 .type   = FIO_OPT_STR_SET,
382                 .off1   = td_var_offset(bs_unaligned),
383                 .help   = "Don't sector align IO buffer sizes",
384         },
385         {
386                 .name   = "offset",
387                 .type   = FIO_OPT_STR_VAL,
388                 .off1   = td_var_offset(start_offset),
389                 .help   = "Start IO from this offset",
390                 .def    = "0",
391         },
392         {
393                 .name   = "randrepeat",
394                 .type   = FIO_OPT_BOOL,
395                 .off1   = td_var_offset(rand_repeatable),
396                 .help   = "Use repeatable random IO pattern",
397                 .def    = "1",
398         },
399         {
400                 .name   = "norandommap",
401                 .type   = FIO_OPT_STR_SET,
402                 .off1   = td_var_offset(norandommap),
403                 .help   = "Accept potential duplicate random blocks",
404         },
405         {
406                 .name   = "nrfiles",
407                 .type   = FIO_OPT_INT,
408                 .off1   = td_var_offset(nr_files),
409                 .help   = "Split job workload between this number of files",
410                 .def    = "1",
411         },
412         {
413                 .name   = "openfiles",
414                 .type   = FIO_OPT_INT,
415                 .off1   = td_var_offset(open_files),
416                 .help   = "Number of files to keep open at the same time",
417         },
418         {
419                 .name   = "file_service_type",
420                 .type   = FIO_OPT_STR,
421                 .cb     = str_fst_cb,
422                 .off1   = td_var_offset(file_service_type),
423                 .help   = "How to select which file to service next",
424                 .def    = "roundrobin",
425                 .posval = {
426                           { .ival = "random",
427                             .oval = FIO_FSERVICE_RANDOM,
428                             .help = "Choose a file at random",
429                           },
430                           { .ival = "roundrobin",
431                             .oval = FIO_FSERVICE_RR,
432                             .help = "Round robin select files",
433                           },
434                 },
435         },
436         {
437                 .name   = "fsync",
438                 .type   = FIO_OPT_INT,
439                 .off1   = td_var_offset(fsync_blocks),
440                 .help   = "Issue fsync for writes every given number of blocks",
441                 .def    = "0",
442         },
443         {
444                 .name   = "direct",
445                 .type   = FIO_OPT_BOOL,
446                 .off1   = td_var_offset(odirect),
447                 .help   = "Use O_DIRECT IO (negates buffered)",
448                 .def    = "0",
449         },
450         {
451                 .name   = "buffered",
452                 .type   = FIO_OPT_BOOL,
453                 .off1   = td_var_offset(odirect),
454                 .neg    = 1,
455                 .help   = "Use buffered IO (negates direct)",
456                 .def    = "1",
457         },
458         {
459                 .name   = "overwrite",
460                 .type   = FIO_OPT_BOOL,
461                 .off1   = td_var_offset(overwrite),
462                 .help   = "When writing, set whether to overwrite current data",
463                 .def    = "0",
464         },
465         {
466                 .name   = "loops",
467                 .type   = FIO_OPT_INT,
468                 .off1   = td_var_offset(loops),
469                 .help   = "Number of times to run the job",
470                 .def    = "1",
471         },
472         {
473                 .name   = "numjobs",
474                 .type   = FIO_OPT_INT,
475                 .off1   = td_var_offset(numjobs),
476                 .help   = "Duplicate this job this many times",
477                 .def    = "1",
478         },
479         {
480                 .name   = "startdelay",
481                 .type   = FIO_OPT_INT,
482                 .off1   = td_var_offset(start_delay),
483                 .help   = "Only start job when this period has passed",
484                 .def    = "0",
485         },
486         {
487                 .name   = "runtime",
488                 .alias  = "timeout",
489                 .type   = FIO_OPT_STR_VAL_TIME,
490                 .off1   = td_var_offset(timeout),
491                 .help   = "Stop workload when this amount of time has passed",
492                 .def    = "0",
493         },
494         {
495                 .name   = "time_based",
496                 .type   = FIO_OPT_STR_SET,
497                 .off1   = td_var_offset(time_based),
498                 .help   = "Keep running until runtime/timeout is met",
499         },
500         {
501                 .name   = "mem",
502                 .alias  = "iomem",
503                 .type   = FIO_OPT_STR,
504                 .cb     = str_mem_cb,
505                 .off1   = td_var_offset(mem_type),
506                 .help   = "Backing type for IO buffers",
507                 .def    = "malloc",
508                 .posval = {
509                           { .ival = "malloc",
510                             .oval = MEM_MALLOC,
511                             .help = "Use malloc(3) for IO buffers",
512                           },
513                           { .ival = "shm",
514                             .oval = MEM_SHM,
515                             .help = "Use shared memory segments for IO buffers",
516                           },
517 #ifdef FIO_HAVE_HUGETLB
518                           { .ival = "shmhuge",
519                             .oval = MEM_SHMHUGE,
520                             .help = "Like shm, but use huge pages",
521                           },
522 #endif
523                           { .ival = "mmap",
524                             .oval = MEM_MMAP,
525                             .help = "Use mmap(2) (file or anon) for IO buffers",
526                           },
527 #ifdef FIO_HAVE_HUGETLB
528                           { .ival = "mmaphuge",
529                             .oval = MEM_MMAPHUGE,
530                             .help = "Like mmap, but use huge pages",
531                           },
532 #endif
533                   },
534         },
535         {
536                 .name   = "verify",
537                 .type   = FIO_OPT_STR,
538                 .off1   = td_var_offset(verify),
539                 .help   = "Verify data written",
540                 .def    = "0",
541                 .posval = {
542                           { .ival = "0",
543                             .oval = VERIFY_NONE,
544                             .help = "Don't do IO verification",
545                           },
546                           { .ival = "crc32",
547                             .oval = VERIFY_CRC32,
548                             .help = "Use crc32 checksums for verification",
549                           },
550                           { .ival = "md5",
551                             .oval = VERIFY_MD5,
552                             .help = "Use md5 checksums for verification",
553                           },
554                           {
555                             .ival = "null",
556                             .oval = VERIFY_NULL,
557                             .help = "Pretend to verify",
558                           },
559                 },
560         },
561         {
562                 .name   = "verifysort",
563                 .type   = FIO_OPT_BOOL,
564                 .off1   = td_var_offset(verifysort),
565                 .help   = "Sort written verify blocks for read back",
566                 .def    = "1",
567         },
568         {
569                 .name   = "write_iolog",
570                 .type   = FIO_OPT_STR_STORE,
571                 .off1   = td_var_offset(write_iolog_file),
572                 .help   = "Store IO pattern to file",
573         },
574         {
575                 .name   = "read_iolog",
576                 .type   = FIO_OPT_STR_STORE,
577                 .off1   = td_var_offset(read_iolog_file),
578                 .help   = "Playback IO pattern from file",
579         },
580         {
581                 .name   = "exec_prerun",
582                 .type   = FIO_OPT_STR_STORE,
583                 .off1   = td_var_offset(exec_prerun),
584                 .help   = "Execute this file prior to running job",
585         },
586         {
587                 .name   = "exec_postrun",
588                 .type   = FIO_OPT_STR_STORE,
589                 .off1   = td_var_offset(exec_postrun),
590                 .help   = "Execute this file after running job",
591         },
592 #ifdef FIO_HAVE_IOSCHED_SWITCH
593         {
594                 .name   = "ioscheduler",
595                 .type   = FIO_OPT_STR_STORE,
596                 .off1   = td_var_offset(ioscheduler),
597                 .help   = "Use this IO scheduler on the backing device",
598         },
599 #endif
600         {
601                 .name   = "zonesize",
602                 .type   = FIO_OPT_STR_VAL,
603                 .off1   = td_var_offset(zone_size),
604                 .help   = "Give size of an IO zone",
605                 .def    = "0",
606         },
607         {
608                 .name   = "zoneskip",
609                 .type   = FIO_OPT_STR_VAL,
610                 .off1   = td_var_offset(zone_skip),
611                 .help   = "Space between IO zones",
612                 .def    = "0",
613         },
614         {
615                 .name   = "lockmem",
616                 .type   = FIO_OPT_STR_VAL,
617                 .cb     = str_lockmem_cb,
618                 .help   = "Lock down this amount of memory",
619                 .def    = "0",
620         },
621         {
622                 .name   = "rwmixcycle",
623                 .type   = FIO_OPT_INT,
624                 .off1   = td_var_offset(rwmixcycle),
625                 .help   = "Cycle period for mixed read/write workloads (msec)",
626                 .def    = "500",
627         },
628         {
629                 .name   = "rwmixread",
630                 .type   = FIO_OPT_INT,
631                 .off1   = td_var_offset(rwmix[DDIR_READ]),
632                 .maxval = 100,
633                 .help   = "Percentage of mixed workload that is reads",
634                 .def    = "50",
635         },
636         {
637                 .name   = "rwmixwrite",
638                 .type   = FIO_OPT_INT,
639                 .off1   = td_var_offset(rwmix[DDIR_WRITE]),
640                 .maxval = 100,
641                 .help   = "Percentage of mixed workload that is writes",
642                 .def    = "50",
643         },
644         {
645                 .name   = "nice",
646                 .type   = FIO_OPT_INT,
647                 .off1   = td_var_offset(nice),
648                 .help   = "Set job CPU nice value",
649                 .minval = -19,
650                 .maxval = 20,
651                 .def    = "0",
652         },
653 #ifdef FIO_HAVE_IOPRIO
654         {
655                 .name   = "prio",
656                 .type   = FIO_OPT_INT,
657                 .cb     = str_prio_cb,
658                 .help   = "Set job IO priority value",
659                 .minval = 0,
660                 .maxval = 7,
661         },
662         {
663                 .name   = "prioclass",
664                 .type   = FIO_OPT_INT,
665                 .cb     = str_prioclass_cb,
666                 .help   = "Set job IO priority class",
667                 .minval = 0,
668                 .maxval = 3,
669         },
670 #endif
671         {
672                 .name   = "thinktime",
673                 .type   = FIO_OPT_INT,
674                 .off1   = td_var_offset(thinktime),
675                 .help   = "Idle time between IO buffers (usec)",
676                 .def    = "0",
677         },
678         {
679                 .name   = "thinktime_spin",
680                 .type   = FIO_OPT_INT,
681                 .off1   = td_var_offset(thinktime_spin),
682                 .help   = "Start think time by spinning this amount (usec)",
683                 .def    = "0",
684         },
685         {
686                 .name   = "thinktime_blocks",
687                 .type   = FIO_OPT_INT,
688                 .off1   = td_var_offset(thinktime_blocks),
689                 .help   = "IO buffer period between 'thinktime'",
690                 .def    = "1",
691         },
692         {
693                 .name   = "rate",
694                 .type   = FIO_OPT_INT,
695                 .off1   = td_var_offset(rate),
696                 .help   = "Set bandwidth rate",
697         },
698         {
699                 .name   = "ratemin",
700                 .type   = FIO_OPT_INT,
701                 .off1   = td_var_offset(ratemin),
702                 .help   = "Job must meet this rate or it will be shutdown",
703         },
704         {
705                 .name   = "rate_iops",
706                 .type   = FIO_OPT_INT,
707                 .off1   = td_var_offset(rate_iops),
708                 .help   = "Limit IO used to this number of IO operations/sec",
709         },
710         {
711                 .name   = "rate_iops_min",
712                 .type   = FIO_OPT_INT,
713                 .off1   = td_var_offset(rate_iops_min),
714                 .help   = "Job must meet this rate or it will be shutdown",
715         },
716         {
717                 .name   = "ratecycle",
718                 .type   = FIO_OPT_INT,
719                 .off1   = td_var_offset(ratecycle),
720                 .help   = "Window average for rate limits (msec)",
721                 .def    = "1000",
722         },
723         {
724                 .name   = "invalidate",
725                 .type   = FIO_OPT_BOOL,
726                 .off1   = td_var_offset(invalidate_cache),
727                 .help   = "Invalidate buffer/page cache prior to running job",
728                 .def    = "1",
729         },
730         {
731                 .name   = "sync",
732                 .type   = FIO_OPT_BOOL,
733                 .off1   = td_var_offset(sync_io),
734                 .help   = "Use O_SYNC for buffered writes",
735                 .def    = "0",
736         },
737         {
738                 .name   = "bwavgtime",
739                 .type   = FIO_OPT_INT,
740                 .off1   = td_var_offset(bw_avg_time),
741                 .help   = "Time window over which to calculate bandwidth (msec)",
742                 .def    = "500",
743         },
744         {
745                 .name   = "create_serialize",
746                 .type   = FIO_OPT_BOOL,
747                 .off1   = td_var_offset(create_serialize),
748                 .help   = "Serialize creating of job files",
749                 .def    = "1",
750         },
751         {
752                 .name   = "create_fsync",
753                 .type   = FIO_OPT_BOOL,
754                 .off1   = td_var_offset(create_fsync),
755                 .help   = "Fsync file after creation",
756                 .def    = "1",
757         },
758         {
759                 .name   = "cpuload",
760                 .type   = FIO_OPT_INT,
761                 .off1   = td_var_offset(cpuload),
762                 .help   = "Use this percentage of CPU",
763         },
764         {
765                 .name   = "cpuchunks",
766                 .type   = FIO_OPT_INT,
767                 .off1   = td_var_offset(cpucycle),
768                 .help   = "Length of the CPU burn cycles (usecs)",
769                 .def    = "50000",
770         },
771 #ifdef FIO_HAVE_CPU_AFFINITY
772         {
773                 .name   = "cpumask",
774                 .type   = FIO_OPT_INT,
775                 .cb     = str_cpumask_cb,
776                 .help   = "CPU affinity mask",
777         },
778 #endif
779         {
780                 .name   = "end_fsync",
781                 .type   = FIO_OPT_BOOL,
782                 .off1   = td_var_offset(end_fsync),
783                 .help   = "Include fsync at the end of job",
784                 .def    = "0",
785         },
786         {
787                 .name   = "fsync_on_close",
788                 .type   = FIO_OPT_BOOL,
789                 .off1   = td_var_offset(fsync_on_close),
790                 .help   = "fsync files on close",
791                 .def    = "0",
792         },
793         {
794                 .name   = "unlink",
795                 .type   = FIO_OPT_BOOL,
796                 .off1   = td_var_offset(unlink),
797                 .help   = "Unlink created files after job has completed",
798                 .def    = "0",
799         },
800         {
801                 .name   = "exitall",
802                 .type   = FIO_OPT_STR_SET,
803                 .cb     = str_exitall_cb,
804                 .help   = "Terminate all jobs when one exits",
805         },
806         {
807                 .name   = "stonewall",
808                 .type   = FIO_OPT_STR_SET,
809                 .off1   = td_var_offset(stonewall),
810                 .help   = "Insert a hard barrier between this job and previous",
811         },
812         {
813                 .name   = "new_group",
814                 .type   = FIO_OPT_STR_SET,
815                 .off1   = td_var_offset(new_group),
816                 .help   = "Mark the start of a new group (for reporting)",
817         },
818         {
819                 .name   = "thread",
820                 .type   = FIO_OPT_STR_SET,
821                 .off1   = td_var_offset(use_thread),
822                 .help   = "Use threads instead of forks",
823         },
824         {
825                 .name   = "write_bw_log",
826                 .type   = FIO_OPT_STR_SET,
827                 .off1   = td_var_offset(write_bw_log),
828                 .help   = "Write log of bandwidth during run",
829         },
830         {
831                 .name   = "write_lat_log",
832                 .type   = FIO_OPT_STR_SET,
833                 .off1   = td_var_offset(write_lat_log),
834                 .help   = "Write log of latency during run",
835         },
836         {
837                 .name   = "hugepage-size",
838                 .type   = FIO_OPT_STR_VAL,
839                 .off1   = td_var_offset(hugepage_size),
840                 .help   = "When using hugepages, specify size of each page",
841                 .def    = __stringify(FIO_HUGE_PAGE),
842         },
843         {
844                 .name   = "group_reporting",
845                 .type   = FIO_OPT_STR_SET,
846                 .off1   = td_var_offset(group_reporting),
847                 .help   = "Do reporting on a per-group basis",
848         },
849         {
850                 .name   = "zero_buffers",
851                 .type   = FIO_OPT_STR_SET,
852                 .off1   = td_var_offset(zero_buffers),
853                 .help   = "Init IO buffers to all zeroes",
854         },
855 #ifdef FIO_HAVE_DISK_UTIL
856         {
857                 .name   = "disk_util",
858                 .type   = FIO_OPT_BOOL,
859                 .off1   = td_var_offset(do_disk_util),
860                 .help   = "Log disk utilization stats",
861                 .def    = "1",
862         },
863 #endif
864         {
865                 .name = NULL,
866         },
867 };
868
869 void fio_options_dup_and_init(struct option *long_options)
870 {
871         struct fio_option *o;
872         unsigned int i;
873
874         options_init(options);
875
876         i = 0;
877         while (long_options[i].name)
878                 i++;
879
880         o = &options[0];
881         while (o->name) {
882                 long_options[i].name = o->name;
883                 long_options[i].val = FIO_GETOPT_JOB;
884                 if (o->type == FIO_OPT_STR_SET)
885                         long_options[i].has_arg = no_argument;
886                 else
887                         long_options[i].has_arg = required_argument;
888
889                 i++;
890                 o++;
891                 assert(i < FIO_NR_OPTIONS);
892         }
893 }
894
895 int fio_option_parse(struct thread_data *td, const char *opt)
896 {
897         return parse_option(opt, options, td);
898 }
899
900 int fio_cmd_option_parse(struct thread_data *td, const char *opt, char *val)
901 {
902         return parse_cmd_option(opt, val, options, td);
903 }
904
905 void fio_fill_default_options(struct thread_data *td)
906 {
907         fill_default_options(td, options);
908 }
909
910 int fio_show_option_help(const char *opt)
911 {
912         return show_cmd_help(options, opt);
913 }
914
915 static void __options_mem(struct thread_data *td, int alloc)
916 {
917         struct thread_options *o = &td->o;
918         struct fio_option *opt;
919         char **ptr;
920         int i;
921
922         for (i = 0, opt = &options[0]; opt->name; i++, opt = &options[i]) {
923                 if (opt->type != FIO_OPT_STR_STORE)
924                         continue;
925
926                 ptr = (void *) o + opt->off1;
927                 if (*ptr) {
928                         if (alloc)
929                                 *ptr = strdup(*ptr);
930                         else {
931                                 free(*ptr);
932                                 *ptr = NULL;
933                         }
934                 }
935         }
936 }
937
938 /*
939  * dupe FIO_OPT_STR_STORE options
940  */
941 void options_mem_dupe(struct thread_data *td)
942 {
943         __options_mem(td, 1);
944 }
945
946 void options_mem_free(struct thread_data fio_unused *td)
947 {
948 #if 0
949         __options_mem(td, 0);
950 #endif
951 }