This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
optimise Perl_sv_gets(): use memchr() for loop
authorDavid Mitchell <davem@iabyn.com>
Mon, 5 Dec 2016 09:37:36 +0000 (09:37 +0000)
committerDavid Mitchell <davem@iabyn.com>
Mon, 5 Dec 2016 11:54:03 +0000 (11:54 +0000)
The inner loop which searches for the next separator character and copies
buffer bytes: replace with memchr() and Copy().  These functions are
likely to be optimised to use whatever hardware facilities are available.

(But first check that the first char in the buffer isn't the separator:
blank lines are quite common, and we can skip the overhead of calling
memchr() in that case).

sv.c

diff --git a/sv.c b/sv.c
index 48de19c..dc392f0 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -8653,13 +8653,27 @@ Perl_sv_gets(pTHX_ SV *const sv, PerlIO *const fp, I32 append)
        if (cnt > 0) {
             /* if there is a separator */
            if (rslen) {
        if (cnt > 0) {
             /* if there is a separator */
            if (rslen) {
-                /* loop until we hit the end of the read-ahead buffer */
-               while (cnt > 0) {                    /* this     |  eat */
-                    /* scan forward copying and searching for rslast as we go */
-                   cnt--;
-                   if ((*bp++ = *ptr++) == rslast)  /* really   |  dust */
-                       goto thats_all_folks;        /* screams  |  sed :-) */
-               }
+                /* find next rslast */
+                STDCHAR *p;
+
+                /* shortcut common case of blank line */
+                cnt--;
+                if ((*bp++ = *ptr++) == rslast)
+                    goto thats_all_folks;
+
+                p = (STDCHAR *)memchr(ptr, rslast, cnt);
+                if (p) {
+                    SSize_t got = p - ptr + 1;
+                    Copy(ptr, bp, got, STDCHAR);
+                    ptr += got;
+                    bp  += got;
+                    cnt -= got;
+                    goto thats_all_folks;
+                }
+                Copy(ptr, bp, cnt, STDCHAR);
+                ptr += cnt;
+                bp  += cnt;
+                cnt = 0;
            }
            else {
                 /* no separator, slurp the full buffer */
            }
            else {
                 /* no separator, slurp the full buffer */