X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=eta.c;h=3c1aeeee98cbd0cb0d3dcbe35f7c1287d7a39450;hp=b0501029c2b29c2e0ea6925be1d39b66e6cd17d5;hb=b678fac65b13dabd0f78ceb338547b9acb5a4f2d;hpb=0de5b26f6e177aacac0683306c47e0cbaf58b0b6 diff --git a/eta.c b/eta.c index b0501029..3c1aeeee 100644 --- a/eta.c +++ b/eta.c @@ -6,15 +6,35 @@ #include #include "fio.h" +#include "lib/pow2.h" -static char run_str[REAL_MAX_JOBS + 1]; +static char __run_str[REAL_MAX_JOBS + 1]; +static char run_str[__THREAD_RUNSTR_SZ(REAL_MAX_JOBS)]; + +static void update_condensed_str(char *rstr, char *run_str_condensed) +{ + if (*rstr) { + while (*rstr) { + int nr = 1; + + *run_str_condensed++ = *rstr++; + while (*(rstr - 1) == *rstr) { + rstr++; + nr++; + } + run_str_condensed += sprintf(run_str_condensed, "(%u),", nr); + } + run_str_condensed--; + } + *run_str_condensed = '\0'; +} /* * Sets the status of the 'td' in the printed status map. */ static void check_str_update(struct thread_data *td) { - char c = run_str[td->thread_number - 1]; + char c = __run_str[td->thread_number - 1]; switch (td->runstate) { case TD_REAPED: @@ -74,6 +94,9 @@ static void check_str_update(struct thread_data *td) case TD_FSYNCING: c = 'F'; break; + case TD_FINISHING: + c = 'f'; + break; case TD_CREATED: c = 'C'; break; @@ -88,7 +111,8 @@ static void check_str_update(struct thread_data *td) log_err("state %d\n", td->runstate); } - run_str[td->thread_number - 1] = c; + __run_str[td->thread_number - 1] = c; + update_condensed_str(__run_str, run_str); } /* @@ -99,6 +123,11 @@ void eta_to_str(char *str, unsigned long eta_sec) unsigned int d, h, m, s; int disp_hour = 0; + if (eta_sec == -1) { + sprintf(str, "--"); + return; + } + s = eta_sec % 60; eta_sec /= 60; m = eta_sec % 60; @@ -122,7 +151,7 @@ void eta_to_str(char *str, unsigned long eta_sec) /* * Best effort calculation of the estimated pending runtime of a job. */ -static int thread_eta(struct thread_data *td) +static unsigned long thread_eta(struct thread_data *td) { unsigned long long bytes_total, bytes_done; unsigned long eta_sec = 0; @@ -134,6 +163,9 @@ static int thread_eta(struct thread_data *td) bytes_total = td->total_io_size; + if (td->flags & TD_F_NO_PROGRESS) + return -1; + if (td->o.fill_device && td->o.size == -1ULL) { if (!td->fill_device_size || td->fill_device_size == -1ULL) return 0; @@ -171,14 +203,26 @@ static int thread_eta(struct thread_data *td) double perc, perc_t; bytes_done = ddir_rw_sum(td->io_bytes); - perc = (double) bytes_done / (double) bytes_total; - if (perc > 1.0) - perc = 1.0; + + if (bytes_total) { + perc = (double) bytes_done / (double) bytes_total; + if (perc > 1.0) + perc = 1.0; + } else + perc = 0.0; if (td->o.time_based) { - perc_t = (double) elapsed / (double) timeout; - if (perc_t < perc) - perc = perc_t; + if (timeout) { + perc_t = (double) elapsed / (double) timeout; + if (perc_t < perc) + perc = perc_t; + } else { + /* + * Will never hit, we can't have time_based + * without a timeout set. + */ + perc = 0.0; + } } eta_sec = (unsigned long) (elapsed * (1.0 / perc)) - elapsed; @@ -199,14 +243,14 @@ static int thread_eta(struct thread_data *td) * if given, otherwise assume it'll run at the specified rate. */ if (td->o.timeout) { - uint64_t timeout = td->o.timeout; + uint64_t __timeout = td->o.timeout; uint64_t start_delay = td->o.start_delay; uint64_t ramp_time = td->o.ramp_time; - t_eta = timeout + start_delay + ramp_time; + t_eta = __timeout + start_delay + ramp_time; t_eta /= 1000000ULL; - if (in_ramp_time(td)) { + if ((td->runstate == TD_RAMP) && in_ramp_time(td)) { unsigned long ramp_left; ramp_left = mtime_since_now(&td->epoch); @@ -246,14 +290,19 @@ static void calc_rate(int unified_rw_rep, unsigned long mtime, int i; for (i = 0; i < DDIR_RWDIR_CNT; i++) { - unsigned long long diff; + unsigned long long diff, this_rate; diff = io_bytes[i] - prev_io_bytes[i]; + if (mtime) + this_rate = ((1000 * diff) / mtime) / 1024; + else + this_rate = 0; + if (unified_rw_rep) { rate[i] = 0; - rate[0] += ((1000 * diff) / mtime) / 1024; + rate[0] += this_rate; } else - rate[i] = ((1000 * diff) / mtime) / 1024; + rate[i] = this_rate; prev_io_bytes[i] = io_bytes[i]; } @@ -266,14 +315,19 @@ static void calc_iops(int unified_rw_rep, unsigned long mtime, int i; for (i = 0; i < DDIR_RWDIR_CNT; i++) { - unsigned long long diff; + unsigned long long diff, this_iops; diff = io_iops[i] - prev_io_iops[i]; + if (mtime) + this_iops = (diff * 1000) / mtime; + else + this_iops = 0; + if (unified_rw_rep) { iops[i] = 0; - iops[0] += (diff * 1000) / mtime; + iops[0] += this_iops; } else - iops[i] = (diff * 1000) / mtime; + iops[i] = this_iops; prev_io_iops[i] = io_iops[i]; } @@ -283,7 +337,7 @@ static void calc_iops(int unified_rw_rep, unsigned long mtime, * Print status of the jobs we know about. This includes rate estimates, * ETA, thread state, etc. */ -int calc_thread_status(struct jobs_eta *je, int force) +bool calc_thread_status(struct jobs_eta *je, int force) { struct thread_data *td; int i, unified_rw_rep; @@ -298,14 +352,14 @@ int calc_thread_status(struct jobs_eta *je, int force) static struct timeval rate_prev_time, disp_prev_time; if (!force) { - if (output_format != FIO_OUTPUT_NORMAL && + if (!(output_format & FIO_OUTPUT_NORMAL) && f_out == stdout) - return 0; + return false; if (temp_stall_ts || eta_print == FIO_ETA_NEVER) - return 0; + return false; if (!isatty(STDOUT_FILENO) && (eta_print != FIO_ETA_ALWAYS)) - return 0; + return false; } if (!ddir_rw_sum(rate_io_bytes)) @@ -331,7 +385,8 @@ int calc_thread_status(struct jobs_eta *je, int force) bw_avg_time = td->o.bw_avg_time; if (td->runstate == TD_RUNNING || td->runstate == TD_VERIFYING || td->runstate == TD_FSYNCING - || td->runstate == TD_PRE_READING) { + || td->runstate == TD_PRE_READING + || td->runstate == TD_FINISHING) { je->nr_running++; if (td_read(td)) { je->t_rate[0] += td->o.rate[DDIR_READ]; @@ -356,10 +411,9 @@ int calc_thread_status(struct jobs_eta *je, int force) } else if (td->runstate == TD_RAMP) { je->nr_running++; je->nr_ramp++; - } else if (td->runstate == TD_SETTING_UP) { - je->nr_running++; + } else if (td->runstate == TD_SETTING_UP) je->nr_setting_up++; - } else if (td->runstate < TD_RUNNING) + else if (td->runstate < TD_RUNNING) je->nr_pending++; if (je->elapsed_sec >= 3) @@ -384,19 +438,25 @@ int calc_thread_status(struct jobs_eta *je, int force) } } - if (exitall_on_terminate) + if (exitall_on_terminate) { je->eta_sec = INT_MAX; - else - je->eta_sec = 0; - - for_each_td(td, i) { - if (exitall_on_terminate) { + for_each_td(td, i) { if (eta_secs[i] < je->eta_sec) je->eta_sec = eta_secs[i]; - } else { - if (eta_secs[i] > je->eta_sec) - je->eta_sec = eta_secs[i]; } + } else { + unsigned long eta_stone = 0; + + je->eta_sec = 0; + for_each_td(td, i) { + if ((td->runstate == TD_NOT_CREATED) && td->o.stonewall) + eta_stone += eta_secs[i]; + else { + if (eta_secs[i] > je->eta_sec) + je->eta_sec = eta_secs[i]; + } + } + je->eta_sec += eta_stone; } free(eta_secs); @@ -419,7 +479,7 @@ int calc_thread_status(struct jobs_eta *je, int force) * Allow a little slack, the target is to print it every 1000 msecs */ if (!force && disp_time < 900) - return 0; + return false; calc_rate(unified_rw_rep, disp_time, io_bytes, disp_io_bytes, je->rate); calc_iops(unified_rw_rep, disp_time, io_iops, disp_io_iops, je->iops); @@ -427,11 +487,12 @@ int calc_thread_status(struct jobs_eta *je, int force) memcpy(&disp_prev_time, &now, sizeof(now)); if (!force && !je->nr_running && !je->nr_pending) - return 0; + return false; je->nr_threads = thread_number; - memcpy(je->run_str, run_str, thread_number * sizeof(char)); - return 1; + update_condensed_str(__run_str, run_str); + memcpy(je->run_str, run_str, strlen(run_str)); + return true; } void display_thread_status(struct jobs_eta *je) @@ -476,7 +537,8 @@ void display_thread_status(struct jobs_eta *je) int l; int ddir; - if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running) + if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running || + je->eta_sec == -1) strcpy(perc_str, "-.-% done"); else { double mult = 100.0; @@ -519,8 +581,7 @@ void display_thread_status(struct jobs_eta *je) if (!eta_new_line_init) { fio_gettime(&disp_eta_new_line, NULL); eta_new_line_init = 1; - } else if (eta_new_line && - mtime_since_now(&disp_eta_new_line) > eta_new_line * 1000) { + } else if (eta_new_line && mtime_since_now(&disp_eta_new_line) > eta_new_line) { fio_gettime(&disp_eta_new_line, NULL); eta_new_line_pending = 1; } @@ -528,19 +589,35 @@ void display_thread_status(struct jobs_eta *je) fflush(stdout); } -void print_thread_status(void) +struct jobs_eta *get_jobs_eta(bool force, size_t *size) { struct jobs_eta *je; - size_t size; if (!thread_number) - return; + return NULL; + + *size = sizeof(*je) + THREAD_RUNSTR_SZ + 8; + je = malloc(*size); + if (!je) + return NULL; + memset(je, 0, *size); - size = sizeof(*je) + thread_number * sizeof(char) + 1; - je = malloc(size); - memset(je, 0, size); + if (!calc_thread_status(je, force)) { + free(je); + return NULL; + } + + *size = sizeof(*je) + strlen((char *) je->run_str) + 1; + return je; +} + +void print_thread_status(void) +{ + struct jobs_eta *je; + size_t size; - if (calc_thread_status(je, 0)) + je = get_jobs_eta(false, &size); + if (je) display_thread_status(je); free(je); @@ -548,5 +625,6 @@ void print_thread_status(void) void print_status_init(int thr_number) { - run_str[thr_number] = 'P'; + __run_str[thr_number] = 'P'; + update_condensed_str(__run_str, run_str); }