git: ffe47c424e0a - main - grep: periodic timer-based fflush instead of unconditional per-line flush

From: Baptiste Daroussin <bapt_at_FreeBSD.org>
Date: Sun, 14 Jun 2026 14:27:09 UTC
The branch main has been updated by bapt:

URL: https://cgit.FreeBSD.org/src/commit/?id=ffe47c424e0a45f5d8d20a5944477821bd946eef

commit ffe47c424e0a45f5d8d20a5944477821bd946eef
Author:     Baptiste Daroussin <bapt@FreeBSD.org>
AuthorDate: 2026-06-12 12:13:35 +0000
Commit:     Baptiste Daroussin <bapt@FreeBSD.org>
CommitDate: 2026-06-14 14:26:30 +0000

    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
---
 usr.bin/grep/util.c | 33 +++++++++++++++++++++++++++++----
 1 file 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);