Re: [PATCH] mailsplit and mailinfo: gracefully handle NUL characters
From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:44:37
Subsystem:
the rest · Maintainer:
Linus Torvalds
Hi, On Fri, 16 May 2008, Avery Pennarun wrote:
On 5/16/08, Johannes Schindelin [off-list ref] wrote:quoted
Hmpf. I hoped to get more definitive information here. Especially given that fgetc() is nothing more than a glorified fread() into a buffer, and then access the buffer. Well, at least you kind of pointed me to the _unlocked() function family.Point taken. /tmp $ for d in test1 test2 test3 test3u; do echo -n "$d: "; /usr/bin/time ./$d </dev/zero; done test1: 0.09user 0.05system 0:00.14elapsed 94%CPU test2: 2.50user 0.05system 0:02.54elapsed 100%CPU test3: 2.48user 0.06system 0:02.53elapsed 100%CPU test3u: 1.05user 0.05system 0:01.10elapsed 99%CPU fread is about 18x faster than fgetc(). getc() is the same speed as fgetc(). getc_unlocked() is definitely faster than getc, but still at least 7x slower than fread().
Well, my question was more about fgetc() vs fgets(). If you feel like it, you might benchmark this patch: -- snipsnap --
diff --git a/builtin-mailsplit.c b/builtin-mailsplit.c
index 021dc16..5d8defd 100644
--- a/builtin-mailsplit.c
+++ b/builtin-mailsplit.c@@ -45,13 +45,32 @@ static int is_from_line(const char *line, int len) /* Could be as small as 64, enough to hold a Unix "From " line. */ static char buf[4096]; +/* + * This is an ugly hack to avoid fgetc(), which is slow, as it is locking. + * The argument "in" must be the same for all calls to this function! + */ +static int fast_fgetc(FILE *in) +{ + static char buf[4096]; + static int offset = 0, len = 0; + + if (offset >= len) { + len = fread(buf, 1, sizeof(buf), in); + offset = 0; + if (!len && feof(in)) + return EOF; + } + + return buf[offset++]; +} + /* We cannot use fgets() because our lines can contain NULs */ int read_line_with_nul(char *buf, int size, FILE *in) { int len = 0, c; for (;;) { - c = fgetc(in); + c = fast_fgetc(in); buf[len++] = c; if (c == EOF || c == '\n' || len + 1 >= size) break;