[PATCH] fio: add rate=x option for the jobs
authorJens Axboe <axboe@suse.de>
Fri, 14 Oct 2005 08:32:42 +0000 (10:32 +0200)
committerJens Axboe <axboe@suse.de>
Fri, 14 Oct 2005 08:32:42 +0000 (10:32 +0200)
Allows you to define a specific rate that the thread will attempt
to satisfy.

README.fio
fio.c

index 2edc567ebbdc5833b49a87667c528dc260c36e3b..0b95e2c24c69ade5e47141328ca1ea2cc3d936a1 100644 (file)
@@ -11,7 +11,7 @@ Options
 
 $ fio
        -s IO is sequential
-       -b block size in bytes for each io
+       -b block size in KiB for each io
        -t <sec> Runtime in seconds
        -w Write statistics
        -r For random io, sequence must be repeatable
@@ -25,11 +25,12 @@ The <jobs> format is as follows:
        prio=x          Run io at prio X, 0-7 is the kernel allowed range
        prioclass=x     Run io at prio class X
        file=foo        Do the io to file foo
-       bs=x            Thread blocksize is x bytes
+       bs=x            Thread blocksize is x KiB
        direct=x        1 for direct IO, 0 for buffered IO
        delay=x         Delay x useconds before each io
        random          IO is randomized
        sequential      IO is sequential
+       rate=x          Throttle rate to x KiB/sec
 
 
 Examples
diff --git a/fio.c b/fio.c
index a85eecdd254cb94048cdcdcc7df1fd2f753434fa..998a9fc059ab77c22faa4d0110566883b6386b3f 100644 (file)
--- a/fio.c
+++ b/fio.c
@@ -112,6 +112,11 @@ struct thread_data {
        int bs;
        int odirect;
        int delay_sleep;
+
+       int rate;
+       int rate_usec_cycle;
+       int rate_pending_usleep;
+
        unsigned long max_latency;      /* msec */
        unsigned long min_latency;      /* msec */
        unsigned long runtime;          /* sec */
@@ -295,27 +300,39 @@ void add_stat_sample(struct thread_data *td, unsigned long block, unsigned long
 #endif
 }
 
-void delay_sleep(int usec)
+void usec_sleep(int usec)
 {
-       unsigned long since;
-       struct timeval start, end;
-
-       gettimeofday(&start, NULL);
+       struct timespec req = { .tv_sec = 0, .tv_nsec = usec * 1000 };
+       struct timespec rem;
 
        do {
-               gettimeofday(&end, NULL);
-
-               since = utime_since(&start, &end);
-               if (since >= usec)
+               rem.tv_sec = rem.tv_nsec = 0;
+               nanosleep(&req, &rem);
+               if (!rem.tv_nsec)
                        break;
+
+               req.tv_nsec = rem.tv_nsec;
        } while (1);
 }
 
+void rate_throttle(struct thread_data *td, unsigned long time_spent)
+{
+       if (time_spent < td->rate_usec_cycle) {
+               unsigned long s = td->rate_usec_cycle - time_spent;
+
+               td->rate_pending_usleep += s;
+               if (td->rate_pending_usleep >= 250000) {
+                       usec_sleep(td->rate_pending_usleep);
+                       td->rate_pending_usleep = 0;
+               }
+       }
+}
+
 void do_thread_io(struct thread_data *td)
 {
        struct timeval s, e, start;
        char *buffer, *ptr;
-       unsigned long blocks, msec;
+       unsigned long blocks, msec, usec;
 
        ptr = malloc(td->bs+MASK);
        buffer = (char *) ALIGN(ptr);
@@ -335,7 +352,7 @@ void do_thread_io(struct thread_data *td)
                }
 
                if (td->delay_sleep)
-                       delay_sleep(td->delay_sleep);
+                       usec_sleep(td->delay_sleep);
 
                gettimeofday(&s, NULL);
 
@@ -344,15 +361,19 @@ void do_thread_io(struct thread_data *td)
                else
                        ret = write(td->fd, buffer, td->bs);
 
-               gettimeofday(&e, NULL);
-
                if (ret < td->bs) {
                        if (ret == -1)
                                td->error = errno;
                        break;
                }
 
-               msec = mtime_since(&s, &e);
+               gettimeofday(&e, NULL);
+
+               usec = utime_since(&s, &e);
+               msec = usec / 1000;
+
+               if (td->rate)
+                       rate_throttle(td, usec);
 
                add_stat_sample(td, offset / td->bs, msec);
 
@@ -475,12 +496,21 @@ void usage(char *progname)
        printf("%s: <-s 0/1> <-b kb> <-t sec> <-w 0/1> <-c r,w,r...> file0... fileN\n", progname);
 }
 
-void add_job(const char *filename, int rw, int bs, int direct, int prio, int random, int delay)
+void setup_rate(struct thread_data *td, int rate)
+{
+       int nr_reads_per_sec = rate * 1024 / td->bs;
+
+       td->rate = rate;
+       td->rate_usec_cycle = 1000000 / nr_reads_per_sec;
+       td->rate_pending_usleep = 0;
+}
+
+void add_job(const char *filename, int rw, int bs, int direct, int prio, int random, int delay, int rate)
 {
-       struct thread_data *td = &threads[thread_number];
+       struct thread_data *td = &threads[thread_number++];
 
        strcpy(td->file_name, filename);
-       td->thread_number = thread_number + 1;
+       td->thread_number = thread_number;
        td->stat_fd = -1;
        sem_init(&td->mutex, 1, 1);
        sem_init(&td->done_mutex, 1, 0);
@@ -492,7 +522,8 @@ void add_job(const char *filename, int rw, int bs, int direct, int prio, int ran
        td->bs = bs;
        td->delay_sleep = delay;
 
-       thread_number++;
+       if (rate)
+               setup_rate(td, rate);
 }
 
 void fill_option(const char *input, char *output)
@@ -518,7 +549,7 @@ void fill_option(const char *input, char *output)
  */
 int parse_jobs(int argc, char *argv[], int index)
 {
-       int rw, bs, direct, prio, random, prioclass, delay;
+       int rw, bs, direct, prio, random, prioclass, delay, rate;
        char *string, *filename, *p, *c;
        int i;
 
@@ -540,6 +571,7 @@ int parse_jobs(int argc, char *argv[], int index)
                random = !sequential;
                prioclass = 2;
                delay = 0;
+               rate = 0;
 
                c = strstr(p, "rw=");
                if (c) {
@@ -592,6 +624,13 @@ int parse_jobs(int argc, char *argv[], int index)
                        delay = strtoul(string, NULL, 10);
                }
 
+               c = strstr(p, "rate=");
+               if (c) {
+                       c += 5;
+                       fill_option(c, string);
+                       rate = strtoul(string, NULL, 10);
+               }
+
                c = strstr(p, "random");
                if (c)
                        random = 1;
@@ -599,7 +638,7 @@ int parse_jobs(int argc, char *argv[], int index)
                if (c)
                        random = 0;
 
-               add_job(filename, rw, bs, direct, (prioclass << IOPRIO_CLASS_SHIFT) | prio, random, delay);
+               add_job(filename, rw, bs, direct, (prioclass << IOPRIO_CLASS_SHIFT) | prio, random, delay, rate);
        }
 
        return thread_number;
@@ -669,13 +708,17 @@ int main(int argc, char *argv[])
                return 1;
        }
 
-       shm_id = shmget(0, (argc - 1) * sizeof(struct thread_data), IPC_CREAT);
+       shm_id = shmget(0, (argc - 1) * sizeof(struct thread_data), IPC_CREAT | 0600);
        if (shm_id == -1) {
                perror("shmget");
                return 1;
        }
 
        threads = shmat(shm_id, NULL, 0);
+       if (threads == (void *) -1 ) {
+               perror("shmat");
+               return 1;
+       }
 
        atexit(free_shm);