On Wed, Jul 13, 2022 at 12:50:24AM -0500, Scott Cheloha wrote:
> We reduce overhead if we only parse the user's format string once.  To
> achieve that, this patch does the following:
> 
> [...]
> 
> - When parsing the user format string in fmtfmt(), keep a list of
>   where each microsecond substring lands in buf.  We'll need it later.
> 
> - Move the printing part of fmtfmt() into a new function, fmtprint().
>   fmtprint() is now called from the main loop instead of fmtfmt().
> 
> - In fmtprint(), before calling strftime(3), update any microsecond
>   substrings in buf using the list we built earlier in fmtfmt().  Note
>   that if there aren't any such substrings we don't call snprintf(3)
>   at all.
> 
> [...]

Two week bump.

Here is a stripped-down patch with only the above changes.  Hopefully
this makes the intent of the patch more obvious.

In short, parse the user format string only once, and then only update
the microsecond parts (if any) when we print each new timestamp.

Index: ts.c
===================================================================
RCS file: /cvs/src/usr.bin/ts/ts.c,v
retrieving revision 1.8
diff -u -p -r1.8 ts.c
--- ts.c        7 Jul 2022 10:40:25 -0000       1.8
+++ ts.c        29 Jul 2022 13:12:07 -0000
@@ -17,6 +17,7 @@
  */
 
 #include <sys/types.h>
+#include <sys/queue.h>
 #include <sys/time.h>
 
 #include <err.h>
@@ -27,13 +28,20 @@
 #include <unistd.h>
 #include <time.h>
 
+SIMPLEQ_HEAD(, usec) usec_queue = SIMPLEQ_HEAD_INITIALIZER(usec_queue);
+struct usec {
+       SIMPLEQ_ENTRY(usec) next;
+       char *pos;
+};
+
 static char            *format = "%b %d %H:%M:%S";
 static char            *buf;
 static char            *outbuf;
 static size_t           bufsize;
 static size_t           obsize;
 
-static void             fmtfmt(const struct timespec *);
+static void             fmtfmt(void);
+static void             fmtprint(const struct timespec *);
 static void __dead      usage(void);
 
 int
@@ -88,6 +96,8 @@ main(int argc, char *argv[])
        if ((outbuf = calloc(1, obsize)) == NULL)
                err(1, NULL);
 
+       fmtfmt();
+
        /* force UTC for interval calculations */
        if (iflag || sflag)
                if (setenv("TZ", "UTC", 1) == -1)
@@ -106,7 +116,7 @@ main(int argc, char *argv[])
                                timespecadd(&now, &utc_offset, &ts);
                        else
                                ts = now;
-                       fmtfmt(&ts);
+                       fmtprint(&ts);
                        if (iflag)
                                start = now;
                }
@@ -132,15 +142,11 @@ usage(void)
  * so you can format while you format
  */
 static void
-fmtfmt(const struct timespec *ts)
+fmtfmt(void)
 {
-       struct tm *tm;
-       char *f, us[7];
-
-       if ((tm = localtime(&ts->tv_sec)) == NULL)
-               err(1, "localtime");
+       char *f;
+       struct usec *u;
 
-       snprintf(us, sizeof(us), "%06ld", ts->tv_nsec / 1000);
        strlcpy(buf, format, bufsize);
        f = buf;
 
@@ -159,12 +165,34 @@ fmtfmt(const struct timespec *ts)
                        f[0] = f[1];
                        f[1] = '.';
                        f += 2;
+                       u = malloc(sizeof u);
+                       if (u == NULL)
+                               err(1, NULL);
+                       u->pos = f;
+                       SIMPLEQ_INSERT_TAIL(&usec_queue, u, next);
                        l = strlen(f);
                        memmove(f + 6, f, l + 1);
-                       memcpy(f, us, 6);
                        f += 6;
                }
        } while (*f != '\0');
+}
+
+static void
+fmtprint(const struct timespec *ts)
+{
+       char us[8];
+       struct tm *tm;
+       struct usec *u;
+
+       if ((tm = localtime(&ts->tv_sec)) == NULL)
+               err(1, "localtime");
+
+       /* Update any microsecond substrings in the format buffer. */
+       if (!SIMPLEQ_EMPTY(&usec_queue)) {
+               snprintf(us, sizeof(us), "%06ld", ts->tv_nsec / 1000);
+               SIMPLEQ_FOREACH(u, &usec_queue, next)
+                       memcpy(u->pos, us, 6);
+       }
 
        *outbuf = '\0';
        if (*buf != '\0') {

Reply via email to