unsigned int mem_type;
cpu_set_t cpumask;
+ struct drand48_data bsrange_state;
+
int shm_id;
off_t cur_off;
struct timeval lastrate;
unsigned long runtime; /* sec */
- unsigned long blocks;
+ unsigned long kb;
unsigned long io_blocks;
unsigned long io_kb;
- unsigned long last_block;
+ unsigned long last_kb;
sem_t mutex;
struct drand48_data random_state;
static int init_random_state(struct thread_data *td)
{
- unsigned long seed;
+ unsigned long seed = DEF_RANDSEED;
+
+ srand48_r(seed, &td->bsrange_state);
if (td->sequential)
return 0;
}
close(fd);
- } else
- seed = DEF_RANDSEED;
+ }
srand48_r(seed, &td->random_state);
return 0;
if (!td->sequential) {
lrand48_r(&td->random_state, &r);
- b = (1+(double) (td->blocks-1) * r / (RAND_MAX+1.0));
- } else {
- b = td->last_block;
- td->last_block++;
+ b = (1+(double) (td->kb-1) * r / (RAND_MAX+1.0));
+ } else
+ b = td->last_kb << 10;
+
+ return b + td->file_offset;
+}
+
+static unsigned int get_next_buflen(struct thread_data *td)
+{
+ unsigned int buflen;
+ long r;
+
+ if (td->min_bs == td->max_bs)
+ buflen = td->min_bs;
+ else {
+ lrand48_r(&td->bsrange_state, &r);
+ buflen = (1 + (double) (td->max_bs - 1) * r / (RAND_MAX + 1.0));
+ buflen = (buflen + td->min_bs - 1) & ~(td->min_bs - 1);
}
- return b * td->bs + td->file_offset;
+ if (buflen > ((td->kb - td->io_kb) << 10))
+ buflen = (td->kb - td->io_kb) << 10;
+
+ td->last_kb += buflen >> 10;
+ return buflen;
}
static inline void add_stat_sample(struct thread_data *td, struct io_stat *is,
if (spent < 500)
return;
- rate = (td->io_kb - td->stat_io_kb) / spent;
+ rate = ((td->io_kb - td->stat_io_kb) * 1024) / spent;
add_stat_sample(td, &td->bw_stat, rate);
if (td->bw_log)
if (spent < td->ratecycle)
return 0;
- rate = (td->io_kb - td->rate_kb) / spent;
+ rate = ((td->io_kb - td->rate_kb) * 1024) / spent;
if (rate < td->ratemin) {
printf("Client%d: min rate %d not met, got %ldKiB/sec\n", td->thread_number, td->ratemin, rate);
if (rate_quit)
static struct io_u *get_io_u(struct thread_data *td)
{
struct io_u *io_u;
+ unsigned int len;
+ unsigned long long off;
if (list_empty(&td->io_u_freelist))
return NULL;
+ off = get_next_offset(td);
+ len = get_next_buflen(td);
+ if (!len)
+ return NULL;
+
io_u = list_entry(td->io_u_freelist.next, struct io_u, list);
list_del(&io_u->list);
list_add(&io_u->list, &td->io_u_busylist);
- io_u->offset = get_next_offset(td);
+ io_u->offset = off;
+ io_u->buflen = len;
if (td->use_aio) {
if (td_read(td))
static void do_sync_io(struct thread_data *td)
{
- unsigned long blocks, msec, usec;
+ unsigned long msec, usec;
struct timeval e;
td->cur_off = 0;
- for (blocks = 0; blocks < td->blocks; blocks++) {
+ for (td->io_kb = 0; td->io_kb < td->kb;) {
struct io_u *io_u;
int ret;
break;
io_u = get_io_u(td);
+ if (!io_u)
+ break;
if (td->cur_off != io_u->offset) {
if (lseek(td->fd, io_u->offset, SEEK_SET) == -1) {
static void do_async_io(struct thread_data *td)
{
struct timeval s, e;
- unsigned long blocks, usec;
+ unsigned long usec;
- for (blocks = 0; blocks < td->blocks; blocks++) {
+ for (td->io_kb = 0; td->io_kb < td->kb;) {
struct timespec ts = { .tv_sec = 0, .tv_nsec = 0};
struct timespec *timeout;
int ret, min_evts = 0;
usec_sleep(td->delay_sleep);
io_u = get_io_u(td);
+ if (!io_u)
+ break;
memcpy(&s, &io_u->start_time, sizeof(s));
else
max_units = td->aio_depth;
- mem_size = td->bs * max_units + MASK;
+ mem_size = td->max_bs * max_units + MASK;
if (td->mem_type == MEM_MALLOC)
td->orig_buffer = malloc(mem_size);
memset(io_u, 0, sizeof(*io_u));
INIT_LIST_HEAD(&io_u->list);
- io_u->buf = p + td->bs * i;
- io_u->buflen = td->bs;
-
+ io_u->buf = p + td->max_bs * i;
list_add(&io_u->list, &td->io_u_freelist);
}
static int create_file(struct thread_data *td)
{
- unsigned int i;
+ unsigned long long left;
char *b;
+ int r, bs;
/*
* unless specifically asked for overwrite, let normal io extend it
return 1;
}
- td->blocks = td->file_size / td->bs;
- b = malloc(td->bs);
- memset(b, 0, td->bs);
+ td->kb = td->file_size >> 10;
+ b = malloc(td->max_bs);
+ memset(b, 0, td->max_bs);
+
+ left = td->file_size;
+ while (left) {
+ bs = td->max_bs;
+ if (bs > left)
+ bs = left;
- for (i = 0; i < td->blocks; i++) {
- int r = write(td->fd, b, td->bs);
+ r = write(td->fd, b, bs);
- if (r == td->bs)
+ if (r == bs) {
+ left -= bs;
continue;
- else {
+ } else {
if (r < 0)
td->error = errno;
else
st.st_size = td->file_size;
}
- td->blocks = (st.st_size - td->file_offset) / td->bs;
- if (!td->blocks) {
+ td->kb = (st.st_size - td->file_offset) / 1024;
+ if (!td->kb) {
fprintf(stderr, "Client%d: no io blocks\n", td->thread_number);
td->error = EINVAL;
return 1;
return;
if (td->runtime)
- bw = td->io_kb / td->runtime;
+ bw = td->io_kb * 1024 / td->runtime;
prio = td->ioprio & 0xff;
prio_class = td->ioprio >> IOPRIO_CLASS_SHIFT;
return -1;
}
- nr_reads_per_sec = td->rate * 1024 / td->bs;
+ nr_reads_per_sec = td->rate * 1024 / td->min_bs;
td->rate_usec_cycle = 1000000 / nr_reads_per_sec;
td->rate_pending_usleep = 0;
return 0;
if (write_bw_log)
setup_log(&td->bw_log);
- printf("Client%d: file=%s, rw=%d, prio=%d/%d, seq=%d, odir=%d, bs=%d, rate=%d, aio=%d, aio_depth=%d\n", td->thread_number, filename, td->ddir, prioclass, prio, td->sequential, td->odirect, td->bs, td->rate, td->use_aio, td->aio_depth);
+ if (td->min_bs == -1)
+ td->min_bs = td->bs;
+ if (td->max_bs == -1)
+ td->max_bs = td->bs;
+
+ printf("Client%d: file=%s, rw=%d, prio=%d/%d, seq=%d, odir=%d, bs=%d-%d, rate=%d, aio=%d, aio_depth=%d\n", td->thread_number, filename, td->ddir, prioclass, prio, td->sequential, td->odirect, td->min_bs, td->max_bs, td->rate, td->use_aio, td->aio_depth);
return 0;
}
output[i] = '\0';
}
+unsigned long get_mult(char c)
+{
+ switch (c) {
+ case 'k':
+ case 'K':
+ return 1024;
+ case 'm':
+ case 'M':
+ return 1024 * 1024;
+ case 'g':
+ case 'G':
+ return 1024 * 1024 * 1024;
+ default:
+ return 1;
+ }
+}
+
/*
* convert string after '=' into decimal value, noting any size suffix
*/
static int str_cnv(char *p, unsigned long long *val)
{
- unsigned long mult;
char *str;
int len;
str++;
len = strlen(str);
- mult = 1;
-
- switch (str[len - 2]) {
- case 'k':
- case 'K':
- mult = 1024;
- break;
- case 'm':
- case 'M':
- mult = 1024 * 1024;
- break;
- case 'g':
- case 'G':
- mult = 1024 * 1024 * 1024;
- break;
- }
*val = strtoul(str, NULL, 10);
if (*val == ULONG_MAX && errno == ERANGE)
return 1;
- *val *= mult;
+ *val *= get_mult(str[len - 2]);
return 0;
-
}
/*
return 1;
}
+static int check_range(char *p, char *name, unsigned long *s, unsigned long *e)
+{
+ char str[128];
+ char s1, s2;
+
+ sprintf(str, "%s=%%lu%%c-%%lu%%c", name);
+ if (sscanf(p, str, s, &s1, e, &s2) == 4) {
+ *s *= get_mult(s1);
+ *e *= get_mult(s2);
+ return 0;
+ }
+
+ sprintf(str, "%s = %%lu%%c-%%lu%%c", name);
+ if (sscanf(p, str, s, &s1, e, &s2) == 4) {
+ *s *= get_mult(s1);
+ *e *= get_mult(s2);
+ return 0;
+ }
+
+ sprintf(str, "%s=%%lu-%%lu", name);
+ if (sscanf(p, str, s, e) == 2)
+ return 0;
+
+ sprintf(str, "%s = %%lu-%%lu", name);
+ if (sscanf(p, str, s, e) == 2)
+ return 0;
+
+ return 1;
+
+}
+
static int check_int(char *p, char *name, unsigned int *val)
{
char str[128];
{
unsigned int prioclass, prio, cpu, global;
unsigned long long ull;
+ unsigned long ul1, ul2;
struct thread_data *td;
char *string, *name;
fpos_t off;
fgetpos(f, &off);
continue;
}
+ if (!check_range(p, "bsrange", &ul1, &ul2)) {
+ td->min_bs = ul1;
+ td->max_bs = ul2;
+ fgetpos(f, &off);
+ continue;
+ }
if (!check_strcnv(p, "bs", &ull)) {
td->bs = ull;
fgetpos(f, &off);
*/
def_thread.ddir = DDIR_READ;
def_thread.bs = DEF_BS;
+ def_thread.min_bs = -1;
+ def_thread.max_bs = -1;
def_thread.odirect = DEF_ODIRECT;
def_thread.ratecycle = DEF_RATE_CYCLE;
def_thread.sequential = DEF_SEQUENTIAL;
max_run[td->ddir] = td->runtime;
if (td->runtime)
- bw = td->io_kb / td->runtime;
+ bw = td->io_kb * 1024 / td->runtime;
if (bw < min_bw[td->ddir])
min_bw[td->ddir] = bw;
if (bw > max_bw[td->ddir])
if (td_read(td)) {
read_mb += td->io_kb >> 10;
if (td->runtime)
- read_agg += td->io_kb / td->runtime;
+ read_agg += td->io_kb * 1024 / td->runtime;
} else {
write_mb += td->io_kb >> 10;
if (td->runtime)
- write_agg += td->io_kb / td->runtime;
+ write_agg += td->io_kb * 1024 / td->runtime;
}
show_stat: