X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=fio.c;h=5c45cae7f64103e0a8e30b16d7f704a2680f45e8;hp=6f122c9bbd0c68692df441d3c1edcf317145771e;hb=0af7b542b69af5ab2400a9960a5bcde82c05723f;hpb=ebac4655dd3624f3296ff83be48e0cdc02852f18 diff --git a/fio.c b/fio.c index 6f122c9b..5c45cae7 100644 --- a/fio.c +++ b/fio.c @@ -51,6 +51,7 @@ static char run_str[MAX_JOBS + 1]; int shm_id = 0; static LIST_HEAD(disk_list); static struct itimerval itimer; +static struct timeval genesis; static void update_io_ticks(void); static void disk_util_timer_arm(void); @@ -158,6 +159,11 @@ static inline unsigned long msec_now(struct timeval *s) return s->tv_sec * 1000 + s->tv_usec / 1000; } +static unsigned long time_since_now(struct timeval *s) +{ + return mtime_since_now(s) / 1000; +} + static int random_map_free(struct thread_data *td, unsigned long long block) { unsigned int idx = RAND_MAP_IDX(td, block); @@ -210,55 +216,6 @@ static void mark_random_map(struct thread_data *td, struct io_u *io_u) io_u->buflen = blocks * td->min_bs; } -static int get_next_offset(struct thread_data *td, unsigned long long *offset) -{ - unsigned long long b, rb; - long r; - - if (!td->sequential) { - unsigned long max_blocks = td->io_size / td->min_bs; - int loops = 50; - - do { - lrand48_r(&td->random_state, &r); - b = ((max_blocks - 1) * r / (RAND_MAX+1.0)); - rb = b + (td->file_offset / td->min_bs); - loops--; - } while (!random_map_free(td, rb) && loops); - - if (!loops) { - if (get_next_free_block(td, &b)) - return 1; - } - } else - b = td->last_bytes / td->min_bs; - - *offset = (b * td->min_bs) + td->file_offset; - if (*offset > td->file_size) - return 1; - - return 0; -} - -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); - } - - if (buflen > td->io_size - td->this_io_bytes[td->ddir]) - buflen = td->io_size - td->this_io_bytes[td->ddir]; - - return buflen; -} - static inline void add_stat_sample(struct io_stat *is, unsigned long val) { if (val > is->max_val) @@ -321,6 +278,55 @@ static void add_bw_sample(struct thread_data *td, int ddir) td->stat_io_bytes[ddir] = td->this_io_bytes[ddir]; } +static int get_next_offset(struct thread_data *td, unsigned long long *offset) +{ + unsigned long long b, rb; + long r; + + if (!td->sequential) { + unsigned long max_blocks = td->io_size / td->min_bs; + int loops = 50; + + do { + lrand48_r(&td->random_state, &r); + b = ((max_blocks - 1) * r / (RAND_MAX+1.0)); + rb = b + (td->file_offset / td->min_bs); + loops--; + } while (!random_map_free(td, rb) && loops); + + if (!loops) { + if (get_next_free_block(td, &b)) + return 1; + } + } else + b = td->last_pos / td->min_bs; + + *offset = (b * td->min_bs) + td->file_offset; + if (*offset > td->real_file_size) + return 1; + + return 0; +} + +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); + } + + if (buflen > td->io_size - td->this_io_bytes[td->ddir]) + buflen = td->io_size - td->this_io_bytes[td->ddir]; + + return buflen; +} + /* * busy looping version for the last few usec */ @@ -560,6 +566,19 @@ static void populate_io_u(struct thread_data *td, struct io_u *io_u) memcpy(io_u->buf, &hdr, sizeof(hdr)); } +static int td_io_prep(struct thread_data *td, struct io_u *io_u, int read) +{ + if (read) + io_u->ddir = DDIR_READ; + else + io_u->ddir = DDIR_WRITE; + + if (td->io_prep && td->io_prep(td, io_u)) + return 1; + + return 0; +} + static void put_io_u(struct thread_data *td, struct io_u *io_u) { list_del(&io_u->list); @@ -585,19 +604,6 @@ static struct io_u *__get_io_u(struct thread_data *td) return io_u; } -static int td_io_prep(struct thread_data *td, struct io_u *io_u, int read) -{ - if (read) - io_u->ddir = DDIR_READ; - else - io_u->ddir = DDIR_WRITE; - - if (td->io_prep && td->io_prep(td, io_u)) - return 1; - - return 0; -} - static struct io_u *get_io_u(struct thread_data *td) { struct io_u *io_u; @@ -606,6 +612,11 @@ static struct io_u *get_io_u(struct thread_data *td) if (!io_u) return NULL; + if (td->zone_bytes >= td->zone_size) { + td->zone_bytes = 0; + td->last_pos += td->zone_skip; + } + if (get_next_offset(td, &io_u->offset)) { put_io_u(td, io_u); return NULL; @@ -617,8 +628,8 @@ static struct io_u *get_io_u(struct thread_data *td) return NULL; } - if (io_u->buflen + io_u->offset > td->file_size) - io_u->buflen = td->file_size - io_u->offset; + if (io_u->buflen + io_u->offset > td->real_file_size) + io_u->buflen = td->real_file_size - io_u->offset; if (!io_u->buflen) { put_io_u(td, io_u); @@ -628,7 +639,7 @@ static struct io_u *get_io_u(struct thread_data *td) if (!td->sequential) mark_random_map(td, io_u); - td->last_bytes += io_u->buflen; + td->last_pos += io_u->buflen; if (td->verify != VERIFY_NONE) populate_io_u(td, io_u); @@ -745,11 +756,13 @@ static void io_completed(struct thread_data *td, struct io_u *io_u, gettimeofday(&e, NULL); if (!io_u->error) { + unsigned int bytes = io_u->buflen - io_u->resid; int idx = io_u->ddir; td->io_blocks[idx]++; - td->io_bytes[idx] += (io_u->buflen - io_u->resid); - td->this_io_bytes[idx] += (io_u->buflen - io_u->resid); + td->io_bytes[idx] += bytes; + td->zone_bytes += bytes; + td->this_io_bytes[idx] += bytes; msec = mtime_since(&io_u->issue_time, &e); @@ -759,7 +772,7 @@ static void io_completed(struct thread_data *td, struct io_u *io_u, if (td_write(td) && io_u->ddir == DDIR_WRITE) log_io_piece(td, io_u); - icd->bytes_done[idx] += (io_u->buflen - io_u->resid); + icd->bytes_done[idx] += bytes; } else icd->error = io_u->error; } @@ -897,8 +910,6 @@ static void do_verify(struct thread_data *td) break; } - td->cur_off = v_io_u->offset + v_io_u->buflen; - /* * if we can't submit more io, we need to verify now */ @@ -1192,15 +1203,17 @@ static int file_size(struct thread_data *td) return 1; } - if (!td->file_size) - td->file_size = st.st_size; + td->real_file_size = st.st_size; + + if (!td->file_size || td->file_size > td->real_file_size) + td->file_size = td->real_file_size; return 0; } static int bdev_size(struct thread_data *td) { - size_t bytes; + unsigned long long bytes; int r; r = blockdev_size(td->fd, &bytes); @@ -1209,39 +1222,46 @@ static int bdev_size(struct thread_data *td) return 1; } + td->real_file_size = bytes; + /* * no extend possibilities, so limit size to device size if too large */ - if (!td->file_size || td->file_size > bytes) - td->file_size = bytes; + if (!td->file_size || td->file_size > td->real_file_size) + td->file_size = td->real_file_size; return 0; } static int get_file_size(struct thread_data *td) { - int ret; + int ret = 0; if (td->filetype == FIO_TYPE_FILE) ret = file_size(td); - else + else if (td->filetype == FIO_TYPE_BD) ret = bdev_size(td); + else + td->real_file_size = -1; if (ret) return ret; - if (td->file_offset > td->file_size) { - fprintf(stderr, "Client%d: offset larger than length (%Lu > %Lu)\n", td->thread_number, td->file_offset, td->file_size); + if (td->file_offset + td->file_size > td->real_file_size) { + fprintf(stderr, "Client%d: offset extends end (%Lu > %Lu)\n", td->thread_number, td->file_offset + td->file_size, td->real_file_size); return 1; } - td->io_size = td->file_size - td->file_offset; + td->io_size = td->file_size; if (td->io_size == 0) { fprintf(stderr, "Client%d: no io blocks\n", td->thread_number); td_verror(td, EINVAL); return 1; } + if (!td->zone_size) + td->zone_size = td->io_size; + td->total_io_size = td->io_size * td->loops; return 0; } @@ -1338,9 +1358,14 @@ static int setup_file(struct thread_data *td) if (td->odirect) flags |= O_DIRECT; - if (td_read(td)) - td->fd = open(td->file_name, flags | O_RDONLY); - else { + if (td_read(td)) { + if (td->filetype == FIO_TYPE_CHAR) + flags |= O_RDWR; + else + flags |= O_RDONLY; + + td->fd = open(td->file_name, flags); + } else { if (td->filetype == FIO_TYPE_FILE) { if (!td->overwrite) flags |= O_TRUNC; @@ -1581,17 +1606,23 @@ static void init_disk_util(struct thread_data *td) return; /* - * if this is inside a partition dir, jump back to parent + * for md/dm, there's no queue dir. we already have the right place */ - sprintf(tmp, "%s/queue", foo); + sprintf(tmp, "%s/stat", foo); if (stat(tmp, &st)) { - p = dirname(foo); - sprintf(tmp, "%s/queue", p); + /* + * if this is inside a partition dir, jump back to parent + */ + sprintf(tmp, "%s/queue", foo); if (stat(tmp, &st)) { - fprintf(stderr, "unknown sysfs layout\n"); - return; + p = dirname(foo); + sprintf(tmp, "%s/queue", p); + if (stat(tmp, &st)) { + fprintf(stderr, "unknown sysfs layout\n"); + return; + } + sprintf(foo, "%s", p); } - sprintf(foo, "%s", p); } disk_util_add(dev, foo); @@ -1609,10 +1640,10 @@ static void clear_io_state(struct thread_data *td) if (td->io_engine == FIO_SYNCIO) lseek(td->fd, SEEK_SET, 0); - td->cur_off = 0; - td->last_bytes = 0; + td->last_pos = 0; td->stat_io_bytes[0] = td->stat_io_bytes[1] = 0; td->this_io_bytes[0] = td->this_io_bytes[1] = 0; + td->zone_bytes = 0; if (td->file_map) memset(td->file_map, 0, td->num_maps * sizeof(long)); @@ -1783,7 +1814,7 @@ static void show_ddir_status(struct thread_data *td, struct group_run_stats *rs, return; bw = td->io_bytes[ddir] / td->runtime[ddir]; - printf(" %s: io=%6luMiB, bw=%6luKiB/s, runt=%6lumsec\n", ddir_str[ddir], td->io_bytes[ddir] >> 20, bw, td->runtime[ddir]); + printf(" %s: io=%6lluMiB, bw=%6luKiB/s, runt=%6lumsec\n", ddir_str[ddir], td->io_bytes[ddir] >> 20, bw, td->runtime[ddir]); if (calc_lat(&td->slat_stat[ddir], &min, &max, &mean, &dev)) printf(" slat (msec): min=%5lu, max=%5lu, avg=%5.02f, dev=%5.02f\n", min, max, mean, dev); @@ -1869,10 +1900,39 @@ static void check_str_update(struct thread_data *td) td->old_runstate = td->runstate; } +static void eta_to_str(char *str, int eta_sec) +{ + unsigned int d, h, m, s; + static int always_d, always_h; + + d = h = m = s = 0; + + s = eta_sec % 60; + eta_sec /= 60; + m = eta_sec % 60; + eta_sec /= 60; + h = eta_sec % 24; + eta_sec /= 24; + d = eta_sec; + + if (d || always_d) { + always_d = 1; + str += sprintf(str, "%02dd:", d); + } + if (h || always_h) { + always_h = 1; + str += sprintf(str, "%02dh:", h); + } + + str += sprintf(str, "%02dm:", m); + str += sprintf(str, "%02ds", s); +} + static void print_thread_status(void) { unsigned long long bytes_done, bytes_total; - int i, nr_running, t_rate, m_rate; + int i, nr_running, t_rate, m_rate, eta_sec; + char eta_str[32]; double perc; bytes_done = bytes_total = 0; @@ -1890,22 +1950,40 @@ static void print_thread_status(void) if (td->verify) bytes_total += td->total_io_size; + if (td->zone_size && td->zone_skip) + bytes_total /= (td->zone_skip / td->zone_size); + bytes_done += td->io_bytes[DDIR_READ] +td->io_bytes[DDIR_WRITE]; check_str_update(td); } perc = 0; + eta_sec = 0; if (bytes_total && bytes_done) { - perc = (double) 100 * bytes_done / (double) bytes_total; - if (perc > 100.0) - perc = 100.0; + unsigned long runtime; + + perc = (double) bytes_done / (double) bytes_total; + if (perc > 1.0) + perc = 1.0; + + runtime = time_since_now(&genesis); + if (runtime >= 5) { + memset(eta_str, 0, sizeof(eta_str)); + eta_sec = (runtime * (1.0 / perc)) - runtime; + eta_to_str(eta_str, eta_sec); + } + + perc *= 100.0; } - printf("Threads now running: %d", nr_running); + printf("Threads now running (%d)", nr_running); if (m_rate || t_rate) printf(", commitrate %d/%dKiB/sec", t_rate, m_rate); - printf(" : [%s] [%3.2f%% done]\r", run_str, perc); + printf(": [%s] [%3.2f%% done]", run_str, perc); + if (eta_sec) + printf(" [eta %s]", eta_str); + printf("\r"); fflush(stdout); } @@ -1940,7 +2018,6 @@ static void reap_threads(int *nr_running, int *t_rate, int *m_rate) static void run_threads(void) { - struct timeval genesis; struct thread_data *td; unsigned long spent; int i, todo, nr_running, m_rate, t_rate, nr_started; @@ -2064,9 +2141,9 @@ static void show_group_stats(struct group_run_stats *rs, int id) printf("\nRun status group %d (all jobs):\n", id); if (rs->max_run[DDIR_READ]) - printf(" READ: io=%luMiB, aggrb=%lu, minb=%lu, maxb=%lu, mint=%lumsec, maxt=%lumsec\n", rs->io_mb[0], rs->agg[0], rs->min_bw[0], rs->max_bw[0], rs->min_run[0], rs->max_run[0]); + printf(" READ: io=%lluMiB, aggrb=%llu, minb=%llu, maxb=%llu, mint=%llumsec, maxt=%llumsec\n", rs->io_mb[0], rs->agg[0], rs->min_bw[0], rs->max_bw[0], rs->min_run[0], rs->max_run[0]); if (rs->max_run[DDIR_WRITE]) - printf(" WRITE: io=%luMiB, aggrb=%lu, minb=%lu, maxb=%lu, mint=%lumsec, maxt=%lumsec\n", rs->io_mb[1], rs->agg[1], rs->min_bw[1], rs->max_bw[1], rs->min_run[1], rs->max_run[1]); + printf(" WRITE: io=%lluMiB, aggrb=%llu, minb=%llu, maxb=%llu, mint=%llumsec, maxt=%llumsec\n", rs->io_mb[1], rs->agg[1], rs->min_bw[1], rs->max_bw[1], rs->min_run[1], rs->max_run[1]); } static void show_disk_util(void)