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