X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=fio.c;h=5dbe9c3d5a23278483badef767add0e2abe89399;hp=c93cbe266c852930744fededf4144c82c2317be4;hb=20dc95c47087d486b5d4608fc15b1c2021761923;hpb=77cf8455a12a36b060b1a7085ba2de7e42b3966f diff --git a/fio.c b/fio.c index c93cbe26..5dbe9c3d 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->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; @@ -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; } @@ -1240,6 +1253,9 @@ static int get_file_size(struct thread_data *td) return 1; } + if (!td->zone_size) + td->zone_size = td->io_size; + td->total_io_size = td->io_size * td->loops; return 0; } @@ -1607,9 +1623,10 @@ static void clear_io_state(struct thread_data *td) if (td->io_engine == FIO_SYNCIO) lseek(td->fd, SEEK_SET, 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)); @@ -1866,10 +1883,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; @@ -1887,22 +1933,40 @@ static void print_thread_status(void) if (td->verify) bytes_total += td->total_io_size; + if (td->zone_size) + 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); } @@ -1937,7 +2001,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;