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