rand: add 64-bit tausworthe variant with a 2^258 cycle
[fio.git] / options.c
... / ...
CommitLineData
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#include <netinet/in.h>
12
13#include "fio.h"
14#include "verify.h"
15#include "parse.h"
16#include "lib/fls.h"
17#include "options.h"
18
19#include "crc/crc32c.h"
20
21char client_sockaddr_str[INET6_ADDRSTRLEN] = { 0 };
22
23/*
24 * Check if mmap/mmaphuge has a :/foo/bar/file at the end. If so, return that.
25 */
26static char *get_opt_postfix(const char *str)
27{
28 char *p = strstr(str, ":");
29
30 if (!p)
31 return NULL;
32
33 p++;
34 strip_blank_front(&p);
35 strip_blank_end(p);
36 return strdup(p);
37}
38
39static int converthexchartoint(char a)
40{
41 int base;
42
43 switch (a) {
44 case '0'...'9':
45 base = '0';
46 break;
47 case 'A'...'F':
48 base = 'A' - 10;
49 break;
50 case 'a'...'f':
51 base = 'a' - 10;
52 break;
53 default:
54 base = 0;
55 }
56 return a - base;
57}
58
59static int bs_cmp(const void *p1, const void *p2)
60{
61 const struct bssplit *bsp1 = p1;
62 const struct bssplit *bsp2 = p2;
63
64 return bsp1->perc < bsp2->perc;
65}
66
67static int bssplit_ddir(struct thread_options *o, int ddir, char *str)
68{
69 struct bssplit *bssplit;
70 unsigned int i, perc, perc_missing;
71 unsigned int max_bs, min_bs;
72 long long val;
73 char *fname;
74
75 o->bssplit_nr[ddir] = 4;
76 bssplit = malloc(4 * sizeof(struct bssplit));
77
78 i = 0;
79 max_bs = 0;
80 min_bs = -1;
81 while ((fname = strsep(&str, ":")) != NULL) {
82 char *perc_str;
83
84 if (!strlen(fname))
85 break;
86
87 /*
88 * grow struct buffer, if needed
89 */
90 if (i == o->bssplit_nr[ddir]) {
91 o->bssplit_nr[ddir] <<= 1;
92 bssplit = realloc(bssplit, o->bssplit_nr[ddir]
93 * sizeof(struct bssplit));
94 }
95
96 perc_str = strstr(fname, "/");
97 if (perc_str) {
98 *perc_str = '\0';
99 perc_str++;
100 perc = atoi(perc_str);
101 if (perc > 100)
102 perc = 100;
103 else if (!perc)
104 perc = -1U;
105 } else
106 perc = -1U;
107
108 if (str_to_decimal(fname, &val, 1, o, 0, 0)) {
109 log_err("fio: bssplit conversion failed\n");
110 free(bssplit);
111 return 1;
112 }
113
114 if (val > max_bs)
115 max_bs = val;
116 if (val < min_bs)
117 min_bs = val;
118
119 bssplit[i].bs = val;
120 bssplit[i].perc = perc;
121 i++;
122 }
123
124 o->bssplit_nr[ddir] = i;
125
126 /*
127 * Now check if the percentages add up, and how much is missing
128 */
129 perc = perc_missing = 0;
130 for (i = 0; i < o->bssplit_nr[ddir]; i++) {
131 struct bssplit *bsp = &bssplit[i];
132
133 if (bsp->perc == -1U)
134 perc_missing++;
135 else
136 perc += bsp->perc;
137 }
138
139 if (perc > 100 && perc_missing > 1) {
140 log_err("fio: bssplit percentages add to more than 100%%\n");
141 free(bssplit);
142 return 1;
143 }
144
145 /*
146 * If values didn't have a percentage set, divide the remains between
147 * them.
148 */
149 if (perc_missing) {
150 if (perc_missing == 1 && o->bssplit_nr[ddir] == 1)
151 perc = 100;
152 for (i = 0; i < o->bssplit_nr[ddir]; i++) {
153 struct bssplit *bsp = &bssplit[i];
154
155 if (bsp->perc == -1U)
156 bsp->perc = (100 - perc) / perc_missing;
157 }
158 }
159
160 o->min_bs[ddir] = min_bs;
161 o->max_bs[ddir] = max_bs;
162
163 /*
164 * now sort based on percentages, for ease of lookup
165 */
166 qsort(bssplit, o->bssplit_nr[ddir], sizeof(struct bssplit), bs_cmp);
167 o->bssplit[ddir] = bssplit;
168 return 0;
169}
170
171static int str_bssplit_cb(void *data, const char *input)
172{
173 struct thread_data *td = data;
174 char *str, *p, *odir, *ddir;
175 int ret = 0;
176
177 if (parse_dryrun())
178 return 0;
179
180 p = str = strdup(input);
181
182 strip_blank_front(&str);
183 strip_blank_end(str);
184
185 odir = strchr(str, ',');
186 if (odir) {
187 ddir = strchr(odir + 1, ',');
188 if (ddir) {
189 ret = bssplit_ddir(&td->o, DDIR_TRIM, ddir + 1);
190 if (!ret)
191 *ddir = '\0';
192 } else {
193 char *op;
194
195 op = strdup(odir + 1);
196 ret = bssplit_ddir(&td->o, DDIR_TRIM, op);
197
198 free(op);
199 }
200 if (!ret)
201 ret = bssplit_ddir(&td->o, DDIR_WRITE, odir + 1);
202 if (!ret) {
203 *odir = '\0';
204 ret = bssplit_ddir(&td->o, DDIR_READ, str);
205 }
206 } else {
207 char *op;
208
209 op = strdup(str);
210 ret = bssplit_ddir(&td->o, DDIR_WRITE, op);
211 free(op);
212
213 if (!ret) {
214 op = strdup(str);
215 ret = bssplit_ddir(&td->o, DDIR_TRIM, op);
216 free(op);
217 }
218 ret = bssplit_ddir(&td->o, DDIR_READ, str);
219 }
220
221 free(p);
222 return ret;
223}
224
225static int str2error(char *str)
226{
227 const char *err[] = { "EPERM", "ENOENT", "ESRCH", "EINTR", "EIO",
228 "ENXIO", "E2BIG", "ENOEXEC", "EBADF",
229 "ECHILD", "EAGAIN", "ENOMEM", "EACCES",
230 "EFAULT", "ENOTBLK", "EBUSY", "EEXIST",
231 "EXDEV", "ENODEV", "ENOTDIR", "EISDIR",
232 "EINVAL", "ENFILE", "EMFILE", "ENOTTY",
233 "ETXTBSY","EFBIG", "ENOSPC", "ESPIPE",
234 "EROFS","EMLINK", "EPIPE", "EDOM", "ERANGE" };
235 int i = 0, num = sizeof(err) / sizeof(void *);
236
237 while (i < num) {
238 if (!strcmp(err[i], str))
239 return i + 1;
240 i++;
241 }
242 return 0;
243}
244
245static int ignore_error_type(struct thread_data *td, int etype, char *str)
246{
247 unsigned int i;
248 int *error;
249 char *fname;
250
251 if (etype >= ERROR_TYPE_CNT) {
252 log_err("Illegal error type\n");
253 return 1;
254 }
255
256 td->o.ignore_error_nr[etype] = 4;
257 error = malloc(4 * sizeof(struct bssplit));
258
259 i = 0;
260 while ((fname = strsep(&str, ":")) != NULL) {
261
262 if (!strlen(fname))
263 break;
264
265 /*
266 * grow struct buffer, if needed
267 */
268 if (i == td->o.ignore_error_nr[etype]) {
269 td->o.ignore_error_nr[etype] <<= 1;
270 error = realloc(error, td->o.ignore_error_nr[etype]
271 * sizeof(int));
272 }
273 if (fname[0] == 'E') {
274 error[i] = str2error(fname);
275 } else {
276 error[i] = atoi(fname);
277 if (error[i] < 0)
278 error[i] = -error[i];
279 }
280 if (!error[i]) {
281 log_err("Unknown error %s, please use number value \n",
282 fname);
283 free(error);
284 return 1;
285 }
286 i++;
287 }
288 if (i) {
289 td->o.continue_on_error |= 1 << etype;
290 td->o.ignore_error_nr[etype] = i;
291 td->o.ignore_error[etype] = error;
292 } else
293 free(error);
294
295 return 0;
296
297}
298
299static int str_ignore_error_cb(void *data, const char *input)
300{
301 struct thread_data *td = data;
302 char *str, *p, *n;
303 int type = 0, ret = 1;
304
305 if (parse_dryrun())
306 return 0;
307
308 p = str = strdup(input);
309
310 strip_blank_front(&str);
311 strip_blank_end(str);
312
313 while (p) {
314 n = strchr(p, ',');
315 if (n)
316 *n++ = '\0';
317 ret = ignore_error_type(td, type, p);
318 if (ret)
319 break;
320 p = n;
321 type++;
322 }
323 free(str);
324 return ret;
325}
326
327static int str_rw_cb(void *data, const char *str)
328{
329 struct thread_data *td = data;
330 struct thread_options *o = &td->o;
331 char *nr;
332
333 if (parse_dryrun())
334 return 0;
335
336 o->ddir_seq_nr = 1;
337 o->ddir_seq_add = 0;
338
339 nr = get_opt_postfix(str);
340 if (!nr)
341 return 0;
342
343 if (td_random(td))
344 o->ddir_seq_nr = atoi(nr);
345 else {
346 long long val;
347
348 if (str_to_decimal(nr, &val, 1, o, 0, 0)) {
349 log_err("fio: rw postfix parsing failed\n");
350 free(nr);
351 return 1;
352 }
353
354 o->ddir_seq_add = val;
355 }
356
357 free(nr);
358 return 0;
359}
360
361static int str_mem_cb(void *data, const char *mem)
362{
363 struct thread_data *td = data;
364
365 if (td->o.mem_type == MEM_MMAPHUGE || td->o.mem_type == MEM_MMAP)
366 td->o.mmapfile = get_opt_postfix(mem);
367
368 return 0;
369}
370
371static int fio_clock_source_cb(void *data, const char *str)
372{
373 struct thread_data *td = data;
374
375 fio_clock_source = td->o.clocksource;
376 fio_clock_source_set = 1;
377 fio_clock_init();
378 return 0;
379}
380
381static int str_rwmix_read_cb(void *data, unsigned long long *val)
382{
383 struct thread_data *td = data;
384
385 td->o.rwmix[DDIR_READ] = *val;
386 td->o.rwmix[DDIR_WRITE] = 100 - *val;
387 return 0;
388}
389
390static int str_rwmix_write_cb(void *data, unsigned long long *val)
391{
392 struct thread_data *td = data;
393
394 td->o.rwmix[DDIR_WRITE] = *val;
395 td->o.rwmix[DDIR_READ] = 100 - *val;
396 return 0;
397}
398
399static int str_exitall_cb(void)
400{
401 exitall_on_terminate = 1;
402 return 0;
403}
404
405#ifdef FIO_HAVE_CPU_AFFINITY
406int fio_cpus_split(os_cpu_mask_t *mask, unsigned int cpu_index)
407{
408 unsigned int i, index, cpus_in_mask;
409 const long max_cpu = cpus_online();
410
411 cpus_in_mask = fio_cpu_count(mask);
412 cpu_index = cpu_index % cpus_in_mask;
413
414 index = 0;
415 for (i = 0; i < max_cpu; i++) {
416 if (!fio_cpu_isset(mask, i))
417 continue;
418
419 if (cpu_index != index)
420 fio_cpu_clear(mask, i);
421
422 index++;
423 }
424
425 return fio_cpu_count(mask);
426}
427
428static int str_cpumask_cb(void *data, unsigned long long *val)
429{
430 struct thread_data *td = data;
431 unsigned int i;
432 long max_cpu;
433 int ret;
434
435 if (parse_dryrun())
436 return 0;
437
438 ret = fio_cpuset_init(&td->o.cpumask);
439 if (ret < 0) {
440 log_err("fio: cpuset_init failed\n");
441 td_verror(td, ret, "fio_cpuset_init");
442 return 1;
443 }
444
445 max_cpu = cpus_online();
446
447 for (i = 0; i < sizeof(int) * 8; i++) {
448 if ((1 << i) & *val) {
449 if (i >= max_cpu) {
450 log_err("fio: CPU %d too large (max=%ld)\n", i,
451 max_cpu - 1);
452 return 1;
453 }
454 dprint(FD_PARSE, "set cpu allowed %d\n", i);
455 fio_cpu_set(&td->o.cpumask, i);
456 }
457 }
458
459 return 0;
460}
461
462static int set_cpus_allowed(struct thread_data *td, os_cpu_mask_t *mask,
463 const char *input)
464{
465 char *cpu, *str, *p;
466 long max_cpu;
467 int ret = 0;
468
469 ret = fio_cpuset_init(mask);
470 if (ret < 0) {
471 log_err("fio: cpuset_init failed\n");
472 td_verror(td, ret, "fio_cpuset_init");
473 return 1;
474 }
475
476 p = str = strdup(input);
477
478 strip_blank_front(&str);
479 strip_blank_end(str);
480
481 max_cpu = cpus_online();
482
483 while ((cpu = strsep(&str, ",")) != NULL) {
484 char *str2, *cpu2;
485 int icpu, icpu2;
486
487 if (!strlen(cpu))
488 break;
489
490 str2 = cpu;
491 icpu2 = -1;
492 while ((cpu2 = strsep(&str2, "-")) != NULL) {
493 if (!strlen(cpu2))
494 break;
495
496 icpu2 = atoi(cpu2);
497 }
498
499 icpu = atoi(cpu);
500 if (icpu2 == -1)
501 icpu2 = icpu;
502 while (icpu <= icpu2) {
503 if (icpu >= FIO_MAX_CPUS) {
504 log_err("fio: your OS only supports up to"
505 " %d CPUs\n", (int) FIO_MAX_CPUS);
506 ret = 1;
507 break;
508 }
509 if (icpu >= max_cpu) {
510 log_err("fio: CPU %d too large (max=%ld)\n",
511 icpu, max_cpu - 1);
512 ret = 1;
513 break;
514 }
515
516 dprint(FD_PARSE, "set cpu allowed %d\n", icpu);
517 fio_cpu_set(mask, icpu);
518 icpu++;
519 }
520 if (ret)
521 break;
522 }
523
524 free(p);
525 return ret;
526}
527
528static int str_cpus_allowed_cb(void *data, const char *input)
529{
530 struct thread_data *td = data;
531
532 if (parse_dryrun())
533 return 0;
534
535 return set_cpus_allowed(td, &td->o.cpumask, input);
536}
537
538static int str_verify_cpus_allowed_cb(void *data, const char *input)
539{
540 struct thread_data *td = data;
541
542 return set_cpus_allowed(td, &td->o.verify_cpumask, input);
543}
544#endif
545
546#ifdef CONFIG_LIBNUMA
547static int str_numa_cpunodes_cb(void *data, char *input)
548{
549 struct thread_data *td = data;
550 struct bitmask *verify_bitmask;
551
552 if (parse_dryrun())
553 return 0;
554
555 /* numa_parse_nodestring() parses a character string list
556 * of nodes into a bit mask. The bit mask is allocated by
557 * numa_allocate_nodemask(), so it should be freed by
558 * numa_free_nodemask().
559 */
560 verify_bitmask = numa_parse_nodestring(input);
561 if (verify_bitmask == NULL) {
562 log_err("fio: numa_parse_nodestring failed\n");
563 td_verror(td, 1, "str_numa_cpunodes_cb");
564 return 1;
565 }
566 numa_free_nodemask(verify_bitmask);
567
568 td->o.numa_cpunodes = strdup(input);
569 return 0;
570}
571
572static int str_numa_mpol_cb(void *data, char *input)
573{
574 struct thread_data *td = data;
575 const char * const policy_types[] =
576 { "default", "prefer", "bind", "interleave", "local", NULL };
577 int i;
578 char *nodelist;
579 struct bitmask *verify_bitmask;
580
581 if (parse_dryrun())
582 return 0;
583
584 nodelist = strchr(input, ':');
585 if (nodelist) {
586 /* NUL-terminate mode */
587 *nodelist++ = '\0';
588 }
589
590 for (i = 0; i <= MPOL_LOCAL; i++) {
591 if (!strcmp(input, policy_types[i])) {
592 td->o.numa_mem_mode = i;
593 break;
594 }
595 }
596 if (i > MPOL_LOCAL) {
597 log_err("fio: memory policy should be: default, prefer, bind, interleave, local\n");
598 goto out;
599 }
600
601 switch (td->o.numa_mem_mode) {
602 case MPOL_PREFERRED:
603 /*
604 * Insist on a nodelist of one node only
605 */
606 if (nodelist) {
607 char *rest = nodelist;
608 while (isdigit(*rest))
609 rest++;
610 if (*rest) {
611 log_err("fio: one node only for \'prefer\'\n");
612 goto out;
613 }
614 } else {
615 log_err("fio: one node is needed for \'prefer\'\n");
616 goto out;
617 }
618 break;
619 case MPOL_INTERLEAVE:
620 /*
621 * Default to online nodes with memory if no nodelist
622 */
623 if (!nodelist)
624 nodelist = strdup("all");
625 break;
626 case MPOL_LOCAL:
627 case MPOL_DEFAULT:
628 /*
629 * Don't allow a nodelist
630 */
631 if (nodelist) {
632 log_err("fio: NO nodelist for \'local\'\n");
633 goto out;
634 }
635 break;
636 case MPOL_BIND:
637 /*
638 * Insist on a nodelist
639 */
640 if (!nodelist) {
641 log_err("fio: a nodelist is needed for \'bind\'\n");
642 goto out;
643 }
644 break;
645 }
646
647
648 /* numa_parse_nodestring() parses a character string list
649 * of nodes into a bit mask. The bit mask is allocated by
650 * numa_allocate_nodemask(), so it should be freed by
651 * numa_free_nodemask().
652 */
653 switch (td->o.numa_mem_mode) {
654 case MPOL_PREFERRED:
655 td->o.numa_mem_prefer_node = atoi(nodelist);
656 break;
657 case MPOL_INTERLEAVE:
658 case MPOL_BIND:
659 verify_bitmask = numa_parse_nodestring(nodelist);
660 if (verify_bitmask == NULL) {
661 log_err("fio: numa_parse_nodestring failed\n");
662 td_verror(td, 1, "str_numa_memnodes_cb");
663 return 1;
664 }
665 td->o.numa_memnodes = strdup(nodelist);
666 numa_free_nodemask(verify_bitmask);
667
668 break;
669 case MPOL_LOCAL:
670 case MPOL_DEFAULT:
671 default:
672 break;
673 }
674
675 return 0;
676out:
677 return 1;
678}
679#endif
680
681static int str_fst_cb(void *data, const char *str)
682{
683 struct thread_data *td = data;
684 char *nr = get_opt_postfix(str);
685
686 td->file_service_nr = 1;
687 if (nr) {
688 td->file_service_nr = atoi(nr);
689 free(nr);
690 }
691
692 return 0;
693}
694
695#ifdef CONFIG_SYNC_FILE_RANGE
696static int str_sfr_cb(void *data, const char *str)
697{
698 struct thread_data *td = data;
699 char *nr = get_opt_postfix(str);
700
701 td->sync_file_range_nr = 1;
702 if (nr) {
703 td->sync_file_range_nr = atoi(nr);
704 free(nr);
705 }
706
707 return 0;
708}
709#endif
710
711static int str_random_distribution_cb(void *data, const char *str)
712{
713 struct thread_data *td = data;
714 double val;
715 char *nr;
716
717 if (parse_dryrun())
718 return 0;
719
720 if (td->o.random_distribution == FIO_RAND_DIST_ZIPF)
721 val = FIO_DEF_ZIPF;
722 else if (td->o.random_distribution == FIO_RAND_DIST_PARETO)
723 val = FIO_DEF_PARETO;
724 else if (td->o.random_distribution == FIO_RAND_DIST_GAUSS)
725 val = 0.0;
726 else
727 return 0;
728
729 nr = get_opt_postfix(str);
730 if (nr && !str_to_float(nr, &val, 0)) {
731 log_err("fio: random postfix parsing failed\n");
732 free(nr);
733 return 1;
734 }
735
736 free(nr);
737
738 if (td->o.random_distribution == FIO_RAND_DIST_ZIPF) {
739 if (val == 1.00) {
740 log_err("fio: zipf theta must different than 1.0\n");
741 return 1;
742 }
743 td->o.zipf_theta.u.f = val;
744 } else if (td->o.random_distribution == FIO_RAND_DIST_PARETO) {
745 if (val <= 0.00 || val >= 1.00) {
746 log_err("fio: pareto input out of range (0 < input < 1.0)\n");
747 return 1;
748 }
749 td->o.pareto_h.u.f = val;
750 } else {
751 if (val <= 0.00 || val >= 100.0) {
752 log_err("fio: normal deviation out of range (0 < input < 100.0)\n");
753 return 1;
754 }
755 td->o.gauss_dev.u.f = val;
756 }
757
758 return 0;
759}
760
761/*
762 * Return next name in the string. Files are separated with ':'. If the ':'
763 * is escaped with a '\', then that ':' is part of the filename and does not
764 * indicate a new file.
765 */
766static char *get_next_name(char **ptr)
767{
768 char *str = *ptr;
769 char *p, *start;
770
771 if (!str || !strlen(str))
772 return NULL;
773
774 start = str;
775 do {
776 /*
777 * No colon, we are done
778 */
779 p = strchr(str, ':');
780 if (!p) {
781 *ptr = NULL;
782 break;
783 }
784
785 /*
786 * We got a colon, but it's the first character. Skip and
787 * continue
788 */
789 if (p == start) {
790 str = ++start;
791 continue;
792 }
793
794 if (*(p - 1) != '\\') {
795 *p = '\0';
796 *ptr = p + 1;
797 break;
798 }
799
800 memmove(p - 1, p, strlen(p) + 1);
801 str = p;
802 } while (1);
803
804 return start;
805}
806
807
808static int get_max_name_idx(char *input)
809{
810 unsigned int cur_idx;
811 char *str, *p;
812
813 p = str = strdup(input);
814 for (cur_idx = 0; ; cur_idx++)
815 if (get_next_name(&str) == NULL)
816 break;
817
818 free(p);
819 return cur_idx;
820}
821
822/*
823 * Returns the directory at the index, indexes > entires will be
824 * assigned via modulo division of the index
825 */
826int set_name_idx(char *target, size_t tlen, char *input, int index)
827{
828 unsigned int cur_idx;
829 int len;
830 char *fname, *str, *p;
831
832 p = str = strdup(input);
833
834 index %= get_max_name_idx(input);
835 for (cur_idx = 0; cur_idx <= index; cur_idx++)
836 fname = get_next_name(&str);
837
838 if (client_sockaddr_str[0]) {
839 len = snprintf(target, tlen, "%s/%s.", fname,
840 client_sockaddr_str);
841 } else
842 len = snprintf(target, tlen, "%s/", fname);
843
844 target[tlen - 1] = '\0';
845 free(p);
846
847 return len;
848}
849
850static int str_filename_cb(void *data, const char *input)
851{
852 struct thread_data *td = data;
853 char *fname, *str, *p;
854
855 p = str = strdup(input);
856
857 strip_blank_front(&str);
858 strip_blank_end(str);
859
860 if (!td->files_index)
861 td->o.nr_files = 0;
862
863 while ((fname = get_next_name(&str)) != NULL) {
864 if (!strlen(fname))
865 break;
866 add_file(td, fname, 0, 1);
867 }
868
869 free(p);
870 return 0;
871}
872
873static int str_directory_cb(void *data, const char fio_unused *unused)
874{
875 struct thread_data *td = data;
876 struct stat sb;
877 char *dirname, *str, *p;
878 int ret = 0;
879
880 if (parse_dryrun())
881 return 0;
882
883 p = str = strdup(td->o.directory);
884 while ((dirname = get_next_name(&str)) != NULL) {
885 if (lstat(dirname, &sb) < 0) {
886 ret = errno;
887
888 log_err("fio: %s is not a directory\n", dirname);
889 td_verror(td, ret, "lstat");
890 goto out;
891 }
892 if (!S_ISDIR(sb.st_mode)) {
893 log_err("fio: %s is not a directory\n", dirname);
894 ret = 1;
895 goto out;
896 }
897 }
898
899out:
900 free(p);
901 return ret;
902}
903
904static int str_opendir_cb(void *data, const char fio_unused *str)
905{
906 struct thread_data *td = data;
907
908 if (parse_dryrun())
909 return 0;
910
911 if (!td->files_index)
912 td->o.nr_files = 0;
913
914 return add_dir_files(td, td->o.opendir);
915}
916
917static int pattern_cb(char *pattern, unsigned int max_size,
918 const char *input, unsigned int *pattern_bytes)
919{
920 long off;
921 int i = 0, j = 0, len, k, base = 10;
922 uint32_t pattern_length;
923 char *loc1, *loc2;
924
925 /*
926 * Check if it's a string input
927 */
928 loc1 = strchr(input, '\"');
929 if (loc1) {
930 do {
931 loc1++;
932 if (*loc1 == '\0' || *loc1 == '\"')
933 break;
934
935 pattern[i] = *loc1;
936 i++;
937 } while (i < max_size);
938
939 if (!i)
940 return 1;
941
942 goto fill;
943 }
944
945 /*
946 * No string, find out if it's decimal or hexidecimal
947 */
948 loc1 = strstr(input, "0x");
949 loc2 = strstr(input, "0X");
950 if (loc1 || loc2)
951 base = 16;
952 off = strtol(input, NULL, base);
953 if (off != LONG_MAX || errno != ERANGE) {
954 while (off) {
955 pattern[i] = off & 0xff;
956 off >>= 8;
957 i++;
958 }
959 } else {
960 len = strlen(input);
961 k = len - 1;
962 if (base == 16) {
963 if (loc1)
964 j = loc1 - input + 2;
965 else
966 j = loc2 - input + 2;
967 } else
968 return 1;
969 if (len - j < max_size * 2) {
970 while (k >= j) {
971 off = converthexchartoint(input[k--]);
972 if (k >= j)
973 off += (converthexchartoint(input[k--])
974 * 16);
975 pattern[i++] = (char) off;
976 }
977 }
978 }
979
980 /*
981 * Fill the pattern all the way to the end. This greatly reduces
982 * the number of memcpy's we have to do when verifying the IO.
983 */
984fill:
985 pattern_length = i;
986 while (i > 1 && i * 2 <= max_size) {
987 memcpy(&pattern[i], &pattern[0], i);
988 i *= 2;
989 }
990
991 /*
992 * Fill remainder, if the pattern multiple ends up not being
993 * max_size.
994 */
995 while (i > 1 && i < max_size) {
996 unsigned int b = min(pattern_length, max_size - i);
997
998 memcpy(&pattern[i], &pattern[0], b);
999 i += b;
1000 }
1001
1002 if (i == 1) {
1003 /*
1004 * The code in verify_io_u_pattern assumes a single byte
1005 * pattern fills the whole verify pattern buffer.
1006 */
1007 memset(pattern, pattern[0], max_size);
1008 }
1009
1010 *pattern_bytes = i;
1011 return 0;
1012}
1013
1014static int str_buffer_pattern_cb(void *data, const char *input)
1015{
1016 struct thread_data *td = data;
1017 int ret;
1018
1019 ret = pattern_cb(td->o.buffer_pattern, MAX_PATTERN_SIZE, input,
1020 &td->o.buffer_pattern_bytes);
1021
1022 if (!ret && td->o.buffer_pattern_bytes) {
1023 if (!td->o.compress_percentage)
1024 td->o.refill_buffers = 0;
1025 td->o.scramble_buffers = 0;
1026 td->o.zero_buffers = 0;
1027 } else {
1028 log_err("fio: failed parsing pattern `%s`\n", input);
1029 ret = 1;
1030 }
1031
1032 return ret;
1033}
1034
1035static int str_buffer_compress_cb(void *data, unsigned long long *il)
1036{
1037 struct thread_data *td = data;
1038
1039 td->flags |= TD_F_COMPRESS;
1040 td->o.compress_percentage = *il;
1041 return 0;
1042}
1043
1044static int str_dedupe_cb(void *data, unsigned long long *il)
1045{
1046 struct thread_data *td = data;
1047
1048 td->flags |= TD_F_COMPRESS;
1049 td->o.dedupe_percentage = *il;
1050 td->o.refill_buffers = 1;
1051 return 0;
1052}
1053
1054static int str_verify_pattern_cb(void *data, const char *input)
1055{
1056 struct thread_data *td = data;
1057 int ret;
1058
1059 ret = pattern_cb(td->o.verify_pattern, MAX_PATTERN_SIZE, input,
1060 &td->o.verify_pattern_bytes);
1061
1062 /*
1063 * VERIFY_META could already be set
1064 */
1065 if (!ret && td->o.verify == VERIFY_NONE)
1066 td->o.verify = VERIFY_PATTERN;
1067
1068 return ret;
1069}
1070
1071static int str_gtod_reduce_cb(void *data, int *il)
1072{
1073 struct thread_data *td = data;
1074 int val = *il;
1075
1076 td->o.disable_lat = !!val;
1077 td->o.disable_clat = !!val;
1078 td->o.disable_slat = !!val;
1079 td->o.disable_bw = !!val;
1080 td->o.clat_percentiles = !val;
1081 if (val)
1082 td->tv_cache_mask = 63;
1083
1084 return 0;
1085}
1086
1087static int str_size_cb(void *data, unsigned long long *__val)
1088{
1089 struct thread_data *td = data;
1090 unsigned long long v = *__val;
1091
1092 if (parse_is_percent(v)) {
1093 td->o.size = 0;
1094 td->o.size_percent = -1ULL - v;
1095 } else
1096 td->o.size = v;
1097
1098 return 0;
1099}
1100
1101static int rw_verify(struct fio_option *o, void *data)
1102{
1103 struct thread_data *td = data;
1104
1105 if (read_only && td_write(td)) {
1106 log_err("fio: job <%s> has write bit set, but fio is in"
1107 " read-only mode\n", td->o.name);
1108 return 1;
1109 }
1110
1111 return 0;
1112}
1113
1114static int gtod_cpu_verify(struct fio_option *o, void *data)
1115{
1116#ifndef FIO_HAVE_CPU_AFFINITY
1117 struct thread_data *td = data;
1118
1119 if (td->o.gtod_cpu) {
1120 log_err("fio: platform must support CPU affinity for"
1121 "gettimeofday() offloading\n");
1122 return 1;
1123 }
1124#endif
1125
1126 return 0;
1127}
1128
1129/*
1130 * Option grouping
1131 */
1132static struct opt_group fio_opt_groups[] = {
1133 {
1134 .name = "General",
1135 .mask = FIO_OPT_C_GENERAL,
1136 },
1137 {
1138 .name = "I/O",
1139 .mask = FIO_OPT_C_IO,
1140 },
1141 {
1142 .name = "File",
1143 .mask = FIO_OPT_C_FILE,
1144 },
1145 {
1146 .name = "Statistics",
1147 .mask = FIO_OPT_C_STAT,
1148 },
1149 {
1150 .name = "Logging",
1151 .mask = FIO_OPT_C_LOG,
1152 },
1153 {
1154 .name = "Profiles",
1155 .mask = FIO_OPT_C_PROFILE,
1156 },
1157 {
1158 .name = NULL,
1159 },
1160};
1161
1162static struct opt_group *__opt_group_from_mask(struct opt_group *ogs, unsigned int *mask,
1163 unsigned int inv_mask)
1164{
1165 struct opt_group *og;
1166 int i;
1167
1168 if (*mask == inv_mask || !*mask)
1169 return NULL;
1170
1171 for (i = 0; ogs[i].name; i++) {
1172 og = &ogs[i];
1173
1174 if (*mask & og->mask) {
1175 *mask &= ~(og->mask);
1176 return og;
1177 }
1178 }
1179
1180 return NULL;
1181}
1182
1183struct opt_group *opt_group_from_mask(unsigned int *mask)
1184{
1185 return __opt_group_from_mask(fio_opt_groups, mask, FIO_OPT_C_INVALID);
1186}
1187
1188static struct opt_group fio_opt_cat_groups[] = {
1189 {
1190 .name = "Latency profiling",
1191 .mask = FIO_OPT_G_LATPROF,
1192 },
1193 {
1194 .name = "Rate",
1195 .mask = FIO_OPT_G_RATE,
1196 },
1197 {
1198 .name = "Zone",
1199 .mask = FIO_OPT_G_ZONE,
1200 },
1201 {
1202 .name = "Read/write mix",
1203 .mask = FIO_OPT_G_RWMIX,
1204 },
1205 {
1206 .name = "Verify",
1207 .mask = FIO_OPT_G_VERIFY,
1208 },
1209 {
1210 .name = "Trim",
1211 .mask = FIO_OPT_G_TRIM,
1212 },
1213 {
1214 .name = "I/O Logging",
1215 .mask = FIO_OPT_G_IOLOG,
1216 },
1217 {
1218 .name = "I/O Depth",
1219 .mask = FIO_OPT_G_IO_DEPTH,
1220 },
1221 {
1222 .name = "I/O Flow",
1223 .mask = FIO_OPT_G_IO_FLOW,
1224 },
1225 {
1226 .name = "Description",
1227 .mask = FIO_OPT_G_DESC,
1228 },
1229 {
1230 .name = "Filename",
1231 .mask = FIO_OPT_G_FILENAME,
1232 },
1233 {
1234 .name = "General I/O",
1235 .mask = FIO_OPT_G_IO_BASIC,
1236 },
1237 {
1238 .name = "Cgroups",
1239 .mask = FIO_OPT_G_CGROUP,
1240 },
1241 {
1242 .name = "Runtime",
1243 .mask = FIO_OPT_G_RUNTIME,
1244 },
1245 {
1246 .name = "Process",
1247 .mask = FIO_OPT_G_PROCESS,
1248 },
1249 {
1250 .name = "Job credentials / priority",
1251 .mask = FIO_OPT_G_CRED,
1252 },
1253 {
1254 .name = "Clock settings",
1255 .mask = FIO_OPT_G_CLOCK,
1256 },
1257 {
1258 .name = "I/O Type",
1259 .mask = FIO_OPT_G_IO_TYPE,
1260 },
1261 {
1262 .name = "I/O Thinktime",
1263 .mask = FIO_OPT_G_THINKTIME,
1264 },
1265 {
1266 .name = "Randomizations",
1267 .mask = FIO_OPT_G_RANDOM,
1268 },
1269 {
1270 .name = "I/O buffers",
1271 .mask = FIO_OPT_G_IO_BUF,
1272 },
1273 {
1274 .name = "Tiobench profile",
1275 .mask = FIO_OPT_G_TIOBENCH,
1276 },
1277 {
1278 .name = "MTD",
1279 .mask = FIO_OPT_G_MTD,
1280 },
1281
1282 {
1283 .name = NULL,
1284 }
1285};
1286
1287struct opt_group *opt_group_cat_from_mask(unsigned int *mask)
1288{
1289 return __opt_group_from_mask(fio_opt_cat_groups, mask, FIO_OPT_G_INVALID);
1290}
1291
1292/*
1293 * Map of job/command line options
1294 */
1295struct fio_option fio_options[FIO_MAX_OPTS] = {
1296 {
1297 .name = "description",
1298 .lname = "Description of job",
1299 .type = FIO_OPT_STR_STORE,
1300 .off1 = td_var_offset(description),
1301 .help = "Text job description",
1302 .category = FIO_OPT_C_GENERAL,
1303 .group = FIO_OPT_G_DESC,
1304 },
1305 {
1306 .name = "name",
1307 .lname = "Job name",
1308 .type = FIO_OPT_STR_STORE,
1309 .off1 = td_var_offset(name),
1310 .help = "Name of this job",
1311 .category = FIO_OPT_C_GENERAL,
1312 .group = FIO_OPT_G_DESC,
1313 },
1314 {
1315 .name = "filename",
1316 .lname = "Filename(s)",
1317 .type = FIO_OPT_STR_STORE,
1318 .off1 = td_var_offset(filename),
1319 .cb = str_filename_cb,
1320 .prio = -1, /* must come after "directory" */
1321 .help = "File(s) to use for the workload",
1322 .category = FIO_OPT_C_FILE,
1323 .group = FIO_OPT_G_FILENAME,
1324 },
1325 {
1326 .name = "directory",
1327 .lname = "Directory",
1328 .type = FIO_OPT_STR_STORE,
1329 .off1 = td_var_offset(directory),
1330 .cb = str_directory_cb,
1331 .help = "Directory to store files in",
1332 .category = FIO_OPT_C_FILE,
1333 .group = FIO_OPT_G_FILENAME,
1334 },
1335 {
1336 .name = "filename_format",
1337 .type = FIO_OPT_STR_STORE,
1338 .off1 = td_var_offset(filename_format),
1339 .prio = -1, /* must come after "directory" */
1340 .help = "Override default $jobname.$jobnum.$filenum naming",
1341 .def = "$jobname.$jobnum.$filenum",
1342 .category = FIO_OPT_C_FILE,
1343 .group = FIO_OPT_G_FILENAME,
1344 },
1345 {
1346 .name = "lockfile",
1347 .lname = "Lockfile",
1348 .type = FIO_OPT_STR,
1349 .off1 = td_var_offset(file_lock_mode),
1350 .help = "Lock file when doing IO to it",
1351 .prio = 1,
1352 .parent = "filename",
1353 .hide = 0,
1354 .def = "none",
1355 .category = FIO_OPT_C_FILE,
1356 .group = FIO_OPT_G_FILENAME,
1357 .posval = {
1358 { .ival = "none",
1359 .oval = FILE_LOCK_NONE,
1360 .help = "No file locking",
1361 },
1362 { .ival = "exclusive",
1363 .oval = FILE_LOCK_EXCLUSIVE,
1364 .help = "Exclusive file lock",
1365 },
1366 {
1367 .ival = "readwrite",
1368 .oval = FILE_LOCK_READWRITE,
1369 .help = "Read vs write lock",
1370 },
1371 },
1372 },
1373 {
1374 .name = "opendir",
1375 .lname = "Open directory",
1376 .type = FIO_OPT_STR_STORE,
1377 .off1 = td_var_offset(opendir),
1378 .cb = str_opendir_cb,
1379 .help = "Recursively add files from this directory and down",
1380 .category = FIO_OPT_C_FILE,
1381 .group = FIO_OPT_G_FILENAME,
1382 },
1383 {
1384 .name = "rw",
1385 .lname = "Read/write",
1386 .alias = "readwrite",
1387 .type = FIO_OPT_STR,
1388 .cb = str_rw_cb,
1389 .off1 = td_var_offset(td_ddir),
1390 .help = "IO direction",
1391 .def = "read",
1392 .verify = rw_verify,
1393 .category = FIO_OPT_C_IO,
1394 .group = FIO_OPT_G_IO_BASIC,
1395 .posval = {
1396 { .ival = "read",
1397 .oval = TD_DDIR_READ,
1398 .help = "Sequential read",
1399 },
1400 { .ival = "write",
1401 .oval = TD_DDIR_WRITE,
1402 .help = "Sequential write",
1403 },
1404 { .ival = "trim",
1405 .oval = TD_DDIR_TRIM,
1406 .help = "Sequential trim",
1407 },
1408 { .ival = "randread",
1409 .oval = TD_DDIR_RANDREAD,
1410 .help = "Random read",
1411 },
1412 { .ival = "randwrite",
1413 .oval = TD_DDIR_RANDWRITE,
1414 .help = "Random write",
1415 },
1416 { .ival = "randtrim",
1417 .oval = TD_DDIR_RANDTRIM,
1418 .help = "Random trim",
1419 },
1420 { .ival = "rw",
1421 .oval = TD_DDIR_RW,
1422 .help = "Sequential read and write mix",
1423 },
1424 { .ival = "readwrite",
1425 .oval = TD_DDIR_RW,
1426 .help = "Sequential read and write mix",
1427 },
1428 { .ival = "randrw",
1429 .oval = TD_DDIR_RANDRW,
1430 .help = "Random read and write mix"
1431 },
1432 { .ival = "trimwrite",
1433 .oval = TD_DDIR_TRIMWRITE,
1434 .help = "Trim and write mix, trims preceding writes"
1435 },
1436 },
1437 },
1438 {
1439 .name = "rw_sequencer",
1440 .lname = "RW Sequencer",
1441 .type = FIO_OPT_STR,
1442 .off1 = td_var_offset(rw_seq),
1443 .help = "IO offset generator modifier",
1444 .def = "sequential",
1445 .category = FIO_OPT_C_IO,
1446 .group = FIO_OPT_G_IO_BASIC,
1447 .posval = {
1448 { .ival = "sequential",
1449 .oval = RW_SEQ_SEQ,
1450 .help = "Generate sequential offsets",
1451 },
1452 { .ival = "identical",
1453 .oval = RW_SEQ_IDENT,
1454 .help = "Generate identical offsets",
1455 },
1456 },
1457 },
1458
1459 {
1460 .name = "ioengine",
1461 .lname = "IO Engine",
1462 .type = FIO_OPT_STR_STORE,
1463 .off1 = td_var_offset(ioengine),
1464 .help = "IO engine to use",
1465 .def = FIO_PREFERRED_ENGINE,
1466 .category = FIO_OPT_C_IO,
1467 .group = FIO_OPT_G_IO_BASIC,
1468 .posval = {
1469 { .ival = "sync",
1470 .help = "Use read/write",
1471 },
1472 { .ival = "psync",
1473 .help = "Use pread/pwrite",
1474 },
1475 { .ival = "vsync",
1476 .help = "Use readv/writev",
1477 },
1478#ifdef CONFIG_PWRITEV
1479 { .ival = "pvsync",
1480 .help = "Use preadv/pwritev",
1481 },
1482#endif
1483#ifdef CONFIG_LIBAIO
1484 { .ival = "libaio",
1485 .help = "Linux native asynchronous IO",
1486 },
1487#endif
1488#ifdef CONFIG_POSIXAIO
1489 { .ival = "posixaio",
1490 .help = "POSIX asynchronous IO",
1491 },
1492#endif
1493#ifdef CONFIG_SOLARISAIO
1494 { .ival = "solarisaio",
1495 .help = "Solaris native asynchronous IO",
1496 },
1497#endif
1498#ifdef CONFIG_WINDOWSAIO
1499 { .ival = "windowsaio",
1500 .help = "Windows native asynchronous IO"
1501 },
1502#endif
1503#ifdef CONFIG_RBD
1504 { .ival = "rbd",
1505 .help = "Rados Block Device asynchronous IO"
1506 },
1507#endif
1508 { .ival = "mmap",
1509 .help = "Memory mapped IO"
1510 },
1511#ifdef CONFIG_LINUX_SPLICE
1512 { .ival = "splice",
1513 .help = "splice/vmsplice based IO",
1514 },
1515 { .ival = "netsplice",
1516 .help = "splice/vmsplice to/from the network",
1517 },
1518#endif
1519#ifdef FIO_HAVE_SGIO
1520 { .ival = "sg",
1521 .help = "SCSI generic v3 IO",
1522 },
1523#endif
1524 { .ival = "null",
1525 .help = "Testing engine (no data transfer)",
1526 },
1527 { .ival = "net",
1528 .help = "Network IO",
1529 },
1530 { .ival = "cpuio",
1531 .help = "CPU cycle burner engine",
1532 },
1533#ifdef CONFIG_GUASI
1534 { .ival = "guasi",
1535 .help = "GUASI IO engine",
1536 },
1537#endif
1538#ifdef FIO_HAVE_BINJECT
1539 { .ival = "binject",
1540 .help = "binject direct inject block engine",
1541 },
1542#endif
1543#ifdef CONFIG_RDMA
1544 { .ival = "rdma",
1545 .help = "RDMA IO engine",
1546 },
1547#endif
1548#ifdef CONFIG_FUSION_AW
1549 { .ival = "fusion-aw-sync",
1550 .help = "Fusion-io atomic write engine",
1551 },
1552#endif
1553#ifdef CONFIG_LINUX_EXT4_MOVE_EXTENT
1554 { .ival = "e4defrag",
1555 .help = "ext4 defrag engine",
1556 },
1557#endif
1558#ifdef CONFIG_LINUX_FALLOCATE
1559 { .ival = "falloc",
1560 .help = "fallocate() file based engine",
1561 },
1562#endif
1563#ifdef CONFIG_GFAPI
1564 { .ival = "gfapi",
1565 .help = "Glusterfs libgfapi(sync) based engine"
1566 },
1567 { .ival = "gfapi_async",
1568 .help = "Glusterfs libgfapi(async) based engine"
1569 },
1570#endif
1571#ifdef CONFIG_LIBHDFS
1572 { .ival = "libhdfs",
1573 .help = "Hadoop Distributed Filesystem (HDFS) engine"
1574 },
1575#endif
1576 { .ival = "external",
1577 .help = "Load external engine (append name)",
1578 },
1579 },
1580 },
1581 {
1582 .name = "iodepth",
1583 .lname = "IO Depth",
1584 .type = FIO_OPT_INT,
1585 .off1 = td_var_offset(iodepth),
1586 .help = "Number of IO buffers to keep in flight",
1587 .minval = 1,
1588 .interval = 1,
1589 .def = "1",
1590 .category = FIO_OPT_C_IO,
1591 .group = FIO_OPT_G_IO_BASIC,
1592 },
1593 {
1594 .name = "iodepth_batch",
1595 .lname = "IO Depth batch",
1596 .alias = "iodepth_batch_submit",
1597 .type = FIO_OPT_INT,
1598 .off1 = td_var_offset(iodepth_batch),
1599 .help = "Number of IO buffers to submit in one go",
1600 .parent = "iodepth",
1601 .hide = 1,
1602 .minval = 1,
1603 .interval = 1,
1604 .def = "1",
1605 .category = FIO_OPT_C_IO,
1606 .group = FIO_OPT_G_IO_BASIC,
1607 },
1608 {
1609 .name = "iodepth_batch_complete",
1610 .lname = "IO Depth batch complete",
1611 .type = FIO_OPT_INT,
1612 .off1 = td_var_offset(iodepth_batch_complete),
1613 .help = "Number of IO buffers to retrieve in one go",
1614 .parent = "iodepth",
1615 .hide = 1,
1616 .minval = 0,
1617 .interval = 1,
1618 .def = "1",
1619 .category = FIO_OPT_C_IO,
1620 .group = FIO_OPT_G_IO_BASIC,
1621 },
1622 {
1623 .name = "iodepth_low",
1624 .lname = "IO Depth batch low",
1625 .type = FIO_OPT_INT,
1626 .off1 = td_var_offset(iodepth_low),
1627 .help = "Low water mark for queuing depth",
1628 .parent = "iodepth",
1629 .hide = 1,
1630 .interval = 1,
1631 .category = FIO_OPT_C_IO,
1632 .group = FIO_OPT_G_IO_BASIC,
1633 },
1634 {
1635 .name = "io_submit_mode",
1636 .lname = "IO submit mode",
1637 .type = FIO_OPT_STR,
1638 .off1 = td_var_offset(io_submit_mode),
1639 .help = "How IO submissions and completions are done",
1640 .def = "inline",
1641 .category = FIO_OPT_C_IO,
1642 .group = FIO_OPT_G_IO_BASIC,
1643 .posval = {
1644 { .ival = "inline",
1645 .oval = IO_MODE_INLINE,
1646 .help = "Submit and complete IO inline",
1647 },
1648 { .ival = "offload",
1649 .oval = IO_MODE_OFFLOAD,
1650 .help = "Offload submit and complete to threads",
1651 },
1652 },
1653 },
1654 {
1655 .name = "size",
1656 .lname = "Size",
1657 .type = FIO_OPT_STR_VAL,
1658 .cb = str_size_cb,
1659 .off1 = td_var_offset(size),
1660 .help = "Total size of device or files",
1661 .interval = 1024 * 1024,
1662 .category = FIO_OPT_C_IO,
1663 .group = FIO_OPT_G_INVALID,
1664 },
1665 {
1666 .name = "io_size",
1667 .alias = "io_limit",
1668 .lname = "IO Size",
1669 .type = FIO_OPT_STR_VAL,
1670 .off1 = td_var_offset(io_limit),
1671 .interval = 1024 * 1024,
1672 .category = FIO_OPT_C_IO,
1673 .group = FIO_OPT_G_INVALID,
1674 },
1675 {
1676 .name = "fill_device",
1677 .lname = "Fill device",
1678 .alias = "fill_fs",
1679 .type = FIO_OPT_BOOL,
1680 .off1 = td_var_offset(fill_device),
1681 .help = "Write until an ENOSPC error occurs",
1682 .def = "0",
1683 .category = FIO_OPT_C_FILE,
1684 .group = FIO_OPT_G_INVALID,
1685 },
1686 {
1687 .name = "filesize",
1688 .lname = "File size",
1689 .type = FIO_OPT_STR_VAL,
1690 .off1 = td_var_offset(file_size_low),
1691 .off2 = td_var_offset(file_size_high),
1692 .minval = 1,
1693 .help = "Size of individual files",
1694 .interval = 1024 * 1024,
1695 .category = FIO_OPT_C_FILE,
1696 .group = FIO_OPT_G_INVALID,
1697 },
1698 {
1699 .name = "file_append",
1700 .lname = "File append",
1701 .type = FIO_OPT_BOOL,
1702 .off1 = td_var_offset(file_append),
1703 .help = "IO will start at the end of the file(s)",
1704 .def = "0",
1705 .category = FIO_OPT_C_FILE,
1706 .group = FIO_OPT_G_INVALID,
1707 },
1708 {
1709 .name = "offset",
1710 .lname = "IO offset",
1711 .alias = "fileoffset",
1712 .type = FIO_OPT_STR_VAL,
1713 .off1 = td_var_offset(start_offset),
1714 .help = "Start IO from this offset",
1715 .def = "0",
1716 .interval = 1024 * 1024,
1717 .category = FIO_OPT_C_IO,
1718 .group = FIO_OPT_G_INVALID,
1719 },
1720 {
1721 .name = "offset_increment",
1722 .lname = "IO offset increment",
1723 .type = FIO_OPT_STR_VAL,
1724 .off1 = td_var_offset(offset_increment),
1725 .help = "What is the increment from one offset to the next",
1726 .parent = "offset",
1727 .hide = 1,
1728 .def = "0",
1729 .interval = 1024 * 1024,
1730 .category = FIO_OPT_C_IO,
1731 .group = FIO_OPT_G_INVALID,
1732 },
1733 {
1734 .name = "number_ios",
1735 .lname = "Number of IOs to perform",
1736 .type = FIO_OPT_STR_VAL,
1737 .off1 = td_var_offset(number_ios),
1738 .help = "Force job completion after this number of IOs",
1739 .def = "0",
1740 .category = FIO_OPT_C_IO,
1741 .group = FIO_OPT_G_INVALID,
1742 },
1743 {
1744 .name = "bs",
1745 .lname = "Block size",
1746 .alias = "blocksize",
1747 .type = FIO_OPT_INT,
1748 .off1 = td_var_offset(bs[DDIR_READ]),
1749 .off2 = td_var_offset(bs[DDIR_WRITE]),
1750 .off3 = td_var_offset(bs[DDIR_TRIM]),
1751 .minval = 1,
1752 .help = "Block size unit",
1753 .def = "4k",
1754 .parent = "rw",
1755 .hide = 1,
1756 .interval = 512,
1757 .category = FIO_OPT_C_IO,
1758 .group = FIO_OPT_G_INVALID,
1759 },
1760 {
1761 .name = "ba",
1762 .lname = "Block size align",
1763 .alias = "blockalign",
1764 .type = FIO_OPT_INT,
1765 .off1 = td_var_offset(ba[DDIR_READ]),
1766 .off2 = td_var_offset(ba[DDIR_WRITE]),
1767 .off3 = td_var_offset(ba[DDIR_TRIM]),
1768 .minval = 1,
1769 .help = "IO block offset alignment",
1770 .parent = "rw",
1771 .hide = 1,
1772 .interval = 512,
1773 .category = FIO_OPT_C_IO,
1774 .group = FIO_OPT_G_INVALID,
1775 },
1776 {
1777 .name = "bsrange",
1778 .lname = "Block size range",
1779 .alias = "blocksize_range",
1780 .type = FIO_OPT_RANGE,
1781 .off1 = td_var_offset(min_bs[DDIR_READ]),
1782 .off2 = td_var_offset(max_bs[DDIR_READ]),
1783 .off3 = td_var_offset(min_bs[DDIR_WRITE]),
1784 .off4 = td_var_offset(max_bs[DDIR_WRITE]),
1785 .off5 = td_var_offset(min_bs[DDIR_TRIM]),
1786 .off6 = td_var_offset(max_bs[DDIR_TRIM]),
1787 .minval = 1,
1788 .help = "Set block size range (in more detail than bs)",
1789 .parent = "rw",
1790 .hide = 1,
1791 .interval = 4096,
1792 .category = FIO_OPT_C_IO,
1793 .group = FIO_OPT_G_INVALID,
1794 },
1795 {
1796 .name = "bssplit",
1797 .lname = "Block size split",
1798 .type = FIO_OPT_STR,
1799 .cb = str_bssplit_cb,
1800 .off1 = td_var_offset(bssplit),
1801 .help = "Set a specific mix of block sizes",
1802 .parent = "rw",
1803 .hide = 1,
1804 .category = FIO_OPT_C_IO,
1805 .group = FIO_OPT_G_INVALID,
1806 },
1807 {
1808 .name = "bs_unaligned",
1809 .lname = "Block size unaligned",
1810 .alias = "blocksize_unaligned",
1811 .type = FIO_OPT_STR_SET,
1812 .off1 = td_var_offset(bs_unaligned),
1813 .help = "Don't sector align IO buffer sizes",
1814 .parent = "rw",
1815 .hide = 1,
1816 .category = FIO_OPT_C_IO,
1817 .group = FIO_OPT_G_INVALID,
1818 },
1819 {
1820 .name = "bs_is_seq_rand",
1821 .lname = "Block size division is seq/random (not read/write)",
1822 .type = FIO_OPT_BOOL,
1823 .off1 = td_var_offset(bs_is_seq_rand),
1824 .help = "Consider any blocksize setting to be sequential,random",
1825 .def = "0",
1826 .parent = "blocksize",
1827 .category = FIO_OPT_C_IO,
1828 .group = FIO_OPT_G_INVALID,
1829 },
1830 {
1831 .name = "randrepeat",
1832 .lname = "Random repeatable",
1833 .type = FIO_OPT_BOOL,
1834 .off1 = td_var_offset(rand_repeatable),
1835 .help = "Use repeatable random IO pattern",
1836 .def = "1",
1837 .parent = "rw",
1838 .hide = 1,
1839 .category = FIO_OPT_C_IO,
1840 .group = FIO_OPT_G_RANDOM,
1841 },
1842 {
1843 .name = "randseed",
1844 .lname = "The random generator seed",
1845 .type = FIO_OPT_STR_VAL,
1846 .off1 = td_var_offset(rand_seed),
1847 .help = "Set the random generator seed value",
1848 .def = "0x89",
1849 .parent = "rw",
1850 .category = FIO_OPT_C_IO,
1851 .group = FIO_OPT_G_RANDOM,
1852 },
1853 {
1854 .name = "use_os_rand",
1855 .lname = "Use OS random",
1856 .type = FIO_OPT_DEPRECATED,
1857 .off1 = td_var_offset(dep_use_os_rand),
1858 .category = FIO_OPT_C_IO,
1859 .group = FIO_OPT_G_RANDOM,
1860 },
1861 {
1862 .name = "norandommap",
1863 .lname = "No randommap",
1864 .type = FIO_OPT_STR_SET,
1865 .off1 = td_var_offset(norandommap),
1866 .help = "Accept potential duplicate random blocks",
1867 .parent = "rw",
1868 .hide = 1,
1869 .hide_on_set = 1,
1870 .category = FIO_OPT_C_IO,
1871 .group = FIO_OPT_G_RANDOM,
1872 },
1873 {
1874 .name = "softrandommap",
1875 .lname = "Soft randommap",
1876 .type = FIO_OPT_BOOL,
1877 .off1 = td_var_offset(softrandommap),
1878 .help = "Set norandommap if randommap allocation fails",
1879 .parent = "norandommap",
1880 .hide = 1,
1881 .def = "0",
1882 .category = FIO_OPT_C_IO,
1883 .group = FIO_OPT_G_RANDOM,
1884 },
1885 {
1886 .name = "random_generator",
1887 .type = FIO_OPT_STR,
1888 .off1 = td_var_offset(random_generator),
1889 .help = "Type of random number generator to use",
1890 .def = "tausworthe",
1891 .posval = {
1892 { .ival = "tausworthe",
1893 .oval = FIO_RAND_GEN_TAUSWORTHE,
1894 .help = "Strong Tausworthe generator",
1895 },
1896 { .ival = "lfsr",
1897 .oval = FIO_RAND_GEN_LFSR,
1898 .help = "Variable length LFSR",
1899 },
1900 {
1901 .ival = "tausworthe64",
1902 .oval = FIO_RAND_GEN_TAUSWORTHE64,
1903 .help = "64-bit Tausworthe variant",
1904 },
1905 },
1906 .category = FIO_OPT_C_IO,
1907 .group = FIO_OPT_G_RANDOM,
1908 },
1909 {
1910 .name = "random_distribution",
1911 .type = FIO_OPT_STR,
1912 .off1 = td_var_offset(random_distribution),
1913 .cb = str_random_distribution_cb,
1914 .help = "Random offset distribution generator",
1915 .def = "random",
1916 .posval = {
1917 { .ival = "random",
1918 .oval = FIO_RAND_DIST_RANDOM,
1919 .help = "Completely random",
1920 },
1921 { .ival = "zipf",
1922 .oval = FIO_RAND_DIST_ZIPF,
1923 .help = "Zipf distribution",
1924 },
1925 { .ival = "pareto",
1926 .oval = FIO_RAND_DIST_PARETO,
1927 .help = "Pareto distribution",
1928 },
1929 { .ival = "normal",
1930 .oval = FIO_RAND_DIST_GAUSS,
1931 .help = "Normal (gaussian) distribution",
1932 },
1933 },
1934 .category = FIO_OPT_C_IO,
1935 .group = FIO_OPT_G_RANDOM,
1936 },
1937 {
1938 .name = "percentage_random",
1939 .lname = "Percentage Random",
1940 .type = FIO_OPT_INT,
1941 .off1 = td_var_offset(perc_rand[DDIR_READ]),
1942 .off2 = td_var_offset(perc_rand[DDIR_WRITE]),
1943 .off3 = td_var_offset(perc_rand[DDIR_TRIM]),
1944 .maxval = 100,
1945 .help = "Percentage of seq/random mix that should be random",
1946 .def = "100,100,100",
1947 .interval = 5,
1948 .inverse = "percentage_sequential",
1949 .category = FIO_OPT_C_IO,
1950 .group = FIO_OPT_G_RANDOM,
1951 },
1952 {
1953 .name = "percentage_sequential",
1954 .lname = "Percentage Sequential",
1955 .type = FIO_OPT_DEPRECATED,
1956 .category = FIO_OPT_C_IO,
1957 .group = FIO_OPT_G_RANDOM,
1958 },
1959 {
1960 .name = "allrandrepeat",
1961 .type = FIO_OPT_BOOL,
1962 .off1 = td_var_offset(allrand_repeatable),
1963 .help = "Use repeatable random numbers for everything",
1964 .def = "0",
1965 .category = FIO_OPT_C_IO,
1966 .group = FIO_OPT_G_RANDOM,
1967 },
1968 {
1969 .name = "nrfiles",
1970 .lname = "Number of files",
1971 .alias = "nr_files",
1972 .type = FIO_OPT_INT,
1973 .off1 = td_var_offset(nr_files),
1974 .help = "Split job workload between this number of files",
1975 .def = "1",
1976 .interval = 1,
1977 .category = FIO_OPT_C_FILE,
1978 .group = FIO_OPT_G_INVALID,
1979 },
1980 {
1981 .name = "openfiles",
1982 .lname = "Number of open files",
1983 .type = FIO_OPT_INT,
1984 .off1 = td_var_offset(open_files),
1985 .help = "Number of files to keep open at the same time",
1986 .category = FIO_OPT_C_FILE,
1987 .group = FIO_OPT_G_INVALID,
1988 },
1989 {
1990 .name = "file_service_type",
1991 .lname = "File service type",
1992 .type = FIO_OPT_STR,
1993 .cb = str_fst_cb,
1994 .off1 = td_var_offset(file_service_type),
1995 .help = "How to select which file to service next",
1996 .def = "roundrobin",
1997 .category = FIO_OPT_C_FILE,
1998 .group = FIO_OPT_G_INVALID,
1999 .posval = {
2000 { .ival = "random",
2001 .oval = FIO_FSERVICE_RANDOM,
2002 .help = "Choose a file at random",
2003 },
2004 { .ival = "roundrobin",
2005 .oval = FIO_FSERVICE_RR,
2006 .help = "Round robin select files",
2007 },
2008 { .ival = "sequential",
2009 .oval = FIO_FSERVICE_SEQ,
2010 .help = "Finish one file before moving to the next",
2011 },
2012 },
2013 .parent = "nrfiles",
2014 .hide = 1,
2015 },
2016#ifdef CONFIG_POSIX_FALLOCATE
2017 {
2018 .name = "fallocate",
2019 .lname = "Fallocate",
2020 .type = FIO_OPT_STR,
2021 .off1 = td_var_offset(fallocate_mode),
2022 .help = "Whether pre-allocation is performed when laying out files",
2023 .def = "posix",
2024 .category = FIO_OPT_C_FILE,
2025 .group = FIO_OPT_G_INVALID,
2026 .posval = {
2027 { .ival = "none",
2028 .oval = FIO_FALLOCATE_NONE,
2029 .help = "Do not pre-allocate space",
2030 },
2031 { .ival = "posix",
2032 .oval = FIO_FALLOCATE_POSIX,
2033 .help = "Use posix_fallocate()",
2034 },
2035#ifdef CONFIG_LINUX_FALLOCATE
2036 { .ival = "keep",
2037 .oval = FIO_FALLOCATE_KEEP_SIZE,
2038 .help = "Use fallocate(..., FALLOC_FL_KEEP_SIZE, ...)",
2039 },
2040#endif
2041 /* Compatibility with former boolean values */
2042 { .ival = "0",
2043 .oval = FIO_FALLOCATE_NONE,
2044 .help = "Alias for 'none'",
2045 },
2046 { .ival = "1",
2047 .oval = FIO_FALLOCATE_POSIX,
2048 .help = "Alias for 'posix'",
2049 },
2050 },
2051 },
2052#endif /* CONFIG_POSIX_FALLOCATE */
2053 {
2054 .name = "fadvise_hint",
2055 .lname = "Fadvise hint",
2056 .type = FIO_OPT_BOOL,
2057 .off1 = td_var_offset(fadvise_hint),
2058 .help = "Use fadvise() to advise the kernel on IO pattern",
2059 .def = "1",
2060 .category = FIO_OPT_C_FILE,
2061 .group = FIO_OPT_G_INVALID,
2062 },
2063#ifdef FIO_HAVE_STREAMID
2064 {
2065 .name = "fadvise_stream",
2066 .lname = "Fadvise stream",
2067 .type = FIO_OPT_INT,
2068 .off1 = td_var_offset(fadvise_stream),
2069 .help = "Use fadvise() to set stream ID",
2070 .category = FIO_OPT_C_FILE,
2071 .group = FIO_OPT_G_INVALID,
2072 },
2073#endif
2074 {
2075 .name = "fsync",
2076 .lname = "Fsync",
2077 .type = FIO_OPT_INT,
2078 .off1 = td_var_offset(fsync_blocks),
2079 .help = "Issue fsync for writes every given number of blocks",
2080 .def = "0",
2081 .interval = 1,
2082 .category = FIO_OPT_C_FILE,
2083 .group = FIO_OPT_G_INVALID,
2084 },
2085 {
2086 .name = "fdatasync",
2087 .lname = "Fdatasync",
2088 .type = FIO_OPT_INT,
2089 .off1 = td_var_offset(fdatasync_blocks),
2090 .help = "Issue fdatasync for writes every given number of blocks",
2091 .def = "0",
2092 .interval = 1,
2093 .category = FIO_OPT_C_FILE,
2094 .group = FIO_OPT_G_INVALID,
2095 },
2096 {
2097 .name = "write_barrier",
2098 .lname = "Write barrier",
2099 .type = FIO_OPT_INT,
2100 .off1 = td_var_offset(barrier_blocks),
2101 .help = "Make every Nth write a barrier write",
2102 .def = "0",
2103 .interval = 1,
2104 .category = FIO_OPT_C_IO,
2105 .group = FIO_OPT_G_INVALID,
2106 },
2107#ifdef CONFIG_SYNC_FILE_RANGE
2108 {
2109 .name = "sync_file_range",
2110 .lname = "Sync file range",
2111 .posval = {
2112 { .ival = "wait_before",
2113 .oval = SYNC_FILE_RANGE_WAIT_BEFORE,
2114 .help = "SYNC_FILE_RANGE_WAIT_BEFORE",
2115 .orval = 1,
2116 },
2117 { .ival = "write",
2118 .oval = SYNC_FILE_RANGE_WRITE,
2119 .help = "SYNC_FILE_RANGE_WRITE",
2120 .orval = 1,
2121 },
2122 {
2123 .ival = "wait_after",
2124 .oval = SYNC_FILE_RANGE_WAIT_AFTER,
2125 .help = "SYNC_FILE_RANGE_WAIT_AFTER",
2126 .orval = 1,
2127 },
2128 },
2129 .type = FIO_OPT_STR_MULTI,
2130 .cb = str_sfr_cb,
2131 .off1 = td_var_offset(sync_file_range),
2132 .help = "Use sync_file_range()",
2133 .category = FIO_OPT_C_FILE,
2134 .group = FIO_OPT_G_INVALID,
2135 },
2136#endif
2137 {
2138 .name = "direct",
2139 .lname = "Direct I/O",
2140 .type = FIO_OPT_BOOL,
2141 .off1 = td_var_offset(odirect),
2142 .help = "Use O_DIRECT IO (negates buffered)",
2143 .def = "0",
2144 .inverse = "buffered",
2145 .category = FIO_OPT_C_IO,
2146 .group = FIO_OPT_G_IO_TYPE,
2147 },
2148 {
2149 .name = "atomic",
2150 .lname = "Atomic I/O",
2151 .type = FIO_OPT_BOOL,
2152 .off1 = td_var_offset(oatomic),
2153 .help = "Use Atomic IO with O_DIRECT (implies O_DIRECT)",
2154 .def = "0",
2155 .category = FIO_OPT_C_IO,
2156 .group = FIO_OPT_G_IO_TYPE,
2157 },
2158 {
2159 .name = "buffered",
2160 .lname = "Buffered I/O",
2161 .type = FIO_OPT_BOOL,
2162 .off1 = td_var_offset(odirect),
2163 .neg = 1,
2164 .help = "Use buffered IO (negates direct)",
2165 .def = "1",
2166 .inverse = "direct",
2167 .category = FIO_OPT_C_IO,
2168 .group = FIO_OPT_G_IO_TYPE,
2169 },
2170 {
2171 .name = "overwrite",
2172 .lname = "Overwrite",
2173 .type = FIO_OPT_BOOL,
2174 .off1 = td_var_offset(overwrite),
2175 .help = "When writing, set whether to overwrite current data",
2176 .def = "0",
2177 .category = FIO_OPT_C_FILE,
2178 .group = FIO_OPT_G_INVALID,
2179 },
2180 {
2181 .name = "loops",
2182 .lname = "Loops",
2183 .type = FIO_OPT_INT,
2184 .off1 = td_var_offset(loops),
2185 .help = "Number of times to run the job",
2186 .def = "1",
2187 .interval = 1,
2188 .category = FIO_OPT_C_GENERAL,
2189 .group = FIO_OPT_G_RUNTIME,
2190 },
2191 {
2192 .name = "numjobs",
2193 .lname = "Number of jobs",
2194 .type = FIO_OPT_INT,
2195 .off1 = td_var_offset(numjobs),
2196 .help = "Duplicate this job this many times",
2197 .def = "1",
2198 .interval = 1,
2199 .category = FIO_OPT_C_GENERAL,
2200 .group = FIO_OPT_G_RUNTIME,
2201 },
2202 {
2203 .name = "startdelay",
2204 .lname = "Start delay",
2205 .type = FIO_OPT_STR_VAL_TIME,
2206 .off1 = td_var_offset(start_delay),
2207 .off2 = td_var_offset(start_delay_high),
2208 .help = "Only start job when this period has passed",
2209 .def = "0",
2210 .is_seconds = 1,
2211 .is_time = 1,
2212 .category = FIO_OPT_C_GENERAL,
2213 .group = FIO_OPT_G_RUNTIME,
2214 },
2215 {
2216 .name = "runtime",
2217 .lname = "Runtime",
2218 .alias = "timeout",
2219 .type = FIO_OPT_STR_VAL_TIME,
2220 .off1 = td_var_offset(timeout),
2221 .help = "Stop workload when this amount of time has passed",
2222 .def = "0",
2223 .is_seconds = 1,
2224 .is_time = 1,
2225 .category = FIO_OPT_C_GENERAL,
2226 .group = FIO_OPT_G_RUNTIME,
2227 },
2228 {
2229 .name = "time_based",
2230 .lname = "Time based",
2231 .type = FIO_OPT_STR_SET,
2232 .off1 = td_var_offset(time_based),
2233 .help = "Keep running until runtime/timeout is met",
2234 .category = FIO_OPT_C_GENERAL,
2235 .group = FIO_OPT_G_RUNTIME,
2236 },
2237 {
2238 .name = "verify_only",
2239 .lname = "Verify only",
2240 .type = FIO_OPT_STR_SET,
2241 .off1 = td_var_offset(verify_only),
2242 .help = "Verifies previously written data is still valid",
2243 .category = FIO_OPT_C_GENERAL,
2244 .group = FIO_OPT_G_RUNTIME,
2245 },
2246 {
2247 .name = "ramp_time",
2248 .lname = "Ramp time",
2249 .type = FIO_OPT_STR_VAL_TIME,
2250 .off1 = td_var_offset(ramp_time),
2251 .help = "Ramp up time before measuring performance",
2252 .is_seconds = 1,
2253 .is_time = 1,
2254 .category = FIO_OPT_C_GENERAL,
2255 .group = FIO_OPT_G_RUNTIME,
2256 },
2257 {
2258 .name = "clocksource",
2259 .lname = "Clock source",
2260 .type = FIO_OPT_STR,
2261 .cb = fio_clock_source_cb,
2262 .off1 = td_var_offset(clocksource),
2263 .help = "What type of timing source to use",
2264 .category = FIO_OPT_C_GENERAL,
2265 .group = FIO_OPT_G_CLOCK,
2266 .posval = {
2267#ifdef CONFIG_GETTIMEOFDAY
2268 { .ival = "gettimeofday",
2269 .oval = CS_GTOD,
2270 .help = "Use gettimeofday(2) for timing",
2271 },
2272#endif
2273#ifdef CONFIG_CLOCK_GETTIME
2274 { .ival = "clock_gettime",
2275 .oval = CS_CGETTIME,
2276 .help = "Use clock_gettime(2) for timing",
2277 },
2278#endif
2279#ifdef ARCH_HAVE_CPU_CLOCK
2280 { .ival = "cpu",
2281 .oval = CS_CPUCLOCK,
2282 .help = "Use CPU private clock",
2283 },
2284#endif
2285 },
2286 },
2287 {
2288 .name = "mem",
2289 .alias = "iomem",
2290 .lname = "I/O Memory",
2291 .type = FIO_OPT_STR,
2292 .cb = str_mem_cb,
2293 .off1 = td_var_offset(mem_type),
2294 .help = "Backing type for IO buffers",
2295 .def = "malloc",
2296 .category = FIO_OPT_C_IO,
2297 .group = FIO_OPT_G_INVALID,
2298 .posval = {
2299 { .ival = "malloc",
2300 .oval = MEM_MALLOC,
2301 .help = "Use malloc(3) for IO buffers",
2302 },
2303#ifndef CONFIG_NO_SHM
2304 { .ival = "shm",
2305 .oval = MEM_SHM,
2306 .help = "Use shared memory segments for IO buffers",
2307 },
2308#ifdef FIO_HAVE_HUGETLB
2309 { .ival = "shmhuge",
2310 .oval = MEM_SHMHUGE,
2311 .help = "Like shm, but use huge pages",
2312 },
2313#endif
2314#endif
2315 { .ival = "mmap",
2316 .oval = MEM_MMAP,
2317 .help = "Use mmap(2) (file or anon) for IO buffers",
2318 },
2319#ifdef FIO_HAVE_HUGETLB
2320 { .ival = "mmaphuge",
2321 .oval = MEM_MMAPHUGE,
2322 .help = "Like mmap, but use huge pages",
2323 },
2324#endif
2325 },
2326 },
2327 {
2328 .name = "iomem_align",
2329 .alias = "mem_align",
2330 .lname = "I/O memory alignment",
2331 .type = FIO_OPT_INT,
2332 .off1 = td_var_offset(mem_align),
2333 .minval = 0,
2334 .help = "IO memory buffer offset alignment",
2335 .def = "0",
2336 .parent = "iomem",
2337 .hide = 1,
2338 .category = FIO_OPT_C_IO,
2339 .group = FIO_OPT_G_INVALID,
2340 },
2341 {
2342 .name = "verify",
2343 .lname = "Verify",
2344 .type = FIO_OPT_STR,
2345 .off1 = td_var_offset(verify),
2346 .help = "Verify data written",
2347 .def = "0",
2348 .category = FIO_OPT_C_IO,
2349 .group = FIO_OPT_G_VERIFY,
2350 .posval = {
2351 { .ival = "0",
2352 .oval = VERIFY_NONE,
2353 .help = "Don't do IO verification",
2354 },
2355 { .ival = "md5",
2356 .oval = VERIFY_MD5,
2357 .help = "Use md5 checksums for verification",
2358 },
2359 { .ival = "crc64",
2360 .oval = VERIFY_CRC64,
2361 .help = "Use crc64 checksums for verification",
2362 },
2363 { .ival = "crc32",
2364 .oval = VERIFY_CRC32,
2365 .help = "Use crc32 checksums for verification",
2366 },
2367 { .ival = "crc32c-intel",
2368 .oval = VERIFY_CRC32C,
2369 .help = "Use crc32c checksums for verification (hw assisted, if available)",
2370 },
2371 { .ival = "crc32c",
2372 .oval = VERIFY_CRC32C,
2373 .help = "Use crc32c checksums for verification (hw assisted, if available)",
2374 },
2375 { .ival = "crc16",
2376 .oval = VERIFY_CRC16,
2377 .help = "Use crc16 checksums for verification",
2378 },
2379 { .ival = "crc7",
2380 .oval = VERIFY_CRC7,
2381 .help = "Use crc7 checksums for verification",
2382 },
2383 { .ival = "sha1",
2384 .oval = VERIFY_SHA1,
2385 .help = "Use sha1 checksums for verification",
2386 },
2387 { .ival = "sha256",
2388 .oval = VERIFY_SHA256,
2389 .help = "Use sha256 checksums for verification",
2390 },
2391 { .ival = "sha512",
2392 .oval = VERIFY_SHA512,
2393 .help = "Use sha512 checksums for verification",
2394 },
2395 { .ival = "xxhash",
2396 .oval = VERIFY_XXHASH,
2397 .help = "Use xxhash checksums for verification",
2398 },
2399 { .ival = "meta",
2400 .oval = VERIFY_META,
2401 .help = "Use io information",
2402 },
2403 {
2404 .ival = "null",
2405 .oval = VERIFY_NULL,
2406 .help = "Pretend to verify",
2407 },
2408 },
2409 },
2410 {
2411 .name = "do_verify",
2412 .lname = "Perform verify step",
2413 .type = FIO_OPT_BOOL,
2414 .off1 = td_var_offset(do_verify),
2415 .help = "Run verification stage after write",
2416 .def = "1",
2417 .parent = "verify",
2418 .hide = 1,
2419 .category = FIO_OPT_C_IO,
2420 .group = FIO_OPT_G_VERIFY,
2421 },
2422 {
2423 .name = "verifysort",
2424 .lname = "Verify sort",
2425 .type = FIO_OPT_BOOL,
2426 .off1 = td_var_offset(verifysort),
2427 .help = "Sort written verify blocks for read back",
2428 .def = "1",
2429 .parent = "verify",
2430 .hide = 1,
2431 .category = FIO_OPT_C_IO,
2432 .group = FIO_OPT_G_VERIFY,
2433 },
2434 {
2435 .name = "verifysort_nr",
2436 .type = FIO_OPT_INT,
2437 .off1 = td_var_offset(verifysort_nr),
2438 .help = "Pre-load and sort verify blocks for a read workload",
2439 .minval = 0,
2440 .maxval = 131072,
2441 .def = "1024",
2442 .parent = "verify",
2443 .category = FIO_OPT_C_IO,
2444 .group = FIO_OPT_G_VERIFY,
2445 },
2446 {
2447 .name = "verify_interval",
2448 .lname = "Verify interval",
2449 .type = FIO_OPT_INT,
2450 .off1 = td_var_offset(verify_interval),
2451 .minval = 2 * sizeof(struct verify_header),
2452 .help = "Store verify buffer header every N bytes",
2453 .parent = "verify",
2454 .hide = 1,
2455 .interval = 2 * sizeof(struct verify_header),
2456 .category = FIO_OPT_C_IO,
2457 .group = FIO_OPT_G_VERIFY,
2458 },
2459 {
2460 .name = "verify_offset",
2461 .lname = "Verify offset",
2462 .type = FIO_OPT_INT,
2463 .help = "Offset verify header location by N bytes",
2464 .off1 = td_var_offset(verify_offset),
2465 .minval = sizeof(struct verify_header),
2466 .parent = "verify",
2467 .hide = 1,
2468 .category = FIO_OPT_C_IO,
2469 .group = FIO_OPT_G_VERIFY,
2470 },
2471 {
2472 .name = "verify_pattern",
2473 .lname = "Verify pattern",
2474 .type = FIO_OPT_STR,
2475 .cb = str_verify_pattern_cb,
2476 .off1 = td_var_offset(verify_pattern),
2477 .help = "Fill pattern for IO buffers",
2478 .parent = "verify",
2479 .hide = 1,
2480 .category = FIO_OPT_C_IO,
2481 .group = FIO_OPT_G_VERIFY,
2482 },
2483 {
2484 .name = "verify_fatal",
2485 .lname = "Verify fatal",
2486 .type = FIO_OPT_BOOL,
2487 .off1 = td_var_offset(verify_fatal),
2488 .def = "0",
2489 .help = "Exit on a single verify failure, don't continue",
2490 .parent = "verify",
2491 .hide = 1,
2492 .category = FIO_OPT_C_IO,
2493 .group = FIO_OPT_G_VERIFY,
2494 },
2495 {
2496 .name = "verify_dump",
2497 .lname = "Verify dump",
2498 .type = FIO_OPT_BOOL,
2499 .off1 = td_var_offset(verify_dump),
2500 .def = "0",
2501 .help = "Dump contents of good and bad blocks on failure",
2502 .parent = "verify",
2503 .hide = 1,
2504 .category = FIO_OPT_C_IO,
2505 .group = FIO_OPT_G_VERIFY,
2506 },
2507 {
2508 .name = "verify_async",
2509 .lname = "Verify asynchronously",
2510 .type = FIO_OPT_INT,
2511 .off1 = td_var_offset(verify_async),
2512 .def = "0",
2513 .help = "Number of async verifier threads to use",
2514 .parent = "verify",
2515 .hide = 1,
2516 .category = FIO_OPT_C_IO,
2517 .group = FIO_OPT_G_VERIFY,
2518 },
2519 {
2520 .name = "verify_backlog",
2521 .lname = "Verify backlog",
2522 .type = FIO_OPT_STR_VAL,
2523 .off1 = td_var_offset(verify_backlog),
2524 .help = "Verify after this number of blocks are written",
2525 .parent = "verify",
2526 .hide = 1,
2527 .category = FIO_OPT_C_IO,
2528 .group = FIO_OPT_G_VERIFY,
2529 },
2530 {
2531 .name = "verify_backlog_batch",
2532 .lname = "Verify backlog batch",
2533 .type = FIO_OPT_INT,
2534 .off1 = td_var_offset(verify_batch),
2535 .help = "Verify this number of IO blocks",
2536 .parent = "verify",
2537 .hide = 1,
2538 .category = FIO_OPT_C_IO,
2539 .group = FIO_OPT_G_VERIFY,
2540 },
2541#ifdef FIO_HAVE_CPU_AFFINITY
2542 {
2543 .name = "verify_async_cpus",
2544 .lname = "Async verify CPUs",
2545 .type = FIO_OPT_STR,
2546 .cb = str_verify_cpus_allowed_cb,
2547 .off1 = td_var_offset(verify_cpumask),
2548 .help = "Set CPUs allowed for async verify threads",
2549 .parent = "verify_async",
2550 .hide = 1,
2551 .category = FIO_OPT_C_IO,
2552 .group = FIO_OPT_G_VERIFY,
2553 },
2554#endif
2555 {
2556 .name = "experimental_verify",
2557 .off1 = td_var_offset(experimental_verify),
2558 .type = FIO_OPT_BOOL,
2559 .help = "Enable experimental verification",
2560 .parent = "verify",
2561 .category = FIO_OPT_C_IO,
2562 .group = FIO_OPT_G_VERIFY,
2563 },
2564 {
2565 .name = "verify_state_load",
2566 .lname = "Load verify state",
2567 .off1 = td_var_offset(verify_state),
2568 .type = FIO_OPT_BOOL,
2569 .help = "Load verify termination state",
2570 .parent = "verify",
2571 .category = FIO_OPT_C_IO,
2572 .group = FIO_OPT_G_VERIFY,
2573 },
2574 {
2575 .name = "verify_state_save",
2576 .lname = "Save verify state",
2577 .off1 = td_var_offset(verify_state_save),
2578 .type = FIO_OPT_BOOL,
2579 .def = "1",
2580 .help = "Save verify state on termination",
2581 .parent = "verify",
2582 .category = FIO_OPT_C_IO,
2583 .group = FIO_OPT_G_VERIFY,
2584 },
2585#ifdef FIO_HAVE_TRIM
2586 {
2587 .name = "trim_percentage",
2588 .lname = "Trim percentage",
2589 .type = FIO_OPT_INT,
2590 .off1 = td_var_offset(trim_percentage),
2591 .minval = 0,
2592 .maxval = 100,
2593 .help = "Number of verify blocks to discard/trim",
2594 .parent = "verify",
2595 .def = "0",
2596 .interval = 1,
2597 .hide = 1,
2598 .category = FIO_OPT_C_IO,
2599 .group = FIO_OPT_G_TRIM,
2600 },
2601 {
2602 .name = "trim_verify_zero",
2603 .lname = "Verify trim zero",
2604 .type = FIO_OPT_BOOL,
2605 .help = "Verify that trim/discarded blocks are returned as zeroes",
2606 .off1 = td_var_offset(trim_zero),
2607 .parent = "trim_percentage",
2608 .hide = 1,
2609 .def = "1",
2610 .category = FIO_OPT_C_IO,
2611 .group = FIO_OPT_G_TRIM,
2612 },
2613 {
2614 .name = "trim_backlog",
2615 .lname = "Trim backlog",
2616 .type = FIO_OPT_STR_VAL,
2617 .off1 = td_var_offset(trim_backlog),
2618 .help = "Trim after this number of blocks are written",
2619 .parent = "trim_percentage",
2620 .hide = 1,
2621 .interval = 1,
2622 .category = FIO_OPT_C_IO,
2623 .group = FIO_OPT_G_TRIM,
2624 },
2625 {
2626 .name = "trim_backlog_batch",
2627 .lname = "Trim backlog batch",
2628 .type = FIO_OPT_INT,
2629 .off1 = td_var_offset(trim_batch),
2630 .help = "Trim this number of IO blocks",
2631 .parent = "trim_percentage",
2632 .hide = 1,
2633 .interval = 1,
2634 .category = FIO_OPT_C_IO,
2635 .group = FIO_OPT_G_TRIM,
2636 },
2637#endif
2638 {
2639 .name = "write_iolog",
2640 .lname = "Write I/O log",
2641 .type = FIO_OPT_STR_STORE,
2642 .off1 = td_var_offset(write_iolog_file),
2643 .help = "Store IO pattern to file",
2644 .category = FIO_OPT_C_IO,
2645 .group = FIO_OPT_G_IOLOG,
2646 },
2647 {
2648 .name = "read_iolog",
2649 .lname = "Read I/O log",
2650 .type = FIO_OPT_STR_STORE,
2651 .off1 = td_var_offset(read_iolog_file),
2652 .help = "Playback IO pattern from file",
2653 .category = FIO_OPT_C_IO,
2654 .group = FIO_OPT_G_IOLOG,
2655 },
2656 {
2657 .name = "replay_no_stall",
2658 .lname = "Don't stall on replay",
2659 .type = FIO_OPT_BOOL,
2660 .off1 = td_var_offset(no_stall),
2661 .def = "0",
2662 .parent = "read_iolog",
2663 .hide = 1,
2664 .help = "Playback IO pattern file as fast as possible without stalls",
2665 .category = FIO_OPT_C_IO,
2666 .group = FIO_OPT_G_IOLOG,
2667 },
2668 {
2669 .name = "replay_redirect",
2670 .lname = "Redirect device for replay",
2671 .type = FIO_OPT_STR_STORE,
2672 .off1 = td_var_offset(replay_redirect),
2673 .parent = "read_iolog",
2674 .hide = 1,
2675 .help = "Replay all I/O onto this device, regardless of trace device",
2676 .category = FIO_OPT_C_IO,
2677 .group = FIO_OPT_G_IOLOG,
2678 },
2679 {
2680 .name = "replay_scale",
2681 .lname = "Replace offset scale factor",
2682 .type = FIO_OPT_INT,
2683 .off1 = td_var_offset(replay_scale),
2684 .parent = "read_iolog",
2685 .def = "1",
2686 .help = "Align offsets to this blocksize",
2687 .category = FIO_OPT_C_IO,
2688 .group = FIO_OPT_G_IOLOG,
2689 },
2690 {
2691 .name = "replay_align",
2692 .lname = "Replace alignment",
2693 .type = FIO_OPT_INT,
2694 .off1 = td_var_offset(replay_align),
2695 .parent = "read_iolog",
2696 .help = "Scale offset down by this factor",
2697 .category = FIO_OPT_C_IO,
2698 .group = FIO_OPT_G_IOLOG,
2699 .pow2 = 1,
2700 },
2701 {
2702 .name = "exec_prerun",
2703 .lname = "Pre-execute runnable",
2704 .type = FIO_OPT_STR_STORE,
2705 .off1 = td_var_offset(exec_prerun),
2706 .help = "Execute this file prior to running job",
2707 .category = FIO_OPT_C_GENERAL,
2708 .group = FIO_OPT_G_INVALID,
2709 },
2710 {
2711 .name = "exec_postrun",
2712 .lname = "Post-execute runnable",
2713 .type = FIO_OPT_STR_STORE,
2714 .off1 = td_var_offset(exec_postrun),
2715 .help = "Execute this file after running job",
2716 .category = FIO_OPT_C_GENERAL,
2717 .group = FIO_OPT_G_INVALID,
2718 },
2719#ifdef FIO_HAVE_IOSCHED_SWITCH
2720 {
2721 .name = "ioscheduler",
2722 .lname = "I/O scheduler",
2723 .type = FIO_OPT_STR_STORE,
2724 .off1 = td_var_offset(ioscheduler),
2725 .help = "Use this IO scheduler on the backing device",
2726 .category = FIO_OPT_C_FILE,
2727 .group = FIO_OPT_G_INVALID,
2728 },
2729#endif
2730 {
2731 .name = "zonesize",
2732 .lname = "Zone size",
2733 .type = FIO_OPT_STR_VAL,
2734 .off1 = td_var_offset(zone_size),
2735 .help = "Amount of data to read per zone",
2736 .def = "0",
2737 .interval = 1024 * 1024,
2738 .category = FIO_OPT_C_IO,
2739 .group = FIO_OPT_G_ZONE,
2740 },
2741 {
2742 .name = "zonerange",
2743 .lname = "Zone range",
2744 .type = FIO_OPT_STR_VAL,
2745 .off1 = td_var_offset(zone_range),
2746 .help = "Give size of an IO zone",
2747 .def = "0",
2748 .interval = 1024 * 1024,
2749 .category = FIO_OPT_C_IO,
2750 .group = FIO_OPT_G_ZONE,
2751 },
2752 {
2753 .name = "zoneskip",
2754 .lname = "Zone skip",
2755 .type = FIO_OPT_STR_VAL,
2756 .off1 = td_var_offset(zone_skip),
2757 .help = "Space between IO zones",
2758 .def = "0",
2759 .interval = 1024 * 1024,
2760 .category = FIO_OPT_C_IO,
2761 .group = FIO_OPT_G_ZONE,
2762 },
2763 {
2764 .name = "lockmem",
2765 .lname = "Lock memory",
2766 .type = FIO_OPT_STR_VAL,
2767 .off1 = td_var_offset(lockmem),
2768 .help = "Lock down this amount of memory (per worker)",
2769 .def = "0",
2770 .interval = 1024 * 1024,
2771 .category = FIO_OPT_C_GENERAL,
2772 .group = FIO_OPT_G_INVALID,
2773 },
2774 {
2775 .name = "rwmixread",
2776 .lname = "Read/write mix read",
2777 .type = FIO_OPT_INT,
2778 .cb = str_rwmix_read_cb,
2779 .off1 = td_var_offset(rwmix[DDIR_READ]),
2780 .maxval = 100,
2781 .help = "Percentage of mixed workload that is reads",
2782 .def = "50",
2783 .interval = 5,
2784 .inverse = "rwmixwrite",
2785 .category = FIO_OPT_C_IO,
2786 .group = FIO_OPT_G_RWMIX,
2787 },
2788 {
2789 .name = "rwmixwrite",
2790 .lname = "Read/write mix write",
2791 .type = FIO_OPT_INT,
2792 .cb = str_rwmix_write_cb,
2793 .off1 = td_var_offset(rwmix[DDIR_WRITE]),
2794 .maxval = 100,
2795 .help = "Percentage of mixed workload that is writes",
2796 .def = "50",
2797 .interval = 5,
2798 .inverse = "rwmixread",
2799 .category = FIO_OPT_C_IO,
2800 .group = FIO_OPT_G_RWMIX,
2801 },
2802 {
2803 .name = "rwmixcycle",
2804 .lname = "Read/write mix cycle",
2805 .type = FIO_OPT_DEPRECATED,
2806 .category = FIO_OPT_C_IO,
2807 .group = FIO_OPT_G_RWMIX,
2808 },
2809 {
2810 .name = "nice",
2811 .lname = "Nice",
2812 .type = FIO_OPT_INT,
2813 .off1 = td_var_offset(nice),
2814 .help = "Set job CPU nice value",
2815 .minval = -19,
2816 .maxval = 20,
2817 .def = "0",
2818 .interval = 1,
2819 .category = FIO_OPT_C_GENERAL,
2820 .group = FIO_OPT_G_CRED,
2821 },
2822#ifdef FIO_HAVE_IOPRIO
2823 {
2824 .name = "prio",
2825 .lname = "I/O nice priority",
2826 .type = FIO_OPT_INT,
2827 .off1 = td_var_offset(ioprio),
2828 .help = "Set job IO priority value",
2829 .minval = 0,
2830 .maxval = 7,
2831 .interval = 1,
2832 .category = FIO_OPT_C_GENERAL,
2833 .group = FIO_OPT_G_CRED,
2834 },
2835 {
2836 .name = "prioclass",
2837 .lname = "I/O nice priority class",
2838 .type = FIO_OPT_INT,
2839 .off1 = td_var_offset(ioprio_class),
2840 .help = "Set job IO priority class",
2841 .minval = 0,
2842 .maxval = 3,
2843 .interval = 1,
2844 .category = FIO_OPT_C_GENERAL,
2845 .group = FIO_OPT_G_CRED,
2846 },
2847#endif
2848 {
2849 .name = "thinktime",
2850 .lname = "Thinktime",
2851 .type = FIO_OPT_INT,
2852 .off1 = td_var_offset(thinktime),
2853 .help = "Idle time between IO buffers (usec)",
2854 .def = "0",
2855 .is_time = 1,
2856 .category = FIO_OPT_C_IO,
2857 .group = FIO_OPT_G_THINKTIME,
2858 },
2859 {
2860 .name = "thinktime_spin",
2861 .lname = "Thinktime spin",
2862 .type = FIO_OPT_INT,
2863 .off1 = td_var_offset(thinktime_spin),
2864 .help = "Start think time by spinning this amount (usec)",
2865 .def = "0",
2866 .is_time = 1,
2867 .parent = "thinktime",
2868 .hide = 1,
2869 .category = FIO_OPT_C_IO,
2870 .group = FIO_OPT_G_THINKTIME,
2871 },
2872 {
2873 .name = "thinktime_blocks",
2874 .lname = "Thinktime blocks",
2875 .type = FIO_OPT_INT,
2876 .off1 = td_var_offset(thinktime_blocks),
2877 .help = "IO buffer period between 'thinktime'",
2878 .def = "1",
2879 .parent = "thinktime",
2880 .hide = 1,
2881 .category = FIO_OPT_C_IO,
2882 .group = FIO_OPT_G_THINKTIME,
2883 },
2884 {
2885 .name = "rate",
2886 .lname = "I/O rate",
2887 .type = FIO_OPT_INT,
2888 .off1 = td_var_offset(rate[DDIR_READ]),
2889 .off2 = td_var_offset(rate[DDIR_WRITE]),
2890 .off3 = td_var_offset(rate[DDIR_TRIM]),
2891 .help = "Set bandwidth rate",
2892 .category = FIO_OPT_C_IO,
2893 .group = FIO_OPT_G_RATE,
2894 },
2895 {
2896 .name = "ratemin",
2897 .lname = "I/O min rate",
2898 .type = FIO_OPT_INT,
2899 .off1 = td_var_offset(ratemin[DDIR_READ]),
2900 .off2 = td_var_offset(ratemin[DDIR_WRITE]),
2901 .off3 = td_var_offset(ratemin[DDIR_TRIM]),
2902 .help = "Job must meet this rate or it will be shutdown",
2903 .parent = "rate",
2904 .hide = 1,
2905 .category = FIO_OPT_C_IO,
2906 .group = FIO_OPT_G_RATE,
2907 },
2908 {
2909 .name = "rate_iops",
2910 .lname = "I/O rate IOPS",
2911 .type = FIO_OPT_INT,
2912 .off1 = td_var_offset(rate_iops[DDIR_READ]),
2913 .off2 = td_var_offset(rate_iops[DDIR_WRITE]),
2914 .off3 = td_var_offset(rate_iops[DDIR_TRIM]),
2915 .help = "Limit IO used to this number of IO operations/sec",
2916 .hide = 1,
2917 .category = FIO_OPT_C_IO,
2918 .group = FIO_OPT_G_RATE,
2919 },
2920 {
2921 .name = "rate_iops_min",
2922 .lname = "I/O min rate IOPS",
2923 .type = FIO_OPT_INT,
2924 .off1 = td_var_offset(rate_iops_min[DDIR_READ]),
2925 .off2 = td_var_offset(rate_iops_min[DDIR_WRITE]),
2926 .off3 = td_var_offset(rate_iops_min[DDIR_TRIM]),
2927 .help = "Job must meet this rate or it will be shut down",
2928 .parent = "rate_iops",
2929 .hide = 1,
2930 .category = FIO_OPT_C_IO,
2931 .group = FIO_OPT_G_RATE,
2932 },
2933 {
2934 .name = "ratecycle",
2935 .lname = "I/O rate cycle",
2936 .type = FIO_OPT_INT,
2937 .off1 = td_var_offset(ratecycle),
2938 .help = "Window average for rate limits (msec)",
2939 .def = "1000",
2940 .parent = "rate",
2941 .hide = 1,
2942 .category = FIO_OPT_C_IO,
2943 .group = FIO_OPT_G_RATE,
2944 },
2945 {
2946 .name = "max_latency",
2947 .type = FIO_OPT_INT,
2948 .off1 = td_var_offset(max_latency),
2949 .help = "Maximum tolerated IO latency (usec)",
2950 .is_time = 1,
2951 .category = FIO_OPT_C_IO,
2952 .group = FIO_OPT_G_LATPROF,
2953 },
2954 {
2955 .name = "latency_target",
2956 .lname = "Latency Target (usec)",
2957 .type = FIO_OPT_STR_VAL_TIME,
2958 .off1 = td_var_offset(latency_target),
2959 .help = "Ramp to max queue depth supporting this latency",
2960 .is_time = 1,
2961 .category = FIO_OPT_C_IO,
2962 .group = FIO_OPT_G_LATPROF,
2963 },
2964 {
2965 .name = "latency_window",
2966 .lname = "Latency Window (usec)",
2967 .type = FIO_OPT_STR_VAL_TIME,
2968 .off1 = td_var_offset(latency_window),
2969 .help = "Time to sustain latency_target",
2970 .is_time = 1,
2971 .category = FIO_OPT_C_IO,
2972 .group = FIO_OPT_G_LATPROF,
2973 },
2974 {
2975 .name = "latency_percentile",
2976 .lname = "Latency Percentile",
2977 .type = FIO_OPT_FLOAT_LIST,
2978 .off1 = td_var_offset(latency_percentile),
2979 .help = "Percentile of IOs must be below latency_target",
2980 .def = "100",
2981 .maxlen = 1,
2982 .minfp = 0.0,
2983 .maxfp = 100.0,
2984 .category = FIO_OPT_C_IO,
2985 .group = FIO_OPT_G_LATPROF,
2986 },
2987 {
2988 .name = "invalidate",
2989 .lname = "Cache invalidate",
2990 .type = FIO_OPT_BOOL,
2991 .off1 = td_var_offset(invalidate_cache),
2992 .help = "Invalidate buffer/page cache prior to running job",
2993 .def = "1",
2994 .category = FIO_OPT_C_IO,
2995 .group = FIO_OPT_G_IO_TYPE,
2996 },
2997 {
2998 .name = "sync",
2999 .lname = "Synchronous I/O",
3000 .type = FIO_OPT_BOOL,
3001 .off1 = td_var_offset(sync_io),
3002 .help = "Use O_SYNC for buffered writes",
3003 .def = "0",
3004 .parent = "buffered",
3005 .hide = 1,
3006 .category = FIO_OPT_C_IO,
3007 .group = FIO_OPT_G_IO_TYPE,
3008 },
3009 {
3010 .name = "create_serialize",
3011 .lname = "Create serialize",
3012 .type = FIO_OPT_BOOL,
3013 .off1 = td_var_offset(create_serialize),
3014 .help = "Serialize creating of job files",
3015 .def = "1",
3016 .category = FIO_OPT_C_FILE,
3017 .group = FIO_OPT_G_INVALID,
3018 },
3019 {
3020 .name = "create_fsync",
3021 .lname = "Create fsync",
3022 .type = FIO_OPT_BOOL,
3023 .off1 = td_var_offset(create_fsync),
3024 .help = "fsync file after creation",
3025 .def = "1",
3026 .category = FIO_OPT_C_FILE,
3027 .group = FIO_OPT_G_INVALID,
3028 },
3029 {
3030 .name = "create_on_open",
3031 .lname = "Create on open",
3032 .type = FIO_OPT_BOOL,
3033 .off1 = td_var_offset(create_on_open),
3034 .help = "Create files when they are opened for IO",
3035 .def = "0",
3036 .category = FIO_OPT_C_FILE,
3037 .group = FIO_OPT_G_INVALID,
3038 },
3039 {
3040 .name = "create_only",
3041 .type = FIO_OPT_BOOL,
3042 .off1 = td_var_offset(create_only),
3043 .help = "Only perform file creation phase",
3044 .category = FIO_OPT_C_FILE,
3045 .def = "0",
3046 },
3047 {
3048 .name = "allow_file_create",
3049 .lname = "Allow file create",
3050 .type = FIO_OPT_BOOL,
3051 .off1 = td_var_offset(allow_create),
3052 .help = "Permit fio to create files, if they don't exist",
3053 .def = "1",
3054 .category = FIO_OPT_C_FILE,
3055 .group = FIO_OPT_G_FILENAME,
3056 },
3057 {
3058 .name = "allow_mounted_write",
3059 .lname = "Allow mounted write",
3060 .type = FIO_OPT_BOOL,
3061 .off1 = td_var_offset(allow_mounted_write),
3062 .help = "Allow writes to a mounted partition",
3063 .def = "0",
3064 .category = FIO_OPT_C_FILE,
3065 .group = FIO_OPT_G_FILENAME,
3066 },
3067 {
3068 .name = "pre_read",
3069 .lname = "Pre-read files",
3070 .type = FIO_OPT_BOOL,
3071 .off1 = td_var_offset(pre_read),
3072 .help = "Pre-read files before starting official testing",
3073 .def = "0",
3074 .category = FIO_OPT_C_FILE,
3075 .group = FIO_OPT_G_INVALID,
3076 },
3077#ifdef FIO_HAVE_CPU_AFFINITY
3078 {
3079 .name = "cpumask",
3080 .lname = "CPU mask",
3081 .type = FIO_OPT_INT,
3082 .cb = str_cpumask_cb,
3083 .off1 = td_var_offset(cpumask),
3084 .help = "CPU affinity mask",
3085 .category = FIO_OPT_C_GENERAL,
3086 .group = FIO_OPT_G_CRED,
3087 },
3088 {
3089 .name = "cpus_allowed",
3090 .lname = "CPUs allowed",
3091 .type = FIO_OPT_STR,
3092 .cb = str_cpus_allowed_cb,
3093 .off1 = td_var_offset(cpumask),
3094 .help = "Set CPUs allowed",
3095 .category = FIO_OPT_C_GENERAL,
3096 .group = FIO_OPT_G_CRED,
3097 },
3098 {
3099 .name = "cpus_allowed_policy",
3100 .lname = "CPUs allowed distribution policy",
3101 .type = FIO_OPT_STR,
3102 .off1 = td_var_offset(cpus_allowed_policy),
3103 .help = "Distribution policy for cpus_allowed",
3104 .parent = "cpus_allowed",
3105 .prio = 1,
3106 .posval = {
3107 { .ival = "shared",
3108 .oval = FIO_CPUS_SHARED,
3109 .help = "Mask shared between threads",
3110 },
3111 { .ival = "split",
3112 .oval = FIO_CPUS_SPLIT,
3113 .help = "Mask split between threads",
3114 },
3115 },
3116 .category = FIO_OPT_C_GENERAL,
3117 .group = FIO_OPT_G_CRED,
3118 },
3119#endif
3120#ifdef CONFIG_LIBNUMA
3121 {
3122 .name = "numa_cpu_nodes",
3123 .type = FIO_OPT_STR,
3124 .cb = str_numa_cpunodes_cb,
3125 .off1 = td_var_offset(numa_cpunodes),
3126 .help = "NUMA CPU nodes bind",
3127 .category = FIO_OPT_C_GENERAL,
3128 .group = FIO_OPT_G_INVALID,
3129 },
3130 {
3131 .name = "numa_mem_policy",
3132 .type = FIO_OPT_STR,
3133 .cb = str_numa_mpol_cb,
3134 .off1 = td_var_offset(numa_memnodes),
3135 .help = "NUMA memory policy setup",
3136 .category = FIO_OPT_C_GENERAL,
3137 .group = FIO_OPT_G_INVALID,
3138 },
3139#endif
3140 {
3141 .name = "end_fsync",
3142 .lname = "End fsync",
3143 .type = FIO_OPT_BOOL,
3144 .off1 = td_var_offset(end_fsync),
3145 .help = "Include fsync at the end of job",
3146 .def = "0",
3147 .category = FIO_OPT_C_FILE,
3148 .group = FIO_OPT_G_INVALID,
3149 },
3150 {
3151 .name = "fsync_on_close",
3152 .lname = "Fsync on close",
3153 .type = FIO_OPT_BOOL,
3154 .off1 = td_var_offset(fsync_on_close),
3155 .help = "fsync files on close",
3156 .def = "0",
3157 .category = FIO_OPT_C_FILE,
3158 .group = FIO_OPT_G_INVALID,
3159 },
3160 {
3161 .name = "unlink",
3162 .lname = "Unlink file",
3163 .type = FIO_OPT_BOOL,
3164 .off1 = td_var_offset(unlink),
3165 .help = "Unlink created files after job has completed",
3166 .def = "0",
3167 .category = FIO_OPT_C_FILE,
3168 .group = FIO_OPT_G_INVALID,
3169 },
3170 {
3171 .name = "exitall",
3172 .lname = "Exit-all on terminate",
3173 .type = FIO_OPT_STR_SET,
3174 .cb = str_exitall_cb,
3175 .help = "Terminate all jobs when one exits",
3176 .category = FIO_OPT_C_GENERAL,
3177 .group = FIO_OPT_G_PROCESS,
3178 },
3179 {
3180 .name = "stonewall",
3181 .lname = "Wait for previous",
3182 .alias = "wait_for_previous",
3183 .type = FIO_OPT_STR_SET,
3184 .off1 = td_var_offset(stonewall),
3185 .help = "Insert a hard barrier between this job and previous",
3186 .category = FIO_OPT_C_GENERAL,
3187 .group = FIO_OPT_G_PROCESS,
3188 },
3189 {
3190 .name = "new_group",
3191 .lname = "New group",
3192 .type = FIO_OPT_STR_SET,
3193 .off1 = td_var_offset(new_group),
3194 .help = "Mark the start of a new group (for reporting)",
3195 .category = FIO_OPT_C_GENERAL,
3196 .group = FIO_OPT_G_PROCESS,
3197 },
3198 {
3199 .name = "thread",
3200 .lname = "Thread",
3201 .type = FIO_OPT_STR_SET,
3202 .off1 = td_var_offset(use_thread),
3203 .help = "Use threads instead of processes",
3204#ifdef CONFIG_NO_SHM
3205 .def = "1",
3206 .no_warn_def = 1,
3207#endif
3208 .category = FIO_OPT_C_GENERAL,
3209 .group = FIO_OPT_G_PROCESS,
3210 },
3211 {
3212 .name = "per_job_logs",
3213 .type = FIO_OPT_BOOL,
3214 .off1 = td_var_offset(per_job_logs),
3215 .help = "Include job number in generated log files or not",
3216 .def = "1",
3217 .category = FIO_OPT_C_LOG,
3218 .group = FIO_OPT_G_INVALID,
3219 },
3220 {
3221 .name = "write_bw_log",
3222 .lname = "Write bandwidth log",
3223 .type = FIO_OPT_STR_STORE,
3224 .off1 = td_var_offset(bw_log_file),
3225 .help = "Write log of bandwidth during run",
3226 .category = FIO_OPT_C_LOG,
3227 .group = FIO_OPT_G_INVALID,
3228 },
3229 {
3230 .name = "write_lat_log",
3231 .lname = "Write latency log",
3232 .type = FIO_OPT_STR_STORE,
3233 .off1 = td_var_offset(lat_log_file),
3234 .help = "Write log of latency during run",
3235 .category = FIO_OPT_C_LOG,
3236 .group = FIO_OPT_G_INVALID,
3237 },
3238 {
3239 .name = "write_iops_log",
3240 .lname = "Write IOPS log",
3241 .type = FIO_OPT_STR_STORE,
3242 .off1 = td_var_offset(iops_log_file),
3243 .help = "Write log of IOPS during run",
3244 .category = FIO_OPT_C_LOG,
3245 .group = FIO_OPT_G_INVALID,
3246 },
3247 {
3248 .name = "log_avg_msec",
3249 .lname = "Log averaging (msec)",
3250 .type = FIO_OPT_INT,
3251 .off1 = td_var_offset(log_avg_msec),
3252 .help = "Average bw/iops/lat logs over this period of time",
3253 .def = "0",
3254 .category = FIO_OPT_C_LOG,
3255 .group = FIO_OPT_G_INVALID,
3256 },
3257 {
3258 .name = "log_offset",
3259 .lname = "Log offset of IO",
3260 .type = FIO_OPT_BOOL,
3261 .off1 = td_var_offset(log_offset),
3262 .help = "Include offset of IO for each log entry",
3263 .def = "0",
3264 .category = FIO_OPT_C_LOG,
3265 .group = FIO_OPT_G_INVALID,
3266 },
3267#ifdef CONFIG_ZLIB
3268 {
3269 .name = "log_compression",
3270 .lname = "Log compression",
3271 .type = FIO_OPT_INT,
3272 .off1 = td_var_offset(log_gz),
3273 .help = "Log in compressed chunks of this size",
3274 .minval = 32 * 1024 * 1024ULL,
3275 .maxval = 512 * 1024 * 1024ULL,
3276 .category = FIO_OPT_C_LOG,
3277 .group = FIO_OPT_G_INVALID,
3278 },
3279 {
3280 .name = "log_store_compressed",
3281 .lname = "Log store compressed",
3282 .type = FIO_OPT_BOOL,
3283 .off1 = td_var_offset(log_gz_store),
3284 .help = "Store logs in a compressed format",
3285 .category = FIO_OPT_C_LOG,
3286 .group = FIO_OPT_G_INVALID,
3287 },
3288#endif
3289 {
3290 .name = "block_error_percentiles",
3291 .lname = "Block error percentiles",
3292 .type = FIO_OPT_BOOL,
3293 .off1 = td_var_offset(block_error_hist),
3294 .help = "Record trim block errors and make a histogram",
3295 .def = "0",
3296 .category = FIO_OPT_C_LOG,
3297 .group = FIO_OPT_G_INVALID,
3298 },
3299 {
3300 .name = "bwavgtime",
3301 .lname = "Bandwidth average time",
3302 .type = FIO_OPT_INT,
3303 .off1 = td_var_offset(bw_avg_time),
3304 .help = "Time window over which to calculate bandwidth"
3305 " (msec)",
3306 .def = "500",
3307 .parent = "write_bw_log",
3308 .hide = 1,
3309 .interval = 100,
3310 .category = FIO_OPT_C_LOG,
3311 .group = FIO_OPT_G_INVALID,
3312 },
3313 {
3314 .name = "iopsavgtime",
3315 .lname = "IOPS average time",
3316 .type = FIO_OPT_INT,
3317 .off1 = td_var_offset(iops_avg_time),
3318 .help = "Time window over which to calculate IOPS (msec)",
3319 .def = "500",
3320 .parent = "write_iops_log",
3321 .hide = 1,
3322 .interval = 100,
3323 .category = FIO_OPT_C_LOG,
3324 .group = FIO_OPT_G_INVALID,
3325 },
3326 {
3327 .name = "group_reporting",
3328 .lname = "Group reporting",
3329 .type = FIO_OPT_STR_SET,
3330 .off1 = td_var_offset(group_reporting),
3331 .help = "Do reporting on a per-group basis",
3332 .category = FIO_OPT_C_STAT,
3333 .group = FIO_OPT_G_INVALID,
3334 },
3335 {
3336 .name = "zero_buffers",
3337 .lname = "Zero I/O buffers",
3338 .type = FIO_OPT_STR_SET,
3339 .off1 = td_var_offset(zero_buffers),
3340 .help = "Init IO buffers to all zeroes",
3341 .category = FIO_OPT_C_IO,
3342 .group = FIO_OPT_G_IO_BUF,
3343 },
3344 {
3345 .name = "refill_buffers",
3346 .lname = "Refill I/O buffers",
3347 .type = FIO_OPT_STR_SET,
3348 .off1 = td_var_offset(refill_buffers),
3349 .help = "Refill IO buffers on every IO submit",
3350 .category = FIO_OPT_C_IO,
3351 .group = FIO_OPT_G_IO_BUF,
3352 },
3353 {
3354 .name = "scramble_buffers",
3355 .lname = "Scramble I/O buffers",
3356 .type = FIO_OPT_BOOL,
3357 .off1 = td_var_offset(scramble_buffers),
3358 .help = "Slightly scramble buffers on every IO submit",
3359 .def = "1",
3360 .category = FIO_OPT_C_IO,
3361 .group = FIO_OPT_G_IO_BUF,
3362 },
3363 {
3364 .name = "buffer_pattern",
3365 .lname = "Buffer pattern",
3366 .type = FIO_OPT_STR,
3367 .cb = str_buffer_pattern_cb,
3368 .off1 = td_var_offset(buffer_pattern),
3369 .help = "Fill pattern for IO buffers",
3370 .category = FIO_OPT_C_IO,
3371 .group = FIO_OPT_G_IO_BUF,
3372 },
3373 {
3374 .name = "buffer_compress_percentage",
3375 .lname = "Buffer compression percentage",
3376 .type = FIO_OPT_INT,
3377 .cb = str_buffer_compress_cb,
3378 .off1 = td_var_offset(compress_percentage),
3379 .maxval = 100,
3380 .minval = 0,
3381 .help = "How compressible the buffer is (approximately)",
3382 .interval = 5,
3383 .category = FIO_OPT_C_IO,
3384 .group = FIO_OPT_G_IO_BUF,
3385 },
3386 {
3387 .name = "buffer_compress_chunk",
3388 .lname = "Buffer compression chunk size",
3389 .type = FIO_OPT_INT,
3390 .off1 = td_var_offset(compress_chunk),
3391 .parent = "buffer_compress_percentage",
3392 .hide = 1,
3393 .help = "Size of compressible region in buffer",
3394 .interval = 256,
3395 .category = FIO_OPT_C_IO,
3396 .group = FIO_OPT_G_IO_BUF,
3397 },
3398 {
3399 .name = "dedupe_percentage",
3400 .lname = "Dedupe percentage",
3401 .type = FIO_OPT_INT,
3402 .cb = str_dedupe_cb,
3403 .off1 = td_var_offset(dedupe_percentage),
3404 .maxval = 100,
3405 .minval = 0,
3406 .help = "Percentage of buffers that are dedupable",
3407 .interval = 1,
3408 .category = FIO_OPT_C_IO,
3409 .group = FIO_OPT_G_IO_BUF,
3410 },
3411 {
3412 .name = "clat_percentiles",
3413 .lname = "Completion latency percentiles",
3414 .type = FIO_OPT_BOOL,
3415 .off1 = td_var_offset(clat_percentiles),
3416 .help = "Enable the reporting of completion latency percentiles",
3417 .def = "1",
3418 .category = FIO_OPT_C_STAT,
3419 .group = FIO_OPT_G_INVALID,
3420 },
3421 {
3422 .name = "percentile_list",
3423 .lname = "Percentile list",
3424 .type = FIO_OPT_FLOAT_LIST,
3425 .off1 = td_var_offset(percentile_list),
3426 .off2 = td_var_offset(percentile_precision),
3427 .help = "Specify a custom list of percentiles to report for "
3428 "completion latency and block errors",
3429 .def = "1:5:10:20:30:40:50:60:70:80:90:95:99:99.5:99.9:99.95:99.99",
3430 .maxlen = FIO_IO_U_LIST_MAX_LEN,
3431 .minfp = 0.0,
3432 .maxfp = 100.0,
3433 .category = FIO_OPT_C_STAT,
3434 .group = FIO_OPT_G_INVALID,
3435 },
3436
3437#ifdef FIO_HAVE_DISK_UTIL
3438 {
3439 .name = "disk_util",
3440 .lname = "Disk utilization",
3441 .type = FIO_OPT_BOOL,
3442 .off1 = td_var_offset(do_disk_util),
3443 .help = "Log disk utilization statistics",
3444 .def = "1",
3445 .category = FIO_OPT_C_STAT,
3446 .group = FIO_OPT_G_INVALID,
3447 },
3448#endif
3449 {
3450 .name = "gtod_reduce",
3451 .lname = "Reduce gettimeofday() calls",
3452 .type = FIO_OPT_BOOL,
3453 .help = "Greatly reduce number of gettimeofday() calls",
3454 .cb = str_gtod_reduce_cb,
3455 .def = "0",
3456 .hide_on_set = 1,
3457 .category = FIO_OPT_C_STAT,
3458 .group = FIO_OPT_G_INVALID,
3459 },
3460 {
3461 .name = "disable_lat",
3462 .lname = "Disable all latency stats",
3463 .type = FIO_OPT_BOOL,
3464 .off1 = td_var_offset(disable_lat),
3465 .help = "Disable latency numbers",
3466 .parent = "gtod_reduce",
3467 .hide = 1,
3468 .def = "0",
3469 .category = FIO_OPT_C_STAT,
3470 .group = FIO_OPT_G_INVALID,
3471 },
3472 {
3473 .name = "disable_clat",
3474 .lname = "Disable completion latency stats",
3475 .type = FIO_OPT_BOOL,
3476 .off1 = td_var_offset(disable_clat),
3477 .help = "Disable completion latency numbers",
3478 .parent = "gtod_reduce",
3479 .hide = 1,
3480 .def = "0",
3481 .category = FIO_OPT_C_STAT,
3482 .group = FIO_OPT_G_INVALID,
3483 },
3484 {
3485 .name = "disable_slat",
3486 .lname = "Disable submission latency stats",
3487 .type = FIO_OPT_BOOL,
3488 .off1 = td_var_offset(disable_slat),
3489 .help = "Disable submission latency numbers",
3490 .parent = "gtod_reduce",
3491 .hide = 1,
3492 .def = "0",
3493 .category = FIO_OPT_C_STAT,
3494 .group = FIO_OPT_G_INVALID,
3495 },
3496 {
3497 .name = "disable_bw_measurement",
3498 .lname = "Disable bandwidth stats",
3499 .type = FIO_OPT_BOOL,
3500 .off1 = td_var_offset(disable_bw),
3501 .help = "Disable bandwidth logging",
3502 .parent = "gtod_reduce",
3503 .hide = 1,
3504 .def = "0",
3505 .category = FIO_OPT_C_STAT,
3506 .group = FIO_OPT_G_INVALID,
3507 },
3508 {
3509 .name = "gtod_cpu",
3510 .lname = "Dedicated gettimeofday() CPU",
3511 .type = FIO_OPT_INT,
3512 .off1 = td_var_offset(gtod_cpu),
3513 .help = "Set up dedicated gettimeofday() thread on this CPU",
3514 .verify = gtod_cpu_verify,
3515 .category = FIO_OPT_C_GENERAL,
3516 .group = FIO_OPT_G_CLOCK,
3517 },
3518 {
3519 .name = "unified_rw_reporting",
3520 .type = FIO_OPT_BOOL,
3521 .off1 = td_var_offset(unified_rw_rep),
3522 .help = "Unify reporting across data direction",
3523 .def = "0",
3524 .category = FIO_OPT_C_GENERAL,
3525 .group = FIO_OPT_G_INVALID,
3526 },
3527 {
3528 .name = "continue_on_error",
3529 .lname = "Continue on error",
3530 .type = FIO_OPT_STR,
3531 .off1 = td_var_offset(continue_on_error),
3532 .help = "Continue on non-fatal errors during IO",
3533 .def = "none",
3534 .category = FIO_OPT_C_GENERAL,
3535 .group = FIO_OPT_G_ERR,
3536 .posval = {
3537 { .ival = "none",
3538 .oval = ERROR_TYPE_NONE,
3539 .help = "Exit when an error is encountered",
3540 },
3541 { .ival = "read",
3542 .oval = ERROR_TYPE_READ,
3543 .help = "Continue on read errors only",
3544 },
3545 { .ival = "write",
3546 .oval = ERROR_TYPE_WRITE,
3547 .help = "Continue on write errors only",
3548 },
3549 { .ival = "io",
3550 .oval = ERROR_TYPE_READ | ERROR_TYPE_WRITE,
3551 .help = "Continue on any IO errors",
3552 },
3553 { .ival = "verify",
3554 .oval = ERROR_TYPE_VERIFY,
3555 .help = "Continue on verify errors only",
3556 },
3557 { .ival = "all",
3558 .oval = ERROR_TYPE_ANY,
3559 .help = "Continue on all io and verify errors",
3560 },
3561 { .ival = "0",
3562 .oval = ERROR_TYPE_NONE,
3563 .help = "Alias for 'none'",
3564 },
3565 { .ival = "1",
3566 .oval = ERROR_TYPE_ANY,
3567 .help = "Alias for 'all'",
3568 },
3569 },
3570 },
3571 {
3572 .name = "ignore_error",
3573 .type = FIO_OPT_STR,
3574 .cb = str_ignore_error_cb,
3575 .off1 = td_var_offset(ignore_error_nr),
3576 .help = "Set a specific list of errors to ignore",
3577 .parent = "rw",
3578 .category = FIO_OPT_C_GENERAL,
3579 .group = FIO_OPT_G_ERR,
3580 },
3581 {
3582 .name = "error_dump",
3583 .type = FIO_OPT_BOOL,
3584 .off1 = td_var_offset(error_dump),
3585 .def = "0",
3586 .help = "Dump info on each error",
3587 .category = FIO_OPT_C_GENERAL,
3588 .group = FIO_OPT_G_ERR,
3589 },
3590 {
3591 .name = "profile",
3592 .lname = "Profile",
3593 .type = FIO_OPT_STR_STORE,
3594 .off1 = td_var_offset(profile),
3595 .help = "Select a specific builtin performance test",
3596 .category = FIO_OPT_C_PROFILE,
3597 .group = FIO_OPT_G_INVALID,
3598 },
3599 {
3600 .name = "cgroup",
3601 .lname = "Cgroup",
3602 .type = FIO_OPT_STR_STORE,
3603 .off1 = td_var_offset(cgroup),
3604 .help = "Add job to cgroup of this name",
3605 .category = FIO_OPT_C_GENERAL,
3606 .group = FIO_OPT_G_CGROUP,
3607 },
3608 {
3609 .name = "cgroup_nodelete",
3610 .lname = "Cgroup no-delete",
3611 .type = FIO_OPT_BOOL,
3612 .off1 = td_var_offset(cgroup_nodelete),
3613 .help = "Do not delete cgroups after job completion",
3614 .def = "0",
3615 .parent = "cgroup",
3616 .category = FIO_OPT_C_GENERAL,
3617 .group = FIO_OPT_G_CGROUP,
3618 },
3619 {
3620 .name = "cgroup_weight",
3621 .lname = "Cgroup weight",
3622 .type = FIO_OPT_INT,
3623 .off1 = td_var_offset(cgroup_weight),
3624 .help = "Use given weight for cgroup",
3625 .minval = 100,
3626 .maxval = 1000,
3627 .parent = "cgroup",
3628 .category = FIO_OPT_C_GENERAL,
3629 .group = FIO_OPT_G_CGROUP,
3630 },
3631 {
3632 .name = "uid",
3633 .lname = "User ID",
3634 .type = FIO_OPT_INT,
3635 .off1 = td_var_offset(uid),
3636 .help = "Run job with this user ID",
3637 .category = FIO_OPT_C_GENERAL,
3638 .group = FIO_OPT_G_CRED,
3639 },
3640 {
3641 .name = "gid",
3642 .lname = "Group ID",
3643 .type = FIO_OPT_INT,
3644 .off1 = td_var_offset(gid),
3645 .help = "Run job with this group ID",
3646 .category = FIO_OPT_C_GENERAL,
3647 .group = FIO_OPT_G_CRED,
3648 },
3649 {
3650 .name = "kb_base",
3651 .lname = "KB Base",
3652 .type = FIO_OPT_INT,
3653 .off1 = td_var_offset(kb_base),
3654 .prio = 1,
3655 .def = "1024",
3656 .posval = {
3657 { .ival = "1024",
3658 .oval = 1024,
3659 .help = "Use 1024 as the K base",
3660 },
3661 { .ival = "1000",
3662 .oval = 1000,
3663 .help = "Use 1000 as the K base",
3664 },
3665 },
3666 .help = "How many bytes per KB for reporting (1000 or 1024)",
3667 .category = FIO_OPT_C_GENERAL,
3668 .group = FIO_OPT_G_INVALID,
3669 },
3670 {
3671 .name = "unit_base",
3672 .lname = "Base unit for reporting (Bits or Bytes)",
3673 .type = FIO_OPT_INT,
3674 .off1 = td_var_offset(unit_base),
3675 .prio = 1,
3676 .posval = {
3677 { .ival = "0",
3678 .oval = 0,
3679 .help = "Auto-detect",
3680 },
3681 { .ival = "8",
3682 .oval = 8,
3683 .help = "Normal (byte based)",
3684 },
3685 { .ival = "1",
3686 .oval = 1,
3687 .help = "Bit based",
3688 },
3689 },
3690 .help = "Bit multiple of result summary data (8 for byte, 1 for bit)",
3691 .category = FIO_OPT_C_GENERAL,
3692 .group = FIO_OPT_G_INVALID,
3693 },
3694 {
3695 .name = "hugepage-size",
3696 .lname = "Hugepage size",
3697 .type = FIO_OPT_INT,
3698 .off1 = td_var_offset(hugepage_size),
3699 .help = "When using hugepages, specify size of each page",
3700 .def = __fio_stringify(FIO_HUGE_PAGE),
3701 .interval = 1024 * 1024,
3702 .category = FIO_OPT_C_GENERAL,
3703 .group = FIO_OPT_G_INVALID,
3704 },
3705 {
3706 .name = "flow_id",
3707 .lname = "I/O flow ID",
3708 .type = FIO_OPT_INT,
3709 .off1 = td_var_offset(flow_id),
3710 .help = "The flow index ID to use",
3711 .def = "0",
3712 .category = FIO_OPT_C_IO,
3713 .group = FIO_OPT_G_IO_FLOW,
3714 },
3715 {
3716 .name = "flow",
3717 .lname = "I/O flow weight",
3718 .type = FIO_OPT_INT,
3719 .off1 = td_var_offset(flow),
3720 .help = "Weight for flow control of this job",
3721 .parent = "flow_id",
3722 .hide = 1,
3723 .def = "0",
3724 .category = FIO_OPT_C_IO,
3725 .group = FIO_OPT_G_IO_FLOW,
3726 },
3727 {
3728 .name = "flow_watermark",
3729 .lname = "I/O flow watermark",
3730 .type = FIO_OPT_INT,
3731 .off1 = td_var_offset(flow_watermark),
3732 .help = "High watermark for flow control. This option"
3733 " should be set to the same value for all threads"
3734 " with non-zero flow.",
3735 .parent = "flow_id",
3736 .hide = 1,
3737 .def = "1024",
3738 .category = FIO_OPT_C_IO,
3739 .group = FIO_OPT_G_IO_FLOW,
3740 },
3741 {
3742 .name = "flow_sleep",
3743 .lname = "I/O flow sleep",
3744 .type = FIO_OPT_INT,
3745 .off1 = td_var_offset(flow_sleep),
3746 .help = "How many microseconds to sleep after being held"
3747 " back by the flow control mechanism",
3748 .parent = "flow_id",
3749 .hide = 1,
3750 .def = "0",
3751 .category = FIO_OPT_C_IO,
3752 .group = FIO_OPT_G_IO_FLOW,
3753 },
3754 {
3755 .name = "skip_bad",
3756 .lname = "Skip operations against bad blocks",
3757 .type = FIO_OPT_BOOL,
3758 .off1 = td_var_offset(skip_bad),
3759 .help = "Skip operations against known bad blocks.",
3760 .hide = 1,
3761 .def = "0",
3762 .category = FIO_OPT_C_IO,
3763 .group = FIO_OPT_G_MTD,
3764 },
3765 {
3766 .name = NULL,
3767 },
3768};
3769
3770static void add_to_lopt(struct option *lopt, struct fio_option *o,
3771 const char *name, int val)
3772{
3773 lopt->name = (char *) name;
3774 lopt->val = val;
3775 if (o->type == FIO_OPT_STR_SET)
3776 lopt->has_arg = optional_argument;
3777 else
3778 lopt->has_arg = required_argument;
3779}
3780
3781static void options_to_lopts(struct fio_option *opts,
3782 struct option *long_options,
3783 int i, int option_type)
3784{
3785 struct fio_option *o = &opts[0];
3786 while (o->name) {
3787 add_to_lopt(&long_options[i], o, o->name, option_type);
3788 if (o->alias) {
3789 i++;
3790 add_to_lopt(&long_options[i], o, o->alias, option_type);
3791 }
3792
3793 i++;
3794 o++;
3795 assert(i < FIO_NR_OPTIONS);
3796 }
3797}
3798
3799void fio_options_set_ioengine_opts(struct option *long_options,
3800 struct thread_data *td)
3801{
3802 unsigned int i;
3803
3804 i = 0;
3805 while (long_options[i].name) {
3806 if (long_options[i].val == FIO_GETOPT_IOENGINE) {
3807 memset(&long_options[i], 0, sizeof(*long_options));
3808 break;
3809 }
3810 i++;
3811 }
3812
3813 /*
3814 * Just clear out the prior ioengine options.
3815 */
3816 if (!td || !td->eo)
3817 return;
3818
3819 options_to_lopts(td->io_ops->options, long_options, i,
3820 FIO_GETOPT_IOENGINE);
3821}
3822
3823void fio_options_dup_and_init(struct option *long_options)
3824{
3825 unsigned int i;
3826
3827 options_init(fio_options);
3828
3829 i = 0;
3830 while (long_options[i].name)
3831 i++;
3832
3833 options_to_lopts(fio_options, long_options, i, FIO_GETOPT_JOB);
3834}
3835
3836struct fio_keyword {
3837 const char *word;
3838 const char *desc;
3839 char *replace;
3840};
3841
3842static struct fio_keyword fio_keywords[] = {
3843 {
3844 .word = "$pagesize",
3845 .desc = "Page size in the system",
3846 },
3847 {
3848 .word = "$mb_memory",
3849 .desc = "Megabytes of memory online",
3850 },
3851 {
3852 .word = "$ncpus",
3853 .desc = "Number of CPUs online in the system",
3854 },
3855 {
3856 .word = NULL,
3857 },
3858};
3859
3860void fio_keywords_exit(void)
3861{
3862 struct fio_keyword *kw;
3863
3864 kw = &fio_keywords[0];
3865 while (kw->word) {
3866 free(kw->replace);
3867 kw->replace = NULL;
3868 kw++;
3869 }
3870}
3871
3872void fio_keywords_init(void)
3873{
3874 unsigned long long mb_memory;
3875 char buf[128];
3876 long l;
3877
3878 sprintf(buf, "%lu", (unsigned long) page_size);
3879 fio_keywords[0].replace = strdup(buf);
3880
3881 mb_memory = os_phys_mem() / (1024 * 1024);
3882 sprintf(buf, "%llu", mb_memory);
3883 fio_keywords[1].replace = strdup(buf);
3884
3885 l = cpus_online();
3886 sprintf(buf, "%lu", l);
3887 fio_keywords[2].replace = strdup(buf);
3888}
3889
3890#define BC_APP "bc"
3891
3892static char *bc_calc(char *str)
3893{
3894 char buf[128], *tmp;
3895 FILE *f;
3896 int ret;
3897
3898 /*
3899 * No math, just return string
3900 */
3901 if ((!strchr(str, '+') && !strchr(str, '-') && !strchr(str, '*') &&
3902 !strchr(str, '/')) || strchr(str, '\''))
3903 return str;
3904
3905 /*
3906 * Split option from value, we only need to calculate the value
3907 */
3908 tmp = strchr(str, '=');
3909 if (!tmp)
3910 return str;
3911
3912 tmp++;
3913
3914 /*
3915 * Prevent buffer overflows; such a case isn't reasonable anyway
3916 */
3917 if (strlen(str) >= 128 || strlen(tmp) > 100)
3918 return str;
3919
3920 sprintf(buf, "which %s > /dev/null", BC_APP);
3921 if (system(buf)) {
3922 log_err("fio: bc is needed for performing math\n");
3923 return NULL;
3924 }
3925
3926 sprintf(buf, "echo '%s' | %s", tmp, BC_APP);
3927 f = popen(buf, "r");
3928 if (!f)
3929 return NULL;
3930
3931 ret = fread(&buf[tmp - str], 1, 128 - (tmp - str), f);
3932 if (ret <= 0) {
3933 pclose(f);
3934 return NULL;
3935 }
3936
3937 pclose(f);
3938 buf[(tmp - str) + ret - 1] = '\0';
3939 memcpy(buf, str, tmp - str);
3940 free(str);
3941 return strdup(buf);
3942}
3943
3944/*
3945 * Return a copy of the input string with substrings of the form ${VARNAME}
3946 * substituted with the value of the environment variable VARNAME. The
3947 * substitution always occurs, even if VARNAME is empty or the corresponding
3948 * environment variable undefined.
3949 */
3950static char *option_dup_subs(const char *opt)
3951{
3952 char out[OPT_LEN_MAX+1];
3953 char in[OPT_LEN_MAX+1];
3954 char *outptr = out;
3955 char *inptr = in;
3956 char *ch1, *ch2, *env;
3957 ssize_t nchr = OPT_LEN_MAX;
3958 size_t envlen;
3959
3960 if (strlen(opt) + 1 > OPT_LEN_MAX) {
3961 log_err("OPT_LEN_MAX (%d) is too small\n", OPT_LEN_MAX);
3962 return NULL;
3963 }
3964
3965 in[OPT_LEN_MAX] = '\0';
3966 strncpy(in, opt, OPT_LEN_MAX);
3967
3968 while (*inptr && nchr > 0) {
3969 if (inptr[0] == '$' && inptr[1] == '{') {
3970 ch2 = strchr(inptr, '}');
3971 if (ch2 && inptr+1 < ch2) {
3972 ch1 = inptr+2;
3973 inptr = ch2+1;
3974 *ch2 = '\0';
3975
3976 env = getenv(ch1);
3977 if (env) {
3978 envlen = strlen(env);
3979 if (envlen <= nchr) {
3980 memcpy(outptr, env, envlen);
3981 outptr += envlen;
3982 nchr -= envlen;
3983 }
3984 }
3985
3986 continue;
3987 }
3988 }
3989
3990 *outptr++ = *inptr++;
3991 --nchr;
3992 }
3993
3994 *outptr = '\0';
3995 return strdup(out);
3996}
3997
3998/*
3999 * Look for reserved variable names and replace them with real values
4000 */
4001static char *fio_keyword_replace(char *opt)
4002{
4003 char *s;
4004 int i;
4005 int docalc = 0;
4006
4007 for (i = 0; fio_keywords[i].word != NULL; i++) {
4008 struct fio_keyword *kw = &fio_keywords[i];
4009
4010 while ((s = strstr(opt, kw->word)) != NULL) {
4011 char *new = malloc(strlen(opt) + 1);
4012 char *o_org = opt;
4013 int olen = s - opt;
4014 int len;
4015
4016 /*
4017 * Copy part of the string before the keyword and
4018 * sprintf() the replacement after it.
4019 */
4020 memcpy(new, opt, olen);
4021 len = sprintf(new + olen, "%s", kw->replace);
4022
4023 /*
4024 * If there's more in the original string, copy that
4025 * in too
4026 */
4027 opt += strlen(kw->word) + olen;
4028 if (strlen(opt))
4029 memcpy(new + olen + len, opt, opt - o_org - 1);
4030
4031 /*
4032 * replace opt and free the old opt
4033 */
4034 opt = new;
4035 free(o_org);
4036
4037 docalc = 1;
4038 }
4039 }
4040
4041 /*
4042 * Check for potential math and invoke bc, if possible
4043 */
4044 if (docalc)
4045 opt = bc_calc(opt);
4046
4047 return opt;
4048}
4049
4050static char **dup_and_sub_options(char **opts, int num_opts)
4051{
4052 int i;
4053 char **opts_copy = malloc(num_opts * sizeof(*opts));
4054 for (i = 0; i < num_opts; i++) {
4055 opts_copy[i] = option_dup_subs(opts[i]);
4056 if (!opts_copy[i])
4057 continue;
4058 opts_copy[i] = fio_keyword_replace(opts_copy[i]);
4059 }
4060 return opts_copy;
4061}
4062
4063static void show_closest_option(const char *opt)
4064{
4065 int best_option, best_distance;
4066 int i, distance;
4067 char *name;
4068
4069 if (!strlen(opt))
4070 return;
4071
4072 name = strdup(opt);
4073 i = 0;
4074 while (name[i] != '\0' && name[i] != '=')
4075 i++;
4076 name[i] = '\0';
4077
4078 best_option = -1;
4079 best_distance = INT_MAX;
4080 i = 0;
4081 while (fio_options[i].name) {
4082 distance = string_distance(name, fio_options[i].name);
4083 if (distance < best_distance) {
4084 best_distance = distance;
4085 best_option = i;
4086 }
4087 i++;
4088 }
4089
4090 if (best_option != -1)
4091 log_err("Did you mean %s?\n", fio_options[best_option].name);
4092
4093 free(name);
4094}
4095
4096int fio_options_parse(struct thread_data *td, char **opts, int num_opts,
4097 int dump_cmdline)
4098{
4099 int i, ret, unknown;
4100 char **opts_copy;
4101
4102 sort_options(opts, fio_options, num_opts);
4103 opts_copy = dup_and_sub_options(opts, num_opts);
4104
4105 for (ret = 0, i = 0, unknown = 0; i < num_opts; i++) {
4106 struct fio_option *o;
4107 int newret = parse_option(opts_copy[i], opts[i], fio_options,
4108 &o, td, dump_cmdline);
4109
4110 if (!newret && o)
4111 fio_option_mark_set(&td->o, o);
4112
4113 if (opts_copy[i]) {
4114 if (newret && !o) {
4115 unknown++;
4116 continue;
4117 }
4118 free(opts_copy[i]);
4119 opts_copy[i] = NULL;
4120 }
4121
4122 ret |= newret;
4123 }
4124
4125 if (unknown) {
4126 ret |= ioengine_load(td);
4127 if (td->eo) {
4128 sort_options(opts_copy, td->io_ops->options, num_opts);
4129 opts = opts_copy;
4130 }
4131 for (i = 0; i < num_opts; i++) {
4132 struct fio_option *o = NULL;
4133 int newret = 1;
4134
4135 if (!opts_copy[i])
4136 continue;
4137
4138 if (td->eo)
4139 newret = parse_option(opts_copy[i], opts[i],
4140 td->io_ops->options, &o,
4141 td->eo, dump_cmdline);
4142
4143 ret |= newret;
4144 if (!o) {
4145 log_err("Bad option <%s>\n", opts[i]);
4146 show_closest_option(opts[i]);
4147 }
4148 free(opts_copy[i]);
4149 opts_copy[i] = NULL;
4150 }
4151 }
4152
4153 free(opts_copy);
4154 return ret;
4155}
4156
4157int fio_cmd_option_parse(struct thread_data *td, const char *opt, char *val)
4158{
4159 int ret;
4160
4161 ret = parse_cmd_option(opt, val, fio_options, td);
4162 if (!ret) {
4163 struct fio_option *o;
4164
4165 o = find_option(fio_options, opt);
4166 if (o)
4167 fio_option_mark_set(&td->o, o);
4168 }
4169
4170 return ret;
4171}
4172
4173int fio_cmd_ioengine_option_parse(struct thread_data *td, const char *opt,
4174 char *val)
4175{
4176 return parse_cmd_option(opt, val, td->io_ops->options, td->eo);
4177}
4178
4179void fio_fill_default_options(struct thread_data *td)
4180{
4181 td->o.magic = OPT_MAGIC;
4182 fill_default_options(td, fio_options);
4183}
4184
4185int fio_show_option_help(const char *opt)
4186{
4187 return show_cmd_help(fio_options, opt);
4188}
4189
4190void options_mem_dupe(void *data, struct fio_option *options)
4191{
4192 struct fio_option *o;
4193 char **ptr;
4194
4195 for (o = &options[0]; o->name; o++) {
4196 if (o->type != FIO_OPT_STR_STORE)
4197 continue;
4198
4199 ptr = td_var(data, o, o->off1);
4200 if (*ptr)
4201 *ptr = strdup(*ptr);
4202 }
4203}
4204
4205/*
4206 * dupe FIO_OPT_STR_STORE options
4207 */
4208void fio_options_mem_dupe(struct thread_data *td)
4209{
4210 options_mem_dupe(&td->o, fio_options);
4211
4212 if (td->eo && td->io_ops) {
4213 void *oldeo = td->eo;
4214
4215 td->eo = malloc(td->io_ops->option_struct_size);
4216 memcpy(td->eo, oldeo, td->io_ops->option_struct_size);
4217 options_mem_dupe(td->eo, td->io_ops->options);
4218 }
4219}
4220
4221unsigned int fio_get_kb_base(void *data)
4222{
4223 struct thread_options *o = data;
4224 unsigned int kb_base = 0;
4225
4226 /*
4227 * This is a hack... For private options, *data is not holding
4228 * a pointer to the thread_options, but to private data. This means
4229 * we can't safely dereference it, but magic is first so mem wise
4230 * it is valid. But this also means that if the job first sets
4231 * kb_base and expects that to be honored by private options,
4232 * it will be disappointed. We will return the global default
4233 * for this.
4234 */
4235 if (o && o->magic == OPT_MAGIC)
4236 kb_base = o->kb_base;
4237 if (!kb_base)
4238 kb_base = 1024;
4239
4240 return kb_base;
4241}
4242
4243int add_option(struct fio_option *o)
4244{
4245 struct fio_option *__o;
4246 int opt_index = 0;
4247
4248 __o = fio_options;
4249 while (__o->name) {
4250 opt_index++;
4251 __o++;
4252 }
4253
4254 if (opt_index + 1 == FIO_MAX_OPTS) {
4255 log_err("fio: FIO_MAX_OPTS is too small\n");
4256 return 1;
4257 }
4258
4259 memcpy(&fio_options[opt_index], o, sizeof(*o));
4260 fio_options[opt_index + 1].name = NULL;
4261 return 0;
4262}
4263
4264void invalidate_profile_options(const char *prof_name)
4265{
4266 struct fio_option *o;
4267
4268 o = fio_options;
4269 while (o->name) {
4270 if (o->prof_name && !strcmp(o->prof_name, prof_name)) {
4271 o->type = FIO_OPT_INVALID;
4272 o->prof_name = NULL;
4273 }
4274 o++;
4275 }
4276}
4277
4278void add_opt_posval(const char *optname, const char *ival, const char *help)
4279{
4280 struct fio_option *o;
4281 unsigned int i;
4282
4283 o = find_option(fio_options, optname);
4284 if (!o)
4285 return;
4286
4287 for (i = 0; i < PARSE_MAX_VP; i++) {
4288 if (o->posval[i].ival)
4289 continue;
4290
4291 o->posval[i].ival = ival;
4292 o->posval[i].help = help;
4293 break;
4294 }
4295}
4296
4297void del_opt_posval(const char *optname, const char *ival)
4298{
4299 struct fio_option *o;
4300 unsigned int i;
4301
4302 o = find_option(fio_options, optname);
4303 if (!o)
4304 return;
4305
4306 for (i = 0; i < PARSE_MAX_VP; i++) {
4307 if (!o->posval[i].ival)
4308 continue;
4309 if (strcmp(o->posval[i].ival, ival))
4310 continue;
4311
4312 o->posval[i].ival = NULL;
4313 o->posval[i].help = NULL;
4314 }
4315}
4316
4317void fio_options_free(struct thread_data *td)
4318{
4319 options_free(fio_options, td);
4320 if (td->eo && td->io_ops && td->io_ops->options) {
4321 options_free(td->io_ops->options, td->eo);
4322 free(td->eo);
4323 td->eo = NULL;
4324 }
4325}
4326
4327struct fio_option *fio_option_find(const char *name)
4328{
4329 return find_option(fio_options, name);
4330}
4331
4332static struct fio_option *find_next_opt(struct thread_options *o,
4333 struct fio_option *from,
4334 unsigned int off1)
4335{
4336 struct fio_option *opt;
4337
4338 if (!from)
4339 from = &fio_options[0];
4340 else
4341 from++;
4342
4343 opt = NULL;
4344 do {
4345 if (off1 == from->off1) {
4346 opt = from;
4347 break;
4348 }
4349 from++;
4350 } while (from->name);
4351
4352 return opt;
4353}
4354
4355static int opt_is_set(struct thread_options *o, struct fio_option *opt)
4356{
4357 unsigned int opt_off, index, offset;
4358
4359 opt_off = opt - &fio_options[0];
4360 index = opt_off / (8 * sizeof(uint64_t));
4361 offset = opt_off & ((8 * sizeof(uint64_t)) - 1);
4362 return (o->set_options[index] & (1UL << offset)) != 0;
4363}
4364
4365int __fio_option_is_set(struct thread_options *o, unsigned int off1)
4366{
4367 struct fio_option *opt, *next;
4368
4369 next = NULL;
4370 while ((opt = find_next_opt(o, next, off1)) != NULL) {
4371 if (opt_is_set(o, opt))
4372 return 1;
4373
4374 next = opt;
4375 }
4376
4377 return 0;
4378}
4379
4380void fio_option_mark_set(struct thread_options *o, struct fio_option *opt)
4381{
4382 unsigned int opt_off, index, offset;
4383
4384 opt_off = opt - &fio_options[0];
4385 index = opt_off / (8 * sizeof(uint64_t));
4386 offset = opt_off & ((8 * sizeof(uint64_t)) - 1);
4387 o->set_options[index] |= 1UL << offset;
4388}