From 4a110807581ebafeed8178fd177e9987f334ce9c Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 7 Feb 2020 08:41:26 +0100 Subject: [PATCH] readhistfile: avoid thousands of lseek(2) syscalls via ftell() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this change, zsh startup time was dominated by lseek(2) system calls on the history file, as shown by strace -c: time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 97,35 1,112890 1 697153 1 lseek 0,99 0,011314 2 5277 read […] This change keeps track of read bytes and the position within the file, removing all of these system calls. I verified correctness of the change by comparing fpos with ftell(in) in every loop iteration. --- Src/hist.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Src/hist.c b/Src/hist.c index 5281e8718..b44463e1b 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -2575,11 +2575,13 @@ resizehistents(void) } static int -readhistline(int start, char **bufp, int *bufsiz, FILE *in) +readhistline(int start, char **bufp, int *bufsiz, FILE *in, int *readbytes) { char *buf = *bufp; if (fgets(buf + start, *bufsiz - start, in)) { - int len = start + strlen(buf + start); + int len = strlen(buf + start); + *readbytes += len; + len += start; if (len == start) return -1; if (buf[len - 1] != '\n') { @@ -2588,7 +2590,7 @@ readhistline(int start, char **bufp, int *bufsiz, FILE *in) return -1; *bufp = zrealloc(buf, 2 * (*bufsiz)); *bufsiz = 2 * (*bufsiz); - return readhistline(len, bufp, bufsiz, in); + return readhistline(len, bufp, bufsiz, in, readbytes); } } else { @@ -2596,7 +2598,7 @@ readhistline(int start, char **bufp, int *bufsiz, FILE *in) if (len > 1 && buf[len - 2] == '\\') { buf[--len - 1] = '\n'; if (!feof(in)) - return readhistline(len, bufp, bufsiz, in); + return readhistline(len, bufp, bufsiz, in, readbytes); } } return len; @@ -2616,7 +2618,7 @@ readhistfile(char *fn, int err, int readflags) short *words; struct stat sb; int nwordpos, nwords, bufsiz; - int searching, newflags, l, ret, uselex; + int searching, newflags, l, ret, uselex, readbytes; if (!fn && !(fn = getsparam("HISTFILE"))) return; @@ -2658,13 +2660,15 @@ readhistfile(char *fn, int err, int readflags) } else searching = 0; + fpos = ftell(in); + readbytes = 0; newflags = HIST_OLD | HIST_READ; if (readflags & HFILE_FAST) newflags |= HIST_FOREIGN; if (readflags & HFILE_SKIPOLD || (hist_ignore_all_dups && newflags & hist_skip_flags)) newflags |= HIST_MAKEUNIQUE; - while (fpos = ftell(in), (l = readhistline(0, &buf, &bufsiz, in))) { + while (fpos += readbytes, readbytes = 0, (l = readhistline(0, &buf, &bufsiz, in, &readbytes))) { char *pt; int remeta = 0; -- 2.25.0