options: move ioprio/ioprio_class into thread_options space
[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 <assert.h>
7 #include <libgen.h>
8 #include <fcntl.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11
12 #include "fio.h"
13 #include "verify.h"
14 #include "parse.h"
15 #include "lib/fls.h"
16 #include "options.h"
17
18 #include "crc/crc32c.h"
19
20 /*
21  * Check if mmap/mmaphuge has a :/foo/bar/file at the end. If so, return that.
22  */
23 static char *get_opt_postfix(const char *str)
24 {
25         char *p = strstr(str, ":");
26
27         if (!p)
28                 return NULL;
29
30         p++;
31         strip_blank_front(&p);
32         strip_blank_end(p);
33         return strdup(p);
34 }
35
36 static int converthexchartoint(char a)
37 {
38         int base;
39
40         switch (a) {
41         case '0'...'9':
42                 base = '0';
43                 break;
44         case 'A'...'F':
45                 base = 'A' - 10;
46                 break;
47         case 'a'...'f':
48                 base = 'a' - 10;
49                 break;
50         default:
51                 base = 0;
52         }
53         return a - base;
54 }
55
56 static int bs_cmp(const void *p1, const void *p2)
57 {
58         const struct bssplit *bsp1 = p1;
59         const struct bssplit *bsp2 = p2;
60
61         return bsp1->perc < bsp2->perc;
62 }
63
64 static int bssplit_ddir(struct thread_options *o, int ddir, char *str)
65 {
66         struct bssplit *bssplit;
67         unsigned int i, perc, perc_missing;
68         unsigned int max_bs, min_bs;
69         long long val;
70         char *fname;
71
72         o->bssplit_nr[ddir] = 4;
73         bssplit = malloc(4 * sizeof(struct bssplit));
74
75         i = 0;
76         max_bs = 0;
77         min_bs = -1;
78         while ((fname = strsep(&str, ":")) != NULL) {
79                 char *perc_str;
80
81                 if (!strlen(fname))
82                         break;
83
84                 /*
85                  * grow struct buffer, if needed
86                  */
87                 if (i == o->bssplit_nr[ddir]) {
88                         o->bssplit_nr[ddir] <<= 1;
89                         bssplit = realloc(bssplit, o->bssplit_nr[ddir]
90                                                   * sizeof(struct bssplit));
91                 }
92
93                 perc_str = strstr(fname, "/");
94                 if (perc_str) {
95                         *perc_str = '\0';
96                         perc_str++;
97                         perc = atoi(perc_str);
98                         if (perc > 100)
99                                 perc = 100;
100                         else if (!perc)
101                                 perc = -1;
102                 } else
103                         perc = -1;
104
105                 if (str_to_decimal(fname, &val, 1, o)) {
106                         log_err("fio: bssplit conversion failed\n");
107                         free(o->bssplit);
108                         return 1;
109                 }
110
111                 if (val > max_bs)
112                         max_bs = val;
113                 if (val < min_bs)
114                         min_bs = val;
115
116                 bssplit[i].bs = val;
117                 bssplit[i].perc = perc;
118                 i++;
119         }
120
121         o->bssplit_nr[ddir] = i;
122
123         /*
124          * Now check if the percentages add up, and how much is missing
125          */
126         perc = perc_missing = 0;
127         for (i = 0; i < o->bssplit_nr[ddir]; i++) {
128                 struct bssplit *bsp = &bssplit[i];
129
130                 if (bsp->perc == (unsigned char) -1)
131                         perc_missing++;
132                 else
133                         perc += bsp->perc;
134         }
135
136         if (perc > 100) {
137                 log_err("fio: bssplit percentages add to more than 100%%\n");
138                 free(bssplit);
139                 return 1;
140         }
141         /*
142          * If values didn't have a percentage set, divide the remains between
143          * them.
144          */
145         if (perc_missing) {
146                 for (i = 0; i < o->bssplit_nr[ddir]; i++) {
147                         struct bssplit *bsp = &bssplit[i];
148
149                         if (bsp->perc == (unsigned char) -1)
150                                 bsp->perc = (100 - perc) / perc_missing;
151                 }
152         }
153
154         o->min_bs[ddir] = min_bs;
155         o->max_bs[ddir] = max_bs;
156
157         /*
158          * now sort based on percentages, for ease of lookup
159          */
160         qsort(bssplit, o->bssplit_nr[ddir], sizeof(struct bssplit), bs_cmp);
161         o->bssplit[ddir] = bssplit;
162         return 0;
163 }
164
165 static int str_bssplit_cb(void *data, const char *input)
166 {
167         struct thread_data *td = data;
168         char *str, *p, *odir;
169         int ret = 0;
170
171         p = str = strdup(input);
172
173         strip_blank_front(&str);
174         strip_blank_end(str);
175
176         odir = strchr(str, ',');
177         if (odir) {
178                 ret = bssplit_ddir(&td->o, DDIR_WRITE, odir + 1);
179                 if (!ret) {
180                         *odir = '\0';
181                         ret = bssplit_ddir(&td->o, DDIR_READ, str);
182                 }
183         } else {
184                 char *op;
185
186                 op = strdup(str);
187
188                 ret = bssplit_ddir(&td->o, DDIR_READ, str);
189                 if (!ret)
190                         ret = bssplit_ddir(&td->o, DDIR_WRITE, op);
191
192                 free(op);
193         }
194
195         free(p);
196         return ret;
197 }
198
199 static int str_rw_cb(void *data, const char *str)
200 {
201         struct thread_data *td = data;
202         struct thread_options *o = &td->o;
203         char *nr = get_opt_postfix(str);
204
205         o->ddir_seq_nr = 1;
206         o->ddir_seq_add = 0;
207
208         if (!nr)
209                 return 0;
210
211         if (td_random(td))
212                 o->ddir_seq_nr = atoi(nr);
213         else {
214                 long long val;
215
216                 if (str_to_decimal(nr, &val, 1, o)) {
217                         log_err("fio: rw postfix parsing failed\n");
218                         free(nr);
219                         return 1;
220                 }
221
222                 o->ddir_seq_add = val;
223         }
224
225         free(nr);
226         return 0;
227 }
228
229 static int str_mem_cb(void *data, const char *mem)
230 {
231         struct thread_data *td = data;
232         struct thread_options *o = &td->o;
233
234         if (o->mem_type == MEM_MMAPHUGE || o->mem_type == MEM_MMAP) {
235                 o->mmapfile = get_opt_postfix(mem);
236                 if (o->mem_type == MEM_MMAPHUGE && !o->mmapfile) {
237                         log_err("fio: mmaphuge:/path/to/file\n");
238                         return 1;
239                 }
240         }
241
242         return 0;
243 }
244
245 static int fio_clock_source_cb(void *data, const char *str)
246 {
247         struct thread_data *td = data;
248
249         fio_clock_source = td->o.clocksource;
250         fio_time_init();
251         return 0;
252 }
253
254 static int str_rwmix_read_cb(void *data, unsigned long long *val)
255 {
256         struct thread_data *td = data;
257
258         td->o.rwmix[DDIR_READ] = *val;
259         td->o.rwmix[DDIR_WRITE] = 100 - *val;
260         return 0;
261 }
262
263 static int str_rwmix_write_cb(void *data, unsigned long long *val)
264 {
265         struct thread_data *td = data;
266
267         td->o.rwmix[DDIR_WRITE] = *val;
268         td->o.rwmix[DDIR_READ] = 100 - *val;
269         return 0;
270 }
271
272 static int str_exitall_cb(void)
273 {
274         exitall_on_terminate = 1;
275         return 0;
276 }
277
278 #ifdef FIO_HAVE_CPU_AFFINITY
279 static int str_cpumask_cb(void *data, unsigned long long *val)
280 {
281         struct thread_data *td = data;
282         unsigned int i;
283         long max_cpu;
284         int ret;
285
286         ret = fio_cpuset_init(&td->o.cpumask);
287         if (ret < 0) {
288                 log_err("fio: cpuset_init failed\n");
289                 td_verror(td, ret, "fio_cpuset_init");
290                 return 1;
291         }
292
293         max_cpu = cpus_online();
294
295         for (i = 0; i < sizeof(int) * 8; i++) {
296                 if ((1 << i) & *val) {
297                         if (i > max_cpu) {
298                                 log_err("fio: CPU %d too large (max=%ld)\n", i,
299                                                                 max_cpu);
300                                 return 1;
301                         }
302                         dprint(FD_PARSE, "set cpu allowed %d\n", i);
303                         fio_cpu_set(&td->o.cpumask, i);
304                 }
305         }
306
307         td->o.cpumask_set = 1;
308         return 0;
309 }
310
311 static int set_cpus_allowed(struct thread_data *td, os_cpu_mask_t *mask,
312                             const char *input)
313 {
314         char *cpu, *str, *p;
315         long max_cpu;
316         int ret = 0;
317
318         ret = fio_cpuset_init(mask);
319         if (ret < 0) {
320                 log_err("fio: cpuset_init failed\n");
321                 td_verror(td, ret, "fio_cpuset_init");
322                 return 1;
323         }
324
325         p = str = strdup(input);
326
327         strip_blank_front(&str);
328         strip_blank_end(str);
329
330         max_cpu = cpus_online();
331
332         while ((cpu = strsep(&str, ",")) != NULL) {
333                 char *str2, *cpu2;
334                 int icpu, icpu2;
335
336                 if (!strlen(cpu))
337                         break;
338
339                 str2 = cpu;
340                 icpu2 = -1;
341                 while ((cpu2 = strsep(&str2, "-")) != NULL) {
342                         if (!strlen(cpu2))
343                                 break;
344
345                         icpu2 = atoi(cpu2);
346                 }
347
348                 icpu = atoi(cpu);
349                 if (icpu2 == -1)
350                         icpu2 = icpu;
351                 while (icpu <= icpu2) {
352                         if (icpu >= FIO_MAX_CPUS) {
353                                 log_err("fio: your OS only supports up to"
354                                         " %d CPUs\n", (int) FIO_MAX_CPUS);
355                                 ret = 1;
356                                 break;
357                         }
358                         if (icpu > max_cpu) {
359                                 log_err("fio: CPU %d too large (max=%ld)\n",
360                                                         icpu, max_cpu);
361                                 ret = 1;
362                                 break;
363                         }
364
365                         dprint(FD_PARSE, "set cpu allowed %d\n", icpu);
366                         fio_cpu_set(mask, icpu);
367                         icpu++;
368                 }
369                 if (ret)
370                         break;
371         }
372
373         free(p);
374         if (!ret)
375                 td->o.cpumask_set = 1;
376         return ret;
377 }
378
379 static int str_cpus_allowed_cb(void *data, const char *input)
380 {
381         struct thread_data *td = data;
382         int ret;
383
384         ret = set_cpus_allowed(td, &td->o.cpumask, input);
385         if (!ret)
386                 td->o.cpumask_set = 1;
387
388         return ret;
389 }
390
391 static int str_verify_cpus_allowed_cb(void *data, const char *input)
392 {
393         struct thread_data *td = data;
394         int ret;
395
396         ret = set_cpus_allowed(td, &td->o.verify_cpumask, input);
397         if (!ret)
398                 td->o.verify_cpumask_set = 1;
399
400         return ret;
401 }
402 #endif
403
404 #ifdef FIO_HAVE_TRIM
405 static int str_verify_trim_cb(void *data, unsigned long long *val)
406 {
407         struct thread_data *td = data;
408
409         td->o.trim_percentage = *val;
410         return 0;
411 }
412 #endif
413
414 static int str_fst_cb(void *data, const char *str)
415 {
416         struct thread_data *td = data;
417         char *nr = get_opt_postfix(str);
418
419         td->file_service_nr = 1;
420         if (nr) {
421                 td->file_service_nr = atoi(nr);
422                 free(nr);
423         }
424
425         return 0;
426 }
427
428 #ifdef FIO_HAVE_SYNC_FILE_RANGE
429 static int str_sfr_cb(void *data, const char *str)
430 {
431         struct thread_data *td = data;
432         char *nr = get_opt_postfix(str);
433
434         td->sync_file_range_nr = 1;
435         if (nr) {
436                 td->sync_file_range_nr = atoi(nr);
437                 free(nr);
438         }
439
440         return 0;
441 }
442 #endif
443
444 static int check_dir(struct thread_data *td, char *fname)
445 {
446 #if 0
447         char file[PATH_MAX], *dir;
448         int elen = 0;
449
450         if (td->o.directory) {
451                 strcpy(file, td->o.directory);
452                 strcat(file, "/");
453                 elen = strlen(file);
454         }
455
456         sprintf(file + elen, "%s", fname);
457         dir = dirname(file);
458
459         {
460         struct stat sb;
461         /*
462          * We can't do this on FIO_DISKLESSIO engines. The engine isn't loaded
463          * yet, so we can't do this check right here...
464          */
465         if (lstat(dir, &sb) < 0) {
466                 int ret = errno;
467
468                 log_err("fio: %s is not a directory\n", dir);
469                 td_verror(td, ret, "lstat");
470                 return 1;
471         }
472
473         if (!S_ISDIR(sb.st_mode)) {
474                 log_err("fio: %s is not a directory\n", dir);
475                 return 1;
476         }
477         }
478 #endif
479
480         return 0;
481 }
482
483 /*
484  * Return next file in the string. Files are separated with ':'. If the ':'
485  * is escaped with a '\', then that ':' is part of the filename and does not
486  * indicate a new file.
487  */
488 static char *get_next_file_name(char **ptr)
489 {
490         char *str = *ptr;
491         char *p, *start;
492
493         if (!str || !strlen(str))
494                 return NULL;
495
496         start = str;
497         do {
498                 /*
499                  * No colon, we are done
500                  */
501                 p = strchr(str, ':');
502                 if (!p) {
503                         *ptr = NULL;
504                         break;
505                 }
506
507                 /*
508                  * We got a colon, but it's the first character. Skip and
509                  * continue
510                  */
511                 if (p == start) {
512                         str = ++start;
513                         continue;
514                 }
515
516                 if (*(p - 1) != '\\') {
517                         *p = '\0';
518                         *ptr = p + 1;
519                         break;
520                 }
521
522                 memmove(p - 1, p, strlen(p) + 1);
523                 str = p;
524         } while (1);
525
526         return start;
527 }
528
529 static int str_filename_cb(void *data, const char *input)
530 {
531         struct thread_data *td = data;
532         char *fname, *str, *p;
533
534         p = str = strdup(input);
535
536         strip_blank_front(&str);
537         strip_blank_end(str);
538
539         if (!td->files_index)
540                 td->o.nr_files = 0;
541
542         while ((fname = get_next_file_name(&str)) != NULL) {
543                 if (!strlen(fname))
544                         break;
545                 if (check_dir(td, fname)) {
546                         free(p);
547                         return 1;
548                 }
549                 add_file(td, fname);
550                 td->o.nr_files++;
551         }
552
553         free(p);
554         return 0;
555 }
556
557 static int str_directory_cb(void *data, const char fio_unused *str)
558 {
559         struct thread_data *td = data;
560         struct stat sb;
561
562         if (lstat(td->o.directory, &sb) < 0) {
563                 int ret = errno;
564
565                 log_err("fio: %s is not a directory\n", td->o.directory);
566                 td_verror(td, ret, "lstat");
567                 return 1;
568         }
569         if (!S_ISDIR(sb.st_mode)) {
570                 log_err("fio: %s is not a directory\n", td->o.directory);
571                 return 1;
572         }
573
574         return 0;
575 }
576
577 static int str_opendir_cb(void *data, const char fio_unused *str)
578 {
579         struct thread_data *td = data;
580
581         if (!td->files_index)
582                 td->o.nr_files = 0;
583
584         return add_dir_files(td, td->o.opendir);
585 }
586
587 static int str_verify_offset_cb(void *data, unsigned long long *off)
588 {
589         struct thread_data *td = data;
590
591         if (*off && *off < sizeof(struct verify_header)) {
592                 log_err("fio: verify_offset too small\n");
593                 return 1;
594         }
595
596         td->o.verify_offset = *off;
597         return 0;
598 }
599
600 static int str_verify_pattern_cb(void *data, const char *input)
601 {
602         struct thread_data *td = data;
603         long off;
604         int i = 0, j = 0, len, k, base = 10;
605         char *loc1, *loc2;
606
607         loc1 = strstr(input, "0x");
608         loc2 = strstr(input, "0X");
609         if (loc1 || loc2)
610                 base = 16;
611         off = strtol(input, NULL, base);
612         if (off != LONG_MAX || errno != ERANGE) {
613                 while (off) {
614                         td->o.verify_pattern[i] = off & 0xff;
615                         off >>= 8;
616                         i++;
617                 }
618         } else {
619                 len = strlen(input);
620                 k = len - 1;
621                 if (base == 16) {
622                         if (loc1)
623                                 j = loc1 - input + 2;
624                         else
625                                 j = loc2 - input + 2;
626                 } else
627                         return 1;
628                 if (len - j < MAX_PATTERN_SIZE * 2) {
629                         while (k >= j) {
630                                 off = converthexchartoint(input[k--]);
631                                 if (k >= j)
632                                         off += (converthexchartoint(input[k--])
633                                                 * 16);
634                                 td->o.verify_pattern[i++] = (char) off;
635                         }
636                 }
637         }
638
639         /*
640          * Fill the pattern all the way to the end. This greatly reduces
641          * the number of memcpy's we have to do when verifying the IO.
642          */
643         while (i > 1 && i * 2 <= MAX_PATTERN_SIZE) {
644                 memcpy(&td->o.verify_pattern[i], &td->o.verify_pattern[0], i);
645                 i *= 2;
646         }
647         if (i == 1) {
648                 /*
649                  * The code in verify_io_u_pattern assumes a single byte pattern
650                  * fills the whole verify pattern buffer.
651                  */
652                 memset(td->o.verify_pattern, td->o.verify_pattern[0],
653                        MAX_PATTERN_SIZE);
654         }
655
656         td->o.verify_pattern_bytes = i;
657
658         /*
659          * VERIFY_META could already be set
660          */
661         if (td->o.verify == VERIFY_NONE)
662                 td->o.verify = VERIFY_PATTERN;
663
664         return 0;
665 }
666
667 static int str_lockfile_cb(void *data, const char *str)
668 {
669         struct thread_data *td = data;
670         char *nr = get_opt_postfix(str);
671
672         td->o.lockfile_batch = 1;
673         if (nr) {
674                 td->o.lockfile_batch = atoi(nr);
675                 free(nr);
676         }
677
678         return 0;
679 }
680
681 static int str_write_bw_log_cb(void *data, const char *str)
682 {
683         struct thread_data *td = data;
684
685         if (str)
686                 td->o.bw_log_file = strdup(str);
687
688         td->o.write_bw_log = 1;
689         return 0;
690 }
691
692 static int str_write_lat_log_cb(void *data, const char *str)
693 {
694         struct thread_data *td = data;
695
696         if (str)
697                 td->o.lat_log_file = strdup(str);
698
699         td->o.write_lat_log = 1;
700         return 0;
701 }
702
703 static int str_write_iops_log_cb(void *data, const char *str)
704 {
705         struct thread_data *td = data;
706
707         if (str)
708                 td->o.iops_log_file = strdup(str);
709
710         td->o.write_iops_log = 1;
711         return 0;
712 }
713
714 static int str_gtod_reduce_cb(void *data, int *il)
715 {
716         struct thread_data *td = data;
717         int val = *il;
718
719         td->o.disable_lat = !!val;
720         td->o.disable_clat = !!val;
721         td->o.disable_slat = !!val;
722         td->o.disable_bw = !!val;
723         td->o.clat_percentiles = !val;
724         if (val)
725                 td->tv_cache_mask = 63;
726
727         return 0;
728 }
729
730 static int str_gtod_cpu_cb(void *data, long long *il)
731 {
732         struct thread_data *td = data;
733         int val = *il;
734
735         td->o.gtod_cpu = val;
736         td->o.gtod_offload = 1;
737         return 0;
738 }
739
740 static int str_size_cb(void *data, unsigned long long *__val)
741 {
742         struct thread_data *td = data;
743         unsigned long long v = *__val;
744
745         if (parse_is_percent(v)) {
746                 td->o.size = 0;
747                 td->o.size_percent = -1ULL - v;
748         } else
749                 td->o.size = v;
750
751         return 0;
752 }
753
754 static int rw_verify(struct fio_option *o, void *data)
755 {
756         struct thread_data *td = data;
757
758         if (read_only && td_write(td)) {
759                 log_err("fio: job <%s> has write bit set, but fio is in"
760                         " read-only mode\n", td->o.name);
761                 return 1;
762         }
763
764         return 0;
765 }
766
767 static int gtod_cpu_verify(struct fio_option *o, void *data)
768 {
769 #ifndef FIO_HAVE_CPU_AFFINITY
770         struct thread_data *td = data;
771
772         if (td->o.gtod_cpu) {
773                 log_err("fio: platform must support CPU affinity for"
774                         "gettimeofday() offloading\n");
775                 return 1;
776         }
777 #endif
778
779         return 0;
780 }
781
782 static int kb_base_verify(struct fio_option *o, void *data)
783 {
784         struct thread_data *td = data;
785
786         if (td->o.kb_base != 1024 && td->o.kb_base != 1000) {
787                 log_err("fio: kb_base set to nonsensical value: %u\n",
788                                 td->o.kb_base);
789                 return 1;
790         }
791
792         return 0;
793 }
794
795 /*
796  * Option grouping
797  */
798 static struct opt_group fio_opt_groups[] = {
799         {
800                 .name   = "General",
801                 .mask   = FIO_OPT_C_GENERAL,
802         },
803         {
804                 .name   = "I/O",
805                 .mask   = FIO_OPT_C_IO,
806         },
807         {
808                 .name   = "File",
809                 .mask   = FIO_OPT_C_FILE,
810         },
811         {
812                 .name   = "Statistics",
813                 .mask   = FIO_OPT_C_STAT,
814         },
815         {
816                 .name   = "Logging",
817                 .mask   = FIO_OPT_C_LOG,
818         },
819         {
820                 .name   = NULL,
821         },
822 };
823
824 static struct opt_group *__opt_group_from_mask(struct opt_group *ogs, unsigned int *mask,
825                                                unsigned int inv_mask)
826 {
827         struct opt_group *og;
828         int i;
829
830         if (*mask == inv_mask || !*mask)
831                 return NULL;
832
833         for (i = 0; ogs[i].name; i++) {
834                 og = &ogs[i];
835
836                 if (*mask & og->mask) {
837                         *mask &= ~(og->mask);
838                         return og;
839                 }
840         }
841
842         return NULL;
843 }
844
845 struct opt_group *opt_group_from_mask(unsigned int *mask)
846 {
847         return __opt_group_from_mask(fio_opt_groups, mask, FIO_OPT_C_INVALID);
848 }
849
850 static struct opt_group fio_opt_cat_groups[] = {
851         {
852                 .name   = "Rate",
853                 .mask   = FIO_OPT_G_RATE,
854         },
855         {
856                 .name   = "Zone",
857                 .mask   = FIO_OPT_G_ZONE,
858         },
859         {
860                 .name   = "Read/write mix",
861                 .mask   = FIO_OPT_G_RWMIX,
862         },
863         {
864                 .name   = "Verify",
865                 .mask   = FIO_OPT_G_VERIFY,
866         },
867         {
868                 .name   = "Trim",
869                 .mask   = FIO_OPT_G_TRIM,
870         },
871         {
872                 .name   = "I/O Logging",
873                 .mask   = FIO_OPT_G_IOLOG,
874         },
875         {
876                 .name   = "I/O Depth",
877                 .mask   = FIO_OPT_G_IO_DEPTH,
878         },
879         {
880                 .name   = "I/O Flow",
881                 .mask   = FIO_OPT_G_IO_FLOW,
882         },
883         {
884                 .name   = "Description",
885                 .mask   = FIO_OPT_G_DESC,
886         },
887         {
888                 .name   = "Filename",
889                 .mask   = FIO_OPT_G_FILENAME,
890         },
891         {
892                 .name   = "General I/O",
893                 .mask   = FIO_OPT_G_IO_BASIC,
894         },
895         {
896                 .name   = "Cgroups",
897                 .mask   = FIO_OPT_G_CGROUP,
898         },
899         {
900                 .name   = "Runtime",
901                 .mask   = FIO_OPT_G_RUNTIME,
902         },
903         {
904                 .name   = "Process",
905                 .mask   = FIO_OPT_G_PROCESS,
906         },
907         {
908                 .name   = "Job credentials / priority",
909                 .mask   = FIO_OPT_G_CRED,
910         },
911         {
912                 .name   = "Clock settings",
913                 .mask   = FIO_OPT_G_CLOCK,
914         },
915         {
916                 .name   = "I/O Type",
917                 .mask   = FIO_OPT_G_IO_TYPE,
918         },
919         {
920                 .name   = "I/O Thinktime",
921                 .mask   = FIO_OPT_G_THINKTIME,
922         },
923         {
924                 .name   = "Randomizations",
925                 .mask   = FIO_OPT_G_RANDOM,
926         },
927         {
928                 .name   = "I/O buffers",
929                 .mask   = FIO_OPT_G_IO_BUF,
930         },
931         {
932                 .name   = NULL,
933         }
934 };
935
936 struct opt_group *opt_group_cat_from_mask(unsigned int *mask)
937 {
938         return __opt_group_from_mask(fio_opt_cat_groups, mask, FIO_OPT_G_INVALID);
939 }
940
941 /*
942  * Map of job/command line options
943  */
944 struct fio_option fio_options[FIO_MAX_OPTS] = {
945         {
946                 .name   = "description",
947                 .lname  = "Description of job",
948                 .type   = FIO_OPT_STR_STORE,
949                 .off1   = td_var_offset(description),
950                 .help   = "Text job description",
951                 .category = FIO_OPT_C_GENERAL,
952                 .group  = FIO_OPT_G_DESC,
953         },
954         {
955                 .name   = "name",
956                 .lname  = "Job name",
957                 .type   = FIO_OPT_STR_STORE,
958                 .off1   = td_var_offset(name),
959                 .help   = "Name of this job",
960                 .category = FIO_OPT_C_GENERAL,
961                 .group  = FIO_OPT_G_DESC,
962         },
963         {
964                 .name   = "filename",
965                 .lname  = "Filename(s)",
966                 .type   = FIO_OPT_STR_STORE,
967                 .off1   = td_var_offset(filename),
968                 .cb     = str_filename_cb,
969                 .prio   = -1, /* must come after "directory" */
970                 .help   = "File(s) to use for the workload",
971                 .category = FIO_OPT_C_FILE,
972                 .group  = FIO_OPT_G_FILENAME,
973         },
974         {
975                 .name   = "directory",
976                 .lname  = "Directory",
977                 .type   = FIO_OPT_STR_STORE,
978                 .off1   = td_var_offset(directory),
979                 .cb     = str_directory_cb,
980                 .help   = "Directory to store files in",
981                 .category = FIO_OPT_C_FILE,
982                 .group  = FIO_OPT_G_FILENAME,
983         },
984         {
985                 .name   = "lockfile",
986                 .lname  = "Lockfile",
987                 .type   = FIO_OPT_STR,
988                 .cb     = str_lockfile_cb,
989                 .off1   = td_var_offset(file_lock_mode),
990                 .help   = "Lock file when doing IO to it",
991                 .parent = "filename",
992                 .hide   = 0,
993                 .def    = "none",
994                 .category = FIO_OPT_C_FILE,
995                 .group  = FIO_OPT_G_FILENAME,
996                 .posval = {
997                           { .ival = "none",
998                             .oval = FILE_LOCK_NONE,
999                             .help = "No file locking",
1000                           },
1001                           { .ival = "exclusive",
1002                             .oval = FILE_LOCK_EXCLUSIVE,
1003                             .help = "Exclusive file lock",
1004                           },
1005                           {
1006                             .ival = "readwrite",
1007                             .oval = FILE_LOCK_READWRITE,
1008                             .help = "Read vs write lock",
1009                           },
1010                 },
1011         },
1012         {
1013                 .name   = "opendir",
1014                 .lname  = "Open directory",
1015                 .type   = FIO_OPT_STR_STORE,
1016                 .off1   = td_var_offset(opendir),
1017                 .cb     = str_opendir_cb,
1018                 .help   = "Recursively add files from this directory and down",
1019                 .category = FIO_OPT_C_FILE,
1020                 .group  = FIO_OPT_G_FILENAME,
1021         },
1022         {
1023                 .name   = "rw",
1024                 .lname  = "Read/write",
1025                 .alias  = "readwrite",
1026                 .type   = FIO_OPT_STR,
1027                 .cb     = str_rw_cb,
1028                 .off1   = td_var_offset(td_ddir),
1029                 .help   = "IO direction",
1030                 .def    = "read",
1031                 .verify = rw_verify,
1032                 .category = FIO_OPT_C_IO,
1033                 .group  = FIO_OPT_G_IO_BASIC,
1034                 .posval = {
1035                           { .ival = "read",
1036                             .oval = TD_DDIR_READ,
1037                             .help = "Sequential read",
1038                           },
1039                           { .ival = "write",
1040                             .oval = TD_DDIR_WRITE,
1041                             .help = "Sequential write",
1042                           },
1043                           { .ival = "randread",
1044                             .oval = TD_DDIR_RANDREAD,
1045                             .help = "Random read",
1046                           },
1047                           { .ival = "randwrite",
1048                             .oval = TD_DDIR_RANDWRITE,
1049                             .help = "Random write",
1050                           },
1051                           { .ival = "rw",
1052                             .oval = TD_DDIR_RW,
1053                             .help = "Sequential read and write mix",
1054                           },
1055                           { .ival = "randrw",
1056                             .oval = TD_DDIR_RANDRW,
1057                             .help = "Random read and write mix"
1058                           },
1059                 },
1060         },
1061         {
1062                 .name   = "rw_sequencer",
1063                 .lname  = "RW Sequencer",
1064                 .type   = FIO_OPT_STR,
1065                 .off1   = td_var_offset(rw_seq),
1066                 .help   = "IO offset generator modifier",
1067                 .def    = "sequential",
1068                 .category = FIO_OPT_C_IO,
1069                 .group  = FIO_OPT_G_IO_BASIC,
1070                 .posval = {
1071                           { .ival = "sequential",
1072                             .oval = RW_SEQ_SEQ,
1073                             .help = "Generate sequential offsets",
1074                           },
1075                           { .ival = "identical",
1076                             .oval = RW_SEQ_IDENT,
1077                             .help = "Generate identical offsets",
1078                           },
1079                 },
1080         },
1081
1082         {
1083                 .name   = "ioengine",
1084                 .lname  = "IO Engine",
1085                 .type   = FIO_OPT_STR_STORE,
1086                 .off1   = td_var_offset(ioengine),
1087                 .help   = "IO engine to use",
1088                 .def    = FIO_PREFERRED_ENGINE,
1089                 .category = FIO_OPT_C_IO,
1090                 .group  = FIO_OPT_G_IO_BASIC,
1091                 .posval = {
1092                           { .ival = "sync",
1093                             .help = "Use read/write",
1094                           },
1095                           { .ival = "psync",
1096                             .help = "Use pread/pwrite",
1097                           },
1098                           { .ival = "vsync",
1099                             .help = "Use readv/writev",
1100                           },
1101 #ifdef FIO_HAVE_LIBAIO
1102                           { .ival = "libaio",
1103                             .help = "Linux native asynchronous IO",
1104                           },
1105 #endif
1106 #ifdef FIO_HAVE_POSIXAIO
1107                           { .ival = "posixaio",
1108                             .help = "POSIX asynchronous IO",
1109                           },
1110 #endif
1111 #ifdef FIO_HAVE_SOLARISAIO
1112                           { .ival = "solarisaio",
1113                             .help = "Solaris native asynchronous IO",
1114                           },
1115 #endif
1116 #ifdef FIO_HAVE_WINDOWSAIO
1117                           { .ival = "windowsaio",
1118                             .help = "Windows native asynchronous IO"
1119                           },
1120 #endif
1121                           { .ival = "mmap",
1122                             .help = "Memory mapped IO"
1123                           },
1124 #ifdef FIO_HAVE_SPLICE
1125                           { .ival = "splice",
1126                             .help = "splice/vmsplice based IO",
1127                           },
1128                           { .ival = "netsplice",
1129                             .help = "splice/vmsplice to/from the network",
1130                           },
1131 #endif
1132 #ifdef FIO_HAVE_SGIO
1133                           { .ival = "sg",
1134                             .help = "SCSI generic v3 IO",
1135                           },
1136 #endif
1137                           { .ival = "null",
1138                             .help = "Testing engine (no data transfer)",
1139                           },
1140                           { .ival = "net",
1141                             .help = "Network IO",
1142                           },
1143 #ifdef FIO_HAVE_SYSLET
1144                           { .ival = "syslet-rw",
1145                             .help = "syslet enabled async pread/pwrite IO",
1146                           },
1147 #endif
1148                           { .ival = "cpuio",
1149                             .help = "CPU cycle burner engine",
1150                           },
1151 #ifdef FIO_HAVE_GUASI
1152                           { .ival = "guasi",
1153                             .help = "GUASI IO engine",
1154                           },
1155 #endif
1156 #ifdef FIO_HAVE_BINJECT
1157                           { .ival = "binject",
1158                             .help = "binject direct inject block engine",
1159                           },
1160 #endif
1161 #ifdef FIO_HAVE_RDMA
1162                           { .ival = "rdma",
1163                             .help = "RDMA IO engine",
1164                           },
1165 #endif
1166                           { .ival = "external",
1167                             .help = "Load external engine (append name)",
1168                           },
1169                 },
1170         },
1171         {
1172                 .name   = "iodepth",
1173                 .lname  = "IO Depth",
1174                 .type   = FIO_OPT_INT,
1175                 .off1   = td_var_offset(iodepth),
1176                 .help   = "Number of IO buffers to keep in flight",
1177                 .minval = 1,
1178                 .interval = 1,
1179                 .def    = "1",
1180                 .category = FIO_OPT_C_IO,
1181                 .group  = FIO_OPT_G_IO_BASIC,
1182         },
1183         {
1184                 .name   = "iodepth_batch",
1185                 .lname  = "IO Depth batch",
1186                 .alias  = "iodepth_batch_submit",
1187                 .type   = FIO_OPT_INT,
1188                 .off1   = td_var_offset(iodepth_batch),
1189                 .help   = "Number of IO buffers to submit in one go",
1190                 .parent = "iodepth",
1191                 .hide   = 1,
1192                 .minval = 1,
1193                 .interval = 1,
1194                 .def    = "1",
1195                 .category = FIO_OPT_C_IO,
1196                 .group  = FIO_OPT_G_IO_BASIC,
1197         },
1198         {
1199                 .name   = "iodepth_batch_complete",
1200                 .lname  = "IO Depth batch complete",
1201                 .type   = FIO_OPT_INT,
1202                 .off1   = td_var_offset(iodepth_batch_complete),
1203                 .help   = "Number of IO buffers to retrieve in one go",
1204                 .parent = "iodepth",
1205                 .hide   = 1,
1206                 .minval = 0,
1207                 .interval = 1,
1208                 .def    = "1",
1209                 .category = FIO_OPT_C_IO,
1210                 .group  = FIO_OPT_G_IO_BASIC,
1211         },
1212         {
1213                 .name   = "iodepth_low",
1214                 .lname  = "IO Depth batch low",
1215                 .type   = FIO_OPT_INT,
1216                 .off1   = td_var_offset(iodepth_low),
1217                 .help   = "Low water mark for queuing depth",
1218                 .parent = "iodepth",
1219                 .hide   = 1,
1220                 .interval = 1,
1221                 .category = FIO_OPT_C_IO,
1222                 .group  = FIO_OPT_G_IO_BASIC,
1223         },
1224         {
1225                 .name   = "size",
1226                 .lname  = "Size",
1227                 .type   = FIO_OPT_STR_VAL,
1228                 .cb     = str_size_cb,
1229                 .help   = "Total size of device or files",
1230                 .interval = 1024 * 1024,
1231                 .category = FIO_OPT_C_IO,
1232                 .group  = FIO_OPT_G_INVALID,
1233         },
1234         {
1235                 .name   = "fill_device",
1236                 .lname  = "Fill device",
1237                 .alias  = "fill_fs",
1238                 .type   = FIO_OPT_BOOL,
1239                 .off1   = td_var_offset(fill_device),
1240                 .help   = "Write until an ENOSPC error occurs",
1241                 .def    = "0",
1242                 .category = FIO_OPT_C_FILE,
1243                 .group  = FIO_OPT_G_INVALID,
1244         },
1245         {
1246                 .name   = "filesize",
1247                 .lname  = "File size",
1248                 .type   = FIO_OPT_STR_VAL,
1249                 .off1   = td_var_offset(file_size_low),
1250                 .off2   = td_var_offset(file_size_high),
1251                 .minval = 1,
1252                 .help   = "Size of individual files",
1253                 .interval = 1024 * 1024,
1254                 .category = FIO_OPT_C_FILE,
1255                 .group  = FIO_OPT_G_INVALID,
1256         },
1257         {
1258                 .name   = "offset",
1259                 .lname  = "IO offset",
1260                 .alias  = "fileoffset",
1261                 .type   = FIO_OPT_STR_VAL,
1262                 .off1   = td_var_offset(start_offset),
1263                 .help   = "Start IO from this offset",
1264                 .def    = "0",
1265                 .interval = 1024 * 1024,
1266                 .category = FIO_OPT_C_IO,
1267                 .group  = FIO_OPT_G_INVALID,
1268         },
1269         {
1270                 .name   = "offset_increment",
1271                 .lname  = "IO offset increment",
1272                 .type   = FIO_OPT_STR_VAL,
1273                 .off1   = td_var_offset(offset_increment),
1274                 .help   = "What is the increment from one offset to the next",
1275                 .parent = "offset",
1276                 .hide   = 1,
1277                 .def    = "0",
1278                 .interval = 1024 * 1024,
1279                 .category = FIO_OPT_C_IO,
1280                 .group  = FIO_OPT_G_INVALID,
1281         },
1282         {
1283                 .name   = "bs",
1284                 .lname  = "Block size",
1285                 .alias  = "blocksize",
1286                 .type   = FIO_OPT_INT,
1287                 .off1   = td_var_offset(bs[DDIR_READ]),
1288                 .off2   = td_var_offset(bs[DDIR_WRITE]),
1289                 .minval = 1,
1290                 .help   = "Block size unit",
1291                 .def    = "4k",
1292                 .parent = "rw",
1293                 .hide   = 1,
1294                 .interval = 512,
1295                 .category = FIO_OPT_C_IO,
1296                 .group  = FIO_OPT_G_INVALID,
1297         },
1298         {
1299                 .name   = "ba",
1300                 .lname  = "Block size align",
1301                 .alias  = "blockalign",
1302                 .type   = FIO_OPT_INT,
1303                 .off1   = td_var_offset(ba[DDIR_READ]),
1304                 .off2   = td_var_offset(ba[DDIR_WRITE]),
1305                 .minval = 1,
1306                 .help   = "IO block offset alignment",
1307                 .parent = "rw",
1308                 .hide   = 1,
1309                 .interval = 512,
1310                 .category = FIO_OPT_C_IO,
1311                 .group  = FIO_OPT_G_INVALID,
1312         },
1313         {
1314                 .name   = "bsrange",
1315                 .lname  = "Block size range",
1316                 .alias  = "blocksize_range",
1317                 .type   = FIO_OPT_RANGE,
1318                 .off1   = td_var_offset(min_bs[DDIR_READ]),
1319                 .off2   = td_var_offset(max_bs[DDIR_READ]),
1320                 .off3   = td_var_offset(min_bs[DDIR_WRITE]),
1321                 .off4   = td_var_offset(max_bs[DDIR_WRITE]),
1322                 .minval = 1,
1323                 .help   = "Set block size range (in more detail than bs)",
1324                 .parent = "rw",
1325                 .hide   = 1,
1326                 .interval = 4096,
1327                 .category = FIO_OPT_C_IO,
1328                 .group  = FIO_OPT_G_INVALID,
1329         },
1330         {
1331                 .name   = "bssplit",
1332                 .lname  = "Block size split",
1333                 .type   = FIO_OPT_STR,
1334                 .cb     = str_bssplit_cb,
1335                 .help   = "Set a specific mix of block sizes",
1336                 .parent = "rw",
1337                 .hide   = 1,
1338                 .category = FIO_OPT_C_IO,
1339                 .group  = FIO_OPT_G_INVALID,
1340         },
1341         {
1342                 .name   = "bs_unaligned",
1343                 .lname  = "Block size unaligned",
1344                 .alias  = "blocksize_unaligned",
1345                 .type   = FIO_OPT_STR_SET,
1346                 .off1   = td_var_offset(bs_unaligned),
1347                 .help   = "Don't sector align IO buffer sizes",
1348                 .parent = "rw",
1349                 .hide   = 1,
1350                 .category = FIO_OPT_C_IO,
1351                 .group  = FIO_OPT_G_INVALID,
1352         },
1353         {
1354                 .name   = "randrepeat",
1355                 .lname  = "Random repeatable",
1356                 .type   = FIO_OPT_BOOL,
1357                 .off1   = td_var_offset(rand_repeatable),
1358                 .help   = "Use repeatable random IO pattern",
1359                 .def    = "1",
1360                 .parent = "rw",
1361                 .hide   = 1,
1362                 .category = FIO_OPT_C_IO,
1363                 .group  = FIO_OPT_G_RANDOM,
1364         },
1365         {
1366                 .name   = "use_os_rand",
1367                 .lname  = "Use OS random",
1368                 .type   = FIO_OPT_BOOL,
1369                 .off1   = td_var_offset(use_os_rand),
1370                 .help   = "Set to use OS random generator",
1371                 .def    = "0",
1372                 .parent = "rw",
1373                 .hide   = 1,
1374                 .category = FIO_OPT_C_IO,
1375                 .group  = FIO_OPT_G_RANDOM,
1376         },
1377         {
1378                 .name   = "norandommap",
1379                 .lname  = "No randommap",
1380                 .type   = FIO_OPT_STR_SET,
1381                 .off1   = td_var_offset(norandommap),
1382                 .help   = "Accept potential duplicate random blocks",
1383                 .parent = "rw",
1384                 .hide   = 1,
1385                 .hide_on_set = 1,
1386                 .category = FIO_OPT_C_IO,
1387                 .group  = FIO_OPT_G_RANDOM,
1388         },
1389         {
1390                 .name   = "softrandommap",
1391                 .lname  = "Soft randommap",
1392                 .type   = FIO_OPT_BOOL,
1393                 .off1   = td_var_offset(softrandommap),
1394                 .help   = "Set norandommap if randommap allocation fails",
1395                 .parent = "norandommap",
1396                 .hide   = 1,
1397                 .def    = "0",
1398                 .category = FIO_OPT_C_IO,
1399                 .group  = FIO_OPT_G_RANDOM,
1400         },
1401         {
1402                 .name   = "nrfiles",
1403                 .lname  = "Number of files",
1404                 .alias  = "nr_files",
1405                 .type   = FIO_OPT_INT,
1406                 .off1   = td_var_offset(nr_files),
1407                 .help   = "Split job workload between this number of files",
1408                 .def    = "1",
1409                 .interval = 1,
1410                 .category = FIO_OPT_C_FILE,
1411                 .group  = FIO_OPT_G_INVALID,
1412         },
1413         {
1414                 .name   = "openfiles",
1415                 .lname  = "Number of open files",
1416                 .type   = FIO_OPT_INT,
1417                 .off1   = td_var_offset(open_files),
1418                 .help   = "Number of files to keep open at the same time",
1419                 .category = FIO_OPT_C_FILE,
1420                 .group  = FIO_OPT_G_INVALID,
1421         },
1422         {
1423                 .name   = "file_service_type",
1424                 .lname  = "File service type",
1425                 .type   = FIO_OPT_STR,
1426                 .cb     = str_fst_cb,
1427                 .off1   = td_var_offset(file_service_type),
1428                 .help   = "How to select which file to service next",
1429                 .def    = "roundrobin",
1430                 .category = FIO_OPT_C_FILE,
1431                 .group  = FIO_OPT_G_INVALID,
1432                 .posval = {
1433                           { .ival = "random",
1434                             .oval = FIO_FSERVICE_RANDOM,
1435                             .help = "Choose a file at random",
1436                           },
1437                           { .ival = "roundrobin",
1438                             .oval = FIO_FSERVICE_RR,
1439                             .help = "Round robin select files",
1440                           },
1441                           { .ival = "sequential",
1442                             .oval = FIO_FSERVICE_SEQ,
1443                             .help = "Finish one file before moving to the next",
1444                           },
1445                 },
1446                 .parent = "nrfiles",
1447                 .hide   = 1,
1448         },
1449 #ifdef FIO_HAVE_FALLOCATE
1450         {
1451                 .name   = "fallocate",
1452                 .lname  = "Fallocate",
1453                 .type   = FIO_OPT_STR,
1454                 .off1   = td_var_offset(fallocate_mode),
1455                 .help   = "Whether pre-allocation is performed when laying out files",
1456                 .def    = "posix",
1457                 .category = FIO_OPT_C_FILE,
1458                 .group  = FIO_OPT_G_INVALID,
1459                 .posval = {
1460                           { .ival = "none",
1461                             .oval = FIO_FALLOCATE_NONE,
1462                             .help = "Do not pre-allocate space",
1463                           },
1464                           { .ival = "posix",
1465                             .oval = FIO_FALLOCATE_POSIX,
1466                             .help = "Use posix_fallocate()",
1467                           },
1468 #ifdef FIO_HAVE_LINUX_FALLOCATE
1469                           { .ival = "keep",
1470                             .oval = FIO_FALLOCATE_KEEP_SIZE,
1471                             .help = "Use fallocate(..., FALLOC_FL_KEEP_SIZE, ...)",
1472                           },
1473 #endif
1474                           /* Compatibility with former boolean values */
1475                           { .ival = "0",
1476                             .oval = FIO_FALLOCATE_NONE,
1477                             .help = "Alias for 'none'",
1478                           },
1479                           { .ival = "1",
1480                             .oval = FIO_FALLOCATE_POSIX,
1481                             .help = "Alias for 'posix'",
1482                           },
1483                 },
1484         },
1485 #endif  /* FIO_HAVE_FALLOCATE */
1486         {
1487                 .name   = "fadvise_hint",
1488                 .lname  = "Fadvise hint",
1489                 .type   = FIO_OPT_BOOL,
1490                 .off1   = td_var_offset(fadvise_hint),
1491                 .help   = "Use fadvise() to advise the kernel on IO pattern",
1492                 .def    = "1",
1493                 .category = FIO_OPT_C_FILE,
1494                 .group  = FIO_OPT_G_INVALID,
1495         },
1496         {
1497                 .name   = "fsync",
1498                 .lname  = "Fsync",
1499                 .type   = FIO_OPT_INT,
1500                 .off1   = td_var_offset(fsync_blocks),
1501                 .help   = "Issue fsync for writes every given number of blocks",
1502                 .def    = "0",
1503                 .interval = 1,
1504                 .category = FIO_OPT_C_FILE,
1505                 .group  = FIO_OPT_G_INVALID,
1506         },
1507         {
1508                 .name   = "fdatasync",
1509                 .lname  = "Fdatasync",
1510                 .type   = FIO_OPT_INT,
1511                 .off1   = td_var_offset(fdatasync_blocks),
1512                 .help   = "Issue fdatasync for writes every given number of blocks",
1513                 .def    = "0",
1514                 .interval = 1,
1515                 .category = FIO_OPT_C_FILE,
1516                 .group  = FIO_OPT_G_INVALID,
1517         },
1518         {
1519                 .name   = "write_barrier",
1520                 .lname  = "Write barrier",
1521                 .type   = FIO_OPT_INT,
1522                 .off1   = td_var_offset(barrier_blocks),
1523                 .help   = "Make every Nth write a barrier write",
1524                 .def    = "0",
1525                 .interval = 1,
1526                 .category = FIO_OPT_C_IO,
1527                 .group  = FIO_OPT_G_INVALID,
1528         },
1529 #ifdef FIO_HAVE_SYNC_FILE_RANGE
1530         {
1531                 .name   = "sync_file_range",
1532                 .lname  = "Sync file range",
1533                 .posval = {
1534                           { .ival = "wait_before",
1535                             .oval = SYNC_FILE_RANGE_WAIT_BEFORE,
1536                             .help = "SYNC_FILE_RANGE_WAIT_BEFORE",
1537                             .or   = 1,
1538                           },
1539                           { .ival = "write",
1540                             .oval = SYNC_FILE_RANGE_WRITE,
1541                             .help = "SYNC_FILE_RANGE_WRITE",
1542                             .or   = 1,
1543                           },
1544                           {
1545                             .ival = "wait_after",
1546                             .oval = SYNC_FILE_RANGE_WAIT_AFTER,
1547                             .help = "SYNC_FILE_RANGE_WAIT_AFTER",
1548                             .or   = 1,
1549                           },
1550                 },
1551                 .type   = FIO_OPT_STR_MULTI,
1552                 .cb     = str_sfr_cb,
1553                 .off1   = td_var_offset(sync_file_range),
1554                 .help   = "Use sync_file_range()",
1555                 .category = FIO_OPT_C_FILE,
1556                 .group  = FIO_OPT_G_INVALID,
1557         },
1558 #endif
1559         {
1560                 .name   = "direct",
1561                 .lname  = "Direct I/O",
1562                 .type   = FIO_OPT_BOOL,
1563                 .off1   = td_var_offset(odirect),
1564                 .help   = "Use O_DIRECT IO (negates buffered)",
1565                 .def    = "0",
1566                 .inverse = "buffered",
1567                 .category = FIO_OPT_C_IO,
1568                 .group  = FIO_OPT_G_IO_TYPE,
1569         },
1570         {
1571                 .name   = "buffered",
1572                 .lname  = "Buffered I/O",
1573                 .type   = FIO_OPT_BOOL,
1574                 .off1   = td_var_offset(odirect),
1575                 .neg    = 1,
1576                 .help   = "Use buffered IO (negates direct)",
1577                 .def    = "1",
1578                 .inverse = "direct",
1579                 .category = FIO_OPT_C_IO,
1580                 .group  = FIO_OPT_G_IO_TYPE,
1581         },
1582         {
1583                 .name   = "overwrite",
1584                 .lname  = "Overwrite",
1585                 .type   = FIO_OPT_BOOL,
1586                 .off1   = td_var_offset(overwrite),
1587                 .help   = "When writing, set whether to overwrite current data",
1588                 .def    = "0",
1589                 .category = FIO_OPT_C_FILE,
1590                 .group  = FIO_OPT_G_INVALID,
1591         },
1592         {
1593                 .name   = "loops",
1594                 .lname  = "Loops",
1595                 .type   = FIO_OPT_INT,
1596                 .off1   = td_var_offset(loops),
1597                 .help   = "Number of times to run the job",
1598                 .def    = "1",
1599                 .interval = 1,
1600                 .category = FIO_OPT_C_GENERAL,
1601                 .group  = FIO_OPT_G_RUNTIME,
1602         },
1603         {
1604                 .name   = "numjobs",
1605                 .lname  = "Number of jobs",
1606                 .type   = FIO_OPT_INT,
1607                 .off1   = td_var_offset(numjobs),
1608                 .help   = "Duplicate this job this many times",
1609                 .def    = "1",
1610                 .interval = 1,
1611                 .category = FIO_OPT_C_GENERAL,
1612                 .group  = FIO_OPT_G_RUNTIME,
1613         },
1614         {
1615                 .name   = "startdelay",
1616                 .lname  = "Start delay",
1617                 .type   = FIO_OPT_STR_VAL_TIME,
1618                 .off1   = td_var_offset(start_delay),
1619                 .help   = "Only start job when this period has passed",
1620                 .def    = "0",
1621                 .category = FIO_OPT_C_GENERAL,
1622                 .group  = FIO_OPT_G_RUNTIME,
1623         },
1624         {
1625                 .name   = "runtime",
1626                 .lname  = "Runtime",
1627                 .alias  = "timeout",
1628                 .type   = FIO_OPT_STR_VAL_TIME,
1629                 .off1   = td_var_offset(timeout),
1630                 .help   = "Stop workload when this amount of time has passed",
1631                 .def    = "0",
1632                 .category = FIO_OPT_C_GENERAL,
1633                 .group  = FIO_OPT_G_RUNTIME,
1634         },
1635         {
1636                 .name   = "time_based",
1637                 .lname  = "Time based",
1638                 .type   = FIO_OPT_STR_SET,
1639                 .off1   = td_var_offset(time_based),
1640                 .help   = "Keep running until runtime/timeout is met",
1641                 .category = FIO_OPT_C_GENERAL,
1642                 .group  = FIO_OPT_G_RUNTIME,
1643         },
1644         {
1645                 .name   = "ramp_time",
1646                 .lname  = "Ramp time",
1647                 .type   = FIO_OPT_STR_VAL_TIME,
1648                 .off1   = td_var_offset(ramp_time),
1649                 .help   = "Ramp up time before measuring performance",
1650                 .category = FIO_OPT_C_GENERAL,
1651                 .group  = FIO_OPT_G_RUNTIME,
1652         },
1653         {
1654                 .name   = "clocksource",
1655                 .lname  = "Clock source",
1656                 .type   = FIO_OPT_STR,
1657                 .cb     = fio_clock_source_cb,
1658                 .off1   = td_var_offset(clocksource),
1659                 .help   = "What type of timing source to use",
1660                 .category = FIO_OPT_C_GENERAL,
1661                 .group  = FIO_OPT_G_CLOCK,
1662                 .posval = {
1663                           { .ival = "gettimeofday",
1664                             .oval = CS_GTOD,
1665                             .help = "Use gettimeofday(2) for timing",
1666                           },
1667                           { .ival = "clock_gettime",
1668                             .oval = CS_CGETTIME,
1669                             .help = "Use clock_gettime(2) for timing",
1670                           },
1671 #ifdef ARCH_HAVE_CPU_CLOCK
1672                           { .ival = "cpu",
1673                             .oval = CS_CPUCLOCK,
1674                             .help = "Use CPU private clock",
1675                           },
1676 #endif
1677                 },
1678         },
1679         {
1680                 .name   = "mem",
1681                 .alias  = "iomem",
1682                 .lname  = "I/O Memory",
1683                 .type   = FIO_OPT_STR,
1684                 .cb     = str_mem_cb,
1685                 .off1   = td_var_offset(mem_type),
1686                 .help   = "Backing type for IO buffers",
1687                 .def    = "malloc",
1688                 .category = FIO_OPT_C_IO,
1689                 .group  = FIO_OPT_G_INVALID,
1690                 .posval = {
1691                           { .ival = "malloc",
1692                             .oval = MEM_MALLOC,
1693                             .help = "Use malloc(3) for IO buffers",
1694                           },
1695                           { .ival = "shm",
1696                             .oval = MEM_SHM,
1697                             .help = "Use shared memory segments for IO buffers",
1698                           },
1699 #ifdef FIO_HAVE_HUGETLB
1700                           { .ival = "shmhuge",
1701                             .oval = MEM_SHMHUGE,
1702                             .help = "Like shm, but use huge pages",
1703                           },
1704 #endif
1705                           { .ival = "mmap",
1706                             .oval = MEM_MMAP,
1707                             .help = "Use mmap(2) (file or anon) for IO buffers",
1708                           },
1709 #ifdef FIO_HAVE_HUGETLB
1710                           { .ival = "mmaphuge",
1711                             .oval = MEM_MMAPHUGE,
1712                             .help = "Like mmap, but use huge pages",
1713                           },
1714 #endif
1715                   },
1716         },
1717         {
1718                 .name   = "iomem_align",
1719                 .alias  = "mem_align",
1720                 .lname  = "I/O memory alignment",
1721                 .type   = FIO_OPT_INT,
1722                 .off1   = td_var_offset(mem_align),
1723                 .minval = 0,
1724                 .help   = "IO memory buffer offset alignment",
1725                 .def    = "0",
1726                 .parent = "iomem",
1727                 .hide   = 1,
1728                 .category = FIO_OPT_C_IO,
1729                 .group  = FIO_OPT_G_INVALID,
1730         },
1731         {
1732                 .name   = "verify",
1733                 .lname  = "Verify",
1734                 .type   = FIO_OPT_STR,
1735                 .off1   = td_var_offset(verify),
1736                 .help   = "Verify data written",
1737                 .def    = "0",
1738                 .category = FIO_OPT_C_IO,
1739                 .group  = FIO_OPT_G_VERIFY,
1740                 .posval = {
1741                           { .ival = "0",
1742                             .oval = VERIFY_NONE,
1743                             .help = "Don't do IO verification",
1744                           },
1745                           { .ival = "md5",
1746                             .oval = VERIFY_MD5,
1747                             .help = "Use md5 checksums for verification",
1748                           },
1749                           { .ival = "crc64",
1750                             .oval = VERIFY_CRC64,
1751                             .help = "Use crc64 checksums for verification",
1752                           },
1753                           { .ival = "crc32",
1754                             .oval = VERIFY_CRC32,
1755                             .help = "Use crc32 checksums for verification",
1756                           },
1757                           { .ival = "crc32c-intel",
1758                             .oval = VERIFY_CRC32C,
1759                             .help = "Use crc32c checksums for verification (hw assisted, if available)",
1760                           },
1761                           { .ival = "crc32c",
1762                             .oval = VERIFY_CRC32C,
1763                             .help = "Use crc32c checksums for verification (hw assisted, if available)",
1764                           },
1765                           { .ival = "crc16",
1766                             .oval = VERIFY_CRC16,
1767                             .help = "Use crc16 checksums for verification",
1768                           },
1769                           { .ival = "crc7",
1770                             .oval = VERIFY_CRC7,
1771                             .help = "Use crc7 checksums for verification",
1772                           },
1773                           { .ival = "sha1",
1774                             .oval = VERIFY_SHA1,
1775                             .help = "Use sha1 checksums for verification",
1776                           },
1777                           { .ival = "sha256",
1778                             .oval = VERIFY_SHA256,
1779                             .help = "Use sha256 checksums for verification",
1780                           },
1781                           { .ival = "sha512",
1782                             .oval = VERIFY_SHA512,
1783                             .help = "Use sha512 checksums for verification",
1784                           },
1785                           { .ival = "meta",
1786                             .oval = VERIFY_META,
1787                             .help = "Use io information",
1788                           },
1789                           {
1790                             .ival = "null",
1791                             .oval = VERIFY_NULL,
1792                             .help = "Pretend to verify",
1793                           },
1794                 },
1795         },
1796         {
1797                 .name   = "do_verify",
1798                 .lname  = "Perform verify step",
1799                 .type   = FIO_OPT_BOOL,
1800                 .off1   = td_var_offset(do_verify),
1801                 .help   = "Run verification stage after write",
1802                 .def    = "1",
1803                 .parent = "verify",
1804                 .hide   = 1,
1805                 .category = FIO_OPT_C_IO,
1806                 .group  = FIO_OPT_G_VERIFY,
1807         },
1808         {
1809                 .name   = "verifysort",
1810                 .lname  = "Verify sort",
1811                 .type   = FIO_OPT_BOOL,
1812                 .off1   = td_var_offset(verifysort),
1813                 .help   = "Sort written verify blocks for read back",
1814                 .def    = "1",
1815                 .parent = "verify",
1816                 .hide   = 1,
1817                 .category = FIO_OPT_C_IO,
1818                 .group  = FIO_OPT_G_VERIFY,
1819         },
1820         {
1821                 .name   = "verify_interval",
1822                 .lname  = "Verify interval",
1823                 .type   = FIO_OPT_INT,
1824                 .off1   = td_var_offset(verify_interval),
1825                 .minval = 2 * sizeof(struct verify_header),
1826                 .help   = "Store verify buffer header every N bytes",
1827                 .parent = "verify",
1828                 .hide   = 1,
1829                 .interval = 2 * sizeof(struct verify_header),
1830                 .category = FIO_OPT_C_IO,
1831                 .group  = FIO_OPT_G_VERIFY,
1832         },
1833         {
1834                 .name   = "verify_offset",
1835                 .lname  = "Verify offset",
1836                 .type   = FIO_OPT_INT,
1837                 .help   = "Offset verify header location by N bytes",
1838                 .def    = "0",
1839                 .cb     = str_verify_offset_cb,
1840                 .parent = "verify",
1841                 .hide   = 1,
1842                 .category = FIO_OPT_C_IO,
1843                 .group  = FIO_OPT_G_VERIFY,
1844         },
1845         {
1846                 .name   = "verify_pattern",
1847                 .lname  = "Verify pattern",
1848                 .type   = FIO_OPT_STR,
1849                 .cb     = str_verify_pattern_cb,
1850                 .help   = "Fill pattern for IO buffers",
1851                 .parent = "verify",
1852                 .hide   = 1,
1853                 .category = FIO_OPT_C_IO,
1854                 .group  = FIO_OPT_G_VERIFY,
1855         },
1856         {
1857                 .name   = "verify_fatal",
1858                 .lname  = "Verify fatal",
1859                 .type   = FIO_OPT_BOOL,
1860                 .off1   = td_var_offset(verify_fatal),
1861                 .def    = "0",
1862                 .help   = "Exit on a single verify failure, don't continue",
1863                 .parent = "verify",
1864                 .hide   = 1,
1865                 .category = FIO_OPT_C_IO,
1866                 .group  = FIO_OPT_G_VERIFY,
1867         },
1868         {
1869                 .name   = "verify_dump",
1870                 .lname  = "Verify dump",
1871                 .type   = FIO_OPT_BOOL,
1872                 .off1   = td_var_offset(verify_dump),
1873                 .def    = "0",
1874                 .help   = "Dump contents of good and bad blocks on failure",
1875                 .parent = "verify",
1876                 .hide   = 1,
1877                 .category = FIO_OPT_C_IO,
1878                 .group  = FIO_OPT_G_VERIFY,
1879         },
1880         {
1881                 .name   = "verify_async",
1882                 .lname  = "Verify asynchronously",
1883                 .type   = FIO_OPT_INT,
1884                 .off1   = td_var_offset(verify_async),
1885                 .def    = "0",
1886                 .help   = "Number of async verifier threads to use",
1887                 .parent = "verify",
1888                 .hide   = 1,
1889                 .category = FIO_OPT_C_IO,
1890                 .group  = FIO_OPT_G_VERIFY,
1891         },
1892         {
1893                 .name   = "verify_backlog",
1894                 .lname  = "Verify backlog",
1895                 .type   = FIO_OPT_STR_VAL,
1896                 .off1   = td_var_offset(verify_backlog),
1897                 .help   = "Verify after this number of blocks are written",
1898                 .parent = "verify",
1899                 .hide   = 1,
1900                 .category = FIO_OPT_C_IO,
1901                 .group  = FIO_OPT_G_VERIFY,
1902         },
1903         {
1904                 .name   = "verify_backlog_batch",
1905                 .lname  = "Verify backlog batch",
1906                 .type   = FIO_OPT_INT,
1907                 .off1   = td_var_offset(verify_batch),
1908                 .help   = "Verify this number of IO blocks",
1909                 .parent = "verify",
1910                 .hide   = 1,
1911                 .category = FIO_OPT_C_IO,
1912                 .group  = FIO_OPT_G_VERIFY,
1913         },
1914 #ifdef FIO_HAVE_CPU_AFFINITY
1915         {
1916                 .name   = "verify_async_cpus",
1917                 .lname  = "Async verify CPUs",
1918                 .type   = FIO_OPT_STR,
1919                 .cb     = str_verify_cpus_allowed_cb,
1920                 .help   = "Set CPUs allowed for async verify threads",
1921                 .parent = "verify_async",
1922                 .hide   = 1,
1923                 .category = FIO_OPT_C_IO,
1924                 .group  = FIO_OPT_G_VERIFY,
1925         },
1926 #endif
1927 #ifdef FIO_HAVE_TRIM
1928         {
1929                 .name   = "trim_percentage",
1930                 .lname  = "Trim percentage",
1931                 .type   = FIO_OPT_INT,
1932                 .cb     = str_verify_trim_cb,
1933                 .minval = 0,
1934                 .maxval = 100,
1935                 .help   = "Number of verify blocks to discard/trim",
1936                 .parent = "verify",
1937                 .def    = "0",
1938                 .interval = 1,
1939                 .hide   = 1,
1940                 .category = FIO_OPT_C_IO,
1941                 .group  = FIO_OPT_G_TRIM,
1942         },
1943         {
1944                 .name   = "trim_verify_zero",
1945                 .lname  = "Verify trim zero",
1946                 .type   = FIO_OPT_BOOL,
1947                 .help   = "Verify that trim/discarded blocks are returned as zeroes",
1948                 .off1   = td_var_offset(trim_zero),
1949                 .parent = "trim_percentage",
1950                 .hide   = 1,
1951                 .def    = "1",
1952                 .category = FIO_OPT_C_IO,
1953                 .group  = FIO_OPT_G_TRIM,
1954         },
1955         {
1956                 .name   = "trim_backlog",
1957                 .lname  = "Trim backlog",
1958                 .type   = FIO_OPT_STR_VAL,
1959                 .off1   = td_var_offset(trim_backlog),
1960                 .help   = "Trim after this number of blocks are written",
1961                 .parent = "trim_percentage",
1962                 .hide   = 1,
1963                 .interval = 1,
1964                 .category = FIO_OPT_C_IO,
1965                 .group  = FIO_OPT_G_TRIM,
1966         },
1967         {
1968                 .name   = "trim_backlog_batch",
1969                 .lname  = "Trim backlog batch",
1970                 .type   = FIO_OPT_INT,
1971                 .off1   = td_var_offset(trim_batch),
1972                 .help   = "Trim this number of IO blocks",
1973                 .parent = "trim_percentage",
1974                 .hide   = 1,
1975                 .interval = 1,
1976                 .category = FIO_OPT_C_IO,
1977                 .group  = FIO_OPT_G_TRIM,
1978         },
1979 #endif
1980         {
1981                 .name   = "write_iolog",
1982                 .lname  = "Write I/O log",
1983                 .type   = FIO_OPT_STR_STORE,
1984                 .off1   = td_var_offset(write_iolog_file),
1985                 .help   = "Store IO pattern to file",
1986                 .category = FIO_OPT_C_IO,
1987                 .group  = FIO_OPT_G_IOLOG,
1988         },
1989         {
1990                 .name   = "read_iolog",
1991                 .lname  = "Read I/O log",
1992                 .type   = FIO_OPT_STR_STORE,
1993                 .off1   = td_var_offset(read_iolog_file),
1994                 .help   = "Playback IO pattern from file",
1995                 .category = FIO_OPT_C_IO,
1996                 .group  = FIO_OPT_G_IOLOG,
1997         },
1998         {
1999                 .name   = "replay_no_stall",
2000                 .lname  = "Don't stall on replay",
2001                 .type   = FIO_OPT_BOOL,
2002                 .off1   = td_var_offset(no_stall),
2003                 .def    = "0",
2004                 .parent = "read_iolog",
2005                 .hide   = 1,
2006                 .help   = "Playback IO pattern file as fast as possible without stalls",
2007                 .category = FIO_OPT_C_IO,
2008                 .group  = FIO_OPT_G_IOLOG,
2009         },
2010         {
2011                 .name   = "replay_redirect",
2012                 .lname  = "Redirect device for replay",
2013                 .type   = FIO_OPT_STR_STORE,
2014                 .off1   = td_var_offset(replay_redirect),
2015                 .parent = "read_iolog",
2016                 .hide   = 1,
2017                 .help   = "Replay all I/O onto this device, regardless of trace device",
2018                 .category = FIO_OPT_C_IO,
2019                 .group  = FIO_OPT_G_IOLOG,
2020         },
2021         {
2022                 .name   = "exec_prerun",
2023                 .lname  = "Pre-execute runnable",
2024                 .type   = FIO_OPT_STR_STORE,
2025                 .off1   = td_var_offset(exec_prerun),
2026                 .help   = "Execute this file prior to running job",
2027                 .category = FIO_OPT_C_GENERAL,
2028                 .group  = FIO_OPT_G_INVALID,
2029         },
2030         {
2031                 .name   = "exec_postrun",
2032                 .lname  = "Post-execute runnable",
2033                 .type   = FIO_OPT_STR_STORE,
2034                 .off1   = td_var_offset(exec_postrun),
2035                 .help   = "Execute this file after running job",
2036                 .category = FIO_OPT_C_GENERAL,
2037                 .group  = FIO_OPT_G_INVALID,
2038         },
2039 #ifdef FIO_HAVE_IOSCHED_SWITCH
2040         {
2041                 .name   = "ioscheduler",
2042                 .lname  = "I/O scheduler",
2043                 .type   = FIO_OPT_STR_STORE,
2044                 .off1   = td_var_offset(ioscheduler),
2045                 .help   = "Use this IO scheduler on the backing device",
2046                 .category = FIO_OPT_C_FILE,
2047                 .group  = FIO_OPT_G_INVALID,
2048         },
2049 #endif
2050         {
2051                 .name   = "zonesize",
2052                 .lname  = "Zone size",
2053                 .type   = FIO_OPT_STR_VAL,
2054                 .off1   = td_var_offset(zone_size),
2055                 .help   = "Amount of data to read per zone",
2056                 .def    = "0",
2057                 .interval = 1024 * 1024,
2058                 .category = FIO_OPT_C_IO,
2059                 .group  = FIO_OPT_G_ZONE,
2060         },
2061         {
2062                 .name   = "zonerange",
2063                 .lname  = "Zone range",
2064                 .type   = FIO_OPT_STR_VAL,
2065                 .off1   = td_var_offset(zone_range),
2066                 .help   = "Give size of an IO zone",
2067                 .def    = "0",
2068                 .interval = 1024 * 1024,
2069                 .category = FIO_OPT_C_IO,
2070                 .group  = FIO_OPT_G_ZONE,
2071         },
2072         {
2073                 .name   = "zoneskip",
2074                 .lname  = "Zone skip",
2075                 .type   = FIO_OPT_STR_VAL,
2076                 .off1   = td_var_offset(zone_skip),
2077                 .help   = "Space between IO zones",
2078                 .def    = "0",
2079                 .interval = 1024 * 1024,
2080                 .category = FIO_OPT_C_IO,
2081                 .group  = FIO_OPT_G_ZONE,
2082         },
2083         {
2084                 .name   = "lockmem",
2085                 .lname  = "Lock memory",
2086                 .type   = FIO_OPT_STR_VAL,
2087                 .off1   = td_var_offset(lockmem),
2088                 .help   = "Lock down this amount of memory",
2089                 .def    = "0",
2090                 .interval = 1024 * 1024,
2091                 .category = FIO_OPT_C_GENERAL,
2092                 .group  = FIO_OPT_G_INVALID,
2093         },
2094         {
2095                 .name   = "rwmixread",
2096                 .lname  = "Read/write mix read",
2097                 .type   = FIO_OPT_INT,
2098                 .cb     = str_rwmix_read_cb,
2099                 .maxval = 100,
2100                 .help   = "Percentage of mixed workload that is reads",
2101                 .def    = "50",
2102                 .interval = 5,
2103                 .inverse = "rwmixwrite",
2104                 .category = FIO_OPT_C_IO,
2105                 .group  = FIO_OPT_G_RWMIX,
2106         },
2107         {
2108                 .name   = "rwmixwrite",
2109                 .lname  = "Read/write mix write",
2110                 .type   = FIO_OPT_INT,
2111                 .cb     = str_rwmix_write_cb,
2112                 .maxval = 100,
2113                 .help   = "Percentage of mixed workload that is writes",
2114                 .def    = "50",
2115                 .interval = 5,
2116                 .inverse = "rwmixread",
2117                 .category = FIO_OPT_C_IO,
2118                 .group  = FIO_OPT_G_RWMIX,
2119         },
2120         {
2121                 .name   = "rwmixcycle",
2122                 .lname  = "Read/write mix cycle",
2123                 .type   = FIO_OPT_DEPRECATED,
2124                 .category = FIO_OPT_C_IO,
2125                 .group  = FIO_OPT_G_RWMIX,
2126         },
2127         {
2128                 .name   = "nice",
2129                 .lname  = "Nice",
2130                 .type   = FIO_OPT_INT,
2131                 .off1   = td_var_offset(nice),
2132                 .help   = "Set job CPU nice value",
2133                 .minval = -19,
2134                 .maxval = 20,
2135                 .def    = "0",
2136                 .interval = 1,
2137                 .category = FIO_OPT_C_GENERAL,
2138                 .group  = FIO_OPT_G_CRED,
2139         },
2140 #ifdef FIO_HAVE_IOPRIO
2141         {
2142                 .name   = "prio",
2143                 .lname  = "I/O nice priority",
2144                 .type   = FIO_OPT_INT,
2145                 .off1   = td_var_offset(ioprio),
2146                 .help   = "Set job IO priority value",
2147                 .minval = 0,
2148                 .maxval = 7,
2149                 .interval = 1,
2150                 .category = FIO_OPT_C_GENERAL,
2151                 .group  = FIO_OPT_G_CRED,
2152         },
2153         {
2154                 .name   = "prioclass",
2155                 .lname  = "I/O nice priority class",
2156                 .type   = FIO_OPT_INT,
2157                 .off1   = td_var_offset(ioprio_class),
2158                 .help   = "Set job IO priority class",
2159                 .minval = 0,
2160                 .maxval = 3,
2161                 .interval = 1,
2162                 .category = FIO_OPT_C_GENERAL,
2163                 .group  = FIO_OPT_G_CRED,
2164         },
2165 #endif
2166         {
2167                 .name   = "thinktime",
2168                 .lname  = "Thinktime",
2169                 .type   = FIO_OPT_INT,
2170                 .off1   = td_var_offset(thinktime),
2171                 .help   = "Idle time between IO buffers (usec)",
2172                 .def    = "0",
2173                 .category = FIO_OPT_C_IO,
2174                 .group  = FIO_OPT_G_THINKTIME,
2175         },
2176         {
2177                 .name   = "thinktime_spin",
2178                 .lname  = "Thinktime spin",
2179                 .type   = FIO_OPT_INT,
2180                 .off1   = td_var_offset(thinktime_spin),
2181                 .help   = "Start think time by spinning this amount (usec)",
2182                 .def    = "0",
2183                 .parent = "thinktime",
2184                 .hide   = 1,
2185                 .category = FIO_OPT_C_IO,
2186                 .group  = FIO_OPT_G_THINKTIME,
2187         },
2188         {
2189                 .name   = "thinktime_blocks",
2190                 .lname  = "Thinktime blocks",
2191                 .type   = FIO_OPT_INT,
2192                 .off1   = td_var_offset(thinktime_blocks),
2193                 .help   = "IO buffer period between 'thinktime'",
2194                 .def    = "1",
2195                 .parent = "thinktime",
2196                 .hide   = 1,
2197                 .category = FIO_OPT_C_IO,
2198                 .group  = FIO_OPT_G_THINKTIME,
2199         },
2200         {
2201                 .name   = "rate",
2202                 .lname  = "I/O rate",
2203                 .type   = FIO_OPT_INT,
2204                 .off1   = td_var_offset(rate[0]),
2205                 .off2   = td_var_offset(rate[1]),
2206                 .help   = "Set bandwidth rate",
2207                 .category = FIO_OPT_C_IO,
2208                 .group  = FIO_OPT_G_RATE,
2209         },
2210         {
2211                 .name   = "ratemin",
2212                 .lname  = "I/O min rate",
2213                 .type   = FIO_OPT_INT,
2214                 .off1   = td_var_offset(ratemin[0]),
2215                 .off2   = td_var_offset(ratemin[1]),
2216                 .help   = "Job must meet this rate or it will be shutdown",
2217                 .parent = "rate",
2218                 .hide   = 1,
2219                 .category = FIO_OPT_C_IO,
2220                 .group  = FIO_OPT_G_RATE,
2221         },
2222         {
2223                 .name   = "rate_iops",
2224                 .lname  = "I/O rate IOPS",
2225                 .type   = FIO_OPT_INT,
2226                 .off1   = td_var_offset(rate_iops[0]),
2227                 .off2   = td_var_offset(rate_iops[1]),
2228                 .help   = "Limit IO used to this number of IO operations/sec",
2229                 .hide   = 1,
2230                 .category = FIO_OPT_C_IO,
2231                 .group  = FIO_OPT_G_RATE,
2232         },
2233         {
2234                 .name   = "rate_iops_min",
2235                 .lname  = "I/O min rate IOPS",
2236                 .type   = FIO_OPT_INT,
2237                 .off1   = td_var_offset(rate_iops_min[0]),
2238                 .off2   = td_var_offset(rate_iops_min[1]),
2239                 .help   = "Job must meet this rate or it will be shut down",
2240                 .parent = "rate_iops",
2241                 .hide   = 1,
2242                 .category = FIO_OPT_C_IO,
2243                 .group  = FIO_OPT_G_RATE,
2244         },
2245         {
2246                 .name   = "ratecycle",
2247                 .lname  = "I/O rate cycle",
2248                 .type   = FIO_OPT_INT,
2249                 .off1   = td_var_offset(ratecycle),
2250                 .help   = "Window average for rate limits (msec)",
2251                 .def    = "1000",
2252                 .parent = "rate",
2253                 .hide   = 1,
2254                 .category = FIO_OPT_C_IO,
2255                 .group  = FIO_OPT_G_RATE,
2256         },
2257         {
2258                 .name   = "invalidate",
2259                 .lname  = "Cache invalidate",
2260                 .type   = FIO_OPT_BOOL,
2261                 .off1   = td_var_offset(invalidate_cache),
2262                 .help   = "Invalidate buffer/page cache prior to running job",
2263                 .def    = "1",
2264                 .category = FIO_OPT_C_IO,
2265                 .group  = FIO_OPT_G_IO_TYPE,
2266         },
2267         {
2268                 .name   = "sync",
2269                 .lname  = "Synchronous I/O",
2270                 .type   = FIO_OPT_BOOL,
2271                 .off1   = td_var_offset(sync_io),
2272                 .help   = "Use O_SYNC for buffered writes",
2273                 .def    = "0",
2274                 .parent = "buffered",
2275                 .hide   = 1,
2276                 .category = FIO_OPT_C_IO,
2277                 .group  = FIO_OPT_G_IO_TYPE,
2278         },
2279         {
2280                 .name   = "create_serialize",
2281                 .lname  = "Create serialize",
2282                 .type   = FIO_OPT_BOOL,
2283                 .off1   = td_var_offset(create_serialize),
2284                 .help   = "Serialize creating of job files",
2285                 .def    = "1",
2286                 .category = FIO_OPT_C_FILE,
2287                 .group  = FIO_OPT_G_INVALID,
2288         },
2289         {
2290                 .name   = "create_fsync",
2291                 .lname  = "Create fsync",
2292                 .type   = FIO_OPT_BOOL,
2293                 .off1   = td_var_offset(create_fsync),
2294                 .help   = "fsync file after creation",
2295                 .def    = "1",
2296                 .category = FIO_OPT_C_FILE,
2297                 .group  = FIO_OPT_G_INVALID,
2298         },
2299         {
2300                 .name   = "create_on_open",
2301                 .lname  = "Create on open",
2302                 .type   = FIO_OPT_BOOL,
2303                 .off1   = td_var_offset(create_on_open),
2304                 .help   = "Create files when they are opened for IO",
2305                 .def    = "0",
2306                 .category = FIO_OPT_C_FILE,
2307                 .group  = FIO_OPT_G_INVALID,
2308         },
2309         {
2310                 .name   = "pre_read",
2311                 .lname  = "Pre-read files",
2312                 .type   = FIO_OPT_BOOL,
2313                 .off1   = td_var_offset(pre_read),
2314                 .help   = "Pre-read files before starting official testing",
2315                 .def    = "0",
2316                 .category = FIO_OPT_C_FILE,
2317                 .group  = FIO_OPT_G_INVALID,
2318         },
2319 #ifdef FIO_HAVE_CPU_AFFINITY
2320         {
2321                 .name   = "cpumask",
2322                 .lname  = "CPU mask",
2323                 .type   = FIO_OPT_INT,
2324                 .cb     = str_cpumask_cb,
2325                 .help   = "CPU affinity mask",
2326                 .category = FIO_OPT_C_GENERAL,
2327                 .group  = FIO_OPT_G_CRED,
2328         },
2329         {
2330                 .name   = "cpus_allowed",
2331                 .lname  = "CPUs allowed",
2332                 .type   = FIO_OPT_STR,
2333                 .cb     = str_cpus_allowed_cb,
2334                 .help   = "Set CPUs allowed",
2335                 .category = FIO_OPT_C_GENERAL,
2336                 .group  = FIO_OPT_G_CRED,
2337         },
2338 #endif
2339         {
2340                 .name   = "end_fsync",
2341                 .lname  = "End fsync",
2342                 .type   = FIO_OPT_BOOL,
2343                 .off1   = td_var_offset(end_fsync),
2344                 .help   = "Include fsync at the end of job",
2345                 .def    = "0",
2346                 .category = FIO_OPT_C_FILE,
2347                 .group  = FIO_OPT_G_INVALID,
2348         },
2349         {
2350                 .name   = "fsync_on_close",
2351                 .lname  = "Fsync on close",
2352                 .type   = FIO_OPT_BOOL,
2353                 .off1   = td_var_offset(fsync_on_close),
2354                 .help   = "fsync files on close",
2355                 .def    = "0",
2356                 .category = FIO_OPT_C_FILE,
2357                 .group  = FIO_OPT_G_INVALID,
2358         },
2359         {
2360                 .name   = "unlink",
2361                 .lname  = "Unlink file",
2362                 .type   = FIO_OPT_BOOL,
2363                 .off1   = td_var_offset(unlink),
2364                 .help   = "Unlink created files after job has completed",
2365                 .def    = "0",
2366                 .category = FIO_OPT_C_FILE,
2367                 .group  = FIO_OPT_G_INVALID,
2368         },
2369         {
2370                 .name   = "exitall",
2371                 .lname  = "Exit-all on terminate",
2372                 .type   = FIO_OPT_STR_SET,
2373                 .cb     = str_exitall_cb,
2374                 .help   = "Terminate all jobs when one exits",
2375                 .category = FIO_OPT_C_GENERAL,
2376                 .group  = FIO_OPT_G_PROCESS,
2377         },
2378         {
2379                 .name   = "stonewall",
2380                 .lname  = "Wait for previous",
2381                 .alias  = "wait_for_previous",
2382                 .type   = FIO_OPT_STR_SET,
2383                 .off1   = td_var_offset(stonewall),
2384                 .help   = "Insert a hard barrier between this job and previous",
2385                 .category = FIO_OPT_C_GENERAL,
2386                 .group  = FIO_OPT_G_PROCESS,
2387         },
2388         {
2389                 .name   = "new_group",
2390                 .lname  = "New group",
2391                 .type   = FIO_OPT_STR_SET,
2392                 .off1   = td_var_offset(new_group),
2393                 .help   = "Mark the start of a new group (for reporting)",
2394                 .category = FIO_OPT_C_GENERAL,
2395                 .group  = FIO_OPT_G_PROCESS,
2396         },
2397         {
2398                 .name   = "thread",
2399                 .lname  = "Thread",
2400                 .type   = FIO_OPT_STR_SET,
2401                 .off1   = td_var_offset(use_thread),
2402                 .help   = "Use threads instead of processes",
2403                 .category = FIO_OPT_C_GENERAL,
2404                 .group  = FIO_OPT_G_PROCESS,
2405         },
2406         {
2407                 .name   = "write_bw_log",
2408                 .lname  = "Write bandwidth log",
2409                 .type   = FIO_OPT_STR,
2410                 .off1   = td_var_offset(write_bw_log),
2411                 .cb     = str_write_bw_log_cb,
2412                 .help   = "Write log of bandwidth during run",
2413                 .category = FIO_OPT_C_LOG,
2414                 .group  = FIO_OPT_G_INVALID,
2415         },
2416         {
2417                 .name   = "write_lat_log",
2418                 .lname  = "Write latency log",
2419                 .type   = FIO_OPT_STR,
2420                 .off1   = td_var_offset(write_lat_log),
2421                 .cb     = str_write_lat_log_cb,
2422                 .help   = "Write log of latency during run",
2423                 .category = FIO_OPT_C_LOG,
2424                 .group  = FIO_OPT_G_INVALID,
2425         },
2426         {
2427                 .name   = "write_iops_log",
2428                 .lname  = "Write IOPS log",
2429                 .type   = FIO_OPT_STR,
2430                 .off1   = td_var_offset(write_iops_log),
2431                 .cb     = str_write_iops_log_cb,
2432                 .help   = "Write log of IOPS during run",
2433                 .category = FIO_OPT_C_LOG,
2434                 .group  = FIO_OPT_G_INVALID,
2435         },
2436         {
2437                 .name   = "log_avg_msec",
2438                 .lname  = "Log averaging (msec)",
2439                 .type   = FIO_OPT_INT,
2440                 .off1   = td_var_offset(log_avg_msec),
2441                 .help   = "Average bw/iops/lat logs over this period of time",
2442                 .def    = "0",
2443                 .category = FIO_OPT_C_LOG,
2444                 .group  = FIO_OPT_G_INVALID,
2445         },
2446         {
2447                 .name   = "bwavgtime",
2448                 .lname  = "Bandwidth average time",
2449                 .type   = FIO_OPT_INT,
2450                 .off1   = td_var_offset(bw_avg_time),
2451                 .help   = "Time window over which to calculate bandwidth"
2452                           " (msec)",
2453                 .def    = "500",
2454                 .parent = "write_bw_log",
2455                 .hide   = 1,
2456                 .interval = 100,
2457                 .category = FIO_OPT_C_LOG,
2458                 .group  = FIO_OPT_G_INVALID,
2459         },
2460         {
2461                 .name   = "iopsavgtime",
2462                 .lname  = "IOPS average time",
2463                 .type   = FIO_OPT_INT,
2464                 .off1   = td_var_offset(iops_avg_time),
2465                 .help   = "Time window over which to calculate IOPS (msec)",
2466                 .def    = "500",
2467                 .parent = "write_iops_log",
2468                 .hide   = 1,
2469                 .interval = 100,
2470                 .category = FIO_OPT_C_LOG,
2471                 .group  = FIO_OPT_G_INVALID,
2472         },
2473         {
2474                 .name   = "group_reporting",
2475                 .lname  = "Group reporting",
2476                 .type   = FIO_OPT_BOOL,
2477                 .off1   = td_var_offset(group_reporting),
2478                 .help   = "Do reporting on a per-group basis",
2479                 .def    = "1",
2480                 .category = FIO_OPT_C_STAT,
2481                 .group  = FIO_OPT_G_INVALID,
2482         },
2483         {
2484                 .name   = "zero_buffers",
2485                 .lname  = "Zero I/O buffers",
2486                 .type   = FIO_OPT_STR_SET,
2487                 .off1   = td_var_offset(zero_buffers),
2488                 .help   = "Init IO buffers to all zeroes",
2489                 .category = FIO_OPT_C_IO,
2490                 .group  = FIO_OPT_G_IO_BUF,
2491         },
2492         {
2493                 .name   = "refill_buffers",
2494                 .lname  = "Refill I/O buffers",
2495                 .type   = FIO_OPT_STR_SET,
2496                 .off1   = td_var_offset(refill_buffers),
2497                 .help   = "Refill IO buffers on every IO submit",
2498                 .category = FIO_OPT_C_IO,
2499                 .group  = FIO_OPT_G_IO_BUF,
2500         },
2501         {
2502                 .name   = "scramble_buffers",
2503                 .lname  = "Scramble I/O buffers",
2504                 .type   = FIO_OPT_BOOL,
2505                 .off1   = td_var_offset(scramble_buffers),
2506                 .help   = "Slightly scramble buffers on every IO submit",
2507                 .def    = "1",
2508                 .category = FIO_OPT_C_IO,
2509                 .group  = FIO_OPT_G_IO_BUF,
2510         },
2511         {
2512                 .name   = "buffer_compress_percentage",
2513                 .lname  = "Buffer compression percentage",
2514                 .type   = FIO_OPT_INT,
2515                 .off1   = td_var_offset(compress_percentage),
2516                 .maxval = 100,
2517                 .minval = 1,
2518                 .help   = "How compressible the buffer is (approximately)",
2519                 .interval = 5,
2520                 .category = FIO_OPT_C_IO,
2521                 .group  = FIO_OPT_G_IO_BUF,
2522         },
2523         {
2524                 .name   = "buffer_compress_chunk",
2525                 .lname  = "Buffer compression chunk size",
2526                 .type   = FIO_OPT_INT,
2527                 .off1   = td_var_offset(compress_chunk),
2528                 .parent = "buffer_compress_percentage",
2529                 .hide   = 1,
2530                 .help   = "Size of compressible region in buffer",
2531                 .interval = 256,
2532                 .category = FIO_OPT_C_IO,
2533                 .group  = FIO_OPT_G_IO_BUF,
2534         },
2535         {
2536                 .name   = "clat_percentiles",
2537                 .lname  = "Completion latency percentiles",
2538                 .type   = FIO_OPT_BOOL,
2539                 .off1   = td_var_offset(clat_percentiles),
2540                 .help   = "Enable the reporting of completion latency percentiles",
2541                 .def    = "1",
2542                 .category = FIO_OPT_C_STAT,
2543                 .group  = FIO_OPT_G_INVALID,
2544         },
2545         {
2546                 .name   = "percentile_list",
2547                 .lname  = "Completion latency percentile list",
2548                 .type   = FIO_OPT_FLOAT_LIST,
2549                 .off1   = td_var_offset(percentile_list),
2550                 .off2   = td_var_offset(overwrite_plist),
2551                 .help   = "Specify a custom list of percentiles to report",
2552                 .maxlen = FIO_IO_U_LIST_MAX_LEN,
2553                 .minfp  = 0.0,
2554                 .maxfp  = 100.0,
2555                 .category = FIO_OPT_C_STAT,
2556                 .group  = FIO_OPT_G_INVALID,
2557         },
2558
2559 #ifdef FIO_HAVE_DISK_UTIL
2560         {
2561                 .name   = "disk_util",
2562                 .lname  = "Disk utilization",
2563                 .type   = FIO_OPT_BOOL,
2564                 .off1   = td_var_offset(do_disk_util),
2565                 .help   = "Log disk utilization statistics",
2566                 .def    = "1",
2567                 .category = FIO_OPT_C_STAT,
2568                 .group  = FIO_OPT_G_INVALID,
2569         },
2570 #endif
2571         {
2572                 .name   = "gtod_reduce",
2573                 .lname  = "Reduce gettimeofday() calls",
2574                 .type   = FIO_OPT_BOOL,
2575                 .help   = "Greatly reduce number of gettimeofday() calls",
2576                 .cb     = str_gtod_reduce_cb,
2577                 .def    = "0",
2578                 .hide_on_set = 1,
2579                 .category = FIO_OPT_C_STAT,
2580                 .group  = FIO_OPT_G_INVALID,
2581         },
2582         {
2583                 .name   = "disable_lat",
2584                 .lname  = "Disable all latency stats",
2585                 .type   = FIO_OPT_BOOL,
2586                 .off1   = td_var_offset(disable_lat),
2587                 .help   = "Disable latency numbers",
2588                 .parent = "gtod_reduce",
2589                 .hide   = 1,
2590                 .def    = "0",
2591                 .category = FIO_OPT_C_STAT,
2592                 .group  = FIO_OPT_G_INVALID,
2593         },
2594         {
2595                 .name   = "disable_clat",
2596                 .lname  = "Disable completion latency stats",
2597                 .type   = FIO_OPT_BOOL,
2598                 .off1   = td_var_offset(disable_clat),
2599                 .help   = "Disable completion latency numbers",
2600                 .parent = "gtod_reduce",
2601                 .hide   = 1,
2602                 .def    = "0",
2603                 .category = FIO_OPT_C_STAT,
2604                 .group  = FIO_OPT_G_INVALID,
2605         },
2606         {
2607                 .name   = "disable_slat",
2608                 .lname  = "Disable submission latency stats",
2609                 .type   = FIO_OPT_BOOL,
2610                 .off1   = td_var_offset(disable_slat),
2611                 .help   = "Disable submission latency numbers",
2612                 .parent = "gtod_reduce",
2613                 .hide   = 1,
2614                 .def    = "0",
2615                 .category = FIO_OPT_C_STAT,
2616                 .group  = FIO_OPT_G_INVALID,
2617         },
2618         {
2619                 .name   = "disable_bw_measurement",
2620                 .lname  = "Disable bandwidth stats",
2621                 .type   = FIO_OPT_BOOL,
2622                 .off1   = td_var_offset(disable_bw),
2623                 .help   = "Disable bandwidth logging",
2624                 .parent = "gtod_reduce",
2625                 .hide   = 1,
2626                 .def    = "0",
2627                 .category = FIO_OPT_C_STAT,
2628                 .group  = FIO_OPT_G_INVALID,
2629         },
2630         {
2631                 .name   = "gtod_cpu",
2632                 .lname  = "Dedicated gettimeofday() CPU",
2633                 .type   = FIO_OPT_INT,
2634                 .cb     = str_gtod_cpu_cb,
2635                 .help   = "Set up dedicated gettimeofday() thread on this CPU",
2636                 .verify = gtod_cpu_verify,
2637                 .category = FIO_OPT_C_GENERAL,
2638                 .group  = FIO_OPT_G_CLOCK,
2639         },
2640         {
2641                 .name   = "continue_on_error",
2642                 .lname  = "Continue on error",
2643                 .type   = FIO_OPT_STR,
2644                 .off1   = td_var_offset(continue_on_error),
2645                 .help   = "Continue on non-fatal errors during IO",
2646                 .def    = "none",
2647                 .category = FIO_OPT_C_GENERAL,
2648                 .group  = FIO_OPT_G_INVALID,
2649                 .posval = {
2650                           { .ival = "none",
2651                             .oval = ERROR_TYPE_NONE,
2652                             .help = "Exit when an error is encountered",
2653                           },
2654                           { .ival = "read",
2655                             .oval = ERROR_TYPE_READ,
2656                             .help = "Continue on read errors only",
2657                           },
2658                           { .ival = "write",
2659                             .oval = ERROR_TYPE_WRITE,
2660                             .help = "Continue on write errors only",
2661                           },
2662                           { .ival = "io",
2663                             .oval = ERROR_TYPE_READ | ERROR_TYPE_WRITE,
2664                             .help = "Continue on any IO errors",
2665                           },
2666                           { .ival = "verify",
2667                             .oval = ERROR_TYPE_VERIFY,
2668                             .help = "Continue on verify errors only",
2669                           },
2670                           { .ival = "all",
2671                             .oval = ERROR_TYPE_ANY,
2672                             .help = "Continue on all io and verify errors",
2673                           },
2674                           { .ival = "0",
2675                             .oval = ERROR_TYPE_NONE,
2676                             .help = "Alias for 'none'",
2677                           },
2678                           { .ival = "1",
2679                             .oval = ERROR_TYPE_ANY,
2680                             .help = "Alias for 'all'",
2681                           },
2682                 },
2683         },
2684         {
2685                 .name   = "profile",
2686                 .lname  = "Profile",
2687                 .type   = FIO_OPT_STR_STORE,
2688                 .off1   = td_var_offset(profile),
2689                 .help   = "Select a specific builtin performance test",
2690                 .category = FIO_OPT_C_GENERAL,
2691                 .group  = FIO_OPT_G_INVALID,
2692         },
2693         {
2694                 .name   = "cgroup",
2695                 .lname  = "Cgroup",
2696                 .type   = FIO_OPT_STR_STORE,
2697                 .off1   = td_var_offset(cgroup),
2698                 .help   = "Add job to cgroup of this name",
2699                 .category = FIO_OPT_C_GENERAL,
2700                 .group  = FIO_OPT_G_CGROUP,
2701         },
2702         {
2703                 .name   = "cgroup_nodelete",
2704                 .lname  = "Cgroup no-delete",
2705                 .type   = FIO_OPT_BOOL,
2706                 .off1   = td_var_offset(cgroup_nodelete),
2707                 .help   = "Do not delete cgroups after job completion",
2708                 .def    = "0",
2709                 .parent = "cgroup",
2710                 .category = FIO_OPT_C_GENERAL,
2711                 .group  = FIO_OPT_G_CGROUP,
2712         },
2713         {
2714                 .name   = "cgroup_weight",
2715                 .lname  = "Cgroup weight",
2716                 .type   = FIO_OPT_INT,
2717                 .off1   = td_var_offset(cgroup_weight),
2718                 .help   = "Use given weight for cgroup",
2719                 .minval = 100,
2720                 .maxval = 1000,
2721                 .parent = "cgroup",
2722                 .category = FIO_OPT_C_GENERAL,
2723                 .group  = FIO_OPT_G_CGROUP,
2724         },
2725         {
2726                 .name   = "uid",
2727                 .lname  = "User ID",
2728                 .type   = FIO_OPT_INT,
2729                 .off1   = td_var_offset(uid),
2730                 .help   = "Run job with this user ID",
2731                 .category = FIO_OPT_C_GENERAL,
2732                 .group  = FIO_OPT_G_CRED,
2733         },
2734         {
2735                 .name   = "gid",
2736                 .lname  = "Group ID",
2737                 .type   = FIO_OPT_INT,
2738                 .off1   = td_var_offset(gid),
2739                 .help   = "Run job with this group ID",
2740                 .category = FIO_OPT_C_GENERAL,
2741                 .group  = FIO_OPT_G_CRED,
2742         },
2743         {
2744                 .name   = "kb_base",
2745                 .lname  = "KB Base",
2746                 .type   = FIO_OPT_INT,
2747                 .off1   = td_var_offset(kb_base),
2748                 .verify = kb_base_verify,
2749                 .prio   = 1,
2750                 .def    = "1024",
2751                 .help   = "How many bytes per KB for reporting (1000 or 1024)",
2752                 .category = FIO_OPT_C_GENERAL,
2753                 .group  = FIO_OPT_G_INVALID,
2754         },
2755         {
2756                 .name   = "hugepage-size",
2757                 .lname  = "Hugepage size",
2758                 .type   = FIO_OPT_INT,
2759                 .off1   = td_var_offset(hugepage_size),
2760                 .help   = "When using hugepages, specify size of each page",
2761                 .def    = __fio_stringify(FIO_HUGE_PAGE),
2762                 .interval = 1024 * 1024,
2763                 .category = FIO_OPT_C_GENERAL,
2764                 .group  = FIO_OPT_G_INVALID,
2765         },
2766         {
2767                 .name   = "flow_id",
2768                 .lname  = "I/O flow ID",
2769                 .type   = FIO_OPT_INT,
2770                 .off1   = td_var_offset(flow_id),
2771                 .help   = "The flow index ID to use",
2772                 .def    = "0",
2773                 .category = FIO_OPT_C_IO,
2774                 .group  = FIO_OPT_G_IO_FLOW,
2775         },
2776         {
2777                 .name   = "flow",
2778                 .lname  = "I/O flow weight",
2779                 .type   = FIO_OPT_INT,
2780                 .off1   = td_var_offset(flow),
2781                 .help   = "Weight for flow control of this job",
2782                 .parent = "flow_id",
2783                 .hide   = 1,
2784                 .def    = "0",
2785                 .category = FIO_OPT_C_IO,
2786                 .group  = FIO_OPT_G_IO_FLOW,
2787         },
2788         {
2789                 .name   = "flow_watermark",
2790                 .lname  = "I/O flow watermark",
2791                 .type   = FIO_OPT_INT,
2792                 .off1   = td_var_offset(flow_watermark),
2793                 .help   = "High watermark for flow control. This option"
2794                         " should be set to the same value for all threads"
2795                         " with non-zero flow.",
2796                 .parent = "flow_id",
2797                 .hide   = 1,
2798                 .def    = "1024",
2799                 .category = FIO_OPT_C_IO,
2800                 .group  = FIO_OPT_G_IO_FLOW,
2801         },
2802         {
2803                 .name   = "flow_sleep",
2804                 .lname  = "I/O flow sleep",
2805                 .type   = FIO_OPT_INT,
2806                 .off1   = td_var_offset(flow_sleep),
2807                 .help   = "How many microseconds to sleep after being held"
2808                         " back by the flow control mechanism",
2809                 .parent = "flow_id",
2810                 .hide   = 1,
2811                 .def    = "0",
2812                 .category = FIO_OPT_C_IO,
2813                 .group  = FIO_OPT_G_IO_FLOW,
2814         },
2815         {
2816                 .name = NULL,
2817         },
2818 };
2819
2820 static void add_to_lopt(struct option *lopt, struct fio_option *o,
2821                         const char *name, int val)
2822 {
2823         lopt->name = (char *) name;
2824         lopt->val = val;
2825         if (o->type == FIO_OPT_STR_SET)
2826                 lopt->has_arg = no_argument;
2827         else
2828                 lopt->has_arg = required_argument;
2829 }
2830
2831 static void options_to_lopts(struct fio_option *opts,
2832                               struct option *long_options,
2833                               int i, int option_type)
2834 {
2835         struct fio_option *o = &opts[0];
2836         while (o->name) {
2837                 add_to_lopt(&long_options[i], o, o->name, option_type);
2838                 if (o->alias) {
2839                         i++;
2840                         add_to_lopt(&long_options[i], o, o->alias, option_type);
2841                 }
2842
2843                 i++;
2844                 o++;
2845                 assert(i < FIO_NR_OPTIONS);
2846         }
2847 }
2848
2849 void fio_options_set_ioengine_opts(struct option *long_options,
2850                                    struct thread_data *td)
2851 {
2852         unsigned int i;
2853
2854         i = 0;
2855         while (long_options[i].name) {
2856                 if (long_options[i].val == FIO_GETOPT_IOENGINE) {
2857                         memset(&long_options[i], 0, sizeof(*long_options));
2858                         break;
2859                 }
2860                 i++;
2861         }
2862
2863         /*
2864          * Just clear out the prior ioengine options.
2865          */
2866         if (!td || !td->eo)
2867                 return;
2868
2869         options_to_lopts(td->io_ops->options, long_options, i,
2870                          FIO_GETOPT_IOENGINE);
2871 }
2872
2873 void fio_options_dup_and_init(struct option *long_options)
2874 {
2875         unsigned int i;
2876
2877         options_init(fio_options);
2878
2879         i = 0;
2880         while (long_options[i].name)
2881                 i++;
2882
2883         options_to_lopts(fio_options, long_options, i, FIO_GETOPT_JOB);
2884 }
2885
2886 struct fio_keyword {
2887         const char *word;
2888         const char *desc;
2889         char *replace;
2890 };
2891
2892 static struct fio_keyword fio_keywords[] = {
2893         {
2894                 .word   = "$pagesize",
2895                 .desc   = "Page size in the system",
2896         },
2897         {
2898                 .word   = "$mb_memory",
2899                 .desc   = "Megabytes of memory online",
2900         },
2901         {
2902                 .word   = "$ncpus",
2903                 .desc   = "Number of CPUs online in the system",
2904         },
2905         {
2906                 .word   = NULL,
2907         },
2908 };
2909
2910 void fio_keywords_init(void)
2911 {
2912         unsigned long long mb_memory;
2913         char buf[128];
2914         long l;
2915
2916         sprintf(buf, "%lu", page_size);
2917         fio_keywords[0].replace = strdup(buf);
2918
2919         mb_memory = os_phys_mem() / (1024 * 1024);
2920         sprintf(buf, "%llu", mb_memory);
2921         fio_keywords[1].replace = strdup(buf);
2922
2923         l = cpus_online();
2924         sprintf(buf, "%lu", l);
2925         fio_keywords[2].replace = strdup(buf);
2926 }
2927
2928 #define BC_APP          "bc"
2929
2930 static char *bc_calc(char *str)
2931 {
2932         char buf[128], *tmp;
2933         FILE *f;
2934         int ret;
2935
2936         /*
2937          * No math, just return string
2938          */
2939         if ((!strchr(str, '+') && !strchr(str, '-') && !strchr(str, '*') &&
2940              !strchr(str, '/')) || strchr(str, '\''))
2941                 return str;
2942
2943         /*
2944          * Split option from value, we only need to calculate the value
2945          */
2946         tmp = strchr(str, '=');
2947         if (!tmp)
2948                 return str;
2949
2950         tmp++;
2951
2952         /*
2953          * Prevent buffer overflows; such a case isn't reasonable anyway
2954          */
2955         if (strlen(str) >= 128 || strlen(tmp) > 100)
2956                 return str;
2957
2958         sprintf(buf, "which %s > /dev/null", BC_APP);
2959         if (system(buf)) {
2960                 log_err("fio: bc is needed for performing math\n");
2961                 return NULL;
2962         }
2963
2964         sprintf(buf, "echo '%s' | %s", tmp, BC_APP);
2965         f = popen(buf, "r");
2966         if (!f)
2967                 return NULL;
2968
2969         ret = fread(&buf[tmp - str], 1, 128 - (tmp - str), f);
2970         if (ret <= 0)
2971                 return NULL;
2972
2973         pclose(f);
2974         buf[(tmp - str) + ret - 1] = '\0';
2975         memcpy(buf, str, tmp - str);
2976         free(str);
2977         return strdup(buf);
2978 }
2979
2980 /*
2981  * Return a copy of the input string with substrings of the form ${VARNAME}
2982  * substituted with the value of the environment variable VARNAME.  The
2983  * substitution always occurs, even if VARNAME is empty or the corresponding
2984  * environment variable undefined.
2985  */
2986 static char *option_dup_subs(const char *opt)
2987 {
2988         char out[OPT_LEN_MAX+1];
2989         char in[OPT_LEN_MAX+1];
2990         char *outptr = out;
2991         char *inptr = in;
2992         char *ch1, *ch2, *env;
2993         ssize_t nchr = OPT_LEN_MAX;
2994         size_t envlen;
2995
2996         if (strlen(opt) + 1 > OPT_LEN_MAX) {
2997                 log_err("OPT_LEN_MAX (%d) is too small\n", OPT_LEN_MAX);
2998                 return NULL;
2999         }
3000
3001         in[OPT_LEN_MAX] = '\0';
3002         strncpy(in, opt, OPT_LEN_MAX);
3003
3004         while (*inptr && nchr > 0) {
3005                 if (inptr[0] == '$' && inptr[1] == '{') {
3006                         ch2 = strchr(inptr, '}');
3007                         if (ch2 && inptr+1 < ch2) {
3008                                 ch1 = inptr+2;
3009                                 inptr = ch2+1;
3010                                 *ch2 = '\0';
3011
3012                                 env = getenv(ch1);
3013                                 if (env) {
3014                                         envlen = strlen(env);
3015                                         if (envlen <= nchr) {
3016                                                 memcpy(outptr, env, envlen);
3017                                                 outptr += envlen;
3018                                                 nchr -= envlen;
3019                                         }
3020                                 }
3021
3022                                 continue;
3023                         }
3024                 }
3025
3026                 *outptr++ = *inptr++;
3027                 --nchr;
3028         }
3029
3030         *outptr = '\0';
3031         return strdup(out);
3032 }
3033
3034 /*
3035  * Look for reserved variable names and replace them with real values
3036  */
3037 static char *fio_keyword_replace(char *opt)
3038 {
3039         char *s;
3040         int i;
3041         int docalc = 0;
3042
3043         for (i = 0; fio_keywords[i].word != NULL; i++) {
3044                 struct fio_keyword *kw = &fio_keywords[i];
3045
3046                 while ((s = strstr(opt, kw->word)) != NULL) {
3047                         char *new = malloc(strlen(opt) + 1);
3048                         char *o_org = opt;
3049                         int olen = s - opt;
3050                         int len;
3051
3052                         /*
3053                          * Copy part of the string before the keyword and
3054                          * sprintf() the replacement after it.
3055                          */
3056                         memcpy(new, opt, olen);
3057                         len = sprintf(new + olen, "%s", kw->replace);
3058
3059                         /*
3060                          * If there's more in the original string, copy that
3061                          * in too
3062                          */
3063                         opt += strlen(kw->word) + olen;
3064                         if (strlen(opt))
3065                                 memcpy(new + olen + len, opt, opt - o_org - 1);
3066
3067                         /*
3068                          * replace opt and free the old opt
3069                          */
3070                         opt = new;
3071                         free(o_org);
3072
3073                         docalc = 1;
3074                 }
3075         }
3076
3077         /*
3078          * Check for potential math and invoke bc, if possible
3079          */
3080         if (docalc)
3081                 opt = bc_calc(opt);
3082
3083         return opt;
3084 }
3085
3086 static char **dup_and_sub_options(char **opts, int num_opts)
3087 {
3088         int i;
3089         char **opts_copy = malloc(num_opts * sizeof(*opts));
3090         for (i = 0; i < num_opts; i++) {
3091                 opts_copy[i] = option_dup_subs(opts[i]);
3092                 if (!opts_copy[i])
3093                         continue;
3094                 opts_copy[i] = fio_keyword_replace(opts_copy[i]);
3095         }
3096         return opts_copy;
3097 }
3098
3099 int fio_options_parse(struct thread_data *td, char **opts, int num_opts)
3100 {
3101         int i, ret, unknown;
3102         char **opts_copy;
3103
3104         sort_options(opts, fio_options, num_opts);
3105         opts_copy = dup_and_sub_options(opts, num_opts);
3106
3107         for (ret = 0, i = 0, unknown = 0; i < num_opts; i++) {
3108                 struct fio_option *o;
3109                 int newret = parse_option(opts_copy[i], opts[i], fio_options,
3110                                                 &o, td);
3111
3112                 if (opts_copy[i]) {
3113                         if (newret && !o) {
3114                                 unknown++;
3115                                 continue;
3116                         }
3117                         free(opts_copy[i]);
3118                         opts_copy[i] = NULL;
3119                 }
3120
3121                 ret |= newret;
3122         }
3123
3124         if (unknown) {
3125                 ret |= ioengine_load(td);
3126                 if (td->eo) {
3127                         sort_options(opts_copy, td->io_ops->options, num_opts);
3128                         opts = opts_copy;
3129                 }
3130                 for (i = 0; i < num_opts; i++) {
3131                         struct fio_option *o = NULL;
3132                         int newret = 1;
3133                         if (!opts_copy[i])
3134                                 continue;
3135
3136                         if (td->eo)
3137                                 newret = parse_option(opts_copy[i], opts[i],
3138                                                       td->io_ops->options, &o,
3139                                                       td->eo);
3140
3141                         ret |= newret;
3142                         if (!o)
3143                                 log_err("Bad option <%s>\n", opts[i]);
3144
3145                         free(opts_copy[i]);
3146                         opts_copy[i] = NULL;
3147                 }
3148         }
3149
3150         free(opts_copy);
3151         return ret;
3152 }
3153
3154 int fio_cmd_option_parse(struct thread_data *td, const char *opt, char *val)
3155 {
3156         return parse_cmd_option(opt, val, fio_options, td);
3157 }
3158
3159 int fio_cmd_ioengine_option_parse(struct thread_data *td, const char *opt,
3160                                 char *val)
3161 {
3162         return parse_cmd_option(opt, val, td->io_ops->options, td);
3163 }
3164
3165 void fio_fill_default_options(struct thread_data *td)
3166 {
3167         fill_default_options(td, fio_options);
3168 }
3169
3170 int fio_show_option_help(const char *opt)
3171 {
3172         return show_cmd_help(fio_options, opt);
3173 }
3174
3175 void options_mem_dupe(void *data, struct fio_option *options)
3176 {
3177         struct fio_option *o;
3178         char **ptr;
3179
3180         for (o = &options[0]; o->name; o++) {
3181                 if (o->type != FIO_OPT_STR_STORE)
3182                         continue;
3183
3184                 ptr = td_var(data, o->off1);
3185                 if (*ptr)
3186                         *ptr = strdup(*ptr);
3187         }
3188 }
3189
3190 /*
3191  * dupe FIO_OPT_STR_STORE options
3192  */
3193 void fio_options_mem_dupe(struct thread_data *td)
3194 {
3195         options_mem_dupe(&td->o, fio_options);
3196
3197         if (td->eo && td->io_ops) {
3198                 void *oldeo = td->eo;
3199
3200                 td->eo = malloc(td->io_ops->option_struct_size);
3201                 memcpy(td->eo, oldeo, td->io_ops->option_struct_size);
3202                 options_mem_dupe(td->eo, td->io_ops->options);
3203         }
3204 }
3205
3206 unsigned int fio_get_kb_base(void *data)
3207 {
3208         struct thread_options *o = data;
3209         unsigned int kb_base = 0;
3210
3211         if (o)
3212                 kb_base = o->kb_base;
3213         if (!kb_base)
3214                 kb_base = 1024;
3215
3216         return kb_base;
3217 }
3218
3219 int add_option(struct fio_option *o)
3220 {
3221         struct fio_option *__o;
3222         int opt_index = 0;
3223
3224         __o = fio_options;
3225         while (__o->name) {
3226                 opt_index++;
3227                 __o++;
3228         }
3229
3230         memcpy(&fio_options[opt_index], o, sizeof(*o));
3231         return 0;
3232 }
3233
3234 void invalidate_profile_options(const char *prof_name)
3235 {
3236         struct fio_option *o;
3237
3238         o = fio_options;
3239         while (o->name) {
3240                 if (o->prof_name && !strcmp(o->prof_name, prof_name)) {
3241                         o->type = FIO_OPT_INVALID;
3242                         o->prof_name = NULL;
3243                 }
3244                 o++;
3245         }
3246 }
3247
3248 void add_opt_posval(const char *optname, const char *ival, const char *help)
3249 {
3250         struct fio_option *o;
3251         unsigned int i;
3252
3253         o = find_option(fio_options, optname);
3254         if (!o)
3255                 return;
3256
3257         for (i = 0; i < PARSE_MAX_VP; i++) {
3258                 if (o->posval[i].ival)
3259                         continue;
3260
3261                 o->posval[i].ival = ival;
3262                 o->posval[i].help = help;
3263                 break;
3264         }
3265 }
3266
3267 void del_opt_posval(const char *optname, const char *ival)
3268 {
3269         struct fio_option *o;
3270         unsigned int i;
3271
3272         o = find_option(fio_options, optname);
3273         if (!o)
3274                 return;
3275
3276         for (i = 0; i < PARSE_MAX_VP; i++) {
3277                 if (!o->posval[i].ival)
3278                         continue;
3279                 if (strcmp(o->posval[i].ival, ival))
3280                         continue;
3281
3282                 o->posval[i].ival = NULL;
3283                 o->posval[i].help = NULL;
3284         }
3285 }
3286
3287 void fio_options_free(struct thread_data *td)
3288 {
3289         options_free(fio_options, td);
3290         if (td->eo && td->io_ops && td->io_ops->options) {
3291                 options_free(td->io_ops->options, td->eo);
3292                 free(td->eo);
3293                 td->eo = NULL;
3294         }
3295 }
3296
3297 struct fio_option *fio_option_find(const char *name)
3298 {
3299         return find_option(fio_options, name);
3300 }
3301