options.c revision b463e9363b826d5ba4f16e0115a26f24b77078f4
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_data *td, 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	td->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 == td->o.bssplit_nr[ddir]) {
88			td->o.bssplit_nr[ddir] <<= 1;
89			bssplit = realloc(bssplit, td->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, td)) {
106			log_err("fio: bssplit conversion failed\n");
107			free(td->o.bssplit);
108			return 1;
109		}
110
111		if (val > max_bs)
112			max_bs = val;
113		if (val < min_bs)
114			min_bs = val;
115
116		bssplit[i].bs = val;
117		bssplit[i].perc = perc;
118		i++;
119	}
120
121	td->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 < td->o.bssplit_nr[ddir]; i++) {
128		struct bssplit *bsp = &bssplit[i];
129
130		if (bsp->perc == (unsigned char) -1)
131			perc_missing++;
132		else
133			perc += bsp->perc;
134	}
135
136	if (perc > 100) {
137		log_err("fio: bssplit percentages add to more than 100%%\n");
138		free(bssplit);
139		return 1;
140	}
141	/*
142	 * If values didn't have a percentage set, divide the remains between
143	 * them.
144	 */
145	if (perc_missing) {
146		for (i = 0; i < td->o.bssplit_nr[ddir]; i++) {
147			struct bssplit *bsp = &bssplit[i];
148
149			if (bsp->perc == (unsigned char) -1)
150				bsp->perc = (100 - perc) / perc_missing;
151		}
152	}
153
154	td->o.min_bs[ddir] = min_bs;
155	td->o.max_bs[ddir] = max_bs;
156
157	/*
158	 * now sort based on percentages, for ease of lookup
159	 */
160	qsort(bssplit, td->o.bssplit_nr[ddir], sizeof(struct bssplit), bs_cmp);
161	td->o.bssplit[ddir] = bssplit;
162	return 0;
163
164}
165
166static int str_bssplit_cb(void *data, const char *input)
167{
168	struct thread_data *td = data;
169	char *str, *p, *odir;
170	int ret = 0;
171
172	p = str = strdup(input);
173
174	strip_blank_front(&str);
175	strip_blank_end(str);
176
177	odir = strchr(str, ',');
178	if (odir) {
179		ret = bssplit_ddir(td, DDIR_WRITE, odir + 1);
180		if (!ret) {
181			*odir = '\0';
182			ret = bssplit_ddir(td, DDIR_READ, str);
183		}
184	} else {
185		char *op;
186
187		op = strdup(str);
188
189		ret = bssplit_ddir(td, DDIR_READ, str);
190		if (!ret)
191			ret = bssplit_ddir(td, DDIR_WRITE, op);
192
193		free(op);
194	}
195
196	free(p);
197	return ret;
198}
199
200static int str_rw_cb(void *data, const char *str)
201{
202	struct thread_data *td = data;
203	char *nr = get_opt_postfix(str);
204
205	td->o.ddir_seq_nr = 1;
206	if (nr) {
207		td->o.ddir_seq_nr = atoi(nr);
208		free(nr);
209	}
210
211	return 0;
212}
213
214static int str_mem_cb(void *data, const char *mem)
215{
216	struct thread_data *td = data;
217
218	if (td->o.mem_type == MEM_MMAPHUGE || td->o.mem_type == MEM_MMAP) {
219		td->mmapfile = get_opt_postfix(mem);
220		if (td->o.mem_type == MEM_MMAPHUGE && !td->mmapfile) {
221			log_err("fio: mmaphuge:/path/to/file\n");
222			return 1;
223		}
224	}
225
226	return 0;
227}
228
229static int str_verify_cb(void *data, const char *mem)
230{
231	struct thread_data *td = data;
232
233	if (td->o.verify != VERIFY_CRC32C_INTEL)
234		return 0;
235
236	if (!crc32c_intel_works()) {
237		log_info("fio: System does not support hw accelerated crc32c. Falling back to sw crc32c.\n");
238		td->o.verify = VERIFY_CRC32C;
239	}
240
241	return 0;
242}
243
244static int fio_clock_source_cb(void *data, const char *str)
245{
246	struct thread_data *td = data;
247
248	fio_clock_source = td->o.clocksource;
249	fio_time_init();
250	return 0;
251}
252
253static int str_lockmem_cb(void fio_unused *data, unsigned long long *val)
254{
255	mlock_size = *val;
256	return 0;
257}
258
259static int str_rwmix_read_cb(void *data, unsigned long long *val)
260{
261	struct thread_data *td = data;
262
263	td->o.rwmix[DDIR_READ] = *val;
264	td->o.rwmix[DDIR_WRITE] = 100 - *val;
265	return 0;
266}
267
268static int str_rwmix_write_cb(void *data, unsigned long long *val)
269{
270	struct thread_data *td = data;
271
272	td->o.rwmix[DDIR_WRITE] = *val;
273	td->o.rwmix[DDIR_READ] = 100 - *val;
274	return 0;
275}
276
277#ifdef FIO_HAVE_IOPRIO
278static int str_prioclass_cb(void *data, unsigned long long *val)
279{
280	struct thread_data *td = data;
281	unsigned short mask;
282
283	/*
284	 * mask off old class bits, str_prio_cb() may have set a default class
285	 */
286	mask = (1 << IOPRIO_CLASS_SHIFT) - 1;
287	td->ioprio &= mask;
288
289	td->ioprio |= *val << IOPRIO_CLASS_SHIFT;
290	td->ioprio_set = 1;
291	return 0;
292}
293
294static int str_prio_cb(void *data, unsigned long long *val)
295{
296	struct thread_data *td = data;
297
298	td->ioprio |= *val;
299
300	/*
301	 * If no class is set, assume BE
302	 */
303	if ((td->ioprio >> IOPRIO_CLASS_SHIFT) == 0)
304		td->ioprio |= IOPRIO_CLASS_BE << IOPRIO_CLASS_SHIFT;
305
306	td->ioprio_set = 1;
307	return 0;
308}
309#endif
310
311static int str_exitall_cb(void)
312{
313	exitall_on_terminate = 1;
314	return 0;
315}
316
317#ifdef FIO_HAVE_CPU_AFFINITY
318static int str_cpumask_cb(void *data, unsigned long long *val)
319{
320	struct thread_data *td = data;
321	unsigned int i;
322	long max_cpu;
323	int ret;
324
325	ret = fio_cpuset_init(&td->o.cpumask);
326	if (ret < 0) {
327		log_err("fio: cpuset_init failed\n");
328		td_verror(td, ret, "fio_cpuset_init");
329		return 1;
330	}
331
332	max_cpu = sysconf(_SC_NPROCESSORS_ONLN);
333
334	for (i = 0; i < sizeof(int) * 8; i++) {
335		if ((1 << i) & *val) {
336			if (i > max_cpu) {
337				log_err("fio: CPU %d too large (max=%ld)\n", i,
338								max_cpu);
339				return 1;
340			}
341			dprint(FD_PARSE, "set cpu allowed %d\n", i);
342			fio_cpu_set(&td->o.cpumask, i);
343		}
344	}
345
346	td->o.cpumask_set = 1;
347	return 0;
348}
349
350static int set_cpus_allowed(struct thread_data *td, os_cpu_mask_t *mask,
351			    const char *input)
352{
353	char *cpu, *str, *p;
354	long max_cpu;
355	int ret = 0;
356
357	ret = fio_cpuset_init(mask);
358	if (ret < 0) {
359		log_err("fio: cpuset_init failed\n");
360		td_verror(td, ret, "fio_cpuset_init");
361		return 1;
362	}
363
364	p = str = strdup(input);
365
366	strip_blank_front(&str);
367	strip_blank_end(str);
368
369	max_cpu = sysconf(_SC_NPROCESSORS_ONLN);
370
371	while ((cpu = strsep(&str, ",")) != NULL) {
372		char *str2, *cpu2;
373		int icpu, icpu2;
374
375		if (!strlen(cpu))
376			break;
377
378		str2 = cpu;
379		icpu2 = -1;
380		while ((cpu2 = strsep(&str2, "-")) != NULL) {
381			if (!strlen(cpu2))
382				break;
383
384			icpu2 = atoi(cpu2);
385		}
386
387		icpu = atoi(cpu);
388		if (icpu2 == -1)
389			icpu2 = icpu;
390		while (icpu <= icpu2) {
391			if (icpu >= FIO_MAX_CPUS) {
392				log_err("fio: your OS only supports up to"
393					" %d CPUs\n", (int) FIO_MAX_CPUS);
394				ret = 1;
395				break;
396			}
397			if (icpu > max_cpu) {
398				log_err("fio: CPU %d too large (max=%ld)\n",
399							icpu, max_cpu);
400				ret = 1;
401				break;
402			}
403
404			dprint(FD_PARSE, "set cpu allowed %d\n", icpu);
405			fio_cpu_set(mask, icpu);
406			icpu++;
407		}
408		if (ret)
409			break;
410	}
411
412	free(p);
413	if (!ret)
414		td->o.cpumask_set = 1;
415	return ret;
416}
417
418static int str_cpus_allowed_cb(void *data, const char *input)
419{
420	struct thread_data *td = data;
421	int ret;
422
423	ret = set_cpus_allowed(td, &td->o.cpumask, input);
424	if (!ret)
425		td->o.cpumask_set = 1;
426
427	return ret;
428}
429
430static int str_verify_cpus_allowed_cb(void *data, const char *input)
431{
432	struct thread_data *td = data;
433	int ret;
434
435	ret = set_cpus_allowed(td, &td->o.verify_cpumask, input);
436	if (!ret)
437		td->o.verify_cpumask_set = 1;
438
439	return ret;
440}
441#endif
442
443#ifdef FIO_HAVE_TRIM
444static int str_verify_trim_cb(void *data, unsigned long long *val)
445{
446	struct thread_data *td = data;
447
448	td->o.trim_percentage = *val;
449	return 0;
450}
451#endif
452
453static int str_fst_cb(void *data, const char *str)
454{
455	struct thread_data *td = data;
456	char *nr = get_opt_postfix(str);
457
458	td->file_service_nr = 1;
459	if (nr) {
460		td->file_service_nr = atoi(nr);
461		free(nr);
462	}
463
464	return 0;
465}
466
467#ifdef FIO_HAVE_SYNC_FILE_RANGE
468static int str_sfr_cb(void *data, const char *str)
469{
470	struct thread_data *td = data;
471	char *nr = get_opt_postfix(str);
472
473	td->sync_file_range_nr = 1;
474	if (nr) {
475		td->sync_file_range_nr = atoi(nr);
476		free(nr);
477	}
478
479	return 0;
480}
481#endif
482
483static int check_dir(struct thread_data *td, char *fname)
484{
485	char file[PATH_MAX], *dir;
486	int elen = 0;
487
488	if (td->o.directory) {
489		strcpy(file, td->o.directory);
490		strcat(file, "/");
491		elen = strlen(file);
492	}
493
494	sprintf(file + elen, "%s", fname);
495	dir = dirname(file);
496
497#if 0
498	{
499	struct stat sb;
500	/*
501	 * We can't do this on FIO_DISKLESSIO engines. The engine isn't loaded
502	 * yet, so we can't do this check right here...
503	 */
504	if (lstat(dir, &sb) < 0) {
505		int ret = errno;
506
507		log_err("fio: %s is not a directory\n", dir);
508		td_verror(td, ret, "lstat");
509		return 1;
510	}
511
512	if (!S_ISDIR(sb.st_mode)) {
513		log_err("fio: %s is not a directory\n", dir);
514		return 1;
515	}
516	}
517#endif
518
519	return 0;
520}
521
522/*
523 * Return next file in the string. Files are separated with ':'. If the ':'
524 * is escaped with a '\', then that ':' is part of the filename and does not
525 * indicate a new file.
526 */
527static char *get_next_file_name(char **ptr)
528{
529	char *str = *ptr;
530	char *p, *start;
531
532	if (!str || !strlen(str))
533		return NULL;
534
535	start = str;
536	do {
537		/*
538		 * No colon, we are done
539		 */
540		p = strchr(str, ':');
541		if (!p) {
542			*ptr = NULL;
543			break;
544		}
545
546		/*
547		 * We got a colon, but it's the first character. Skip and
548		 * continue
549		 */
550		if (p == start) {
551			str = ++start;
552			continue;
553		}
554
555		if (*(p - 1) != '\\') {
556			*p = '\0';
557			*ptr = p + 1;
558			break;
559		}
560
561		memmove(p - 1, p, strlen(p) + 1);
562		str = p;
563	} while (1);
564
565	return start;
566}
567
568static int str_filename_cb(void *data, const char *input)
569{
570	struct thread_data *td = data;
571	char *fname, *str, *p;
572
573	p = str = strdup(input);
574
575	strip_blank_front(&str);
576	strip_blank_end(str);
577
578	if (!td->files_index)
579		td->o.nr_files = 0;
580
581	while ((fname = get_next_file_name(&str)) != NULL) {
582		if (!strlen(fname))
583			break;
584		if (check_dir(td, fname)) {
585			free(p);
586			return 1;
587		}
588		add_file(td, fname);
589		td->o.nr_files++;
590	}
591
592	free(p);
593	return 0;
594}
595
596static int str_directory_cb(void *data, const char fio_unused *str)
597{
598	struct thread_data *td = data;
599	struct stat sb;
600
601	if (lstat(td->o.directory, &sb) < 0) {
602		int ret = errno;
603
604		log_err("fio: %s is not a directory\n", td->o.directory);
605		td_verror(td, ret, "lstat");
606		return 1;
607	}
608	if (!S_ISDIR(sb.st_mode)) {
609		log_err("fio: %s is not a directory\n", td->o.directory);
610		return 1;
611	}
612
613	return 0;
614}
615
616static int str_opendir_cb(void *data, const char fio_unused *str)
617{
618	struct thread_data *td = data;
619
620	if (!td->files_index)
621		td->o.nr_files = 0;
622
623	return add_dir_files(td, td->o.opendir);
624}
625
626static int str_verify_offset_cb(void *data, unsigned long long *off)
627{
628	struct thread_data *td = data;
629
630	if (*off && *off < sizeof(struct verify_header)) {
631		log_err("fio: verify_offset too small\n");
632		return 1;
633	}
634
635	td->o.verify_offset = *off;
636	return 0;
637}
638
639static int str_verify_pattern_cb(void *data, const char *input)
640{
641	struct thread_data *td = data;
642	long off;
643	int i = 0, j = 0, len, k, base = 10;
644	char* loc1, * loc2;
645
646	loc1 = strstr(input, "0x");
647	loc2 = strstr(input, "0X");
648	if (loc1 || loc2)
649		base = 16;
650	off = strtol(input, NULL, base);
651	if (off != LONG_MAX || errno != ERANGE) {
652		while (off) {
653			td->o.verify_pattern[i] = off & 0xff;
654			off >>= 8;
655			i++;
656		}
657	} else {
658		len = strlen(input);
659		k = len - 1;
660		if (base == 16) {
661			if (loc1)
662				j = loc1 - input + 2;
663			else
664				j = loc2 - input + 2;
665		} else
666			return 1;
667		if (len - j < MAX_PATTERN_SIZE * 2) {
668			while (k >= j) {
669				off = converthexchartoint(input[k--]);
670				if (k >= j)
671					off += (converthexchartoint(input[k--])
672						* 16);
673				td->o.verify_pattern[i++] = (char) off;
674			}
675		}
676	}
677	td->o.verify_pattern_bytes = i;
678	return 0;
679}
680
681static int str_lockfile_cb(void *data, const char *str)
682{
683	struct thread_data *td = data;
684	char *nr = get_opt_postfix(str);
685
686	td->o.lockfile_batch = 1;
687	if (nr) {
688		td->o.lockfile_batch = atoi(nr);
689		free(nr);
690	}
691
692	return 0;
693}
694
695static int str_write_bw_log_cb(void *data, const char *str)
696{
697	struct thread_data *td = data;
698
699	if (str)
700		td->o.bw_log_file = strdup(str);
701
702	td->o.write_bw_log = 1;
703	return 0;
704}
705
706static int str_write_lat_log_cb(void *data, const char *str)
707{
708	struct thread_data *td = data;
709
710	if (str)
711		td->o.lat_log_file = strdup(str);
712
713	td->o.write_lat_log = 1;
714	return 0;
715}
716
717static int str_gtod_reduce_cb(void *data, int *il)
718{
719	struct thread_data *td = data;
720	int val = *il;
721
722	td->o.disable_lat = !!val;
723	td->o.disable_clat = !!val;
724	td->o.disable_slat = !!val;
725	td->o.disable_bw = !!val;
726	if (val)
727		td->tv_cache_mask = 63;
728
729	return 0;
730}
731
732static int str_gtod_cpu_cb(void *data, long long *il)
733{
734	struct thread_data *td = data;
735	int val = *il;
736
737	td->o.gtod_cpu = val;
738	td->o.gtod_offload = 1;
739	return 0;
740}
741
742static int rw_verify(struct fio_option *o, void *data)
743{
744	struct thread_data *td = data;
745
746	if (read_only && td_write(td)) {
747		log_err("fio: job <%s> has write bit set, but fio is in"
748			" read-only mode\n", td->o.name);
749		return 1;
750	}
751
752	return 0;
753}
754
755static int gtod_cpu_verify(struct fio_option *o, void *data)
756{
757#ifndef FIO_HAVE_CPU_AFFINITY
758	struct thread_data *td = data;
759
760	if (td->o.gtod_cpu) {
761		log_err("fio: platform must support CPU affinity for"
762			"gettimeofday() offloading\n");
763		return 1;
764	}
765#endif
766
767	return 0;
768}
769
770static int kb_base_verify(struct fio_option *o, void *data)
771{
772	struct thread_data *td = data;
773
774	if (td->o.kb_base != 1024 && td->o.kb_base != 1000) {
775		log_err("fio: kb_base set to nonsensical value: %u\n",
776				td->o.kb_base);
777		return 1;
778	}
779
780	return 0;
781}
782
783#define __stringify_1(x)	#x
784#define __stringify(x)		__stringify_1(x)
785
786/*
787 * Map of job/command line options
788 */
789static struct fio_option options[FIO_MAX_OPTS] = {
790	{
791		.name	= "description",
792		.type	= FIO_OPT_STR_STORE,
793		.off1	= td_var_offset(description),
794		.help	= "Text job description",
795	},
796	{
797		.name	= "name",
798		.type	= FIO_OPT_STR_STORE,
799		.off1	= td_var_offset(name),
800		.help	= "Name of this job",
801	},
802	{
803		.name	= "directory",
804		.type	= FIO_OPT_STR_STORE,
805		.off1	= td_var_offset(directory),
806		.cb	= str_directory_cb,
807		.help	= "Directory to store files in",
808	},
809	{
810		.name	= "filename",
811		.type	= FIO_OPT_STR_STORE,
812		.off1	= td_var_offset(filename),
813		.cb	= str_filename_cb,
814		.prio	= -1, /* must come after "directory" */
815		.help	= "File(s) to use for the workload",
816	},
817	{
818		.name	= "kb_base",
819		.type	= FIO_OPT_INT,
820		.off1	= td_var_offset(kb_base),
821		.verify	= kb_base_verify,
822		.prio	= 1,
823		.def	= "1024",
824		.help	= "How many bytes per KB for reporting (1000 or 1024)",
825	},
826	{
827		.name	= "lockfile",
828		.type	= FIO_OPT_STR,
829		.cb	= str_lockfile_cb,
830		.off1	= td_var_offset(file_lock_mode),
831		.help	= "Lock file when doing IO to it",
832		.parent	= "filename",
833		.def	= "none",
834		.posval = {
835			  { .ival = "none",
836			    .oval = FILE_LOCK_NONE,
837			    .help = "No file locking",
838			  },
839			  { .ival = "exclusive",
840			    .oval = FILE_LOCK_EXCLUSIVE,
841			    .help = "Exclusive file lock",
842			  },
843			  {
844			    .ival = "readwrite",
845			    .oval = FILE_LOCK_READWRITE,
846			    .help = "Read vs write lock",
847			  },
848		},
849	},
850	{
851		.name	= "opendir",
852		.type	= FIO_OPT_STR_STORE,
853		.off1	= td_var_offset(opendir),
854		.cb	= str_opendir_cb,
855		.help	= "Recursively add files from this directory and down",
856	},
857	{
858		.name	= "rw",
859		.alias	= "readwrite",
860		.type	= FIO_OPT_STR,
861		.cb	= str_rw_cb,
862		.off1	= td_var_offset(td_ddir),
863		.help	= "IO direction",
864		.def	= "read",
865		.verify	= rw_verify,
866		.posval = {
867			  { .ival = "read",
868			    .oval = TD_DDIR_READ,
869			    .help = "Sequential read",
870			  },
871			  { .ival = "write",
872			    .oval = TD_DDIR_WRITE,
873			    .help = "Sequential write",
874			  },
875			  { .ival = "randread",
876			    .oval = TD_DDIR_RANDREAD,
877			    .help = "Random read",
878			  },
879			  { .ival = "randwrite",
880			    .oval = TD_DDIR_RANDWRITE,
881			    .help = "Random write",
882			  },
883			  { .ival = "rw",
884			    .oval = TD_DDIR_RW,
885			    .help = "Sequential read and write mix",
886			  },
887			  { .ival = "randrw",
888			    .oval = TD_DDIR_RANDRW,
889			    .help = "Random read and write mix"
890			  },
891		},
892	},
893	{
894		.name	= "rw_sequencer",
895		.type	= FIO_OPT_STR,
896		.off1	= td_var_offset(rw_seq),
897		.help	= "IO offset generator modifier",
898		.def	= "sequential",
899		.posval = {
900			  { .ival = "sequential",
901			    .oval = RW_SEQ_SEQ,
902			    .help = "Generate sequential offsets",
903			  },
904			  { .ival = "identical",
905			    .oval = RW_SEQ_IDENT,
906			    .help = "Generate identical offsets",
907			  },
908		},
909	},
910
911	{
912		.name	= "ioengine",
913		.type	= FIO_OPT_STR_STORE,
914		.off1	= td_var_offset(ioengine),
915		.help	= "IO engine to use",
916		.def	= "sync",
917		.posval	= {
918			  { .ival = "sync",
919			    .help = "Use read/write",
920			  },
921			  { .ival = "psync",
922			    .help = "Use pread/pwrite",
923			  },
924			  { .ival = "vsync",
925			    .help = "Use readv/writev",
926			  },
927#ifdef FIO_HAVE_LIBAIO
928			  { .ival = "libaio",
929			    .help = "Linux native asynchronous IO",
930			  },
931#endif
932#ifdef FIO_HAVE_POSIXAIO
933			  { .ival = "posixaio",
934			    .help = "POSIX asynchronous IO",
935			  },
936#endif
937#ifdef FIO_HAVE_SOLARISAIO
938			  { .ival = "solarisaio",
939			    .help = "Solaris native asynchronous IO",
940			  },
941#endif
942#ifdef FIO_HAVE_WINDOWSAIO
943			  { .ival = "windowsaio",
944			  	.help = "Windows native asynchronous IO"
945		  	  },
946			  { .ival = "mmap",
947			    .help = "Memory mapped IO"
948			  },
949#endif
950#ifdef FIO_HAVE_SPLICE
951			  { .ival = "splice",
952			    .help = "splice/vmsplice based IO",
953			  },
954			  { .ival = "netsplice",
955			    .help = "splice/vmsplice to/from the network",
956			  },
957#endif
958#ifdef FIO_HAVE_SGIO
959			  { .ival = "sg",
960			    .help = "SCSI generic v3 IO",
961			  },
962#endif
963			  { .ival = "null",
964			    .help = "Testing engine (no data transfer)",
965			  },
966			  { .ival = "net",
967			    .help = "Network IO",
968			  },
969#ifdef FIO_HAVE_SYSLET
970			  { .ival = "syslet-rw",
971			    .help = "syslet enabled async pread/pwrite IO",
972			  },
973#endif
974			  { .ival = "cpuio",
975			    .help = "CPU cycle burner engine",
976			  },
977#ifdef FIO_HAVE_GUASI
978			  { .ival = "guasi",
979			    .help = "GUASI IO engine",
980			  },
981#endif
982#ifdef FIO_HAVE_BINJECT
983			  { .ival = "binject",
984			    .help = "binject direct inject block engine",
985			  },
986#endif
987			  { .ival = "external",
988			    .help = "Load external engine (append name)",
989			  },
990		},
991	},
992	{
993		.name	= "iodepth",
994		.type	= FIO_OPT_INT,
995		.off1	= td_var_offset(iodepth),
996		.help	= "Number of IO buffers to keep in flight",
997		.minval = 1,
998		.def	= "1",
999	},
1000	{
1001		.name	= "iodepth_batch",
1002		.alias	= "iodepth_batch_submit",
1003		.type	= FIO_OPT_INT,
1004		.off1	= td_var_offset(iodepth_batch),
1005		.help	= "Number of IO buffers to submit in one go",
1006		.parent	= "iodepth",
1007		.minval	= 1,
1008		.def	= "1",
1009	},
1010	{
1011		.name	= "iodepth_batch_complete",
1012		.type	= FIO_OPT_INT,
1013		.off1	= td_var_offset(iodepth_batch_complete),
1014		.help	= "Number of IO buffers to retrieve in one go",
1015		.parent	= "iodepth",
1016		.minval	= 0,
1017		.def	= "1",
1018	},
1019	{
1020		.name	= "iodepth_low",
1021		.type	= FIO_OPT_INT,
1022		.off1	= td_var_offset(iodepth_low),
1023		.help	= "Low water mark for queuing depth",
1024		.parent	= "iodepth",
1025	},
1026	{
1027		.name	= "size",
1028		.type	= FIO_OPT_STR_VAL,
1029		.off1	= td_var_offset(size),
1030		.minval = 1,
1031		.help	= "Total size of device or files",
1032	},
1033	{
1034		.name	= "fill_device",
1035		.type	= FIO_OPT_BOOL,
1036		.off1	= td_var_offset(fill_device),
1037		.help	= "Write until an ENOSPC error occurs",
1038		.def	= "0",
1039	},
1040	{
1041		.name	= "filesize",
1042		.type	= FIO_OPT_STR_VAL,
1043		.off1	= td_var_offset(file_size_low),
1044		.off2	= td_var_offset(file_size_high),
1045		.minval = 1,
1046		.help	= "Size of individual files",
1047	},
1048	{
1049		.name	= "offset",
1050		.alias	= "fileoffset",
1051		.type	= FIO_OPT_STR_VAL,
1052		.off1	= td_var_offset(start_offset),
1053		.help	= "Start IO from this offset",
1054		.def	= "0",
1055	},
1056	{
1057		.name	= "bs",
1058		.alias	= "blocksize",
1059		.type	= FIO_OPT_INT,
1060		.off1	= td_var_offset(bs[DDIR_READ]),
1061		.off2	= td_var_offset(bs[DDIR_WRITE]),
1062		.minval = 1,
1063		.help	= "Block size unit",
1064		.def	= "4k",
1065		.parent = "rw",
1066	},
1067	{
1068		.name	= "ba",
1069		.alias	= "blockalign",
1070		.type	= FIO_OPT_INT,
1071		.off1	= td_var_offset(ba[DDIR_READ]),
1072		.off2	= td_var_offset(ba[DDIR_WRITE]),
1073		.minval	= 1,
1074		.help	= "IO block offset alignment",
1075		.parent	= "rw",
1076	},
1077	{
1078		.name	= "bsrange",
1079		.alias	= "blocksize_range",
1080		.type	= FIO_OPT_RANGE,
1081		.off1	= td_var_offset(min_bs[DDIR_READ]),
1082		.off2	= td_var_offset(max_bs[DDIR_READ]),
1083		.off3	= td_var_offset(min_bs[DDIR_WRITE]),
1084		.off4	= td_var_offset(max_bs[DDIR_WRITE]),
1085		.minval = 1,
1086		.help	= "Set block size range (in more detail than bs)",
1087		.parent = "rw",
1088	},
1089	{
1090		.name	= "bssplit",
1091		.type	= FIO_OPT_STR,
1092		.cb	= str_bssplit_cb,
1093		.help	= "Set a specific mix of block sizes",
1094		.parent	= "rw",
1095	},
1096	{
1097		.name	= "bs_unaligned",
1098		.alias	= "blocksize_unaligned",
1099		.type	= FIO_OPT_STR_SET,
1100		.off1	= td_var_offset(bs_unaligned),
1101		.help	= "Don't sector align IO buffer sizes",
1102		.parent = "rw",
1103	},
1104	{
1105		.name	= "randrepeat",
1106		.type	= FIO_OPT_BOOL,
1107		.off1	= td_var_offset(rand_repeatable),
1108		.help	= "Use repeatable random IO pattern",
1109		.def	= "1",
1110		.parent = "rw",
1111	},
1112	{
1113		.name	= "norandommap",
1114		.type	= FIO_OPT_STR_SET,
1115		.off1	= td_var_offset(norandommap),
1116		.help	= "Accept potential duplicate random blocks",
1117		.parent = "rw",
1118	},
1119	{
1120		.name	= "softrandommap",
1121		.type	= FIO_OPT_BOOL,
1122		.off1	= td_var_offset(softrandommap),
1123		.help	= "Set norandommap if randommap allocation fails",
1124		.parent	= "norandommap",
1125		.def	= "0",
1126	},
1127	{
1128		.name	= "nrfiles",
1129		.alias	= "nr_files",
1130		.type	= FIO_OPT_INT,
1131		.off1	= td_var_offset(nr_files),
1132		.help	= "Split job workload between this number of files",
1133		.def	= "1",
1134	},
1135	{
1136		.name	= "openfiles",
1137		.type	= FIO_OPT_INT,
1138		.off1	= td_var_offset(open_files),
1139		.help	= "Number of files to keep open at the same time",
1140	},
1141	{
1142		.name	= "file_service_type",
1143		.type	= FIO_OPT_STR,
1144		.cb	= str_fst_cb,
1145		.off1	= td_var_offset(file_service_type),
1146		.help	= "How to select which file to service next",
1147		.def	= "roundrobin",
1148		.posval	= {
1149			  { .ival = "random",
1150			    .oval = FIO_FSERVICE_RANDOM,
1151			    .help = "Choose a file at random",
1152			  },
1153			  { .ival = "roundrobin",
1154			    .oval = FIO_FSERVICE_RR,
1155			    .help = "Round robin select files",
1156			  },
1157			  { .ival = "sequential",
1158			    .oval = FIO_FSERVICE_SEQ,
1159			    .help = "Finish one file before moving to the next",
1160			  },
1161		},
1162		.parent = "nrfiles",
1163	},
1164#ifdef FIO_HAVE_FALLOCATE
1165	{
1166		.name	= "fallocate",
1167		.type	= FIO_OPT_BOOL,
1168		.off1	= td_var_offset(fallocate),
1169		.help	= "Use fallocate() when laying out files",
1170		.def	= "1",
1171	},
1172#endif
1173	{
1174		.name	= "fadvise_hint",
1175		.type	= FIO_OPT_BOOL,
1176		.off1	= td_var_offset(fadvise_hint),
1177		.help	= "Use fadvise() to advise the kernel on IO pattern",
1178		.def	= "1",
1179	},
1180	{
1181		.name	= "fsync",
1182		.type	= FIO_OPT_INT,
1183		.off1	= td_var_offset(fsync_blocks),
1184		.help	= "Issue fsync for writes every given number of blocks",
1185		.def	= "0",
1186	},
1187	{
1188		.name	= "fdatasync",
1189		.type	= FIO_OPT_INT,
1190		.off1	= td_var_offset(fdatasync_blocks),
1191		.help	= "Issue fdatasync for writes every given number of blocks",
1192		.def	= "0",
1193	},
1194	{
1195		.name	= "write_barrier",
1196		.type	= FIO_OPT_INT,
1197		.off1	= td_var_offset(barrier_blocks),
1198		.help	= "Make every Nth write a barrier write",
1199		.def	= "0",
1200	},
1201#ifdef FIO_HAVE_SYNC_FILE_RANGE
1202	{
1203		.name	= "sync_file_range",
1204		.posval	= {
1205			  { .ival = "wait_before",
1206			    .oval = SYNC_FILE_RANGE_WAIT_BEFORE,
1207			    .help = "SYNC_FILE_RANGE_WAIT_BEFORE",
1208			    .or	  = 1,
1209			  },
1210			  { .ival = "write",
1211			    .oval = SYNC_FILE_RANGE_WRITE,
1212			    .help = "SYNC_FILE_RANGE_WRITE",
1213			    .or	  = 1,
1214			  },
1215			  {
1216			    .ival = "wait_after",
1217			    .oval = SYNC_FILE_RANGE_WAIT_AFTER,
1218			    .help = "SYNC_FILE_RANGE_WAIT_AFTER",
1219			    .or	  = 1,
1220			  },
1221		},
1222		.type	= FIO_OPT_STR_MULTI,
1223		.cb	= str_sfr_cb,
1224		.off1	= td_var_offset(sync_file_range),
1225		.help	= "Use sync_file_range()",
1226	},
1227#endif
1228	{
1229		.name	= "direct",
1230		.type	= FIO_OPT_BOOL,
1231		.off1	= td_var_offset(odirect),
1232		.help	= "Use O_DIRECT IO (negates buffered)",
1233		.def	= "0",
1234	},
1235	{
1236		.name	= "buffered",
1237		.type	= FIO_OPT_BOOL,
1238		.off1	= td_var_offset(odirect),
1239		.neg	= 1,
1240		.help	= "Use buffered IO (negates direct)",
1241		.def	= "1",
1242	},
1243	{
1244		.name	= "overwrite",
1245		.type	= FIO_OPT_BOOL,
1246		.off1	= td_var_offset(overwrite),
1247		.help	= "When writing, set whether to overwrite current data",
1248		.def	= "0",
1249	},
1250	{
1251		.name	= "loops",
1252		.type	= FIO_OPT_INT,
1253		.off1	= td_var_offset(loops),
1254		.help	= "Number of times to run the job",
1255		.def	= "1",
1256	},
1257	{
1258		.name	= "numjobs",
1259		.type	= FIO_OPT_INT,
1260		.off1	= td_var_offset(numjobs),
1261		.help	= "Duplicate this job this many times",
1262		.def	= "1",
1263	},
1264	{
1265		.name	= "startdelay",
1266		.type	= FIO_OPT_STR_VAL_TIME,
1267		.off1	= td_var_offset(start_delay),
1268		.help	= "Only start job when this period has passed",
1269		.def	= "0",
1270	},
1271	{
1272		.name	= "runtime",
1273		.alias	= "timeout",
1274		.type	= FIO_OPT_STR_VAL_TIME,
1275		.off1	= td_var_offset(timeout),
1276		.help	= "Stop workload when this amount of time has passed",
1277		.def	= "0",
1278	},
1279	{
1280		.name	= "time_based",
1281		.type	= FIO_OPT_STR_SET,
1282		.off1	= td_var_offset(time_based),
1283		.help	= "Keep running until runtime/timeout is met",
1284	},
1285	{
1286		.name	= "ramp_time",
1287		.type	= FIO_OPT_STR_VAL_TIME,
1288		.off1	= td_var_offset(ramp_time),
1289		.help	= "Ramp up time before measuring performance",
1290	},
1291	{
1292		.name	= "clocksource",
1293		.type	= FIO_OPT_STR,
1294		.cb	= fio_clock_source_cb,
1295		.off1	= td_var_offset(clocksource),
1296		.help	= "What type of timing source to use",
1297		.posval	= {
1298			  { .ival = "gettimeofday",
1299			    .oval = CS_GTOD,
1300			    .help = "Use gettimeofday(2) for timing",
1301			  },
1302			  { .ival = "clock_gettime",
1303			    .oval = CS_CGETTIME,
1304			    .help = "Use clock_gettime(2) for timing",
1305			  },
1306#ifdef ARCH_HAVE_CPU_CLOCK
1307			  { .ival = "cpu",
1308			    .oval = CS_CPUCLOCK,
1309			    .help = "Use CPU private clock",
1310			  },
1311#endif
1312		},
1313	},
1314	{
1315		.name	= "mem",
1316		.alias	= "iomem",
1317		.type	= FIO_OPT_STR,
1318		.cb	= str_mem_cb,
1319		.off1	= td_var_offset(mem_type),
1320		.help	= "Backing type for IO buffers",
1321		.def	= "malloc",
1322		.posval	= {
1323			  { .ival = "malloc",
1324			    .oval = MEM_MALLOC,
1325			    .help = "Use malloc(3) for IO buffers",
1326			  },
1327			  { .ival = "shm",
1328			    .oval = MEM_SHM,
1329			    .help = "Use shared memory segments for IO buffers",
1330			  },
1331#ifdef FIO_HAVE_HUGETLB
1332			  { .ival = "shmhuge",
1333			    .oval = MEM_SHMHUGE,
1334			    .help = "Like shm, but use huge pages",
1335			  },
1336#endif
1337			  { .ival = "mmap",
1338			    .oval = MEM_MMAP,
1339			    .help = "Use mmap(2) (file or anon) for IO buffers",
1340			  },
1341#ifdef FIO_HAVE_HUGETLB
1342			  { .ival = "mmaphuge",
1343			    .oval = MEM_MMAPHUGE,
1344			    .help = "Like mmap, but use huge pages",
1345			  },
1346#endif
1347		  },
1348	},
1349	{
1350		.name	= "iomem_align",
1351		.alias	= "mem_align",
1352		.type	= FIO_OPT_INT,
1353		.off1	= td_var_offset(mem_align),
1354		.minval	= 0,
1355		.help	= "IO memory buffer offset alignment",
1356		.def	= "0",
1357		.parent	= "iomem",
1358	},
1359	{
1360		.name	= "verify",
1361		.type	= FIO_OPT_STR,
1362		.off1	= td_var_offset(verify),
1363		.help	= "Verify data written",
1364		.cb	= str_verify_cb,
1365		.def	= "0",
1366		.posval = {
1367			  { .ival = "0",
1368			    .oval = VERIFY_NONE,
1369			    .help = "Don't do IO verification",
1370			  },
1371			  { .ival = "md5",
1372			    .oval = VERIFY_MD5,
1373			    .help = "Use md5 checksums for verification",
1374			  },
1375			  { .ival = "crc64",
1376			    .oval = VERIFY_CRC64,
1377			    .help = "Use crc64 checksums for verification",
1378			  },
1379			  { .ival = "crc32",
1380			    .oval = VERIFY_CRC32,
1381			    .help = "Use crc32 checksums for verification",
1382			  },
1383			  { .ival = "crc32c-intel",
1384			    .oval = VERIFY_CRC32C_INTEL,
1385			    .help = "Use hw crc32c checksums for verification",
1386			  },
1387			  { .ival = "crc32c",
1388			    .oval = VERIFY_CRC32C,
1389			    .help = "Use crc32c checksums for verification",
1390			  },
1391			  { .ival = "crc16",
1392			    .oval = VERIFY_CRC16,
1393			    .help = "Use crc16 checksums for verification",
1394			  },
1395			  { .ival = "crc7",
1396			    .oval = VERIFY_CRC7,
1397			    .help = "Use crc7 checksums for verification",
1398			  },
1399			  { .ival = "sha1",
1400			    .oval = VERIFY_SHA1,
1401			    .help = "Use sha1 checksums for verification",
1402			  },
1403			  { .ival = "sha256",
1404			    .oval = VERIFY_SHA256,
1405			    .help = "Use sha256 checksums for verification",
1406			  },
1407			  { .ival = "sha512",
1408			    .oval = VERIFY_SHA512,
1409			    .help = "Use sha512 checksums for verification",
1410			  },
1411			  { .ival = "meta",
1412			    .oval = VERIFY_META,
1413			    .help = "Use io information",
1414			  },
1415			  {
1416			    .ival = "null",
1417			    .oval = VERIFY_NULL,
1418			    .help = "Pretend to verify",
1419			  },
1420		},
1421	},
1422	{
1423		.name	= "do_verify",
1424		.type	= FIO_OPT_BOOL,
1425		.off1	= td_var_offset(do_verify),
1426		.help	= "Run verification stage after write",
1427		.def	= "1",
1428		.parent = "verify",
1429	},
1430	{
1431		.name	= "verifysort",
1432		.type	= FIO_OPT_BOOL,
1433		.off1	= td_var_offset(verifysort),
1434		.help	= "Sort written verify blocks for read back",
1435		.def	= "1",
1436		.parent = "verify",
1437	},
1438	{
1439		.name   = "verify_interval",
1440		.type   = FIO_OPT_INT,
1441		.off1   = td_var_offset(verify_interval),
1442		.minval	= 2 * sizeof(struct verify_header),
1443		.help   = "Store verify buffer header every N bytes",
1444		.parent	= "verify",
1445	},
1446	{
1447		.name	= "verify_offset",
1448		.type	= FIO_OPT_INT,
1449		.help	= "Offset verify header location by N bytes",
1450		.def	= "0",
1451		.cb	= str_verify_offset_cb,
1452		.parent	= "verify",
1453	},
1454	{
1455		.name	= "verify_pattern",
1456		.type	= FIO_OPT_STR,
1457		.cb	= str_verify_pattern_cb,
1458		.help	= "Fill pattern for IO buffers",
1459		.parent	= "verify",
1460	},
1461	{
1462		.name	= "verify_fatal",
1463		.type	= FIO_OPT_BOOL,
1464		.off1	= td_var_offset(verify_fatal),
1465		.def	= "0",
1466		.help	= "Exit on a single verify failure, don't continue",
1467		.parent = "verify",
1468	},
1469	{
1470		.name	= "verify_dump",
1471		.type	= FIO_OPT_BOOL,
1472		.off1	= td_var_offset(verify_dump),
1473		.def	= "1",
1474		.help	= "Dump contents of good and bad blocks on failure",
1475		.parent = "verify",
1476	},
1477	{
1478		.name	= "verify_async",
1479		.type	= FIO_OPT_INT,
1480		.off1	= td_var_offset(verify_async),
1481		.def	= "0",
1482		.help	= "Number of async verifier threads to use",
1483		.parent	= "verify",
1484	},
1485	{
1486		.name	= "verify_backlog",
1487		.type	= FIO_OPT_STR_VAL,
1488		.off1	= td_var_offset(verify_backlog),
1489		.help	= "Verify after this number of blocks are written",
1490		.parent	= "verify",
1491	},
1492	{
1493		.name	= "verify_backlog_batch",
1494		.type	= FIO_OPT_INT,
1495		.off1	= td_var_offset(verify_batch),
1496		.help	= "Verify this number of IO blocks",
1497		.parent	= "verify",
1498	},
1499#ifdef FIO_HAVE_CPU_AFFINITY
1500	{
1501		.name	= "verify_async_cpus",
1502		.type	= FIO_OPT_STR,
1503		.cb	= str_verify_cpus_allowed_cb,
1504		.help	= "Set CPUs allowed for async verify threads",
1505		.parent	= "verify_async",
1506	},
1507#endif
1508#ifdef FIO_HAVE_TRIM
1509	{
1510		.name	= "trim_percentage",
1511		.type	= FIO_OPT_INT,
1512		.cb	= str_verify_trim_cb,
1513		.maxval = 100,
1514		.help	= "Number of verify blocks to discard/trim",
1515		.parent	= "verify",
1516		.def	= "0",
1517	},
1518	{
1519		.name	= "trim_verify_zero",
1520		.type	= FIO_OPT_INT,
1521		.help	= "Verify that trim/discarded blocks are returned as zeroes",
1522		.off1	= td_var_offset(trim_zero),
1523		.parent	= "trim_percentage",
1524		.def	= "1",
1525	},
1526	{
1527		.name	= "trim_backlog",
1528		.type	= FIO_OPT_STR_VAL,
1529		.off1	= td_var_offset(trim_backlog),
1530		.help	= "Trim after this number of blocks are written",
1531		.parent	= "trim_percentage",
1532	},
1533	{
1534		.name	= "trim_backlog_batch",
1535		.type	= FIO_OPT_INT,
1536		.off1	= td_var_offset(trim_batch),
1537		.help	= "Trim this number of IO blocks",
1538		.parent	= "trim_percentage",
1539	},
1540#endif
1541	{
1542		.name	= "write_iolog",
1543		.type	= FIO_OPT_STR_STORE,
1544		.off1	= td_var_offset(write_iolog_file),
1545		.help	= "Store IO pattern to file",
1546	},
1547	{
1548		.name	= "read_iolog",
1549		.type	= FIO_OPT_STR_STORE,
1550		.off1	= td_var_offset(read_iolog_file),
1551		.help	= "Playback IO pattern from file",
1552	},
1553	{
1554		.name	= "replay_no_stall",
1555		.type	= FIO_OPT_INT,
1556		.off1	= td_var_offset(no_stall),
1557		.def	= "0",
1558		.parent	= "read_iolog",
1559		.help	= "Playback IO pattern file as fast as possible without stalls",
1560	},
1561	{
1562		.name	= "replay_redirect",
1563		.type	= FIO_OPT_STR_STORE,
1564		.off1	= td_var_offset(replay_redirect),
1565		.parent	= "read_iolog",
1566		.help	= "Replay all I/O onto this device, regardless of trace device",
1567	},
1568	{
1569		.name	= "exec_prerun",
1570		.type	= FIO_OPT_STR_STORE,
1571		.off1	= td_var_offset(exec_prerun),
1572		.help	= "Execute this file prior to running job",
1573	},
1574	{
1575		.name	= "exec_postrun",
1576		.type	= FIO_OPT_STR_STORE,
1577		.off1	= td_var_offset(exec_postrun),
1578		.help	= "Execute this file after running job",
1579	},
1580#ifdef FIO_HAVE_IOSCHED_SWITCH
1581	{
1582		.name	= "ioscheduler",
1583		.type	= FIO_OPT_STR_STORE,
1584		.off1	= td_var_offset(ioscheduler),
1585		.help	= "Use this IO scheduler on the backing device",
1586	},
1587#endif
1588	{
1589		.name	= "zonesize",
1590		.type	= FIO_OPT_STR_VAL,
1591		.off1	= td_var_offset(zone_size),
1592		.help	= "Give size of an IO zone",
1593		.def	= "0",
1594	},
1595	{
1596		.name	= "zoneskip",
1597		.type	= FIO_OPT_STR_VAL,
1598		.off1	= td_var_offset(zone_skip),
1599		.help	= "Space between IO zones",
1600		.def	= "0",
1601	},
1602	{
1603		.name	= "lockmem",
1604		.type	= FIO_OPT_STR_VAL,
1605		.cb	= str_lockmem_cb,
1606		.help	= "Lock down this amount of memory",
1607		.def	= "0",
1608	},
1609	{
1610		.name	= "rwmixread",
1611		.type	= FIO_OPT_INT,
1612		.cb	= str_rwmix_read_cb,
1613		.maxval	= 100,
1614		.help	= "Percentage of mixed workload that is reads",
1615		.def	= "50",
1616	},
1617	{
1618		.name	= "rwmixwrite",
1619		.type	= FIO_OPT_INT,
1620		.cb	= str_rwmix_write_cb,
1621		.maxval	= 100,
1622		.help	= "Percentage of mixed workload that is writes",
1623		.def	= "50",
1624	},
1625	{
1626		.name	= "rwmixcycle",
1627		.type	= FIO_OPT_DEPRECATED,
1628	},
1629	{
1630		.name	= "nice",
1631		.type	= FIO_OPT_INT,
1632		.off1	= td_var_offset(nice),
1633		.help	= "Set job CPU nice value",
1634		.minval	= -19,
1635		.maxval	= 20,
1636		.def	= "0",
1637	},
1638#ifdef FIO_HAVE_IOPRIO
1639	{
1640		.name	= "prio",
1641		.type	= FIO_OPT_INT,
1642		.cb	= str_prio_cb,
1643		.help	= "Set job IO priority value",
1644		.minval	= 0,
1645		.maxval	= 7,
1646	},
1647	{
1648		.name	= "prioclass",
1649		.type	= FIO_OPT_INT,
1650		.cb	= str_prioclass_cb,
1651		.help	= "Set job IO priority class",
1652		.minval	= 0,
1653		.maxval	= 3,
1654	},
1655#endif
1656	{
1657		.name	= "thinktime",
1658		.type	= FIO_OPT_INT,
1659		.off1	= td_var_offset(thinktime),
1660		.help	= "Idle time between IO buffers (usec)",
1661		.def	= "0",
1662	},
1663	{
1664		.name	= "thinktime_spin",
1665		.type	= FIO_OPT_INT,
1666		.off1	= td_var_offset(thinktime_spin),
1667		.help	= "Start think time by spinning this amount (usec)",
1668		.def	= "0",
1669		.parent	= "thinktime",
1670	},
1671	{
1672		.name	= "thinktime_blocks",
1673		.type	= FIO_OPT_INT,
1674		.off1	= td_var_offset(thinktime_blocks),
1675		.help	= "IO buffer period between 'thinktime'",
1676		.def	= "1",
1677		.parent	= "thinktime",
1678	},
1679	{
1680		.name	= "rate",
1681		.type	= FIO_OPT_INT,
1682		.off1	= td_var_offset(rate[0]),
1683		.off2	= td_var_offset(rate[1]),
1684		.help	= "Set bandwidth rate",
1685	},
1686	{
1687		.name	= "ratemin",
1688		.type	= FIO_OPT_INT,
1689		.off1	= td_var_offset(ratemin[0]),
1690		.off2	= td_var_offset(ratemin[1]),
1691		.help	= "Job must meet this rate or it will be shutdown",
1692		.parent	= "rate",
1693	},
1694	{
1695		.name	= "rate_iops",
1696		.type	= FIO_OPT_INT,
1697		.off1	= td_var_offset(rate_iops[0]),
1698		.off2	= td_var_offset(rate_iops[1]),
1699		.help	= "Limit IO used to this number of IO operations/sec",
1700	},
1701	{
1702		.name	= "rate_iops_min",
1703		.type	= FIO_OPT_INT,
1704		.off1	= td_var_offset(rate_iops_min[0]),
1705		.off2	= td_var_offset(rate_iops_min[1]),
1706		.help	= "Job must meet this rate or it will be shut down",
1707		.parent	= "rate_iops",
1708	},
1709	{
1710		.name	= "ratecycle",
1711		.type	= FIO_OPT_INT,
1712		.off1	= td_var_offset(ratecycle),
1713		.help	= "Window average for rate limits (msec)",
1714		.def	= "1000",
1715		.parent = "rate",
1716	},
1717	{
1718		.name	= "invalidate",
1719		.type	= FIO_OPT_BOOL,
1720		.off1	= td_var_offset(invalidate_cache),
1721		.help	= "Invalidate buffer/page cache prior to running job",
1722		.def	= "1",
1723	},
1724	{
1725		.name	= "sync",
1726		.type	= FIO_OPT_BOOL,
1727		.off1	= td_var_offset(sync_io),
1728		.help	= "Use O_SYNC for buffered writes",
1729		.def	= "0",
1730		.parent = "buffered",
1731	},
1732	{
1733		.name	= "bwavgtime",
1734		.type	= FIO_OPT_INT,
1735		.off1	= td_var_offset(bw_avg_time),
1736		.help	= "Time window over which to calculate bandwidth"
1737			  " (msec)",
1738		.def	= "500",
1739	},
1740	{
1741		.name	= "create_serialize",
1742		.type	= FIO_OPT_BOOL,
1743		.off1	= td_var_offset(create_serialize),
1744		.help	= "Serialize creating of job files",
1745		.def	= "1",
1746	},
1747	{
1748		.name	= "create_fsync",
1749		.type	= FIO_OPT_BOOL,
1750		.off1	= td_var_offset(create_fsync),
1751		.help	= "fsync file after creation",
1752		.def	= "1",
1753	},
1754	{
1755		.name	= "create_on_open",
1756		.type	= FIO_OPT_BOOL,
1757		.off1	= td_var_offset(create_on_open),
1758		.help	= "Create files when they are opened for IO",
1759		.def	= "0",
1760	},
1761	{
1762		.name	= "pre_read",
1763		.type	= FIO_OPT_BOOL,
1764		.off1	= td_var_offset(pre_read),
1765		.help	= "Pre-read files before starting official testing",
1766		.def	= "0",
1767	},
1768	{
1769		.name	= "cpuload",
1770		.type	= FIO_OPT_INT,
1771		.off1	= td_var_offset(cpuload),
1772		.help	= "Use this percentage of CPU",
1773	},
1774	{
1775		.name	= "cpuchunks",
1776		.type	= FIO_OPT_INT,
1777		.off1	= td_var_offset(cpucycle),
1778		.help	= "Length of the CPU burn cycles (usecs)",
1779		.def	= "50000",
1780		.parent = "cpuload",
1781	},
1782#ifdef FIO_HAVE_CPU_AFFINITY
1783	{
1784		.name	= "cpumask",
1785		.type	= FIO_OPT_INT,
1786		.cb	= str_cpumask_cb,
1787		.help	= "CPU affinity mask",
1788	},
1789	{
1790		.name	= "cpus_allowed",
1791		.type	= FIO_OPT_STR,
1792		.cb	= str_cpus_allowed_cb,
1793		.help	= "Set CPUs allowed",
1794	},
1795#endif
1796	{
1797		.name	= "end_fsync",
1798		.type	= FIO_OPT_BOOL,
1799		.off1	= td_var_offset(end_fsync),
1800		.help	= "Include fsync at the end of job",
1801		.def	= "0",
1802	},
1803	{
1804		.name	= "fsync_on_close",
1805		.type	= FIO_OPT_BOOL,
1806		.off1	= td_var_offset(fsync_on_close),
1807		.help	= "fsync files on close",
1808		.def	= "0",
1809	},
1810	{
1811		.name	= "unlink",
1812		.type	= FIO_OPT_BOOL,
1813		.off1	= td_var_offset(unlink),
1814		.help	= "Unlink created files after job has completed",
1815		.def	= "0",
1816	},
1817	{
1818		.name	= "exitall",
1819		.type	= FIO_OPT_STR_SET,
1820		.cb	= str_exitall_cb,
1821		.help	= "Terminate all jobs when one exits",
1822	},
1823	{
1824		.name	= "stonewall",
1825		.type	= FIO_OPT_STR_SET,
1826		.off1	= td_var_offset(stonewall),
1827		.help	= "Insert a hard barrier between this job and previous",
1828	},
1829	{
1830		.name	= "new_group",
1831		.type	= FIO_OPT_STR_SET,
1832		.off1	= td_var_offset(new_group),
1833		.help	= "Mark the start of a new group (for reporting)",
1834	},
1835	{
1836		.name	= "thread",
1837		.type	= FIO_OPT_STR_SET,
1838		.off1	= td_var_offset(use_thread),
1839		.help	= "Use threads instead of forks",
1840	},
1841	{
1842		.name	= "write_bw_log",
1843		.type	= FIO_OPT_STR,
1844		.off1	= td_var_offset(write_bw_log),
1845		.cb	= str_write_bw_log_cb,
1846		.help	= "Write log of bandwidth during run",
1847	},
1848	{
1849		.name	= "write_lat_log",
1850		.type	= FIO_OPT_STR,
1851		.off1	= td_var_offset(write_lat_log),
1852		.cb	= str_write_lat_log_cb,
1853		.help	= "Write log of latency during run",
1854	},
1855	{
1856		.name	= "hugepage-size",
1857		.type	= FIO_OPT_INT,
1858		.off1	= td_var_offset(hugepage_size),
1859		.help	= "When using hugepages, specify size of each page",
1860		.def	= __stringify(FIO_HUGE_PAGE),
1861	},
1862	{
1863		.name	= "group_reporting",
1864		.type	= FIO_OPT_STR_SET,
1865		.off1	= td_var_offset(group_reporting),
1866		.help	= "Do reporting on a per-group basis",
1867	},
1868	{
1869		.name	= "zero_buffers",
1870		.type	= FIO_OPT_STR_SET,
1871		.off1	= td_var_offset(zero_buffers),
1872		.help	= "Init IO buffers to all zeroes",
1873	},
1874	{
1875		.name	= "refill_buffers",
1876		.type	= FIO_OPT_STR_SET,
1877		.off1	= td_var_offset(refill_buffers),
1878		.help	= "Refill IO buffers on every IO submit",
1879	},
1880#ifdef FIO_HAVE_DISK_UTIL
1881	{
1882		.name	= "disk_util",
1883		.type	= FIO_OPT_BOOL,
1884		.off1	= td_var_offset(do_disk_util),
1885		.help	= "Log disk utilization statistics",
1886		.def	= "1",
1887	},
1888#endif
1889	{
1890		.name	= "gtod_reduce",
1891		.type	= FIO_OPT_BOOL,
1892		.help	= "Greatly reduce number of gettimeofday() calls",
1893		.cb	= str_gtod_reduce_cb,
1894		.def	= "0",
1895	},
1896	{
1897		.name	= "disable_lat",
1898		.type	= FIO_OPT_BOOL,
1899		.off1	= td_var_offset(disable_lat),
1900		.help	= "Disable latency numbers",
1901		.parent	= "gtod_reduce",
1902		.def	= "0",
1903	},
1904	{
1905		.name	= "disable_clat",
1906		.type	= FIO_OPT_BOOL,
1907		.off1	= td_var_offset(disable_clat),
1908		.help	= "Disable completion latency numbers",
1909		.parent	= "gtod_reduce",
1910		.def	= "0",
1911	},
1912	{
1913		.name	= "disable_slat",
1914		.type	= FIO_OPT_BOOL,
1915		.off1	= td_var_offset(disable_slat),
1916		.help	= "Disable submission latency numbers",
1917		.parent	= "gtod_reduce",
1918		.def	= "0",
1919	},
1920	{
1921		.name	= "disable_bw_measurement",
1922		.type	= FIO_OPT_BOOL,
1923		.off1	= td_var_offset(disable_bw),
1924		.help	= "Disable bandwidth logging",
1925		.parent	= "gtod_reduce",
1926		.def	= "0",
1927	},
1928	{
1929		.name	= "gtod_cpu",
1930		.type	= FIO_OPT_INT,
1931		.cb	= str_gtod_cpu_cb,
1932		.help	= "Set up dedicated gettimeofday() thread on this CPU",
1933		.verify	= gtod_cpu_verify,
1934	},
1935	{
1936		.name	= "continue_on_error",
1937		.type	= FIO_OPT_BOOL,
1938		.off1	= td_var_offset(continue_on_error),
1939		.help	= "Continue on non-fatal errors during IO",
1940		.def	= "0",
1941	},
1942	{
1943		.name	= "profile",
1944		.type	= FIO_OPT_STR_STORE,
1945		.off1	= td_var_offset(profile),
1946		.help	= "Select a specific builtin performance test",
1947	},
1948	{
1949		.name	= "cgroup",
1950		.type	= FIO_OPT_STR_STORE,
1951		.off1	= td_var_offset(cgroup),
1952		.help	= "Add job to cgroup of this name",
1953	},
1954	{
1955		.name	= "cgroup_weight",
1956		.type	= FIO_OPT_INT,
1957		.off1	= td_var_offset(cgroup_weight),
1958		.help	= "Use given weight for cgroup",
1959		.minval = 100,
1960		.maxval	= 1000,
1961	},
1962	{
1963		.name	= "cgroup_nodelete",
1964		.type	= FIO_OPT_BOOL,
1965		.off1	= td_var_offset(cgroup_nodelete),
1966		.help	= "Do not delete cgroups after job completion",
1967		.def	= "0",
1968	},
1969	{
1970		.name	= "uid",
1971		.type	= FIO_OPT_INT,
1972		.off1	= td_var_offset(uid),
1973		.help	= "Run job with this user ID",
1974	},
1975	{
1976		.name	= "gid",
1977		.type	= FIO_OPT_INT,
1978		.off1	= td_var_offset(gid),
1979		.help	= "Run job with this group ID",
1980	},
1981	{
1982		.name = NULL,
1983	},
1984};
1985
1986static void add_to_lopt(struct option *lopt, struct fio_option *o,
1987			const char *name)
1988{
1989	lopt->name = (char *) name;
1990	lopt->val = FIO_GETOPT_JOB;
1991	if (o->type == FIO_OPT_STR_SET)
1992		lopt->has_arg = no_argument;
1993	else
1994		lopt->has_arg = required_argument;
1995}
1996
1997void fio_options_dup_and_init(struct option *long_options)
1998{
1999	struct fio_option *o;
2000	unsigned int i;
2001
2002	options_init(options);
2003
2004	i = 0;
2005	while (long_options[i].name)
2006		i++;
2007
2008	o = &options[0];
2009	while (o->name) {
2010		add_to_lopt(&long_options[i], o, o->name);
2011		if (o->alias) {
2012			i++;
2013			add_to_lopt(&long_options[i], o, o->alias);
2014		}
2015
2016		i++;
2017		o++;
2018		assert(i < FIO_NR_OPTIONS);
2019	}
2020}
2021
2022struct fio_keyword {
2023	const char *word;
2024	const char *desc;
2025	char *replace;
2026};
2027
2028static struct fio_keyword fio_keywords[] = {
2029	{
2030		.word	= "$pagesize",
2031		.desc	= "Page size in the system",
2032	},
2033	{
2034		.word	= "$mb_memory",
2035		.desc	= "Megabytes of memory online",
2036	},
2037	{
2038		.word	= "$ncpus",
2039		.desc	= "Number of CPUs online in the system",
2040	},
2041	{
2042		.word	= NULL,
2043	},
2044};
2045
2046void fio_keywords_init(void)
2047{
2048	unsigned long long mb_memory;
2049	char buf[128];
2050	long l;
2051
2052	sprintf(buf, "%lu", page_size);
2053	fio_keywords[0].replace = strdup(buf);
2054
2055	mb_memory = os_phys_mem() / page_size;
2056	sprintf(buf, "%llu", mb_memory);
2057	fio_keywords[1].replace = strdup(buf);
2058
2059	l = sysconf(_SC_NPROCESSORS_ONLN);
2060	sprintf(buf, "%lu", l);
2061	fio_keywords[2].replace = strdup(buf);
2062}
2063
2064#define BC_APP		"bc"
2065
2066static char *bc_calc(char *str)
2067{
2068	char *buf, *tmp, opt[80];
2069	FILE *f;
2070	int ret;
2071
2072	/*
2073	 * No math, just return string
2074	 */
2075	if (!strchr(str, '+') && !strchr(str, '-') && !strchr(str, '*') &&
2076	    !strchr(str, '/'))
2077		return str;
2078
2079	/*
2080	 * Split option from value, we only need to calculate the value
2081	 */
2082	tmp = strchr(str, '=');
2083	if (!tmp)
2084		return str;
2085
2086	tmp++;
2087	memset(opt, 0, sizeof(opt));
2088	strncpy(opt, str, tmp - str);
2089
2090	buf = malloc(128);
2091
2092	sprintf(buf, "which %s > /dev/null", BC_APP);
2093	if (system(buf)) {
2094		log_err("fio: bc is needed for performing math\n");
2095		free(buf);
2096		return NULL;
2097	}
2098
2099	sprintf(buf, "echo %s | %s", tmp, BC_APP);
2100	f = popen(buf, "r");
2101	if (!f) {
2102		free(buf);
2103		return NULL;
2104	}
2105
2106	ret = fread(buf, 1, 128, f);
2107	if (ret <= 0) {
2108		free(buf);
2109		return NULL;
2110	}
2111
2112	buf[ret - 1] = '\0';
2113	strcat(opt, buf);
2114	strcpy(buf, opt);
2115	pclose(f);
2116	free(str);
2117	return buf;
2118}
2119
2120/*
2121 * Look for reserved variable names and replace them with real values
2122 */
2123static char *fio_keyword_replace(char *opt)
2124{
2125	char *s;
2126	int i;
2127
2128	for (i = 0; fio_keywords[i].word != NULL; i++) {
2129		struct fio_keyword *kw = &fio_keywords[i];
2130
2131		while ((s = strstr(opt, kw->word)) != NULL) {
2132			char *new = malloc(strlen(opt) + 1);
2133			char *o_org = opt;
2134			int olen = s - opt;
2135			int len;
2136
2137			/*
2138			 * Copy part of the string before the keyword and
2139			 * sprintf() the replacement after it.
2140			 */
2141			memcpy(new, opt, olen);
2142			len = sprintf(new + olen, "%s", kw->replace);
2143
2144			/*
2145			 * If there's more in the original string, copy that
2146			 * in too
2147			 */
2148			opt += strlen(kw->word) + olen;
2149			if (strlen(opt))
2150				memcpy(new + olen + len, opt, opt - o_org - 1);
2151
2152			/*
2153			 * replace opt and free the old opt
2154			 */
2155			opt = new;
2156			//free(o_org);
2157
2158			/*
2159			 * Check for potential math and invoke bc, if possible
2160			 */
2161			opt = bc_calc(opt);
2162		}
2163	}
2164
2165	return opt;
2166}
2167
2168int fio_options_parse(struct thread_data *td, char **opts, int num_opts)
2169{
2170	int i, ret;
2171
2172	sort_options(opts, options, num_opts);
2173
2174	for (ret = 0, i = 0; i < num_opts; i++) {
2175		opts[i] = fio_keyword_replace(opts[i]);
2176		ret |= parse_option(opts[i], options, td);
2177	}
2178
2179	return ret;
2180}
2181
2182int fio_cmd_option_parse(struct thread_data *td, const char *opt, char *val)
2183{
2184	return parse_cmd_option(opt, val, options, td);
2185}
2186
2187void fio_fill_default_options(struct thread_data *td)
2188{
2189	fill_default_options(td, options);
2190}
2191
2192int fio_show_option_help(const char *opt)
2193{
2194	return show_cmd_help(options, opt);
2195}
2196
2197static void __options_mem(struct thread_data *td, int alloc)
2198{
2199	struct thread_options *o = &td->o;
2200	struct fio_option *opt;
2201	char **ptr;
2202	int i;
2203
2204	for (i = 0, opt = &options[0]; opt->name; i++, opt = &options[i]) {
2205		if (opt->type != FIO_OPT_STR_STORE)
2206			continue;
2207
2208		ptr = (void *) o + opt->off1;
2209		if (*ptr) {
2210			if (alloc)
2211				*ptr = strdup(*ptr);
2212			else {
2213				free(*ptr);
2214				*ptr = NULL;
2215			}
2216		}
2217	}
2218}
2219
2220/*
2221 * dupe FIO_OPT_STR_STORE options
2222 */
2223void options_mem_dupe(struct thread_data *td)
2224{
2225	__options_mem(td, 1);
2226}
2227
2228void options_mem_free(struct thread_data fio_unused *td)
2229{
2230#if 0
2231	__options_mem(td, 0);
2232#endif
2233}
2234
2235unsigned int fio_get_kb_base(void *data)
2236{
2237	struct thread_data *td = data;
2238	unsigned int kb_base = 0;
2239
2240	if (td)
2241		kb_base = td->o.kb_base;
2242	if (!kb_base)
2243		kb_base = 1024;
2244
2245	return kb_base;
2246}
2247
2248int add_option(struct fio_option *o)
2249{
2250	struct fio_option *__o;
2251	int opt_index = 0;
2252
2253	__o = options;
2254	while (__o->name) {
2255		opt_index++;
2256		__o++;
2257	}
2258
2259	memcpy(&options[opt_index], o, sizeof(*o));
2260	return 0;
2261}
2262
2263void invalidate_profile_options(const char *prof_name)
2264{
2265	struct fio_option *o;
2266
2267	o = options;
2268	while (o->name) {
2269		if (o->prof_name && !strcmp(o->prof_name, prof_name)) {
2270			o->type = FIO_OPT_INVALID;
2271			o->prof_name = NULL;
2272		}
2273		o++;
2274	}
2275}
2276
2277void add_opt_posval(const char *optname, const char *ival, const char *help)
2278{
2279	struct fio_option *o;
2280	unsigned int i;
2281
2282	o = find_option(options, optname);
2283	if (!o)
2284		return;
2285
2286	for (i = 0; i < PARSE_MAX_VP; i++) {
2287		if (o->posval[i].ival)
2288			continue;
2289
2290		o->posval[i].ival = ival;
2291		o->posval[i].help = help;
2292		break;
2293	}
2294}
2295
2296void del_opt_posval(const char *optname, const char *ival)
2297{
2298	struct fio_option *o;
2299	unsigned int i;
2300
2301	o = find_option(options, optname);
2302	if (!o)
2303		return;
2304
2305	for (i = 0; i < PARSE_MAX_VP; i++) {
2306		if (!o->posval[i].ival)
2307			continue;
2308		if (strcmp(o->posval[i].ival, ival))
2309			continue;
2310
2311		o->posval[i].ival = NULL;
2312		o->posval[i].help = NULL;
2313	}
2314}
2315