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') {