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