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