[PATCH] fio: add support for ini file job descriptions
authorJens Axboe <axboe@suse.de>
Tue, 18 Oct 2005 09:37:36 +0000 (11:37 +0200)
committerJens Axboe <axboe@suse.de>
Tue, 18 Oct 2005 09:37:36 +0000 (11:37 +0200)
The cmd line options are a little screwy to use, so add support
for defining the wanted jobs in a config file.

README.fio
fio.c

index 0b95e2c24c69ade5e47141328ca1ea2cc3d936a1..1bd93afb0c3bd01e58921fe8357da8be8e6184b4 100644 (file)
@@ -16,6 +16,7 @@ $ fio
        -w Write statistics
        -r For random io, sequence must be repeatable
        -o <on> Use direct IO is 1, buffered if 0
+       -f <file> Read <file> for job descriptions
 
        <jobs>
 
@@ -33,8 +34,8 @@ The <jobs> format is as follows:
        rate=x          Throttle rate to x KiB/sec
 
 
-Examples
---------
+Examples using cmd line jobs
+----------------------------
 
 Spawn 2 threads, one read and one writer. Both threads want direct and
 sequential io, set these as global options. The reader wants a 4kb block
@@ -48,3 +49,39 @@ size.
 
 $ fio -o0 -s -b4096 "{rw=0,file=rf1,prio=6}" "{rw=0,file=rf2,prio=3}" "{rw=0,file=rf3,prio=0,direct=1}"
 
+Examples using a job file
+-------------------------
+
+A sample job file doing the same as above would look like this:
+
+[read_file]
+rw=0
+bs=4096
+
+[write_file]
+rw=1
+bs=16384
+
+And fio would be invoked as:
+
+$ fio -o1 -s -f file_with_above
+
+The second example would look like this:
+
+[rf1]
+rw=0
+prio=6
+
+[rf2]
+rw=0
+prio=3
+
+[rf3]
+rw=0
+prio=0
+direct=1
+
+And fio would be invoked as:
+
+$ fio -o0 -s -b4096 -f file_with_above
+
diff --git a/fio.c b/fio.c
index a7a9ec80209fbe91acf1d93e17e89f1176c624cd..685c64a262ad6491c60bc3401994afe143f92350 100644 (file)
--- a/fio.c
+++ b/fio.c
@@ -26,6 +26,7 @@
 #include <errno.h>
 #include <signal.h>
 #include <time.h>
+#include <ctype.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -91,6 +92,7 @@ static int thread_number;
 static int timeout = TIMEOUT;
 static int odirect = 1;
 static int global_bs = BS;
+static char *ini_file;
 
 static int shm_id;
 
@@ -112,9 +114,9 @@ struct thread_data {
        int odirect;
        int delay_sleep;
 
-       int rate;
-       int rate_usec_cycle;
-       int rate_pending_usleep;
+       unsigned int rate;
+       unsigned int rate_usec_cycle;
+       unsigned int rate_pending_usleep;
 
        unsigned long max_latency;      /* msec */
        unsigned long min_latency;      /* msec */
@@ -164,7 +166,7 @@ int init_random_state(struct thread_data *td)
                        return 1;
                }
 
-               if (read(fd, &seed, sizeof(seed)) < sizeof(seed)) {
+               if (read(fd, &seed, sizeof(seed)) < (int) sizeof(seed)) {
                        td->error = EIO;
                        close(fd);
                        return 1;
@@ -272,7 +274,7 @@ unsigned long get_next_offset(struct thread_data *td)
        return b * td->bs;
 }
 
-void add_stat_sample(struct thread_data *td, unsigned long block, unsigned long msec)
+void add_stat_sample(struct thread_data *td, unsigned long msec)
 {
        char sample[256];
 
@@ -381,7 +383,7 @@ void do_thread_io(struct thread_data *td)
                if (td->rate)
                        rate_throttle(td, usec);
 
-               add_stat_sample(td, offset / td->bs, msec);
+               add_stat_sample(td, msec);
 
                td->blocks_read++;
 
@@ -419,15 +421,15 @@ void *thread_main(int shm_id, int offset, char *argv[])
 
        sprintf(argv[0], "%s%d\n", argv[0], offset);
 
-       if (td->ddir == DDIR_READ)
-               flags = O_RDONLY;
-       else
-               flags = O_WRONLY | O_CREAT | O_TRUNC;
-
+       flags = 0;
        if (td->odirect)
                flags |= O_DIRECT;
 
-       td->fd = open(td->file_name, flags);
+       if (td->ddir == DDIR_READ)
+               td->fd = open(td->file_name, flags | O_RDONLY);
+       else
+               td->fd = open(td->file_name, flags | O_WRONLY | O_CREAT | O_TRUNC, 0644);
+
        if (td->fd == -1) {
                td->error = errno;
                goto err;
@@ -530,6 +532,8 @@ void add_job(const char *filename, int rw, int bs, int direct, int prio, int ran
 
        if (rate)
                setup_rate(td, rate);
+
+       printf("Client%d: file=%s, rw=%d, prio=%d, seq=%d, odir=%d, bs=%d, rate=%d\n", thread_number, filename, rw, prio, !random, direct, bs, rate);
 }
 
 void fill_option(const char *input, char *output)
@@ -553,7 +557,7 @@ void fill_option(const char *input, char *output)
  * rw=
  * direct=
  */
-int parse_jobs(int argc, char *argv[], int index)
+int parse_jobs_cmd(int argc, char *argv[], int index)
 {
        int rw, bs, direct, prio, random, prioclass, delay, rate;
        char *string, *filename, *p, *c;
@@ -647,9 +651,126 @@ int parse_jobs(int argc, char *argv[], int index)
                add_job(filename, rw, bs, direct, (prioclass << IOPRIO_CLASS_SHIFT) | prio, random, delay, rate);
        }
 
+       free(string);
+       free(filename);
        return thread_number;
 }
 
+int check_int(char *p, char *name, int *val)
+{
+       char str[128];
+
+       sprintf(str, "%s=%%d", name);
+       if (sscanf(p, str, val) == 1)
+               return 0;
+
+       sprintf(str, "%s = %%d", name);
+       if (sscanf(p, str, val) == 1)
+               return 0;
+
+       return 1;
+}
+
+int is_empty(char *line)
+{
+       unsigned int i;
+
+       for (i = 0; i < strlen(line); i++)
+               if (!isspace(line[i]) && !iscntrl(line[i]))
+                       return 0;
+
+       return 1;
+}
+
+int parse_jobs_ini(char *file)
+{
+       int rw, bs, direct, prio, random, prioclass, delay, rate, jobs;
+       char *string, *name;
+       fpos_t off;
+       FILE *f;
+       char *p;
+
+       f = fopen(file, "r");
+       if (!f) {
+               perror("fopen");
+               return 0;
+       }
+
+       string = malloc(4096);
+       name = malloc(256);
+
+       jobs = 0;
+
+       while ((p = fgets(string, 4096, f)) != NULL) {
+               if (sscanf(p, "[%s]", name) != 1)
+                       continue;
+
+               name[strlen(name) - 1] = '\0';
+
+               rw = DDIR_READ;
+               bs = global_bs;
+               direct = 1;
+               prio = 4;
+               random = !sequential;
+               prioclass = 2;
+               delay = 0;
+               rate = 0;
+
+               fgetpos(f, &off);
+               while ((p = fgets(string, 4096, f)) != NULL) {
+                       if (is_empty(p))
+                               break;
+                       if (!check_int(p, "bs", &bs)) {
+                               bs <<= 10;
+                               fgetpos(f, &off);
+                               continue;
+                       }
+                       if (!check_int(p, "rw", &rw)) {
+                               fgetpos(f, &off);
+                               continue;
+                       }
+                       if (!check_int(p, "prio", &prio)) {
+                               fgetpos(f, &off);
+                               continue;
+                       }
+                       if (!check_int(p, "prioclass", &prioclass)) {
+                               fgetpos(f, &off);
+                               continue;
+                       }
+                       if (!check_int(p, "direct", &direct)) {
+                               fgetpos(f, &off);
+                               continue;
+                       }
+                       if (!check_int(p, "rate", &rate)) {
+                               fgetpos(f, &off);
+                               continue;
+                       }
+                       if (!check_int(p, "delay", &delay)) {
+                               fgetpos(f, &off);
+                               continue;
+                       }
+                       if (!strcmp(p, "sequential")) {
+                               sequential = 1;
+                               fgetpos(f, &off);
+                               continue;
+                       }
+                       if (!strcmp(p, "random")) {
+                               sequential = 0;
+                               fgetpos(f, &off);
+                               continue;
+                       }
+               }
+               fsetpos(f, &off);
+
+               add_job(name, rw, bs, direct, (prioclass << IOPRIO_CLASS_SHIFT) | prio, random, delay, rate);
+               jobs++;
+       }
+
+       free(string);
+       free(name);
+       return jobs;
+}
+
 int parse_options(int argc, char *argv[])
 {
        int i;
@@ -687,18 +808,19 @@ int parse_options(int argc, char *argv[])
                                parm++;
                                odirect = !!atoi(parm);
                                break;
+                       case 'f':
+                               if (i + 1 >= argc) {
+                                       printf("-f needs file as arg\n");
+                                       break;
+                               }
+                               ini_file = strdup(argv[i+1]);
+                               break;
                        default:
-                               printf("bad option %s\n", argv[1]);
+                               printf("bad option %s\n", argv[i]);
                                break;
                }
        }
 
-       if (global_bs <= 0)
-               global_bs = BS;
-       if (timeout <= 0)
-               timeout = TIMEOUT;
-
-       printf("%s: %s, bs=%uKiB, timeo=%u, write_stat=%u, odirect=%d\n", argv[0], sequential ? "sequential" : "random", global_bs >> 10, timeout, write_stat, odirect);
        return i;
 }
 
@@ -724,12 +846,24 @@ int main(int argc, char *argv[])
        atexit(free_shm);
 
        i = parse_options(argc, argv);
-       jobs = parse_jobs(argc, argv, i);
-       
+
+       if (ini_file)
+               jobs = parse_jobs_ini(ini_file);
+       else
+               jobs = parse_jobs_cmd(argc, argv, i);
+
+       if (global_bs <= 0)
+               global_bs = BS;
+       if (timeout <= 0)
+               timeout = TIMEOUT;
+
+       printf("%s: %s, bs=%uKiB, timeo=%u, write_stat=%u, odirect=%d\n", argv[0], sequential ? "sequential" : "random", global_bs >> 10, timeout, write_stat, odirect);
+
        if (!jobs) {
                printf("Nothing to do\n");
                return 1;
-       }
+       } else
+               printf("%d Clients configured\n", jobs);
 
        for (i = 0; i < jobs; i++) {
                sem_init(&startup_sem, 1, 1);
@@ -771,7 +905,7 @@ int main(int argc, char *argv[])
                unsigned long bw = 0;
 
                if (td->error)
-                       continue;
+                       goto show_stat;
 
                if (td->runtime < min_run[td->ddir])
                        min_run[td->ddir] = td->runtime;
@@ -802,6 +936,7 @@ int main(int argc, char *argv[])
                                write_agg += (td->blocks_read * td->bs) / td->runtime;
                }
 
+show_stat:
                show_thread_status(td);
        }