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