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
This commit is contained in:
Baptiste Daroussin
2026-06-12 14:13:35 +02:00
parent 8a13adf80c
commit ffe47c424e
+29 -4
View File
@@ -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);