init.c revision 313cb206ffc6e50c089314d322ebf1c523f37531
1/*
2 * This file contains job initialization and setup functions.
3 */
4#include <stdio.h>
5#include <stdlib.h>
6#include <unistd.h>
7#include <fcntl.h>
8#include <ctype.h>
9#include <string.h>
10#include <errno.h>
11#include <getopt.h>
12#include <assert.h>
13#include <sys/ipc.h>
14#include <sys/shm.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17
18#include "fio.h"
19#include "parse.h"
20
21/*
22 * The default options
23 */
24#define DEF_BS			(4096)
25#define DEF_TIMEOUT		(0)
26#define DEF_RATE_CYCLE		(1000)
27#define DEF_ODIRECT		(1)
28#define DEF_IO_ENGINE		(FIO_SYNCIO)
29#define DEF_IO_ENGINE_NAME	"sync"
30#define DEF_SEQUENTIAL		(1)
31#define DEF_RAND_REPEAT		(1)
32#define DEF_OVERWRITE		(0)
33#define DEF_INVALIDATE		(1)
34#define DEF_SYNCIO		(0)
35#define DEF_RANDSEED		(0xb1899bedUL)
36#define DEF_BWAVGTIME		(500)
37#define DEF_CREATE_SER		(1)
38#define DEF_CREATE_FSYNC	(1)
39#define DEF_LOOPS		(1)
40#define DEF_VERIFY		(0)
41#define DEF_STONEWALL		(0)
42#define DEF_NUMJOBS		(1)
43#define DEF_USE_THREAD		(0)
44#define DEF_FILE_SIZE		(1024 * 1024 * 1024UL)
45#define DEF_ZONE_SIZE		(0)
46#define DEF_ZONE_SKIP		(0)
47#define DEF_RWMIX_CYCLE		(500)
48#define DEF_RWMIX_READ		(50)
49#define DEF_NICE		(0)
50#define DEF_NR_FILES		(1)
51#define DEF_UNLINK		(1)
52#define DEF_WRITE_BW_LOG	(0)
53#define DEF_WRITE_LAT_LOG	(0)
54#define DEF_NO_RAND_MAP		(0)
55#define DEF_HUGEPAGE_SIZE	FIO_HUGE_PAGE
56
57#define td_var_offset(var)	((size_t) &((struct thread_data *)0)->var)
58
59static int str_rw_cb(void *, const char *);
60static int str_ioengine_cb(void *, const char *);
61static int str_mem_cb(void *, const char *);
62static int str_verify_cb(void *, const char *);
63static int str_lockmem_cb(void *, unsigned long *);
64#ifdef FIO_HAVE_IOPRIO
65static int str_prio_cb(void *, unsigned int *);
66static int str_prioclass_cb(void *, unsigned int *);
67#endif
68static int str_exitall_cb(void);
69static int str_cpumask_cb(void *, unsigned int *);
70
71/*
72 * Map of job/command line options
73 */
74static struct fio_option options[] = {
75	{
76		.name	= "name",
77		.type	= FIO_OPT_STR_STORE,
78		.off1	= td_var_offset(name),
79	},
80	{
81		.name	= "directory",
82		.type	= FIO_OPT_STR_STORE,
83		.off1	= td_var_offset(directory),
84	},
85	{
86		.name	= "filename",
87		.type	= FIO_OPT_STR_STORE,
88		.off1	= td_var_offset(filename),
89	},
90	{
91		.name	= "rw",
92		.type	= FIO_OPT_STR,
93		.cb	= str_rw_cb,
94	},
95	{
96		.name	= "ioengine",
97		.type	= FIO_OPT_STR,
98		.cb	= str_ioengine_cb,
99	},
100	{
101		.name	= "mem",
102		.type	= FIO_OPT_STR,
103		.cb	= str_mem_cb,
104	},
105	{
106		.name	= "verify",
107		.type	= FIO_OPT_STR,
108		.cb	= str_verify_cb,
109	},
110	{
111		.name	= "write_iolog",
112		.type	= FIO_OPT_STR_STORE,
113		.off1	= td_var_offset(write_iolog_file),
114	},
115	{
116		.name	= "read_iolog",
117		.type	= FIO_OPT_STR_STORE,
118		.off1	= td_var_offset(read_iolog_file),
119	},
120	{
121		.name	= "exec_prerun",
122		.type	= FIO_OPT_STR_STORE,
123		.off1	= td_var_offset(exec_prerun),
124	},
125	{
126		.name	= "exec_postrun",
127		.type	= FIO_OPT_STR_STORE,
128		.off1	= td_var_offset(exec_postrun),
129	},
130#ifdef FIO_HAVE_IOSCHED_SWITCH
131	{
132		.name	= "ioscheduler",
133		.type	= FIO_OPT_STR_STORE,
134		.off1	= td_var_offset(ioscheduler),
135	},
136#endif
137	{
138		.name	= "size",
139		.type	= FIO_OPT_STR_VAL,
140		.off1	= td_var_offset(total_file_size),
141	},
142	{
143		.name	= "bs",
144		.type	= FIO_OPT_STR_VAL_INT,
145		.off1	= td_var_offset(bs[DDIR_READ]),
146		.off2	= td_var_offset(bs[DDIR_WRITE]),
147	},
148	{
149		.name	= "offset",
150		.type	= FIO_OPT_STR_VAL,
151		.off1	= td_var_offset(start_offset),
152	},
153	{
154		.name	= "zonesize",
155		.type	= FIO_OPT_STR_VAL,
156		.off1	= td_var_offset(zone_size),
157	},
158	{
159		.name	= "zoneskip",
160		.type	= FIO_OPT_STR_VAL,
161		.off1	= td_var_offset(zone_skip),
162	},
163	{
164		.name	= "lockmem",
165		.type	= FIO_OPT_STR_VAL,
166		.cb	= str_lockmem_cb,
167	},
168	{
169		.name	= "bsrange",
170		.type	= FIO_OPT_RANGE,
171		.off1	= td_var_offset(min_bs[DDIR_READ]),
172		.off2	= td_var_offset(max_bs[DDIR_READ]),
173		.off3	= td_var_offset(min_bs[DDIR_WRITE]),
174		.off4	= td_var_offset(max_bs[DDIR_WRITE]),
175	},
176	{
177		.name	= "nrfiles",
178		.type	= FIO_OPT_INT,
179		.off1	= td_var_offset(nr_files),
180	},
181	{
182		.name	= "iodepth",
183		.type	= FIO_OPT_INT,
184		.off1	= td_var_offset(iodepth),
185	},
186	{
187		.name	= "fsync",
188		.type	= FIO_OPT_INT,
189		.off1	= td_var_offset(fsync_blocks),
190	},
191	{
192		.name	= "rwmixcycle",
193		.type	= FIO_OPT_INT,
194		.off1	= td_var_offset(rwmixcycle),
195	},
196	{
197		.name	= "rwmixread",
198		.type	= FIO_OPT_INT,
199		.off1	= td_var_offset(rwmixread),
200		.max_val= 100,
201	},
202	{
203		.name	= "rwmixwrite",
204		.type	= FIO_OPT_INT,
205		.off1	= td_var_offset(rwmixwrite),
206		.max_val= 100,
207	},
208	{
209		.name	= "nice",
210		.type	= FIO_OPT_INT,
211		.off1	= td_var_offset(nice),
212	},
213#ifdef FIO_HAVE_IOPRIO
214	{
215		.name	= "prio",
216		.type	= FIO_OPT_INT,
217		.cb	= str_prio_cb,
218	},
219	{
220		.name	= "prioclass",
221		.type	= FIO_OPT_INT,
222		.cb	= str_prioclass_cb,
223	},
224#endif
225	{
226		.name	= "thinktime",
227		.type	= FIO_OPT_INT,
228		.off1	= td_var_offset(thinktime)
229	},
230	{
231		.name	= "rate",
232		.type	= FIO_OPT_INT,
233		.off1	= td_var_offset(rate)
234	},
235	{
236		.name	= "ratemin",
237		.type	= FIO_OPT_INT,
238		.off1	= td_var_offset(ratemin)
239	},
240	{
241		.name	= "ratecycle",
242		.type	= FIO_OPT_INT,
243		.off1	= td_var_offset(ratecycle)
244	},
245	{
246		.name	= "startdelay",
247		.type	= FIO_OPT_INT,
248		.off1	= td_var_offset(start_delay)
249	},
250	{
251		.name	= "timeout",
252		.type	= FIO_OPT_STR_VAL_TIME,
253		.off1	= td_var_offset(timeout)
254	},
255	{
256		.name	= "invalidate",
257		.type	= FIO_OPT_INT,
258		.off1	= td_var_offset(invalidate_cache)
259	},
260	{
261		.name	= "sync",
262		.type	= FIO_OPT_INT,
263		.off1	= td_var_offset(sync_io)
264	},
265	{
266		.name	= "bwavgtime",
267		.type	= FIO_OPT_INT,
268		.off1	= td_var_offset(bw_avg_time)
269	},
270	{
271		.name	= "create_serialize",
272		.type	= FIO_OPT_INT,
273		.off1	= td_var_offset(create_serialize)
274	},
275	{
276		.name	= "create_fsync",
277		.type	= FIO_OPT_INT,
278		.off1	= td_var_offset(create_fsync)
279	},
280	{
281		.name	= "loops",
282		.type	= FIO_OPT_INT,
283		.off1	= td_var_offset(loops)
284	},
285	{
286		.name	= "numjobs",
287		.type	= FIO_OPT_INT,
288		.off1	= td_var_offset(numjobs)
289	},
290	{
291		.name	= "cpuload",
292		.type	= FIO_OPT_INT,
293		.off1	= td_var_offset(cpuload)
294	},
295	{
296		.name	= "cpuchunks",
297		.type	= FIO_OPT_INT,
298		.off1	= td_var_offset(cpucycle)
299	},
300	{
301		.name	= "direct",
302		.type	= FIO_OPT_INT,
303		.off1	= td_var_offset(odirect)
304	},
305	{
306		.name	= "overwrite",
307		.type	= FIO_OPT_INT,
308		.off1	= td_var_offset(overwrite)
309	},
310#ifdef FIO_HAVE_CPU_AFFINITY
311	{
312		.name	= "cpumask",
313		.type	= FIO_OPT_INT,
314		.cb	= str_cpumask_cb,
315	},
316#endif
317	{
318		.name	= "end_fsync",
319		.type	= FIO_OPT_INT,
320		.off1	= td_var_offset(end_fsync)
321	},
322	{
323		.name	= "unlink",
324		.type	= FIO_OPT_STR_SET,
325		.off1	= td_var_offset(unlink),
326	},
327	{
328		.name	= "exitall",
329		.type	= FIO_OPT_STR_SET,
330		.cb	= str_exitall_cb,
331	},
332	{
333		.name	= "stonewall",
334		.type	= FIO_OPT_STR_SET,
335		.off1	= td_var_offset(stonewall),
336	},
337	{
338		.name	= "thread",
339		.type	= FIO_OPT_STR_SET,
340		.off1	= td_var_offset(thread),
341	},
342	{
343		.name	= "write_bw_log",
344		.type	= FIO_OPT_STR_SET,
345		.off1	= td_var_offset(write_bw_log),
346	},
347	{
348		.name	= "write_lat_log",
349		.type	= FIO_OPT_STR_SET,
350		.off1	= td_var_offset(write_lat_log),
351	},
352	{
353		.name	= "norandommap",
354		.type	= FIO_OPT_STR_SET,
355		.off1	= td_var_offset(norandommap),
356	},
357	{
358		.name	= "bs_unaligned",
359		.type	= FIO_OPT_STR_SET,
360		.off1	= td_var_offset(bs_unaligned),
361	},
362	{
363		.name	= "hugepage-size",
364		.type	= FIO_OPT_STR_VAL,
365		.off1	= td_var_offset(hugepage_size),
366	},
367	{
368		.name = NULL,
369	},
370};
371
372#define FIO_JOB_OPTS	(sizeof(options) / sizeof(struct fio_option))
373#define FIO_CMD_OPTS	(16)
374#define FIO_GETOPT_JOB	(0x89988998)
375
376/*
377 * Command line options. These will contain the above, plus a few
378 * extra that only pertain to fio itself and not jobs.
379 */
380static struct option long_options[FIO_JOB_OPTS + FIO_CMD_OPTS] = {
381	{
382		.name		= "output",
383		.has_arg	= required_argument,
384		.val		= 'o',
385	},
386	{
387		.name		= "timeout",
388		.has_arg	= required_argument,
389		.val		= 't',
390	},
391	{
392		.name		= "latency-log",
393		.has_arg	= required_argument,
394		.val		= 'l',
395	},
396	{
397		.name		= "bandwidth-log",
398		.has_arg	= required_argument,
399		.val		= 'b',
400	},
401	{
402		.name		= "minimal",
403		.has_arg	= optional_argument,
404		.val		= 'm',
405	},
406	{
407		.name		= "version",
408		.has_arg	= no_argument,
409		.val		= 'v',
410	},
411	{
412		.name		= NULL,
413	},
414};
415
416static int def_timeout = DEF_TIMEOUT;
417
418static char fio_version_string[] = "fio 1.9";
419
420static char **ini_file;
421static int max_jobs = MAX_JOBS;
422
423struct thread_data def_thread;
424struct thread_data *threads = NULL;
425
426int exitall_on_terminate = 0;
427int terse_output = 0;
428unsigned long long mlock_size = 0;
429FILE *f_out = NULL;
430FILE *f_err = NULL;
431
432static int write_lat_log = DEF_WRITE_LAT_LOG;
433static int write_bw_log = DEF_WRITE_BW_LOG;
434
435/*
436 * Return a free job structure.
437 */
438static struct thread_data *get_new_job(int global, struct thread_data *parent)
439{
440	struct thread_data *td;
441
442	if (global)
443		return &def_thread;
444	if (thread_number >= max_jobs)
445		return NULL;
446
447	td = &threads[thread_number++];
448	*td = *parent;
449
450	td->thread_number = thread_number;
451	return td;
452}
453
454static void put_job(struct thread_data *td)
455{
456	if (td == &def_thread)
457		return;
458
459	memset(&threads[td->thread_number - 1], 0, sizeof(*td));
460	thread_number--;
461}
462
463/*
464 * Lazy way of fixing up options that depend on each other. We could also
465 * define option callback handlers, but this is easier.
466 */
467static void fixup_options(struct thread_data *td)
468{
469	if (!td->rwmixread && td->rwmixwrite)
470		td->rwmixread = 100 - td->rwmixwrite;
471
472	if (td->write_iolog_file && td->read_iolog_file) {
473		log_err("fio: read iolog overrides write_iolog\n");
474		free(td->write_iolog_file);
475		td->write_iolog_file = NULL;
476	}
477
478	if (td->io_ops->flags & FIO_SYNCIO)
479		td->iodepth = 1;
480	else {
481		if (!td->iodepth)
482			td->iodepth = td->nr_files;
483	}
484
485	/*
486	 * only really works for sequential io for now, and with 1 file
487	 */
488	if (td->zone_size && !td->sequential && td->nr_files == 1)
489		td->zone_size = 0;
490
491	/*
492	 * Reads can do overwrites, we always need to pre-create the file
493	 */
494	if (td_read(td) || td_rw(td))
495		td->overwrite = 1;
496
497	if (!td->min_bs[DDIR_READ])
498		td->min_bs[DDIR_READ]= td->bs[DDIR_READ];
499	if (!td->max_bs[DDIR_READ])
500		td->max_bs[DDIR_READ] = td->bs[DDIR_READ];
501	if (!td->min_bs[DDIR_WRITE])
502		td->min_bs[DDIR_WRITE]= td->bs[DDIR_WRITE];
503	if (!td->max_bs[DDIR_WRITE])
504		td->max_bs[DDIR_WRITE] = td->bs[DDIR_WRITE];
505
506	td->rw_min_bs = min(td->min_bs[DDIR_READ], td->min_bs[DDIR_WRITE]);
507
508	if (td_read(td) && !td_rw(td))
509		td->verify = 0;
510
511	if (td->norandommap && td->verify != VERIFY_NONE) {
512		log_err("fio: norandommap given, verify disabled\n");
513		td->verify = VERIFY_NONE;
514	}
515	if (td->bs_unaligned && (td->odirect || td->io_ops->flags & FIO_RAWIO))
516		log_err("fio: bs_unaligned may not work with raw io\n");
517
518	/*
519	 * O_DIRECT and char doesn't mix, clear that flag if necessary.
520	 */
521	if (td->filetype == FIO_TYPE_CHAR && td->odirect)
522		td->odirect = 0;
523}
524
525/*
526 * This function leaks the buffer
527 */
528static char *to_kmg(unsigned int val)
529{
530	char *buf = malloc(32);
531	char post[] = { 0, 'K', 'M', 'G', 'P', 0 };
532	char *p = post;
533
534	do {
535		if (val & 1023)
536			break;
537
538		val >>= 10;
539		p++;
540	} while (*p);
541
542	snprintf(buf, 31, "%u%c", val, *p);
543	return buf;
544}
545
546/*
547 * Adds a job to the list of things todo. Sanitizes the various options
548 * to make sure we don't have conflicts, and initializes various
549 * members of td.
550 */
551static int add_job(struct thread_data *td, const char *jobname, int job_add_num)
552{
553	const char *ddir_str[] = { "read", "write", "randread", "randwrite",
554				   "rw", NULL, "randrw" };
555	struct stat sb;
556	int numjobs, ddir, i;
557	struct fio_file *f;
558
559	/*
560	 * the def_thread is just for options, it's not a real job
561	 */
562	if (td == &def_thread)
563		return 0;
564
565	/*
566	 * Set default io engine, if none set
567	 */
568	if (!td->io_ops) {
569		td->io_ops = load_ioengine(td, DEF_IO_ENGINE_NAME);
570		if (!td->io_ops) {
571			log_err("default engine %s not there?\n", DEF_IO_ENGINE_NAME);
572			return 1;
573		}
574	}
575
576	if (td->odirect)
577		td->io_ops->flags |= FIO_RAWIO;
578
579	td->filetype = FIO_TYPE_FILE;
580	if (!stat(jobname, &sb)) {
581		if (S_ISBLK(sb.st_mode))
582			td->filetype = FIO_TYPE_BD;
583		else if (S_ISCHR(sb.st_mode))
584			td->filetype = FIO_TYPE_CHAR;
585	}
586
587	fixup_options(td);
588
589	if (td->filename)
590		td->nr_uniq_files = 1;
591	else
592		td->nr_uniq_files = td->nr_files;
593
594	if (td->filetype == FIO_TYPE_FILE || td->filename) {
595		char tmp[PATH_MAX];
596		int len = 0;
597
598		if (td->directory && td->directory[0] != '\0')
599			sprintf(tmp, "%s/", td->directory);
600
601		td->files = malloc(sizeof(struct fio_file) * td->nr_files);
602
603		for_each_file(td, f, i) {
604			memset(f, 0, sizeof(*f));
605			f->fd = -1;
606
607			if (td->filename)
608				sprintf(tmp + len, "%s", td->filename);
609			else
610				sprintf(tmp + len, "%s.%d.%d", jobname, td->thread_number, i);
611			f->file_name = strdup(tmp);
612		}
613	} else {
614		td->nr_files = 1;
615		td->files = malloc(sizeof(struct fio_file));
616		f = &td->files[0];
617
618		memset(f, 0, sizeof(*f));
619		f->fd = -1;
620		f->file_name = strdup(jobname);
621	}
622
623	for_each_file(td, f, i) {
624		f->file_size = td->total_file_size / td->nr_files;
625		f->file_offset = td->start_offset;
626	}
627
628	fio_sem_init(&td->mutex, 0);
629
630	td->clat_stat[0].min_val = td->clat_stat[1].min_val = ULONG_MAX;
631	td->slat_stat[0].min_val = td->slat_stat[1].min_val = ULONG_MAX;
632	td->bw_stat[0].min_val = td->bw_stat[1].min_val = ULONG_MAX;
633
634	if (td->stonewall && td->thread_number > 1)
635		groupid++;
636
637	td->groupid = groupid;
638
639	if (setup_rate(td))
640		goto err;
641
642	if (td->write_lat_log) {
643		setup_log(&td->slat_log);
644		setup_log(&td->clat_log);
645	}
646	if (td->write_bw_log)
647		setup_log(&td->bw_log);
648
649	if (!td->name)
650		td->name = strdup(jobname);
651
652	ddir = td->ddir + (!td->sequential << 1) + (td->iomix << 2);
653
654	if (!terse_output) {
655		if (!job_add_num) {
656			if (td->io_ops->flags & FIO_CPUIO)
657				fprintf(f_out, "%s: ioengine=cpu, cpuload=%u, cpucycle=%u\n", td->name, td->cpuload, td->cpucycle);
658			else {
659				char *c1, *c2, *c3, *c4;
660
661				c1 = to_kmg(td->min_bs[DDIR_READ]);
662				c2 = to_kmg(td->max_bs[DDIR_READ]);
663				c3 = to_kmg(td->min_bs[DDIR_WRITE]);
664				c4 = to_kmg(td->max_bs[DDIR_WRITE]);
665
666				fprintf(f_out, "%s: (g=%d): rw=%s, odir=%u, bs=%s-%s/%s-%s, rate=%u, ioengine=%s, iodepth=%u\n", td->name, td->groupid, ddir_str[ddir], td->odirect, c1, c2, c3, c4, td->rate, td->io_ops->name, td->iodepth);
667
668				free(c1);
669				free(c2);
670				free(c3);
671				free(c4);
672			}
673		} else if (job_add_num == 1)
674			fprintf(f_out, "...\n");
675	}
676
677	/*
678	 * recurse add identical jobs, clear numjobs and stonewall options
679	 * as they don't apply to sub-jobs
680	 */
681	numjobs = td->numjobs;
682	while (--numjobs) {
683		struct thread_data *td_new = get_new_job(0, td);
684
685		if (!td_new)
686			goto err;
687
688		td_new->numjobs = 1;
689		td_new->stonewall = 0;
690		job_add_num = numjobs - 1;
691
692		if (add_job(td_new, jobname, job_add_num))
693			goto err;
694	}
695	return 0;
696err:
697	put_job(td);
698	return -1;
699}
700
701/*
702 * Initialize the various random states we need (random io, block size ranges,
703 * read/write mix, etc).
704 */
705int init_random_state(struct thread_data *td)
706{
707	unsigned long seeds[4];
708	int fd, num_maps, blocks, i;
709	struct fio_file *f;
710
711	if (td->io_ops->flags & FIO_CPUIO)
712		return 0;
713
714	fd = open("/dev/urandom", O_RDONLY);
715	if (fd == -1) {
716		td_verror(td, errno);
717		return 1;
718	}
719
720	if (read(fd, seeds, sizeof(seeds)) < (int) sizeof(seeds)) {
721		td_verror(td, EIO);
722		close(fd);
723		return 1;
724	}
725
726	close(fd);
727
728	os_random_seed(seeds[0], &td->bsrange_state);
729	os_random_seed(seeds[1], &td->verify_state);
730	os_random_seed(seeds[2], &td->rwmix_state);
731
732	if (td->sequential)
733		return 0;
734
735	if (td->rand_repeatable)
736		seeds[3] = DEF_RANDSEED;
737
738	if (!td->norandommap) {
739		for_each_file(td, f, i) {
740			blocks = (f->file_size + td->rw_min_bs - 1) / td->rw_min_bs;
741			num_maps = (blocks + BLOCKS_PER_MAP-1)/ BLOCKS_PER_MAP;
742			f->file_map = malloc(num_maps * sizeof(long));
743			f->num_maps = num_maps;
744			memset(f->file_map, 0, num_maps * sizeof(long));
745		}
746	}
747
748	os_random_seed(seeds[3], &td->random_state);
749	return 0;
750}
751
752static void fill_cpu_mask(os_cpu_mask_t cpumask, int cpu)
753{
754#ifdef FIO_HAVE_CPU_AFFINITY
755	unsigned int i;
756
757	CPU_ZERO(&cpumask);
758
759	for (i = 0; i < sizeof(int) * 8; i++) {
760		if ((1 << i) & cpu)
761			CPU_SET(i, &cpumask);
762	}
763#endif
764}
765
766static int is_empty_or_comment(char *line)
767{
768	unsigned int i;
769
770	for (i = 0; i < strlen(line); i++) {
771		if (line[i] == ';')
772			return 1;
773		if (!isspace(line[i]) && !iscntrl(line[i]))
774			return 0;
775	}
776
777	return 1;
778}
779
780static int str_rw_cb(void *data, const char *mem)
781{
782	struct thread_data *td = data;
783
784	if (!strncmp(mem, "read", 4) || !strncmp(mem, "0", 1)) {
785		td->ddir = DDIR_READ;
786		td->sequential = 1;
787		return 0;
788	} else if (!strncmp(mem, "randread", 8)) {
789		td->ddir = DDIR_READ;
790		td->sequential = 0;
791		return 0;
792	} else if (!strncmp(mem, "write", 5) || !strncmp(mem, "1", 1)) {
793		td->ddir = DDIR_WRITE;
794		td->sequential = 1;
795		return 0;
796	} else if (!strncmp(mem, "randwrite", 9)) {
797		td->ddir = DDIR_WRITE;
798		td->sequential = 0;
799		return 0;
800	} else if (!strncmp(mem, "rw", 2)) {
801		td->ddir = DDIR_READ;
802		td->iomix = 1;
803		td->sequential = 1;
804		return 0;
805	} else if (!strncmp(mem, "randrw", 6)) {
806		td->ddir = DDIR_READ;
807		td->iomix = 1;
808		td->sequential = 0;
809		return 0;
810	}
811
812	log_err("fio: data direction: read, write, randread, randwrite, rw, randrw\n");
813	return 1;
814}
815
816static int str_verify_cb(void *data, const char *mem)
817{
818	struct thread_data *td = data;
819
820	if (!strncmp(mem, "0", 1)) {
821		td->verify = VERIFY_NONE;
822		return 0;
823	} else if (!strncmp(mem, "md5", 3) || !strncmp(mem, "1", 1)) {
824		td->verify = VERIFY_MD5;
825		return 0;
826	} else if (!strncmp(mem, "crc32", 5)) {
827		td->verify = VERIFY_CRC32;
828		return 0;
829	}
830
831	log_err("fio: verify types: md5, crc32\n");
832	return 1;
833}
834
835/*
836 * Check if mmap/mmaphuge has a :/foo/bar/file at the end. If so, return that.
837 */
838static char *get_mmap_file(const char *str)
839{
840	char *p = strstr(str, ":");
841
842	if (!p)
843		return NULL;
844
845	p++;
846	strip_blank_front(&p);
847	strip_blank_end(p);
848	return strdup(p);
849}
850
851static int str_mem_cb(void *data, const char *mem)
852{
853	struct thread_data *td = data;
854
855	if (!strncmp(mem, "malloc", 6)) {
856		td->mem_type = MEM_MALLOC;
857		return 0;
858	} else if (!strncmp(mem, "mmaphuge", 8)) {
859#ifdef FIO_HAVE_HUGETLB
860		/*
861		 * mmaphuge must be appended with the actual file
862		 */
863		td->mmapfile = get_mmap_file(mem);
864		if (!td->mmapfile) {
865			log_err("fio: mmaphuge:/path/to/file\n");
866			return 1;
867		}
868
869		td->mem_type = MEM_MMAPHUGE;
870		return 0;
871#else
872		log_err("fio: mmaphuge not available\n");
873		return 1;
874#endif
875	} else if (!strncmp(mem, "mmap", 4)) {
876		/*
877		 * Check if the user wants file backed memory. It's ok
878		 * if there's no file given, we'll just use anon mamp then.
879		 */
880		td->mmapfile = get_mmap_file(mem);
881		td->mem_type = MEM_MMAP;
882		return 0;
883	} else if (!strncmp(mem, "shmhuge", 7)) {
884#ifdef FIO_HAVE_HUGETLB
885		td->mem_type = MEM_SHMHUGE;
886		return 0;
887#else
888		log_err("fio: shmhuge not available\n");
889		return 1;
890#endif
891	} else if (!strncmp(mem, "shm", 3)) {
892		td->mem_type = MEM_SHM;
893		return 0;
894	}
895
896	log_err("fio: mem type: malloc, shm, shmhuge, mmap, mmaphuge\n");
897	return 1;
898}
899
900static int str_ioengine_cb(void *data, const char *str)
901{
902	struct thread_data *td = data;
903
904	td->io_ops = load_ioengine(td, str);
905	if (td->io_ops)
906		return 0;
907
908	log_err("fio: ioengine= libaio, posixaio, sync, mmap, sgio, splice, cpu, null\n");
909	log_err("fio: or specify path to dynamic ioengine module\n");
910	return 1;
911}
912
913static int str_lockmem_cb(void fio_unused *data, unsigned long *val)
914{
915	mlock_size = *val;
916	return 0;
917}
918
919#ifdef FIO_HAVE_IOPRIO
920static int str_prioclass_cb(void *data, unsigned int *val)
921{
922	struct thread_data *td = data;
923
924	td->ioprio |= *val << IOPRIO_CLASS_SHIFT;
925	return 0;
926}
927
928static int str_prio_cb(void *data, unsigned int *val)
929{
930	struct thread_data *td = data;
931
932	td->ioprio |= *val;
933	return 0;
934}
935#endif
936
937static int str_exitall_cb(void)
938{
939	exitall_on_terminate = 1;
940	return 0;
941}
942
943static int str_cpumask_cb(void *data, unsigned int *val)
944{
945	struct thread_data *td = data;
946
947	fill_cpu_mask(td->cpumask, *val);
948	return 0;
949}
950
951/*
952 * This is our [ini] type file parser.
953 */
954static int parse_jobs_ini(char *file, int stonewall_flag)
955{
956	unsigned int global;
957	struct thread_data *td;
958	char *string, *name;
959	fpos_t off;
960	FILE *f;
961	char *p;
962	int ret = 0, stonewall;
963
964	f = fopen(file, "r");
965	if (!f) {
966		perror("fopen job file");
967		return 1;
968	}
969
970	string = malloc(4096);
971	name = malloc(256);
972	memset(name, 0, 256);
973
974	stonewall = stonewall_flag;
975	do {
976		p = fgets(string, 4095, f);
977		if (!p)
978			break;
979		if (is_empty_or_comment(p))
980			continue;
981		if (sscanf(p, "[%255s]", name) != 1)
982			continue;
983
984		global = !strncmp(name, "global", 6);
985
986		name[strlen(name) - 1] = '\0';
987
988		td = get_new_job(global, &def_thread);
989		if (!td) {
990			ret = 1;
991			break;
992		}
993
994		/*
995		 * Seperate multiple job files by a stonewall
996		 */
997		if (!global && stonewall) {
998			td->stonewall = stonewall;
999			stonewall = 0;
1000		}
1001
1002		fgetpos(f, &off);
1003		while ((p = fgets(string, 4096, f)) != NULL) {
1004			if (is_empty_or_comment(p))
1005				continue;
1006
1007			strip_blank_front(&p);
1008
1009			if (p[0] == '[')
1010				break;
1011
1012			strip_blank_end(p);
1013
1014			fgetpos(f, &off);
1015
1016			/*
1017			 * Don't break here, continue parsing options so we
1018			 * dump all the bad ones. Makes trial/error fixups
1019			 * easier on the user.
1020			 */
1021			ret |= parse_option(p, options, td);
1022		}
1023
1024		if (!ret) {
1025			fsetpos(f, &off);
1026			ret = add_job(td, name, 0);
1027		} else {
1028			log_err("fio: job %s dropped\n", name);
1029			put_job(td);
1030		}
1031	} while (!ret);
1032
1033	free(string);
1034	free(name);
1035	fclose(f);
1036	return ret;
1037}
1038
1039static int fill_def_thread(void)
1040{
1041	memset(&def_thread, 0, sizeof(def_thread));
1042
1043	if (fio_getaffinity(getpid(), &def_thread.cpumask) == -1) {
1044		perror("sched_getaffinity");
1045		return 1;
1046	}
1047
1048	/*
1049	 * fill globals
1050	 */
1051	def_thread.ddir = DDIR_READ;
1052	def_thread.iomix = 0;
1053	def_thread.bs[DDIR_READ] = DEF_BS;
1054	def_thread.bs[DDIR_WRITE] = DEF_BS;
1055	def_thread.min_bs[DDIR_READ] = def_thread.min_bs[DDIR_WRITE] = 0;
1056	def_thread.max_bs[DDIR_READ] = def_thread.max_bs[DDIR_WRITE] = 0;
1057	def_thread.odirect = DEF_ODIRECT;
1058	def_thread.ratecycle = DEF_RATE_CYCLE;
1059	def_thread.sequential = DEF_SEQUENTIAL;
1060	def_thread.timeout = def_timeout;
1061	def_thread.overwrite = DEF_OVERWRITE;
1062	def_thread.invalidate_cache = DEF_INVALIDATE;
1063	def_thread.sync_io = DEF_SYNCIO;
1064	def_thread.mem_type = MEM_MALLOC;
1065	def_thread.bw_avg_time = DEF_BWAVGTIME;
1066	def_thread.create_serialize = DEF_CREATE_SER;
1067	def_thread.create_fsync = DEF_CREATE_FSYNC;
1068	def_thread.loops = DEF_LOOPS;
1069	def_thread.verify = DEF_VERIFY;
1070	def_thread.stonewall = DEF_STONEWALL;
1071	def_thread.numjobs = DEF_NUMJOBS;
1072	def_thread.use_thread = DEF_USE_THREAD;
1073	def_thread.rwmixcycle = DEF_RWMIX_CYCLE;
1074	def_thread.rwmixread = DEF_RWMIX_READ;
1075	def_thread.nice = DEF_NICE;
1076	def_thread.rand_repeatable = DEF_RAND_REPEAT;
1077	def_thread.nr_files = DEF_NR_FILES;
1078	def_thread.unlink = DEF_UNLINK;
1079	def_thread.write_bw_log = write_bw_log;
1080	def_thread.write_lat_log = write_lat_log;
1081	def_thread.norandommap = DEF_NO_RAND_MAP;
1082	def_thread.hugepage_size = DEF_HUGEPAGE_SIZE;
1083#ifdef FIO_HAVE_DISK_UTIL
1084	def_thread.do_disk_util = 1;
1085#endif
1086
1087	return 0;
1088}
1089
1090static void usage(void)
1091{
1092	printf("%s\n", fio_version_string);
1093	printf("\t--output\tWrite output to file\n");
1094	printf("\t--timeout\tRuntime in seconds\n");
1095	printf("\t--latency-log\tGenerate per-job latency logs\n");
1096	printf("\t--bandwidth-log\tGenerate per-job bandwidth logs\n");
1097	printf("\t--minimal\tMinimal (terse) output\n");
1098	printf("\t--version\tPrint version info and exit\n");
1099}
1100
1101static int parse_cmd_line(int argc, char *argv[])
1102{
1103	struct thread_data *td = NULL;
1104	int c, ini_idx = 0, lidx, ret;
1105
1106	while ((c = getopt_long(argc, argv, "", long_options, &lidx)) != -1) {
1107		switch (c) {
1108		case 't':
1109			def_timeout = atoi(optarg);
1110			break;
1111		case 'l':
1112			write_lat_log = 1;
1113			break;
1114		case 'w':
1115			write_bw_log = 1;
1116			break;
1117		case 'o':
1118			f_out = fopen(optarg, "w+");
1119			if (!f_out) {
1120				perror("fopen output");
1121				exit(1);
1122			}
1123			f_err = f_out;
1124			break;
1125		case 'm':
1126			terse_output = 1;
1127			break;
1128		case 'h':
1129			usage();
1130			exit(0);
1131		case 'v':
1132			printf("%s\n", fio_version_string);
1133			exit(0);
1134		case FIO_GETOPT_JOB: {
1135			const char *opt = long_options[lidx].name;
1136			char *val = optarg;
1137
1138			if (!strncmp(opt, "name", 4) && td) {
1139				ret = add_job(td, td->name ?: "fio", 0);
1140				if (ret) {
1141					put_job(td);
1142					return 0;
1143				}
1144				td = NULL;
1145			}
1146			if (!td) {
1147				int global = !strncmp(val, "global", 6);
1148
1149				td = get_new_job(global, &def_thread);
1150				if (!td)
1151					return 0;
1152			}
1153
1154			ret = parse_cmd_option(opt, val, options, td);
1155			if (ret) {
1156				log_err("fio: job dropped\n");
1157				put_job(td);
1158				td = NULL;
1159			}
1160			break;
1161		}
1162		default:
1163			printf("optarg <<%s>>\n", argv[optind]);
1164			break;
1165		}
1166	}
1167
1168	if (td) {
1169		ret = add_job(td, td->name ?: "fio", 0);
1170		if (ret)
1171			put_job(td);
1172	}
1173
1174	while (optind < argc) {
1175		ini_idx++;
1176		ini_file = realloc(ini_file, ini_idx * sizeof(char *));
1177		ini_file[ini_idx - 1] = strdup(argv[optind]);
1178		optind++;
1179	}
1180
1181	return ini_idx;
1182}
1183
1184static void free_shm(void)
1185{
1186	struct shmid_ds sbuf;
1187
1188	if (threads) {
1189		shmdt((void *) threads);
1190		threads = NULL;
1191		shmctl(shm_id, IPC_RMID, &sbuf);
1192	}
1193}
1194
1195/*
1196 * The thread area is shared between the main process and the job
1197 * threads/processes. So setup a shared memory segment that will hold
1198 * all the job info.
1199 */
1200static int setup_thread_area(void)
1201{
1202	/*
1203	 * 1024 is too much on some machines, scale max_jobs if
1204	 * we get a failure that looks like too large a shm segment
1205	 */
1206	do {
1207		size_t size = max_jobs * sizeof(struct thread_data);
1208
1209		shm_id = shmget(0, size, IPC_CREAT | 0600);
1210		if (shm_id != -1)
1211			break;
1212		if (errno != EINVAL) {
1213			perror("shmget");
1214			break;
1215		}
1216
1217		max_jobs >>= 1;
1218	} while (max_jobs);
1219
1220	if (shm_id == -1)
1221		return 1;
1222
1223	threads = shmat(shm_id, NULL, 0);
1224	if (threads == (void *) -1) {
1225		perror("shmat");
1226		return 1;
1227	}
1228
1229	atexit(free_shm);
1230	return 0;
1231}
1232
1233/*
1234 * Copy the fio options into the long options map, so we mirror
1235 * job and cmd line options.
1236 */
1237static void dupe_job_options(void)
1238{
1239	struct fio_option *o;
1240	unsigned int i;
1241
1242	i = 0;
1243	while (long_options[i].name)
1244		i++;
1245
1246	o = &options[0];
1247	while (o->name) {
1248		long_options[i].name = o->name;
1249		long_options[i].val = FIO_GETOPT_JOB;
1250		if (o->type == FIO_OPT_STR_SET)
1251			long_options[i].has_arg = no_argument;
1252		else
1253			long_options[i].has_arg = required_argument;
1254
1255		i++;
1256		o++;
1257		assert(i < FIO_JOB_OPTS + FIO_CMD_OPTS);
1258	}
1259}
1260
1261int parse_options(int argc, char *argv[])
1262{
1263	int job_files, i;
1264
1265	f_out = stdout;
1266	f_err = stderr;
1267
1268	dupe_job_options();
1269
1270	if (setup_thread_area())
1271		return 1;
1272	if (fill_def_thread())
1273		return 1;
1274
1275	job_files = parse_cmd_line(argc, argv);
1276
1277	for (i = 0; i < job_files; i++) {
1278		if (fill_def_thread())
1279			return 1;
1280		if (parse_jobs_ini(ini_file[i], i))
1281			return 1;
1282		free(ini_file[i]);
1283	}
1284
1285	free(ini_file);
1286
1287	if (!thread_number) {
1288		log_err("No jobs defined(s)\n");
1289		return 1;
1290	}
1291
1292	return 0;
1293}
1294