From: Jens Axboe Date: Fri, 14 Oct 2005 08:32:42 +0000 (+0200) Subject: [PATCH] fio: add rate=x option for the jobs X-Git-Url: https://git.kernel.dk/?a=commitdiff_plain;h=86184d14f0a24049e447dd96dd8f3712d79b2d42;p=disktools.git [PATCH] fio: add rate=x option for the jobs Allows you to define a specific rate that the thread will attempt to satisfy. --- diff --git a/README.fio b/README.fio index 2edc567..0b95e2c 100644 --- a/README.fio +++ b/README.fio @@ -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 Runtime in seconds -w Write statistics -r For random io, sequence must be repeatable @@ -25,11 +25,12 @@ The 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 a85eecd..998a9fc 100644 --- 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);