init.c revision c3383b96a3d8dddd719a8d4d2888485edf9b3812
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 <sys/ipc.h>
13#include <sys/shm.h>
14#include <sys/types.h>
15#include <sys/stat.h>
16
17#include "fio.h"
18#include "parse.h"
19#include "smalloc.h"
20#include "filehash.h"
21
22static char fio_version_string[] = "fio 1.22";
23
24#define FIO_RANDSEED		(0xb1899bedUL)
25
26static char **ini_file;
27static int max_jobs = MAX_JOBS;
28static int dump_cmdline;
29
30struct thread_data def_thread;
31struct thread_data *threads = NULL;
32
33int exitall_on_terminate = 0;
34int terse_output = 0;
35int eta_print;
36unsigned long long mlock_size = 0;
37FILE *f_out = NULL;
38FILE *f_err = NULL;
39char *job_section = NULL;
40
41int write_bw_log = 0;
42int read_only = 0;
43
44static int def_timeout;
45static int write_lat_log;
46
47static int prev_group_jobs;
48
49unsigned long fio_debug = 0;
50unsigned int fio_debug_jobno = -1;
51unsigned int *fio_debug_jobp = NULL;
52
53/*
54 * Command line options. These will contain the above, plus a few
55 * extra that only pertain to fio itself and not jobs.
56 */
57static struct option l_opts[FIO_NR_OPTIONS] = {
58	{
59		.name		= "output",
60		.has_arg	= required_argument,
61		.val		= 'o',
62	},
63	{
64		.name		= "timeout",
65		.has_arg	= required_argument,
66		.val		= 't',
67	},
68	{
69		.name		= "latency-log",
70		.has_arg	= required_argument,
71		.val		= 'l',
72	},
73	{
74		.name		= "bandwidth-log",
75		.has_arg	= required_argument,
76		.val		= 'b',
77	},
78	{
79		.name		= "minimal",
80		.has_arg	= optional_argument,
81		.val		= 'm',
82	},
83	{
84		.name		= "version",
85		.has_arg	= no_argument,
86		.val		= 'v',
87	},
88	{
89		.name		= "help",
90		.has_arg	= no_argument,
91		.val		= 'h',
92	},
93	{
94		.name		= "cmdhelp",
95		.has_arg	= optional_argument,
96		.val		= 'c',
97	},
98	{
99		.name		= "showcmd",
100		.has_arg	= no_argument,
101		.val		= 's',
102	},
103	{
104		.name		= "readonly",
105		.has_arg	= no_argument,
106		.val		= 'r',
107	},
108	{
109		.name		= "eta",
110		.has_arg	= required_argument,
111		.val		= 'e',
112	},
113	{
114		.name		= "debug",
115		.has_arg	= required_argument,
116		.val		= 'd',
117	},
118	{
119		.name		= "section",
120		.has_arg	= required_argument,
121		.val		= 'x',
122	},
123	{
124		.name		= "alloc-size",
125		.has_arg	= required_argument,
126		.val		= 'a',
127	},
128	{
129		.name		= NULL,
130	},
131};
132
133FILE *get_f_out()
134{
135	return f_out;
136}
137
138FILE *get_f_err()
139{
140	return f_err;
141}
142
143/*
144 * Return a free job structure.
145 */
146static struct thread_data *get_new_job(int global, struct thread_data *parent)
147{
148	struct thread_data *td;
149
150	if (global)
151		return &def_thread;
152	if (thread_number >= max_jobs)
153		return NULL;
154
155	td = &threads[thread_number++];
156	*td = *parent;
157
158	dup_files(td, parent);
159	options_mem_dupe(td);
160
161	td->thread_number = thread_number;
162	return td;
163}
164
165static void put_job(struct thread_data *td)
166{
167	if (td == &def_thread)
168		return;
169
170	if (td->error)
171		log_info("fio: %s\n", td->verror);
172
173	memset(&threads[td->thread_number - 1], 0, sizeof(*td));
174	thread_number--;
175}
176
177static int setup_rate(struct thread_data *td)
178{
179	unsigned long nr_reads_per_msec;
180	unsigned long long rate;
181	unsigned int bs;
182
183	if (!td->o.rate && !td->o.rate_iops)
184		return 0;
185
186	if (td_rw(td))
187		bs = td->o.rw_min_bs;
188	else if (td_read(td))
189		bs = td->o.min_bs[DDIR_READ];
190	else
191		bs = td->o.min_bs[DDIR_WRITE];
192
193	if (td->o.rate) {
194		rate = td->o.rate;
195		nr_reads_per_msec = (rate * 1024 * 1000LL) / bs;
196	} else
197		nr_reads_per_msec = td->o.rate_iops * 1000UL;
198
199	if (!nr_reads_per_msec) {
200		log_err("rate lower than supported\n");
201		return -1;
202	}
203
204	td->rate_usec_cycle = 1000000000ULL / nr_reads_per_msec;
205	td->rate_pending_usleep = 0;
206	return 0;
207}
208
209/*
210 * Lazy way of fixing up options that depend on each other. We could also
211 * define option callback handlers, but this is easier.
212 */
213static int fixup_options(struct thread_data *td)
214{
215	struct thread_options *o = &td->o;
216
217	if (read_only && td_write(td)) {
218		log_err("fio: job <%s> has write bit set, but fio is in"
219			" read-only mode\n", td->o.name);
220		return 1;
221	}
222
223	if (o->write_iolog_file && o->read_iolog_file) {
224		log_err("fio: read iolog overrides write_iolog\n");
225		free(o->write_iolog_file);
226		o->write_iolog_file = NULL;
227	}
228
229	/*
230	 * only really works for sequential io for now, and with 1 file
231	 */
232	if (o->zone_size && td_random(td) && o->open_files == 1)
233		o->zone_size = 0;
234
235	/*
236	 * Reads can do overwrites, we always need to pre-create the file
237	 */
238	if (td_read(td) || td_rw(td))
239		o->overwrite = 1;
240
241	if (!o->min_bs[DDIR_READ])
242		o->min_bs[DDIR_READ] = o->bs[DDIR_READ];
243	if (!o->max_bs[DDIR_READ])
244		o->max_bs[DDIR_READ] = o->bs[DDIR_READ];
245	if (!o->min_bs[DDIR_WRITE])
246		o->min_bs[DDIR_WRITE] = o->bs[DDIR_WRITE];
247	if (!o->max_bs[DDIR_WRITE])
248		o->max_bs[DDIR_WRITE] = o->bs[DDIR_WRITE];
249
250	o->rw_min_bs = min(o->min_bs[DDIR_READ], o->min_bs[DDIR_WRITE]);
251
252	if (!o->file_size_high)
253		o->file_size_high = o->file_size_low;
254
255	if (o->norandommap && o->verify != VERIFY_NONE) {
256		log_err("fio: norandommap given, verify disabled\n");
257		o->verify = VERIFY_NONE;
258	}
259	if (o->bs_unaligned && (o->odirect || td->io_ops->flags & FIO_RAWIO))
260		log_err("fio: bs_unaligned may not work with raw io\n");
261
262	/*
263	 * thinktime_spin must be less than thinktime
264	 */
265	if (o->thinktime_spin > o->thinktime)
266		o->thinktime_spin = o->thinktime;
267
268	/*
269	 * The low water mark cannot be bigger than the iodepth
270	 */
271	if (o->iodepth_low > o->iodepth || !o->iodepth_low) {
272		/*
273		 * syslet work around - if the workload is sequential,
274		 * we want to let the queue drain all the way down to
275		 * avoid seeking between async threads
276		 */
277		if (!strcmp(td->io_ops->name, "syslet-rw") && !td_random(td))
278			o->iodepth_low = 1;
279		else
280			o->iodepth_low = o->iodepth;
281	}
282
283	/*
284	 * If batch number isn't set, default to the same as iodepth
285	 */
286	if (o->iodepth_batch > o->iodepth || !o->iodepth_batch)
287		o->iodepth_batch = o->iodepth;
288
289	if (o->nr_files > td->files_index)
290		o->nr_files = td->files_index;
291
292	if (o->open_files > o->nr_files || !o->open_files)
293		o->open_files = o->nr_files;
294
295	if ((o->rate && o->rate_iops) || (o->ratemin && o->rate_iops_min)) {
296		log_err("fio: rate and rate_iops are mutually exclusive\n");
297		return 1;
298	}
299	if ((o->rate < o->ratemin) || (o->rate_iops < o->rate_iops_min)) {
300		log_err("fio: minimum rate exceeds rate\n");
301		return 1;
302	}
303
304	if (!o->timeout && o->time_based) {
305		log_err("fio: time_based requires a runtime/timeout setting\n");
306		o->time_based = 0;
307	}
308
309	if (o->fill_device && !o->size)
310		o->size = -1ULL;
311
312	if (td_rw(td) && td->o.verify != VERIFY_NONE)
313		log_info("fio: mixed read/write workload with verify. May not "
314		 "work as expected, unless you pre-populated the file\n");
315
316	if (td->o.verify != VERIFY_NONE)
317		td->o.refill_buffers = 1;
318
319	return 0;
320}
321
322/*
323 * This function leaks the buffer
324 */
325static char *to_kmg(unsigned int val)
326{
327	char *buf = malloc(32);
328	char post[] = { 0, 'K', 'M', 'G', 'P', 'E', 0 };
329	char *p = post;
330
331	do {
332		if (val & 1023)
333			break;
334
335		val >>= 10;
336		p++;
337	} while (*p);
338
339	snprintf(buf, 31, "%u%c", val, *p);
340	return buf;
341}
342
343/* External engines are specified by "external:name.o") */
344static const char *get_engine_name(const char *str)
345{
346	char *p = strstr(str, ":");
347
348	if (!p)
349		return str;
350
351	p++;
352	strip_blank_front(&p);
353	strip_blank_end(p);
354	return p;
355}
356
357static int exists_and_not_file(const char *filename)
358{
359	struct stat sb;
360
361	if (lstat(filename, &sb) == -1)
362		return 0;
363
364	if (S_ISREG(sb.st_mode))
365		return 0;
366
367	return 1;
368}
369
370/*
371 * Initialize the various random states we need (random io, block size ranges,
372 * read/write mix, etc).
373 */
374static int init_random_state(struct thread_data *td)
375{
376	unsigned long seeds[6];
377	int fd;
378
379	fd = open("/dev/urandom", O_RDONLY);
380	if (fd == -1) {
381		td_verror(td, errno, "open");
382		return 1;
383	}
384
385	if (read(fd, seeds, sizeof(seeds)) < (int) sizeof(seeds)) {
386		td_verror(td, EIO, "read");
387		close(fd);
388		return 1;
389	}
390
391	close(fd);
392
393	os_random_seed(seeds[0], &td->bsrange_state);
394	os_random_seed(seeds[1], &td->verify_state);
395	os_random_seed(seeds[2], &td->rwmix_state);
396
397	if (td->o.file_service_type == FIO_FSERVICE_RANDOM)
398		os_random_seed(seeds[3], &td->next_file_state);
399
400	os_random_seed(seeds[5], &td->file_size_state);
401
402	if (!td_random(td))
403		return 0;
404
405	if (td->o.rand_repeatable)
406		seeds[4] = FIO_RANDSEED * td->thread_number;
407
408	os_random_seed(seeds[4], &td->random_state);
409	return 0;
410}
411
412/*
413 * Adds a job to the list of things todo. Sanitizes the various options
414 * to make sure we don't have conflicts, and initializes various
415 * members of td.
416 */
417static int add_job(struct thread_data *td, const char *jobname, int job_add_num)
418{
419	const char *ddir_str[] = { NULL, "read", "write", "rw", NULL,
420				   "randread", "randwrite", "randrw" };
421	unsigned int i;
422	const char *engine;
423	char fname[PATH_MAX];
424	int numjobs, file_alloced;
425
426	/*
427	 * the def_thread is just for options, it's not a real job
428	 */
429	if (td == &def_thread)
430		return 0;
431
432	/*
433	 * if we are just dumping the output command line, don't add the job
434	 */
435	if (dump_cmdline) {
436		put_job(td);
437		return 0;
438	}
439
440	engine = get_engine_name(td->o.ioengine);
441	td->io_ops = load_ioengine(td, engine);
442	if (!td->io_ops) {
443		log_err("fio: failed to load engine %s\n", engine);
444		goto err;
445	}
446
447	if (td->o.use_thread)
448		nr_thread++;
449	else
450		nr_process++;
451
452	if (td->o.odirect)
453		td->io_ops->flags |= FIO_RAWIO;
454
455	file_alloced = 0;
456	if (!td->o.filename && !td->files_index && !td->o.read_iolog_file) {
457		file_alloced = 1;
458
459		if (td->o.nr_files == 1 && exists_and_not_file(jobname))
460			add_file(td, jobname);
461		else {
462			for (i = 0; i < td->o.nr_files; i++) {
463				sprintf(fname, "%s.%d.%d", jobname,
464							td->thread_number, i);
465				add_file(td, fname);
466			}
467		}
468	}
469
470	if (fixup_options(td))
471		goto err;
472
473	if (td->io_ops->flags & FIO_DISKLESSIO) {
474		struct fio_file *f;
475
476		for_each_file(td, f, i)
477			f->real_file_size = -1ULL;
478	}
479
480	td->mutex = fio_mutex_init(0);
481
482	td->ts.clat_stat[0].min_val = td->ts.clat_stat[1].min_val = ULONG_MAX;
483	td->ts.slat_stat[0].min_val = td->ts.slat_stat[1].min_val = ULONG_MAX;
484	td->ts.bw_stat[0].min_val = td->ts.bw_stat[1].min_val = ULONG_MAX;
485	td->ddir_nr = td->o.ddir_nr;
486
487	if ((td->o.stonewall || td->o.numjobs > 1 || td->o.new_group)
488	     && prev_group_jobs) {
489		prev_group_jobs = 0;
490		groupid++;
491	}
492
493	td->groupid = groupid;
494	prev_group_jobs++;
495
496	if (init_random_state(td))
497		goto err;
498
499	if (setup_rate(td))
500		goto err;
501
502	if (td->o.write_lat_log) {
503		setup_log(&td->ts.slat_log);
504		setup_log(&td->ts.clat_log);
505	}
506	if (td->o.write_bw_log)
507		setup_log(&td->ts.bw_log);
508
509	if (!td->o.name)
510		td->o.name = strdup(jobname);
511
512	if (!terse_output) {
513		if (!job_add_num) {
514			if (!strcmp(td->io_ops->name, "cpuio")) {
515				log_info("%s: ioengine=cpu, cpuload=%u,"
516					 " cpucycle=%u\n", td->o.name,
517							td->o.cpuload,
518							td->o.cpucycle);
519			} else {
520				char *c1, *c2, *c3, *c4;
521
522				c1 = to_kmg(td->o.min_bs[DDIR_READ]);
523				c2 = to_kmg(td->o.max_bs[DDIR_READ]);
524				c3 = to_kmg(td->o.min_bs[DDIR_WRITE]);
525				c4 = to_kmg(td->o.max_bs[DDIR_WRITE]);
526
527				log_info("%s: (g=%d): rw=%s, bs=%s-%s/%s-%s,"
528					 " ioengine=%s, iodepth=%u\n",
529						td->o.name, td->groupid,
530						ddir_str[td->o.td_ddir],
531						c1, c2, c3, c4,
532						td->io_ops->name,
533						td->o.iodepth);
534
535				free(c1);
536				free(c2);
537				free(c3);
538				free(c4);
539			}
540		} else if (job_add_num == 1)
541			log_info("...\n");
542	}
543
544	/*
545	 * recurse add identical jobs, clear numjobs and stonewall options
546	 * as they don't apply to sub-jobs
547	 */
548	numjobs = td->o.numjobs;
549	while (--numjobs) {
550		struct thread_data *td_new = get_new_job(0, td);
551
552		if (!td_new)
553			goto err;
554
555		td_new->o.numjobs = 1;
556		td_new->o.stonewall = 0;
557		td_new->o.new_group = 0;
558
559		if (file_alloced) {
560			td_new->o.filename = NULL;
561			td_new->files_index = 0;
562			td_new->files = NULL;
563		}
564
565		job_add_num = numjobs - 1;
566
567		if (add_job(td_new, jobname, job_add_num))
568			goto err;
569	}
570
571	return 0;
572err:
573	put_job(td);
574	return -1;
575}
576
577static int skip_this_section(const char *name)
578{
579	if (!job_section)
580		return 0;
581	if (!strncmp(name, "global", 6))
582		return 0;
583
584	return strncmp(job_section, name, strlen(job_section));
585}
586
587static int is_empty_or_comment(char *line)
588{
589	unsigned int i;
590
591	for (i = 0; i < strlen(line); i++) {
592		if (line[i] == ';')
593			return 1;
594		if (line[i] == '#')
595			return 1;
596		if (!isspace(line[i]) && !iscntrl(line[i]))
597			return 0;
598	}
599
600	return 1;
601}
602
603/*
604 * This is our [ini] type file parser.
605 */
606static int parse_jobs_ini(char *file, int stonewall_flag)
607{
608	unsigned int global;
609	struct thread_data *td;
610	char *string, *name;
611	FILE *f;
612	char *p;
613	int ret = 0, stonewall;
614	int first_sect = 1;
615	int skip_fgets = 0;
616	int inside_skip = 0;
617	char **opts;
618	int i, alloc_opts, num_opts;
619
620	if (!strcmp(file, "-"))
621		f = stdin;
622	else
623		f = fopen(file, "r");
624
625	if (!f) {
626		perror("fopen job file");
627		return 1;
628	}
629
630	string = malloc(4096);
631
632	/*
633	 * it's really 256 + small bit, 280 should suffice
634	 */
635	name = malloc(280);
636	memset(name, 0, 280);
637
638	alloc_opts = 8;
639	opts = malloc(sizeof(char *) * alloc_opts);
640	num_opts = 0;
641
642	stonewall = stonewall_flag;
643	do {
644		/*
645		 * if skip_fgets is set, we already have loaded a line we
646		 * haven't handled.
647		 */
648		if (!skip_fgets) {
649			p = fgets(string, 4095, f);
650			if (!p)
651				break;
652		}
653
654		skip_fgets = 0;
655		strip_blank_front(&p);
656		strip_blank_end(p);
657
658		if (is_empty_or_comment(p))
659			continue;
660		if (sscanf(p, "[%255s]", name) != 1) {
661			if (inside_skip)
662				continue;
663			log_err("fio: option <%s> outside of [] job section\n",
664									p);
665			break;
666		}
667
668		if (skip_this_section(name)) {
669			inside_skip = 1;
670			continue;
671		} else
672			inside_skip = 0;
673
674		global = !strncmp(name, "global", 6);
675
676		name[strlen(name) - 1] = '\0';
677
678		if (dump_cmdline) {
679			if (first_sect)
680				log_info("fio ");
681			if (!global)
682				log_info("--name=%s ", name);
683			first_sect = 0;
684		}
685
686		td = get_new_job(global, &def_thread);
687		if (!td) {
688			ret = 1;
689			break;
690		}
691
692		/*
693		 * Seperate multiple job files by a stonewall
694		 */
695		if (!global && stonewall) {
696			td->o.stonewall = stonewall;
697			stonewall = 0;
698		}
699
700		num_opts = 0;
701		memset(opts, 0, alloc_opts * sizeof(char *));
702
703		while ((p = fgets(string, 4096, f)) != NULL) {
704			if (is_empty_or_comment(p))
705				continue;
706
707			strip_blank_front(&p);
708
709			/*
710			 * new section, break out and make sure we don't
711			 * fgets() a new line at the top.
712			 */
713			if (p[0] == '[') {
714				skip_fgets = 1;
715				break;
716			}
717
718			strip_blank_end(p);
719
720			if (num_opts == alloc_opts) {
721				alloc_opts <<= 1;
722				opts = realloc(opts,
723						alloc_opts * sizeof(char *));
724			}
725
726			opts[num_opts] = strdup(p);
727			num_opts++;
728		}
729
730		ret = fio_options_parse(td, opts, num_opts);
731		if (!ret) {
732			if (dump_cmdline)
733				for (i = 0; i < num_opts; i++)
734					log_info("--%s ", opts[i]);
735
736			ret = add_job(td, name, 0);
737		} else {
738			log_err("fio: job %s dropped\n", name);
739			put_job(td);
740		}
741
742		for (i = 0; i < num_opts; i++)
743			free(opts[i]);
744		num_opts = 0;
745	} while (!ret);
746
747	if (dump_cmdline)
748		log_info("\n");
749
750	for (i = 0; i < num_opts; i++)
751		free(opts[i]);
752
753	free(string);
754	free(name);
755	free(opts);
756	if (f != stdin)
757		fclose(f);
758	return ret;
759}
760
761static int fill_def_thread(void)
762{
763	memset(&def_thread, 0, sizeof(def_thread));
764
765	fio_getaffinity(getpid(), &def_thread.o.cpumask);
766
767	/*
768	 * fill default options
769	 */
770	fio_fill_default_options(&def_thread);
771
772	def_thread.o.timeout = def_timeout;
773	def_thread.o.write_bw_log = write_bw_log;
774	def_thread.o.write_lat_log = write_lat_log;
775
776	return 0;
777}
778
779static void free_shm(void)
780{
781	struct shmid_ds sbuf;
782
783	if (threads) {
784		void *tp = threads;
785
786		threads = NULL;
787		file_hash_exit();
788		fio_debug_jobp = NULL;
789		shmdt(tp);
790		shmctl(shm_id, IPC_RMID, &sbuf);
791	}
792
793	scleanup();
794}
795
796/*
797 * The thread area is shared between the main process and the job
798 * threads/processes. So setup a shared memory segment that will hold
799 * all the job info. We use the end of the region for keeping track of
800 * open files across jobs, for file sharing.
801 */
802static int setup_thread_area(void)
803{
804	void *hash;
805
806	/*
807	 * 1024 is too much on some machines, scale max_jobs if
808	 * we get a failure that looks like too large a shm segment
809	 */
810	do {
811		size_t size = max_jobs * sizeof(struct thread_data);
812
813		size += file_hash_size;
814		size += sizeof(unsigned int);
815
816		shm_id = shmget(0, size, IPC_CREAT | 0600);
817		if (shm_id != -1)
818			break;
819		if (errno != EINVAL) {
820			perror("shmget");
821			break;
822		}
823
824		max_jobs >>= 1;
825	} while (max_jobs);
826
827	if (shm_id == -1)
828		return 1;
829
830	threads = shmat(shm_id, NULL, 0);
831	if (threads == (void *) -1) {
832		perror("shmat");
833		return 1;
834	}
835
836	memset(threads, 0, max_jobs * sizeof(struct thread_data));
837	hash = (void *) threads + max_jobs * sizeof(struct thread_data);
838	fio_debug_jobp = (void *) hash + file_hash_size;
839	*fio_debug_jobp = -1;
840	file_hash_init(hash);
841	atexit(free_shm);
842	return 0;
843}
844
845static void usage(const char *name)
846{
847	printf("%s\n", fio_version_string);
848	printf("%s [options] [job options] <job file(s)>\n", name);
849	printf("\t--debug=options\tEnable debug logging\n");
850	printf("\t--output\tWrite output to file\n");
851	printf("\t--timeout\tRuntime in seconds\n");
852	printf("\t--latency-log\tGenerate per-job latency logs\n");
853	printf("\t--bandwidth-log\tGenerate per-job bandwidth logs\n");
854	printf("\t--minimal\tMinimal (terse) output\n");
855	printf("\t--version\tPrint version info and exit\n");
856	printf("\t--help\t\tPrint this page\n");
857	printf("\t--cmdhelp=cmd\tPrint command help, \"all\" for all of"
858		" them\n");
859	printf("\t--showcmd\tTurn a job file into command line options\n");
860	printf("\t--eta=when\tWhen ETA estimate should be printed\n");
861	printf("\t          \tMay be \"always\", \"never\" or \"auto\"\n");
862	printf("\t--readonly\tTurn on safety read-only checks, preventing"
863		" writes\n");
864	printf("\t--section=name\tOnly run specified section in job file\n");
865	printf("\t--alloc-size=kb\tSet smalloc pool to this size in kb"
866		" (def 1024)\n");
867}
868
869#ifdef FIO_INC_DEBUG
870struct debug_level debug_levels[] = {
871	{ .name = "process",	.shift = FD_PROCESS, },
872	{ .name = "file",	.shift = FD_FILE, },
873	{ .name = "io",		.shift = FD_IO, },
874	{ .name = "mem",	.shift = FD_MEM, },
875	{ .name = "blktrace",	.shift = FD_BLKTRACE },
876	{ .name = "verify",	.shift = FD_VERIFY },
877	{ .name = "random",	.shift = FD_RANDOM },
878	{ .name = "parse",	.shift = FD_PARSE },
879	{ .name = "diskutil",	.shift = FD_DISKUTIL },
880	{ .name = "job",	.shift = FD_JOB },
881	{ .name = NULL, },
882};
883
884static int set_debug(const char *string)
885{
886	struct debug_level *dl;
887	char *p = (char *) string;
888	char *opt;
889	int i;
890
891	if (!strcmp(string, "?") || !strcmp(string, "help")) {
892		int i;
893
894		log_info("fio: dumping debug options:");
895		for (i = 0; debug_levels[i].name; i++) {
896			dl = &debug_levels[i];
897			log_info("%s,", dl->name);
898		}
899		log_info("all\n");
900		return 1;
901	}
902
903	while ((opt = strsep(&p, ",")) != NULL) {
904		int found = 0;
905
906		if (!strncmp(opt, "all", 3)) {
907			log_info("fio: set all debug options\n");
908			fio_debug = ~0UL;
909			continue;
910		}
911
912		for (i = 0; debug_levels[i].name; i++) {
913			dl = &debug_levels[i];
914			found = !strncmp(opt, dl->name, strlen(dl->name));
915			if (!found)
916				continue;
917
918			if (dl->shift == FD_JOB) {
919				opt = strchr(opt, ':');
920				if (!opt) {
921					log_err("fio: missing job number\n");
922					break;
923				}
924				opt++;
925				fio_debug_jobno = atoi(opt);
926				log_info("fio: set debug jobno %d\n",
927							fio_debug_jobno);
928			} else {
929				log_info("fio: set debug option %s\n", opt);
930				fio_debug |= (1UL << dl->shift);
931			}
932			break;
933		}
934
935		if (!found)
936			log_err("fio: debug mask %s not found\n", opt);
937	}
938	return 0;
939}
940#else
941static int set_debug(const char *string)
942{
943	log_err("fio: debug tracing not included in build\n");
944	return 1;
945}
946#endif
947
948static int parse_cmd_line(int argc, char *argv[])
949{
950	struct thread_data *td = NULL;
951	int c, ini_idx = 0, lidx, ret = 0, do_exit = 0, exit_val = 0;
952
953	while ((c = getopt_long_only(argc, argv, "", l_opts, &lidx)) != -1) {
954		switch (c) {
955		case 'a':
956			smalloc_pool_size = atoi(optarg);
957			break;
958		case 't':
959			def_timeout = atoi(optarg);
960			break;
961		case 'l':
962			write_lat_log = 1;
963			break;
964		case 'w':
965			write_bw_log = 1;
966			break;
967		case 'o':
968			f_out = fopen(optarg, "w+");
969			if (!f_out) {
970				perror("fopen output");
971				exit(1);
972			}
973			f_err = f_out;
974			break;
975		case 'm':
976			terse_output = 1;
977			break;
978		case 'h':
979			usage(argv[0]);
980			exit(0);
981		case 'c':
982			exit(fio_show_option_help(optarg));
983		case 's':
984			dump_cmdline = 1;
985			break;
986		case 'r':
987			read_only = 1;
988			break;
989		case 'v':
990			printf("%s\n", fio_version_string);
991			exit(0);
992		case 'e':
993			if (!strcmp("always", optarg))
994				eta_print = FIO_ETA_ALWAYS;
995			else if (!strcmp("never", optarg))
996				eta_print = FIO_ETA_NEVER;
997			break;
998		case 'd':
999			if (set_debug(optarg))
1000				do_exit++;
1001			break;
1002		case 'x':
1003			if (!strcmp(optarg, "global")) {
1004				log_err("fio: can't use global as only "
1005					"section\n");
1006				do_exit++;
1007				exit_val = 1;
1008				break;
1009			}
1010			if (job_section)
1011				free(job_section);
1012			job_section = strdup(optarg);
1013			break;
1014		case FIO_GETOPT_JOB: {
1015			const char *opt = l_opts[lidx].name;
1016			char *val = optarg;
1017
1018			if (!strncmp(opt, "name", 4) && td) {
1019				ret = add_job(td, td->o.name ?: "fio", 0);
1020				if (ret) {
1021					put_job(td);
1022					return 0;
1023				}
1024				td = NULL;
1025			}
1026			if (!td) {
1027				int is_section = !strncmp(opt, "name", 4);
1028				int global = 0;
1029
1030				if (!is_section || !strncmp(val, "global", 6))
1031					global = 1;
1032
1033				if (is_section && skip_this_section(val))
1034					continue;
1035
1036				td = get_new_job(global, &def_thread);
1037				if (!td)
1038					return 0;
1039			}
1040
1041			ret = fio_cmd_option_parse(td, opt, val);
1042			break;
1043		}
1044		default:
1045			do_exit++;
1046			exit_val = 1;
1047			break;
1048		}
1049	}
1050
1051	if (do_exit)
1052		exit(exit_val);
1053
1054	if (td) {
1055		if (!ret)
1056			ret = add_job(td, td->o.name ?: "fio", 0);
1057		if (ret)
1058			put_job(td);
1059	}
1060
1061	while (optind < argc) {
1062		ini_idx++;
1063		ini_file = realloc(ini_file, ini_idx * sizeof(char *));
1064		ini_file[ini_idx - 1] = strdup(argv[optind]);
1065		optind++;
1066	}
1067
1068	return ini_idx;
1069}
1070
1071int parse_options(int argc, char *argv[])
1072{
1073	int job_files, i;
1074
1075	f_out = stdout;
1076	f_err = stderr;
1077
1078	fio_options_dup_and_init(l_opts);
1079
1080	if (setup_thread_area())
1081		return 1;
1082	if (fill_def_thread())
1083		return 1;
1084
1085	job_files = parse_cmd_line(argc, argv);
1086
1087	for (i = 0; i < job_files; i++) {
1088		if (fill_def_thread())
1089			return 1;
1090		if (parse_jobs_ini(ini_file[i], i))
1091			return 1;
1092		free(ini_file[i]);
1093	}
1094
1095	free(ini_file);
1096	options_mem_free(&def_thread);
1097
1098	if (!thread_number) {
1099		if (dump_cmdline)
1100			return 0;
1101
1102		log_err("No jobs defined(s)\n");
1103		usage(argv[0]);
1104		return 1;
1105	}
1106
1107	return 0;
1108}
1109