]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
scriptreplay: use struct timeval for delay
authorKarel Zak <kzak@redhat.com>
Mon, 29 Jul 2019 10:50:17 +0000 (12:50 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 8 Oct 2019 11:11:54 +0000 (13:11 +0200)
* use timeval rather than double for delay
* use sys/time.h macros for wirk with timeval
* add delay normalization to script-playutils.c API

Signed-off-by: Karel Zak <kzak@redhat.com>
term-utils/script-playutils.c
term-utils/script-playutils.h
term-utils/scriptreplay.c

index 9594aef20dc179374c319ee8a4ef6f23df87b1a6..39662250d926cc728000b647463c3ad2749eb21c 100644 (file)
@@ -7,6 +7,7 @@
 #include <limits.h>
 #include <math.h>
 #include <unistd.h>
+#include <sys/time.h>
 
 #include "c.h"
 #include "xalloc.h"
@@ -44,12 +45,12 @@ struct replay_log {
 
 struct replay_step {
        char    type;           /* 'I'nput, 'O'utput, ... */
-       double  delay;
        size_t  size;
 
        char    *name;          /* signals / heders */
        char    *value;
 
+       struct timeval delay;
        struct replay_log *data;
 };
 
@@ -64,6 +65,10 @@ struct replay_setup {
        int                     timing_format;
        int                     timing_line;
 
+       struct timeval          delay_max;
+       struct timeval          delay_min;
+       double                  delay_div;
+
        char                    default_type;   /* type for REPLAY_TIMING_SIMPLE */
        int                     crmode;
 };
@@ -85,6 +90,16 @@ static int ignore_line(FILE *f)
        return 0;
 }
 
+/* incretemt @a by @b */
+static inline void timerinc(struct timeval *a, struct timeval *b)
+{
+       struct timeval res;
+
+       timeradd(a, b, &res);
+       a->tv_sec = res.tv_sec;
+       a->tv_usec = res.tv_usec;
+};
+
 struct replay_setup *replay_new_setup(void)
 {
        return xcalloc(1, sizeof(struct replay_setup));
@@ -108,6 +123,26 @@ int replay_set_crmode(struct replay_setup *stp, int mode)
        return 0;
 }
 
+int replay_set_delay_min(struct replay_setup *stp, const struct timeval *tv)
+{
+       stp->delay_min.tv_sec = tv->tv_sec;
+       stp->delay_min.tv_usec = tv->tv_usec;
+       return 0;
+}
+
+int replay_set_delay_max(struct replay_setup *stp, const struct timeval *tv)
+{
+       stp->delay_max.tv_sec = tv->tv_sec;
+       stp->delay_max.tv_usec = tv->tv_usec;
+       return 0;
+}
+
+int replay_set_delay_div(struct replay_setup *stp, const double divi)
+{
+       stp->delay_div = divi;
+       return 0;
+}
+
 static struct replay_log *replay_new_log(struct replay_setup *stp,
                                         const char *streams,
                                         const char *filename,
@@ -169,7 +204,7 @@ int replay_set_timing_file(struct replay_setup *stp, const char *filename)
                        rc = -ENOMEM;
                else {
                        log->noseek = 1;
-                       DBG(LOG, ul_debug("accociate log file '%s' with 'SH'", filename));
+                       DBG(LOG, ul_debug("accociate file '%s' for streams 'SH'", filename));
                }
        }
 
@@ -206,7 +241,7 @@ int replay_associate_log(struct replay_setup *stp,
        if (rc == 0)
                replay_new_log(stp, streams, filename, f);
 
-       DBG(LOG, ul_debug("accociate log file '%s' with '%s' [rc=%d]", filename, streams, rc));
+       DBG(LOG, ul_debug("accociate log file '%s', streams '%s' [rc=%d]", filename, streams, rc));
        return rc;
 }
 
@@ -224,15 +259,15 @@ static void replay_reset_step(struct replay_step *step)
        assert(step);
 
        step->size = 0;
-       step->delay = 0;
        step->data = NULL;
        step->type = 0;
+       timerclear(&step->delay);
 }
 
-double replay_step_get_delay(struct replay_step *step)
+struct timeval *replay_step_get_delay(struct replay_step *step)
 {
        assert(step);
-       return step->delay;
+       return &step->delay;
 }
 
 /* current data log file */
@@ -251,8 +286,11 @@ static int read_multistream_step(struct replay_step *step, FILE *f, char type)
        switch (type) {
        case 'O': /* output */
        case 'I': /* input */
-               rc = fscanf(f, "%lf %zu%c\n", &step->delay, &step->size, &nl);
-               if (rc != 3 || nl != '\n')
+               rc = fscanf(f, "%ld.%06ld %zu%c\n",
+                               &step->delay.tv_sec,
+                               &step->delay.tv_usec,
+                               &step->size, &nl);
+               if (rc != 4 || nl != '\n')
                        rc = -EINVAL;
                else
                        rc = 0;
@@ -263,8 +301,11 @@ static int read_multistream_step(struct replay_step *step, FILE *f, char type)
        {
                char buf[BUFSIZ];
 
-               rc = fscanf(f, "%lf ", &step->delay);   /* delay */
-               if (rc != 1)
+               rc = fscanf(f, "%ld.%06ld ",
+                               &step->delay.tv_sec,
+                               &step->delay.tv_usec);
+
+               if (rc != 2)
                        break;
 
                rc = fscanf(f, "%s", buf);              /* name */
@@ -326,7 +367,7 @@ int replay_get_next_step(struct replay_setup *stp, char *streams, struct replay_
 {
        struct replay_step *step;
        int rc;
-       double ignored_delay = 0;
+       struct timeval ignored_delay;
 
        assert(stp);
        assert(stp->timing_fp);
@@ -335,6 +376,8 @@ int replay_get_next_step(struct replay_setup *stp, char *streams, struct replay_
        step = &stp->step;
        *xstep = NULL;
 
+       timerclear(&ignored_delay);
+
        do {
                struct replay_log *log = NULL;
 
@@ -388,17 +431,42 @@ int replay_get_next_step(struct replay_setup *stp, char *streams, struct replay_
                } else
                        DBG(TIMING, ul_debug(" not found log for '%c' stream", step->type));
 
-               DBG(TIMING, ul_debug(" ignore step '%c' [delay=%f]",
-                                       step->type, step->delay));
-               ignored_delay += step->delay;
+               DBG(TIMING, ul_debug(" ignore step '%c' [delay=%ld.%06ld]",
+                                       step->type,
+                                       step->delay.tv_sec,
+                                       step->delay.tv_usec));
+
+               timerinc(&ignored_delay, &step->delay);
        } while (rc == 0);
 
 done:
-       if (ignored_delay)
-               step->delay += ignored_delay;
+       if (timerisset(&ignored_delay))
+               timerinc(&step->delay, &ignored_delay);
+
+       DBG(TIMING, ul_debug("reading next step done [rc=%d delay=%ld.%06ld (ignored=%ld.%06ld) size=%zu]",
+                               rc,
+                               step->delay.tv_sec, step->delay.tv_usec,
+                               ignored_delay.tv_sec, ignored_delay.tv_usec,
+                               step->size));
+
+       /* normalize delay */
+       if (stp->delay_div) {
+               DBG(TIMING, ul_debug(" normalize delay: divide"));
+               step->delay.tv_sec /= stp->delay_div;
+               step->delay.tv_usec /= stp->delay_div;
+       }
+       if (timerisset(&stp->delay_max) &&
+           timercmp(&step->delay, &stp->delay_max, >)) {
+               DBG(TIMING, ul_debug(" normalize delay: align to max"));
+               step->delay.tv_sec = stp->delay_max.tv_sec;
+               step->delay.tv_usec = stp->delay_max.tv_usec;
+       }
+       if (timerisset(&stp->delay_min) &&
+           timercmp(&step->delay, &stp->delay_min, <)) {
+               DBG(TIMING, ul_debug(" normalize delay: align to min"));
+               timerclear(&step->delay);
+       }
 
-       DBG(TIMING, ul_debug("reading next step done [rc=%d delay=%f (ignored=%f) size=%zu]",
-                               rc, step->delay, ignored_delay, step->size));
        return rc;
 }
 
index 9e803fa334779c9c1289f4caff5323203ab49d0c..9e2e8aa247b6e2f63b55b99ada6894ea59ce1227 100644 (file)
@@ -36,7 +36,11 @@ const char *replay_get_timing_file(struct replay_setup *setup);
 int replay_get_timing_line(struct replay_setup *setup);
 int replay_associate_log(struct replay_setup *stp, const char *streams, const char *filename);
 
-double replay_step_get_delay(struct replay_step *step);
+int replay_set_delay_min(struct replay_setup *stp, const struct timeval *tv);
+int replay_set_delay_max(struct replay_setup *stp, const struct timeval *tv);
+int replay_set_delay_div(struct replay_setup *stp, const double divi);
+
+struct timeval *replay_step_get_delay(struct replay_step *step);
 const char *replay_step_get_filename(struct replay_step *step);
 int replay_get_next_step(struct replay_setup *stp, char *streams, struct replay_step **xstep);
 
index a6bbeaf814e3bced1581d26639131ae440ca36f3..da9e4fb12a4aeb36dcfcd3b99d75ee5388ae0ecd 100644 (file)
@@ -27,6 +27,7 @@
 #include <sys/select.h>
 #include <unistd.h>
 #include <getopt.h>
+#include <sys/time.h>
 
 #include "c.h"
 #include "xalloc.h"
@@ -36,8 +37,6 @@
 #include "optutils.h"
 #include "script-playutils.h"
 
-#define SCRIPT_MIN_DELAY 0.0001                /* from original sripreplay.pl */
-
 static void __attribute__((__noreturn__))
 usage(void)
 {
@@ -85,14 +84,16 @@ getnum(const char *s)
 }
 
 static void
-delay_for(double delay)
+delay_for(struct timeval *delay)
 {
 #ifdef HAVE_NANOSLEEP
        struct timespec ts, remainder;
-       ts.tv_sec = (time_t) delay;
-       ts.tv_nsec = (delay - ts.tv_sec) * 1.0e9;
+       ts.tv_sec = (time_t) delay->tv_sec;
+       ts.tv_nsec = delay->tv_usec * 1000;
 
-       DBG(TIMING, ul_debug("going to sleep for %fs", delay));
+       DBG(TIMING, ul_debug("going to sleep for %ld.%06ld",
+                               delay->tv_sec,
+                               delay->tv_usec));
 
        while (-1 == nanosleep(&ts, &remainder)) {
                if (EINTR == errno)
@@ -101,10 +102,7 @@ delay_for(double delay)
                        break;
        }
 #else
-       struct timeval tv;
-       tv.tv_sec = (long) delay;
-       tv.tv_usec = (delay - tv.tv_sec) * 1.0e6;
-       select(0, NULL, NULL, NULL, &tv);
+       select(0, NULL, NULL, NULL, delay);
 #endif
 }
 
@@ -123,6 +121,9 @@ static void appendchr(char *buf, size_t bufsz, int c)
 int
 main(int argc, char *argv[])
 {
+       static const struct timeval mindelay = { .tv_sec = 0, .tv_usec = 100 };
+       struct timeval maxdelay;
+
        struct replay_setup *setup = NULL;
        struct replay_step *step = NULL;
        char streams[6] = {0};          /* IOSI - in, out, signal,info */
@@ -130,8 +131,8 @@ main(int argc, char *argv[])
                   *log_in = NULL,
                   *log_io = NULL,
                   *log_tm = NULL;
-       double divi = 1, maxdelay = 0;
-       int diviopt = FALSE, maxdelayopt = FALSE, idx;
+       double divi = 1;
+       int diviopt = FALSE, idx;
        int ch, rc, crmode = REPLAY_CRMODE_AUTO, summary = 0;
        enum {
                OPT_SUMMARY = CHAR_MAX + 1
@@ -169,6 +170,7 @@ main(int argc, char *argv[])
        close_stdout_atexit();
 
        replay_init_debug();
+       timerclear(&maxdelay);
 
        while ((ch = getopt_long(argc, argv, "B:c:I:O:t:s:d:m:x:Vh", longopts, NULL)) != -1) {
 
@@ -203,8 +205,7 @@ main(int argc, char *argv[])
                        divi = getnum(optarg);
                        break;
                case 'm':
-                       maxdelayopt = TRUE;
-                       maxdelay = getnum(optarg);
+                       strtotimeval_or_err(optarg, &maxdelay, _("failed to parse maximal delay argument"));
                        break;
                case 'x':
                        if (strcmp("in", optarg) == 0)
@@ -243,8 +244,6 @@ main(int argc, char *argv[])
 
        if (!diviopt)
                divi = idx < argc ? getnum(argv[idx]) : 1;
-       if (maxdelay < 0)
-               maxdelay = 0;
 
        if (!log_tm)
                errx(EXIT_FAILURE, _("timing file not specified"));
@@ -277,21 +276,23 @@ main(int argc, char *argv[])
                        *streams && streams[1] == '\0' ? *streams : 'O');
        replay_set_crmode(setup, crmode);
 
+       if (divi != 1)
+               replay_set_delay_div(setup, divi);
+       if (timerisset(&maxdelay))
+               replay_set_delay_max(setup, &maxdelay);
+       replay_set_delay_min(setup, &mindelay);
+
        do {
                rc = replay_get_next_step(setup, streams, &step);
                if (rc)
                        break;
 
                if (!summary) {
-                       double delay = replay_step_get_delay(step);
+                       struct timeval *delay = replay_step_get_delay(step);
 
-                       delay /= divi;
-                       if (maxdelayopt && delay > maxdelay)
-                               delay = maxdelay;
-                       if (delay > SCRIPT_MIN_DELAY)
+                       if (delay && timerisset(delay))
                                delay_for(delay);
                }
-
                rc = replay_emit_step_data(setup, step, STDOUT_FILENO);
        } while (rc == 0);