diff options
| author | Baptiste Daroussin <bapt@FreeBSD.org> | 2026-06-12 12:13:35 +0000 |
|---|---|---|
| committer | Baptiste Daroussin <bapt@FreeBSD.org> | 2026-06-14 14:26:30 +0000 |
| commit | ffe47c424e0a45f5d8d20a5944477821bd946eef (patch) | |
| tree | dfc35b200afea75716ceb5f5f9ba8ea123f3580f | |
| parent | 8a13adf80cb0dffb9fa7ca515664171c2362ad5e (diff) | |
grep: periodic timer-based fflush instead of unconditional per-line flush
Replace the unconditional fflush(stdout) in grep_printline and
procmatches with a periodic timer that flushes at most once every
100ms. This preserves interactive responsiveness (grep | tee,
grep | tail -f) while avoiding 1M+ write(2) syscalls when
processing large inputs.
The flush interval is tracked via clock_gettime(CLOCK_MONOTONIC)
and a static timespec. --line-buffered continues to flush
immediately via setlinebuf(3), as before.
Benchmark on 1M lines (37MB output to file):
unconditional fflush: 1.90s (sys 1.22s)
periodic 100ms timer: 0.49s (sys 0.007s)
Reviewed by: kevans
Differential Revision: https://reviews.freebsd.org/D57528
| -rw-r--r-- | usr.bin/grep/util.c | 33 |
1 files changed, 29 insertions, 4 deletions
diff --git a/usr.bin/grep/util.c b/usr.bin/grep/util.c index 5b40405852b3..dbb21dcfd78e 100644 --- a/usr.bin/grep/util.c +++ b/usr.bin/grep/util.c @@ -45,6 +45,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include <unistd.h> #include <wchar.h> #include <wctype.h> @@ -724,12 +725,36 @@ grep_strdup(const char *str) * Print an entire line as-is, there are no inline matches to consider. This is * used for printing context. */ -void grep_printline(struct str *line, int sep) { +static struct timespec printline_last_flush = { 0, 0 }; + +static void +flush_if_stalled(void) +{ + struct timespec now; + + if (lbflag && fileeol == '\n') + return; + + clock_gettime(CLOCK_MONOTONIC, &now); + if (now.tv_sec > printline_last_flush.tv_sec || + (now.tv_sec == printline_last_flush.tv_sec && + now.tv_nsec - printline_last_flush.tv_nsec > 100000000)) { + fflush(stdout); + printline_last_flush = now; + } +} + +void +grep_printline(struct str *line, int sep) +{ printline_metadata(line, sep); fwrite(line->dat, line->len, 1, stdout); putchar(fileeol); - fflush(stdout); + if (lbflag) + fflush(stdout); + else + flush_if_stalled(); } static void @@ -836,7 +861,7 @@ printline(struct parsec *pc, int sep, size_t *last_out) *last_out = pc->ln.len; } putchar('\n'); - fflush(stdout); + flush_if_stalled(); } else if (!oflag) { /* * -o is terminated on every match output, so this @@ -847,7 +872,7 @@ printline(struct parsec *pc, int sep, size_t *last_out) */ terminated = false; } else { - fflush(stdout); + flush_if_stalled(); } } else grep_printline(&pc->ln, sep); |
