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