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 */
#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);
}
if (td->delay_sleep)
- delay_sleep(td->delay_sleep);
+ usec_sleep(td->delay_sleep);
gettimeofday(&s, NULL);
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);
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);
td->bs = bs;
td->delay_sleep = delay;
- thread_number++;
+ if (rate)
+ setup_rate(td, rate);
}
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;
random = !sequential;
prioclass = 2;
delay = 0;
+ rate = 0;
c = strstr(p, "rw=");
if (c) {
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;
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;
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);