Add support for mixing a random IO workload a bit
[fio.git] / options.c
CommitLineData
214e1eca
JA
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <ctype.h>
5#include <string.h>
6#include <getopt.h>
7#include <assert.h>
8
9#include "fio.h"
10#include "parse.h"
11
2dc1bbeb 12#define td_var_offset(var) ((size_t) &((struct thread_options *)0)->var)
214e1eca
JA
13
14/*
15 * Check if mmap/mmaphuge has a :/foo/bar/file at the end. If so, return that.
16 */
17static char *get_opt_postfix(const char *str)
18{
19 char *p = strstr(str, ":");
20
21 if (!p)
22 return NULL;
23
24 p++;
25 strip_blank_front(&p);
26 strip_blank_end(p);
27 return strdup(p);
28}
29
211097b2
JA
30static int str_rw_cb(void *data, const char *str)
31{
32 struct thread_data *td = data;
33 char *nr = get_opt_postfix(str);
34
35 td->o.ddir_nr = 0;
36 if (nr)
37 td->o.ddir_nr = atoi(nr);
38
39 printf("ddir_nr=%d\n", td->o.ddir_nr);
40
41 return 0;
42}
43
214e1eca
JA
44static int str_mem_cb(void *data, const char *mem)
45{
46 struct thread_data *td = data;
47
2dc1bbeb 48 if (td->o.mem_type == MEM_MMAPHUGE || td->o.mem_type == MEM_MMAP) {
214e1eca 49 td->mmapfile = get_opt_postfix(mem);
2dc1bbeb 50 if (td->o.mem_type == MEM_MMAPHUGE && !td->mmapfile) {
214e1eca
JA
51 log_err("fio: mmaphuge:/path/to/file\n");
52 return 1;
53 }
54 }
55
56 return 0;
57}
58
59static int str_lockmem_cb(void fio_unused *data, unsigned long *val)
60{
61 mlock_size = *val;
62 return 0;
63}
64
65#ifdef FIO_HAVE_IOPRIO
66static int str_prioclass_cb(void *data, unsigned int *val)
67{
68 struct thread_data *td = data;
69
70 td->ioprio |= *val << IOPRIO_CLASS_SHIFT;
71 return 0;
72}
73
74static int str_prio_cb(void *data, unsigned int *val)
75{
76 struct thread_data *td = data;
77
78 td->ioprio |= *val;
79 return 0;
80}
81#endif
82
83static int str_exitall_cb(void)
84{
85 exitall_on_terminate = 1;
86 return 0;
87}
88
89static void fill_cpu_mask(os_cpu_mask_t cpumask, int cpu)
90{
91#ifdef FIO_HAVE_CPU_AFFINITY
92 unsigned int i;
93
94 CPU_ZERO(&cpumask);
95
96 for (i = 0; i < sizeof(int) * 8; i++) {
97 if ((1 << i) & cpu)
98 CPU_SET(i, &cpumask);
99 }
100#endif
101}
102
103static int str_cpumask_cb(void *data, unsigned int *val)
104{
105 struct thread_data *td = data;
106
2dc1bbeb 107 fill_cpu_mask(td->o.cpumask, *val);
214e1eca
JA
108 return 0;
109}
110
111static int str_fst_cb(void *data, const char *str)
112{
113 struct thread_data *td = data;
114 char *nr = get_opt_postfix(str);
115
116 td->file_service_nr = 1;
117 if (nr)
118 td->file_service_nr = atoi(nr);
119
120 return 0;
121}
122
123static int str_filename_cb(void *data, const char *input)
124{
125 struct thread_data *td = data;
126 char *fname, *str, *p;
127
128 p = str = strdup(input);
129
130 strip_blank_front(&str);
131 strip_blank_end(str);
132
133 if (!td->files_index)
2dc1bbeb 134 td->o.nr_files = 0;
214e1eca
JA
135
136 while ((fname = strsep(&str, ":")) != NULL) {
137 if (!strlen(fname))
138 break;
139 add_file(td, fname);
2dc1bbeb 140 td->o.nr_files++;
214e1eca
JA
141 }
142
143 free(p);
144 return 0;
145}
146
147static int str_directory_cb(void *data, const char fio_unused *str)
148{
149 struct thread_data *td = data;
150 struct stat sb;
151
2dc1bbeb
JA
152 if (lstat(td->o.directory, &sb) < 0) {
153 log_err("fio: %s is not a directory\n", td->o.directory);
214e1eca
JA
154 td_verror(td, errno, "lstat");
155 return 1;
156 }
157 if (!S_ISDIR(sb.st_mode)) {
2dc1bbeb 158 log_err("fio: %s is not a directory\n", td->o.directory);
214e1eca
JA
159 return 1;
160 }
161
162 return 0;
163}
164
165static int str_opendir_cb(void *data, const char fio_unused *str)
166{
167 struct thread_data *td = data;
168
169 if (!td->files_index)
2dc1bbeb 170 td->o.nr_files = 0;
214e1eca 171
2dc1bbeb 172 return add_dir_files(td, td->o.opendir);
214e1eca
JA
173}
174
175
176#define __stringify_1(x) #x
177#define __stringify(x) __stringify_1(x)
178
179/*
180 * Map of job/command line options
181 */
182static struct fio_option options[] = {
183 {
184 .name = "description",
185 .type = FIO_OPT_STR_STORE,
186 .off1 = td_var_offset(description),
187 .help = "Text job description",
188 },
189 {
190 .name = "name",
191 .type = FIO_OPT_STR_STORE,
192 .off1 = td_var_offset(name),
193 .help = "Name of this job",
194 },
195 {
196 .name = "directory",
197 .type = FIO_OPT_STR_STORE,
198 .off1 = td_var_offset(directory),
199 .cb = str_directory_cb,
200 .help = "Directory to store files in",
201 },
202 {
203 .name = "filename",
204 .type = FIO_OPT_STR_STORE,
205 .off1 = td_var_offset(filename),
206 .cb = str_filename_cb,
207 .help = "File(s) to use for the workload",
208 },
209 {
210 .name = "opendir",
211 .type = FIO_OPT_STR_STORE,
212 .off1 = td_var_offset(opendir),
213 .cb = str_opendir_cb,
214 .help = "Recursively add files from this directory and down",
215 },
216 {
217 .name = "rw",
d3aad8f2 218 .alias = "readwrite",
214e1eca 219 .type = FIO_OPT_STR,
211097b2 220 .cb = str_rw_cb,
214e1eca
JA
221 .off1 = td_var_offset(td_ddir),
222 .help = "IO direction",
223 .def = "read",
224 .posval = {
225 { .ival = "read",
226 .oval = TD_DDIR_READ,
227 .help = "Sequential read",
228 },
229 { .ival = "write",
230 .oval = TD_DDIR_WRITE,
231 .help = "Sequential write",
232 },
233 { .ival = "randread",
234 .oval = TD_DDIR_RANDREAD,
235 .help = "Random read",
236 },
237 { .ival = "randwrite",
238 .oval = TD_DDIR_RANDWRITE,
239 .help = "Random write",
240 },
241 { .ival = "rw",
242 .oval = TD_DDIR_RW,
243 .help = "Sequential read and write mix",
244 },
245 { .ival = "randrw",
246 .oval = TD_DDIR_RANDRW,
247 .help = "Random read and write mix"
248 },
249 },
250 },
251 {
252 .name = "ioengine",
253 .type = FIO_OPT_STR_STORE,
254 .off1 = td_var_offset(ioengine),
255 .help = "IO engine to use",
256 .def = "sync",
257 .posval = {
258 { .ival = "sync",
259 .help = "Use read/write",
260 },
261#ifdef FIO_HAVE_LIBAIO
262 { .ival = "libaio",
263 .help = "Linux native asynchronous IO",
264 },
265#endif
266#ifdef FIO_HAVE_POSIXAIO
267 { .ival = "posixaio",
268 .help = "POSIX asynchronous IO",
269 },
270#endif
271 { .ival = "mmap",
272 .help = "Memory mapped IO",
273 },
274#ifdef FIO_HAVE_SPLICE
275 { .ival = "splice",
276 .help = "splice/vmsplice based IO",
277 },
278#endif
279#ifdef FIO_HAVE_SGIO
280 { .ival = "sg",
281 .help = "SCSI generic v3 IO",
282 },
283#endif
284 { .ival = "null",
285 .help = "Testing engine (no data transfer)",
286 },
287 { .ival = "net",
288 .help = "Network IO",
289 },
290#ifdef FIO_HAVE_SYSLET
291 { .ival = "syslet-rw",
292 .help = "syslet enabled async pread/pwrite IO",
293 },
294#endif
295 { .ival = "cpuio",
296 .help = "CPU cycler burner engine",
297 },
b8c82a46
JA
298#ifdef FIO_HAVE_GUASI
299 { .ival = "guasi",
300 .help = "GUASI IO engine",
301 },
302#endif
214e1eca
JA
303 { .ival = "external",
304 .help = "Load external engine (append name)",
305 },
306 },
307 },
308 {
309 .name = "iodepth",
310 .type = FIO_OPT_INT,
311 .off1 = td_var_offset(iodepth),
312 .help = "Amount of IO buffers to keep in flight",
313 .def = "1",
314 },
315 {
316 .name = "iodepth_batch",
317 .type = FIO_OPT_INT,
318 .off1 = td_var_offset(iodepth_batch),
319 .help = "Number of IO to submit in one go",
320 },
321 {
322 .name = "iodepth_low",
323 .type = FIO_OPT_INT,
324 .off1 = td_var_offset(iodepth_low),
325 .help = "Low water mark for queuing depth",
326 },
327 {
328 .name = "size",
329 .type = FIO_OPT_STR_VAL,
2dc1bbeb 330 .off1 = td_var_offset(size),
214e1eca
JA
331 .help = "Total size of device or files",
332 },
333 {
334 .name = "filesize",
335 .type = FIO_OPT_STR_VAL,
336 .off1 = td_var_offset(file_size_low),
337 .off2 = td_var_offset(file_size_high),
338 .help = "Size of individual files",
339 },
340 {
341 .name = "bs",
d3aad8f2 342 .alias = "blocksize",
214e1eca
JA
343 .type = FIO_OPT_STR_VAL_INT,
344 .off1 = td_var_offset(bs[DDIR_READ]),
345 .off2 = td_var_offset(bs[DDIR_WRITE]),
346 .help = "Block size unit",
347 .def = "4k",
348 },
349 {
350 .name = "bsrange",
d3aad8f2 351 .alias = "blocksize_range",
214e1eca
JA
352 .type = FIO_OPT_RANGE,
353 .off1 = td_var_offset(min_bs[DDIR_READ]),
354 .off2 = td_var_offset(max_bs[DDIR_READ]),
355 .off3 = td_var_offset(min_bs[DDIR_WRITE]),
356 .off4 = td_var_offset(max_bs[DDIR_WRITE]),
357 .help = "Set block size range (in more detail than bs)",
358 },
359 {
360 .name = "bs_unaligned",
d3aad8f2 361 .alias = "blocksize_unaligned",
214e1eca
JA
362 .type = FIO_OPT_STR_SET,
363 .off1 = td_var_offset(bs_unaligned),
364 .help = "Don't sector align IO buffer sizes",
365 },
366 {
367 .name = "offset",
368 .type = FIO_OPT_STR_VAL,
369 .off1 = td_var_offset(start_offset),
370 .help = "Start IO from this offset",
371 .def = "0",
372 },
373 {
374 .name = "randrepeat",
375 .type = FIO_OPT_BOOL,
376 .off1 = td_var_offset(rand_repeatable),
377 .help = "Use repeatable random IO pattern",
378 .def = "1",
379 },
380 {
381 .name = "norandommap",
382 .type = FIO_OPT_STR_SET,
383 .off1 = td_var_offset(norandommap),
384 .help = "Accept potential duplicate random blocks",
385 },
386 {
387 .name = "nrfiles",
388 .type = FIO_OPT_INT,
389 .off1 = td_var_offset(nr_files),
390 .help = "Split job workload between this number of files",
391 .def = "1",
392 },
393 {
394 .name = "openfiles",
395 .type = FIO_OPT_INT,
396 .off1 = td_var_offset(open_files),
397 .help = "Number of files to keep open at the same time",
398 },
399 {
400 .name = "file_service_type",
401 .type = FIO_OPT_STR,
402 .cb = str_fst_cb,
403 .off1 = td_var_offset(file_service_type),
404 .help = "How to select which file to service next",
405 .def = "roundrobin",
406 .posval = {
407 { .ival = "random",
408 .oval = FIO_FSERVICE_RANDOM,
409 .help = "Choose a file at random",
410 },
411 { .ival = "roundrobin",
412 .oval = FIO_FSERVICE_RR,
413 .help = "Round robin select files",
414 },
415 },
416 },
417 {
418 .name = "fsync",
419 .type = FIO_OPT_INT,
420 .off1 = td_var_offset(fsync_blocks),
421 .help = "Issue fsync for writes every given number of blocks",
422 .def = "0",
423 },
424 {
425 .name = "direct",
426 .type = FIO_OPT_BOOL,
427 .off1 = td_var_offset(odirect),
428 .help = "Use O_DIRECT IO (negates buffered)",
429 .def = "0",
430 },
431 {
432 .name = "buffered",
433 .type = FIO_OPT_BOOL,
434 .off1 = td_var_offset(odirect),
435 .neg = 1,
436 .help = "Use buffered IO (negates direct)",
437 .def = "1",
438 },
439 {
440 .name = "overwrite",
441 .type = FIO_OPT_BOOL,
442 .off1 = td_var_offset(overwrite),
443 .help = "When writing, set whether to overwrite current data",
444 .def = "0",
445 },
446 {
447 .name = "loops",
448 .type = FIO_OPT_INT,
449 .off1 = td_var_offset(loops),
450 .help = "Number of times to run the job",
451 .def = "1",
452 },
453 {
454 .name = "numjobs",
455 .type = FIO_OPT_INT,
456 .off1 = td_var_offset(numjobs),
457 .help = "Duplicate this job this many times",
458 .def = "1",
459 },
460 {
461 .name = "startdelay",
462 .type = FIO_OPT_INT,
463 .off1 = td_var_offset(start_delay),
464 .help = "Only start job when this period has passed",
465 .def = "0",
466 },
467 {
468 .name = "runtime",
469 .alias = "timeout",
470 .type = FIO_OPT_STR_VAL_TIME,
471 .off1 = td_var_offset(timeout),
472 .help = "Stop workload when this amount of time has passed",
473 .def = "0",
474 },
475 {
476 .name = "mem",
d3aad8f2 477 .alias = "iomem",
214e1eca
JA
478 .type = FIO_OPT_STR,
479 .cb = str_mem_cb,
480 .off1 = td_var_offset(mem_type),
481 .help = "Backing type for IO buffers",
482 .def = "malloc",
483 .posval = {
484 { .ival = "malloc",
485 .oval = MEM_MALLOC,
486 .help = "Use malloc(3) for IO buffers",
487 },
37c8cdfe
JA
488 { .ival = "shm",
489 .oval = MEM_SHM,
490 .help = "Use shared memory segments for IO buffers",
491 },
214e1eca
JA
492#ifdef FIO_HAVE_HUGETLB
493 { .ival = "shmhuge",
494 .oval = MEM_SHMHUGE,
495 .help = "Like shm, but use huge pages",
496 },
b370e46a 497#endif
37c8cdfe
JA
498 { .ival = "mmap",
499 .oval = MEM_MMAP,
500 .help = "Use mmap(2) (file or anon) for IO buffers",
501 },
214e1eca
JA
502#ifdef FIO_HAVE_HUGETLB
503 { .ival = "mmaphuge",
504 .oval = MEM_MMAPHUGE,
505 .help = "Like mmap, but use huge pages",
506 },
507#endif
508 },
509 },
510 {
511 .name = "verify",
512 .type = FIO_OPT_STR,
513 .off1 = td_var_offset(verify),
514 .help = "Verify data written",
515 .def = "0",
516 .posval = {
517 { .ival = "0",
518 .oval = VERIFY_NONE,
519 .help = "Don't do IO verification",
520 },
521 { .ival = "crc32",
522 .oval = VERIFY_CRC32,
523 .help = "Use crc32 checksums for verification",
524 },
525 { .ival = "md5",
526 .oval = VERIFY_MD5,
527 .help = "Use md5 checksums for verification",
528 },
529 },
530 },
531 {
532 .name = "write_iolog",
533 .type = FIO_OPT_STR_STORE,
534 .off1 = td_var_offset(write_iolog_file),
535 .help = "Store IO pattern to file",
536 },
537 {
538 .name = "read_iolog",
539 .type = FIO_OPT_STR_STORE,
540 .off1 = td_var_offset(read_iolog_file),
541 .help = "Playback IO pattern from file",
542 },
543 {
544 .name = "exec_prerun",
545 .type = FIO_OPT_STR_STORE,
546 .off1 = td_var_offset(exec_prerun),
547 .help = "Execute this file prior to running job",
548 },
549 {
550 .name = "exec_postrun",
551 .type = FIO_OPT_STR_STORE,
552 .off1 = td_var_offset(exec_postrun),
553 .help = "Execute this file after running job",
554 },
555#ifdef FIO_HAVE_IOSCHED_SWITCH
556 {
557 .name = "ioscheduler",
558 .type = FIO_OPT_STR_STORE,
559 .off1 = td_var_offset(ioscheduler),
560 .help = "Use this IO scheduler on the backing device",
561 },
562#endif
563 {
564 .name = "zonesize",
565 .type = FIO_OPT_STR_VAL,
566 .off1 = td_var_offset(zone_size),
567 .help = "Give size of an IO zone",
568 .def = "0",
569 },
570 {
571 .name = "zoneskip",
572 .type = FIO_OPT_STR_VAL,
573 .off1 = td_var_offset(zone_skip),
574 .help = "Space between IO zones",
575 .def = "0",
576 },
577 {
578 .name = "lockmem",
579 .type = FIO_OPT_STR_VAL,
580 .cb = str_lockmem_cb,
581 .help = "Lock down this amount of memory",
582 .def = "0",
583 },
584 {
585 .name = "rwmixcycle",
586 .type = FIO_OPT_INT,
587 .off1 = td_var_offset(rwmixcycle),
588 .help = "Cycle period for mixed read/write workloads (msec)",
589 .def = "500",
590 },
591 {
592 .name = "rwmixread",
593 .type = FIO_OPT_INT,
e47f799f 594 .off1 = td_var_offset(rwmix[DDIR_READ]),
214e1eca
JA
595 .maxval = 100,
596 .help = "Percentage of mixed workload that is reads",
597 .def = "50",
598 },
599 {
600 .name = "rwmixwrite",
601 .type = FIO_OPT_INT,
e47f799f 602 .off1 = td_var_offset(rwmix[DDIR_WRITE]),
214e1eca
JA
603 .maxval = 100,
604 .help = "Percentage of mixed workload that is writes",
605 .def = "50",
606 },
607 {
608 .name = "nice",
609 .type = FIO_OPT_INT,
610 .off1 = td_var_offset(nice),
611 .help = "Set job CPU nice value",
612 .minval = -19,
613 .maxval = 20,
614 .def = "0",
615 },
616#ifdef FIO_HAVE_IOPRIO
617 {
618 .name = "prio",
619 .type = FIO_OPT_INT,
620 .cb = str_prio_cb,
621 .help = "Set job IO priority value",
622 .minval = 0,
623 .maxval = 7,
624 },
625 {
626 .name = "prioclass",
627 .type = FIO_OPT_INT,
628 .cb = str_prioclass_cb,
629 .help = "Set job IO priority class",
630 .minval = 0,
631 .maxval = 3,
632 },
633#endif
634 {
635 .name = "thinktime",
636 .type = FIO_OPT_INT,
637 .off1 = td_var_offset(thinktime),
638 .help = "Idle time between IO buffers (usec)",
639 .def = "0",
640 },
641 {
642 .name = "thinktime_spin",
643 .type = FIO_OPT_INT,
644 .off1 = td_var_offset(thinktime_spin),
645 .help = "Start think time by spinning this amount (usec)",
646 .def = "0",
647 },
648 {
649 .name = "thinktime_blocks",
650 .type = FIO_OPT_INT,
651 .off1 = td_var_offset(thinktime_blocks),
652 .help = "IO buffer period between 'thinktime'",
653 .def = "1",
654 },
655 {
656 .name = "rate",
657 .type = FIO_OPT_INT,
658 .off1 = td_var_offset(rate),
659 .help = "Set bandwidth rate",
660 },
661 {
662 .name = "ratemin",
663 .type = FIO_OPT_INT,
664 .off1 = td_var_offset(ratemin),
4e991c23
JA
665 .help = "Job must meet this rate or it will be shutdown",
666 },
667 {
668 .name = "rate_iops",
669 .type = FIO_OPT_INT,
670 .off1 = td_var_offset(rate_iops),
671 .help = "Limit IO used to this number of IO operations/sec",
672 },
673 {
674 .name = "rate_iops_min",
675 .type = FIO_OPT_INT,
676 .off1 = td_var_offset(rate_iops_min),
677 .help = "Job must meet this rate or it will be shutdown",
214e1eca
JA
678 },
679 {
680 .name = "ratecycle",
681 .type = FIO_OPT_INT,
682 .off1 = td_var_offset(ratecycle),
683 .help = "Window average for rate limits (msec)",
684 .def = "1000",
685 },
686 {
687 .name = "invalidate",
688 .type = FIO_OPT_BOOL,
689 .off1 = td_var_offset(invalidate_cache),
690 .help = "Invalidate buffer/page cache prior to running job",
691 .def = "1",
692 },
693 {
694 .name = "sync",
695 .type = FIO_OPT_BOOL,
696 .off1 = td_var_offset(sync_io),
697 .help = "Use O_SYNC for buffered writes",
698 .def = "0",
699 },
700 {
701 .name = "bwavgtime",
702 .type = FIO_OPT_INT,
703 .off1 = td_var_offset(bw_avg_time),
704 .help = "Time window over which to calculate bandwidth (msec)",
705 .def = "500",
706 },
707 {
708 .name = "create_serialize",
709 .type = FIO_OPT_BOOL,
710 .off1 = td_var_offset(create_serialize),
711 .help = "Serialize creating of job files",
712 .def = "1",
713 },
714 {
715 .name = "create_fsync",
716 .type = FIO_OPT_BOOL,
717 .off1 = td_var_offset(create_fsync),
718 .help = "Fsync file after creation",
719 .def = "1",
720 },
721 {
722 .name = "cpuload",
723 .type = FIO_OPT_INT,
724 .off1 = td_var_offset(cpuload),
725 .help = "Use this percentage of CPU",
726 },
727 {
728 .name = "cpuchunks",
729 .type = FIO_OPT_INT,
730 .off1 = td_var_offset(cpucycle),
731 .help = "Length of the CPU burn cycles (usecs)",
732 .def = "50000",
733 },
734#ifdef FIO_HAVE_CPU_AFFINITY
735 {
736 .name = "cpumask",
737 .type = FIO_OPT_INT,
738 .cb = str_cpumask_cb,
739 .help = "CPU affinity mask",
740 },
741#endif
742 {
743 .name = "end_fsync",
744 .type = FIO_OPT_BOOL,
745 .off1 = td_var_offset(end_fsync),
746 .help = "Include fsync at the end of job",
747 .def = "0",
748 },
749 {
750 .name = "fsync_on_close",
751 .type = FIO_OPT_BOOL,
752 .off1 = td_var_offset(fsync_on_close),
753 .help = "fsync files on close",
754 .def = "0",
755 },
756 {
757 .name = "unlink",
758 .type = FIO_OPT_BOOL,
759 .off1 = td_var_offset(unlink),
760 .help = "Unlink created files after job has completed",
761 .def = "0",
762 },
763 {
764 .name = "exitall",
765 .type = FIO_OPT_STR_SET,
766 .cb = str_exitall_cb,
767 .help = "Terminate all jobs when one exits",
768 },
769 {
770 .name = "stonewall",
771 .type = FIO_OPT_STR_SET,
772 .off1 = td_var_offset(stonewall),
773 .help = "Insert a hard barrier between this job and previous",
774 },
b3d62a75
JA
775 {
776 .name = "new_group",
777 .type = FIO_OPT_STR_SET,
778 .off1 = td_var_offset(new_group),
779 .help = "Mark the start of a new group (for reporting)",
780 },
214e1eca
JA
781 {
782 .name = "thread",
783 .type = FIO_OPT_STR_SET,
784 .off1 = td_var_offset(use_thread),
785 .help = "Use threads instead of forks",
786 },
787 {
788 .name = "write_bw_log",
789 .type = FIO_OPT_STR_SET,
790 .off1 = td_var_offset(write_bw_log),
791 .help = "Write log of bandwidth during run",
792 },
793 {
794 .name = "write_lat_log",
795 .type = FIO_OPT_STR_SET,
796 .off1 = td_var_offset(write_lat_log),
797 .help = "Write log of latency during run",
798 },
799 {
800 .name = "hugepage-size",
801 .type = FIO_OPT_STR_VAL,
802 .off1 = td_var_offset(hugepage_size),
803 .help = "When using hugepages, specify size of each page",
804 .def = __stringify(FIO_HUGE_PAGE),
805 },
806 {
807 .name = "group_reporting",
808 .type = FIO_OPT_STR_SET,
809 .off1 = td_var_offset(group_reporting),
810 .help = "Do reporting on a per-group basis",
811 },
812 {
813 .name = NULL,
814 },
815};
816
817void fio_options_dup_and_init(struct option *long_options)
818{
819 struct fio_option *o;
820 unsigned int i;
821
822 options_init(options);
823
824 i = 0;
825 while (long_options[i].name)
826 i++;
827
828 o = &options[0];
829 while (o->name) {
830 long_options[i].name = o->name;
831 long_options[i].val = FIO_GETOPT_JOB;
832 if (o->type == FIO_OPT_STR_SET)
833 long_options[i].has_arg = no_argument;
834 else
835 long_options[i].has_arg = required_argument;
836
837 i++;
838 o++;
839 assert(i < FIO_NR_OPTIONS);
840 }
841}
842
843int fio_option_parse(struct thread_data *td, const char *opt)
844{
845 return parse_option(opt, options, td);
846}
847
848int fio_cmd_option_parse(struct thread_data *td, const char *opt, char *val)
849{
850 return parse_cmd_option(opt, val, options, td);
851}
852
853void fio_fill_default_options(struct thread_data *td)
854{
855 fill_default_options(td, options);
856}
857
858int fio_show_option_help(const char *opt)
859{
860 return show_cmd_help(options, opt);
861}