From: cheloha Date: Thu, 1 Sep 2022 00:14:36 +0000 (+0000) Subject: ts(1): parse user format string only once X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=34a84998a99ecc4e5f09fb81d875c3779648ebba;p=openbsd ts(1): parse user format string only once Currently, ts(1) reparses the user format string every time it prints a timestamp. This is wasteful. If we isolate the parsing loop in fmtfmt() and move the rest of the work into a new function, fmtprint(), we can cut some overhead out of the hot loop. We still need to update any microsecond substrings in the parsed format string every time we print a timestamp. So during parsing in fmtfmt() we build a list of pointers to locations in the parsed buffer where the microsecond substring needs to be copied during fmtprint(). With input from deraadt@. Link1: https://marc.info/?l=openbsd-tech&m=165769139318084&w=2 Link2: https://marc.info/?l=openbsd-tech&m=165910022501353&w=2 OK job@ --- diff --git a/usr.bin/ts/ts.c b/usr.bin/ts/ts.c index 284d8ccee0b..62987ca10e5 100644 --- a/usr.bin/ts/ts.c +++ b/usr.bin/ts/ts.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ts.c,v 1.9 2022/08/03 16:54:30 job Exp $ */ +/* $OpenBSD: ts.c,v 1.10 2022/09/01 00:14:36 cheloha Exp $ */ /* * Copyright (c) 2022 Job Snijders * Copyright (c) 2022 Claudio Jeker @@ -17,6 +17,7 @@ */ #include +#include #include #include @@ -27,13 +28,20 @@ #include #include +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 @@ -90,6 +98,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) @@ -108,7 +118,7 @@ main(int argc, char *argv[]) timespecadd(&now, &utc_offset, &ts); else ts = now; - fmtfmt(&ts); + fmtprint(&ts); if (iflag) start = now; } @@ -134,15 +144,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]; + char *f; + struct usec *u; - if ((tm = localtime(&ts->tv_sec)) == NULL) - err(1, "localtime"); - - snprintf(us, sizeof(us), "%06ld", ts->tv_nsec / 1000); strlcpy(buf, format, bufsize); f = buf; @@ -161,12 +167,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') {