Unify the time handling
authorJens Axboe <axboe@fb.com>
Fri, 21 Feb 2014 23:26:01 +0000 (15:26 -0800)
committerJens Axboe <axboe@fb.com>
Fri, 21 Feb 2014 23:26:01 +0000 (15:26 -0800)
Some options are in seconds, if no units are given. These include
runtime/timeout, startdelay, and ramp_time. Handle this
appropriately. Internally it should all be microseconds now, it's
just the conversion factor.

Signed-off-by: Jens Axboe <axboe@fb.com>
HOWTO
backend.c
eta.c
fio.1
init.c
options.c
parse.c
parse.h
time.c
time.h

diff --git a/HOWTO b/HOWTO
index bafad93..4dacd98 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -223,7 +223,8 @@ a string. The following types are used:
 str    String. This is a sequence of alpha characters.
 time   Integer with possible time suffix. In seconds unless otherwise
        specified, use eg 10m for 10 minutes. Accepts s/m/h for seconds,
-       minutes, and hours.
+       minutes, and hours, and accepts 'ms' (or 'msec') for milliseconds,
+       and 'us' (or 'usec') for microseconds.
 int    SI integer. A whole number value, which may contain a suffix
        describing the base of the number. Accepted suffixes are k/m/g/t/p,
        meaning kilo, mega, giga, tera, and peta. The suffix is not case
index 87aec87..ee395bd 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -346,7 +346,7 @@ static inline int runtime_exceeded(struct thread_data *td, struct timeval *t)
                return 0;
        if (!td->o.timeout)
                return 0;
-       if (mtime_since(&td->epoch, t) >= td->o.timeout )
+       if (utime_since(&td->epoch, t) >= td->o.timeout)
                return 1;
 
        return 0;
@@ -1683,8 +1683,8 @@ static void do_usleep(unsigned int usecs)
 static void run_threads(void)
 {
        struct thread_data *td;
-       unsigned long spent;
        unsigned int i, todo, nr_running, m_rate, t_rate, nr_started;
+       uint64_t spent;
 
        if (fio_gtod_offload && fio_start_gtod_thread())
                return;
@@ -1782,7 +1782,7 @@ static void run_threads(void)
                        }
 
                        if (td->o.start_delay) {
-                               spent = mtime_since_genesis();
+                               spent = utime_since_genesis();
 
                                if (td->o.start_delay > spent)
                                        continue;
diff --git a/eta.c b/eta.c
index e12e4fc..b050102 100644 (file)
--- a/eta.c
+++ b/eta.c
@@ -127,8 +127,10 @@ static int thread_eta(struct thread_data *td)
        unsigned long long bytes_total, bytes_done;
        unsigned long eta_sec = 0;
        unsigned long elapsed;
+       uint64_t timeout;
 
        elapsed = (mtime_since_now(&td->epoch) + 999) / 1000;
+       timeout = td->o.timeout / 1000000UL;
 
        bytes_total = td->total_io_size;
 
@@ -174,8 +176,7 @@ static int thread_eta(struct thread_data *td)
                        perc = 1.0;
 
                if (td->o.time_based) {
-                       perc_t = (double) elapsed /
-                                       (double) (td->o.timeout / 1000);
+                       perc_t = (double) elapsed / (double) timeout;
                        if (perc_t < perc)
                                perc = perc_t;
                }
@@ -183,9 +184,8 @@ static int thread_eta(struct thread_data *td)
                eta_sec = (unsigned long) (elapsed * (1.0 / perc)) - elapsed;
 
                if (td->o.timeout &&
-                   eta_sec > ( (td->o.timeout / 1000) + done_secs - elapsed))
-                       eta_sec = (td->o.timeout / 1000)  + done_secs
-                                       - elapsed;
+                   eta_sec > (timeout + done_secs - elapsed))
+                       eta_sec = timeout + done_secs - elapsed;
        } else if (td->runstate == TD_NOT_CREATED || td->runstate == TD_CREATED
                        || td->runstate == TD_INITIALIZED
                        || td->runstate == TD_SETTING_UP
@@ -199,8 +199,12 @@ static int thread_eta(struct thread_data *td)
                 * if given, otherwise assume it'll run at the specified rate.
                 */
                if (td->o.timeout) {
-                       t_eta = (td->o.timeout + td->o.start_delay  +
-                                       td->o.ramp_time ) / 1000;
+                       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 /= 1000000ULL;
 
                        if (in_ramp_time(td)) {
                                unsigned long ramp_left;
@@ -214,7 +218,7 @@ static int thread_eta(struct thread_data *td)
                rate_bytes = ddir_rw_sum(td->o.rate);
                if (rate_bytes) {
                        r_eta = (bytes_total / 1024) / rate_bytes;
-                       r_eta += td->o.start_delay / 1000;
+                       r_eta += (td->o.start_delay / 1000000ULL);
                }
 
                if (r_eta && t_eta)
diff --git a/fio.1 b/fio.1
index 81b03f7..c530d84 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -131,8 +131,8 @@ etc. This is useful for disk drives where values are often given in base 10
 values. Specifying '30GiB' will get you 30*1000^3 bytes.
 When specifying times the default suffix meaning changes, still denoting the
 base unit of the value, but accepted suffixes are 'D' (days), 'H' (hours), 'M'
-(minutes), 'S' Seconds, 'ms' milli seconds. Time values without a unit specify
-seconds.
+(minutes), 'S' Seconds, 'ms' (or msec) milli seconds, 'us' (or 'usec') micro
+seconds. Time values without a unit specify seconds.
 The suffixes are not case sensitive.
 .TP
 .I bool
diff --git a/init.c b/init.c
index 5fc3b22..6a65e55 100644 (file)
--- a/init.c
+++ b/init.c
@@ -1773,7 +1773,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                case 'E': {
                        long long t = 0;
 
-                       if (str_to_decimal(optarg, &t, 0, NULL)) {
+                       if (str_to_decimal(optarg, &t, 0, NULL, 1)) {
                                log_err("fio: failed parsing eta time %s\n", optarg);
                                exit_val = 1;
                                do_exit++;
@@ -1933,7 +1933,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                case 'L': {
                        long long val;
 
-                       if (check_str_time(optarg, &val)) {
+                       if (check_str_time(optarg, &val, 1)) {
                                log_err("fio: failed parsing time %s\n", optarg);
                                do_exit++;
                                exit_val = 1;
index 87a4432..5355982 100644 (file)
--- a/options.c
+++ b/options.c
@@ -102,7 +102,7 @@ static int bssplit_ddir(struct thread_options *o, int ddir, char *str)
                } else
                        perc = -1;
 
-               if (str_to_decimal(fname, &val, 1, o)) {
+               if (str_to_decimal(fname, &val, 1, o, 0)) {
                        log_err("fio: bssplit conversion failed\n");
                        free(bssplit);
                        return 1;
@@ -336,7 +336,7 @@ static int str_rw_cb(void *data, const char *str)
        else {
                long long val;
 
-               if (str_to_decimal(nr, &val, 1, o)) {
+               if (str_to_decimal(nr, &val, 1, o, 0)) {
                        log_err("fio: rw postfix parsing failed\n");
                        free(nr);
                        return 1;
@@ -2068,6 +2068,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .off2   = td_var_offset(start_delay_high),
                .help   = "Only start job when this period has passed",
                .def    = "0",
+               .is_seconds = 1,
                .category = FIO_OPT_C_GENERAL,
                .group  = FIO_OPT_G_RUNTIME,
        },
@@ -2079,6 +2080,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .off1   = td_var_offset(timeout),
                .help   = "Stop workload when this amount of time has passed",
                .def    = "0",
+               .is_seconds = 1,
                .category = FIO_OPT_C_GENERAL,
                .group  = FIO_OPT_G_RUNTIME,
        },
@@ -2106,6 +2108,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .type   = FIO_OPT_STR_VAL_TIME,
                .off1   = td_var_offset(ramp_time),
                .help   = "Ramp up time before measuring performance",
+               .is_seconds = 1,
                .category = FIO_OPT_C_GENERAL,
                .group  = FIO_OPT_G_RUNTIME,
        },
diff --git a/parse.c b/parse.c
index 5c23d91..079f19e 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -122,7 +122,8 @@ static void show_option_help(struct fio_option *o, int is_err)
        show_option_values(o);
 }
 
-static unsigned long long get_mult_time(const char *str, int len)
+static unsigned long long get_mult_time(const char *str, int len,
+                                       int is_seconds)
 {
        const char *p = str;
        char *c;
@@ -137,8 +138,12 @@ static unsigned long long get_mult_time(const char *str, int len)
                p++;
        }
 
-       if (!isalpha((int) *p))
-               return mult;
+       if (!isalpha((int) *p)) {
+               if (is_seconds)
+                       return 1000000UL;
+               else
+                       return 1;
+       }
 
        c = strdup(p);
        for (int i = 0; i < strlen(c); i++)
@@ -270,7 +275,8 @@ int str_to_float(const char *str, double *val)
 /*
  * convert string into decimal value, noting any size suffix
  */
-int str_to_decimal(const char *str, long long *val, int kilo, void *data)
+int str_to_decimal(const char *str, long long *val, int kilo, void *data,
+                  int is_seconds)
 {
        int len, base;
 
@@ -297,19 +303,19 @@ int str_to_decimal(const char *str, long long *val, int kilo, void *data)
                else
                        *val *= mult;
        } else
-               *val *= get_mult_time(str, len);
+               *val *= get_mult_time(str, len, is_seconds);
 
        return 0;
 }
 
 int check_str_bytes(const char *p, long long *val, void *data)
 {
-       return str_to_decimal(p, val, 1, data);
+       return str_to_decimal(p, val, 1, data, 0);
 }
 
-int check_str_time(const char *p, long long *val)
+int check_str_time(const char *p, long long *val, int is_seconds)
 {
-       return str_to_decimal(p, val, 0, NULL);
+       return str_to_decimal(p, val, 0, NULL, is_seconds);
 }
 
 void strip_blank_front(char **p)
@@ -351,7 +357,7 @@ static int check_range_bytes(const char *str, long *val, void *data)
 {
        long long __val;
 
-       if (!str_to_decimal(str, &__val, 1, data)) {
+       if (!str_to_decimal(str, &__val, 1, data, 0)) {
                *val = __val;
                return 0;
        }
@@ -461,7 +467,7 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data,
                        *p = '\0';
 
                if (is_time)
-                       ret = check_str_time(tmp, &ull);
+                       ret = check_str_time(tmp, &ull, o->is_seconds);
                else
                        ret = check_str_bytes(tmp, &ull, data);
 
diff --git a/parse.h b/parse.h
index 1009252..c797b92 100644 (file)
--- a/parse.h
+++ b/parse.h
@@ -72,6 +72,7 @@ struct fio_option {
        unsigned int category;          /* what type of option */
        unsigned int group;             /* who to group with */
        void *gui_data;
+       int is_seconds;                 /* time value with seconds base */
 };
 
 typedef int (str_cb_fn)(void *, char *);
@@ -87,9 +88,9 @@ extern void options_free(struct fio_option *, void *);
 
 extern void strip_blank_front(char **);
 extern void strip_blank_end(char *);
-extern int str_to_decimal(const char *, long long *, int, void *);
+extern int str_to_decimal(const char *, long long *, int, void *, int);
 extern int check_str_bytes(const char *p, long long *val, void *data);
-extern int check_str_time(const char *p, long long *val);
+extern int check_str_time(const char *p, long long *val, int);
 extern int str_to_float(const char *str, double *val);
 
 /*
diff --git a/time.c b/time.c
index b374d3e..f3de3e7 100644 (file)
--- a/time.c
+++ b/time.c
@@ -58,6 +58,11 @@ uint64_t mtime_since_genesis(void)
        return mtime_since_now(&genesis);
 }
 
+uint64_t utime_since_genesis(void)
+{
+       return utime_since_now(&genesis);
+}
+
 int in_ramp_time(struct thread_data *td)
 {
        return td->o.ramp_time && !td->ramp_time_over;
@@ -71,7 +76,7 @@ int ramp_time_over(struct thread_data *td)
                return 1;
 
        fio_gettime(&tv, NULL);
-       if (mtime_since(&td->epoch, &tv) >= td->o.ramp_time ) {
+       if (utime_since(&td->epoch, &tv) >= td->o.ramp_time) {
                td->ramp_time_over = 1;
                reset_all_stats(td);
                td_set_runstate(td, TD_RAMP);
diff --git a/time.h b/time.h
index d835191..c550a55 100644 (file)
--- a/time.h
+++ b/time.h
@@ -7,6 +7,7 @@ extern uint64_t mtime_since(struct timeval *, struct timeval *);
 extern uint64_t mtime_since_now(struct timeval *);
 extern uint64_t time_since_now(struct timeval *);
 extern uint64_t mtime_since_genesis(void);
+extern uint64_t utime_since_genesis(void);
 extern void usec_spin(unsigned int);
 extern void usec_sleep(struct thread_data *, unsigned long);
 extern void fill_start_time(struct timeval *);