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