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:
+29
-4
@@ -45,6 +45,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <wctype.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
|
* Print an entire line as-is, there are no inline matches to consider. This is
|
||||||
* used for printing context.
|
* 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);
|
printline_metadata(line, sep);
|
||||||
fwrite(line->dat, line->len, 1, stdout);
|
fwrite(line->dat, line->len, 1, stdout);
|
||||||
putchar(fileeol);
|
putchar(fileeol);
|
||||||
|
|
||||||
fflush(stdout);
|
if (lbflag)
|
||||||
|
fflush(stdout);
|
||||||
|
else
|
||||||
|
flush_if_stalled();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -836,7 +861,7 @@ printline(struct parsec *pc, int sep, size_t *last_out)
|
|||||||
*last_out = pc->ln.len;
|
*last_out = pc->ln.len;
|
||||||
}
|
}
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
fflush(stdout);
|
flush_if_stalled();
|
||||||
} else if (!oflag) {
|
} else if (!oflag) {
|
||||||
/*
|
/*
|
||||||
* -o is terminated on every match output, so this
|
* -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;
|
terminated = false;
|
||||||
} else {
|
} else {
|
||||||
fflush(stdout);
|
flush_if_stalled();
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
grep_printline(&pc->ln, sep);
|
grep_printline(&pc->ln, sep);
|
||||||
|
|||||||
Reference in New Issue
Block a user