aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBaptiste Daroussin <bapt@FreeBSD.org>2026-06-12 12:13:35 +0000
committerBaptiste Daroussin <bapt@FreeBSD.org>2026-06-14 14:26:30 +0000
commitffe47c424e0a45f5d8d20a5944477821bd946eef (patch)
treedfc35b200afea75716ceb5f5f9ba8ea123f3580f
parent8a13adf80cb0dffb9fa7ca515664171c2362ad5e (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.c33
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);