[PATCH 5/8] common/iobuf: optimize iobuf_read_line

Jussi Kivilinna jussi.kivilinna at iki.fi
Sat Oct 27 23:06:05 CEST 2018


* common/iobuf.c (iobuf_read_line): Add fast path for finding '\n'
character in buffer.
--

This patch reduce per byte overhead in iobuf_read_line by avoiding
using iobuf_get when possible and use memchr to find '\n'. This
speeds armored decryption.

Benchmark results below, tested on Intel Core i7-4790K (turbo off).
Encrypted 2 GiB through pipe to ramfs file using AES128. Decrypt
ramfs file out through pipe to /dev/null.

before patch-set
----------------
               gpg process
armor:         user time    pipe transfer rate
 encrypt-aead:  13.8         140 MB/s
 decrypt-aead:  30.6         68 MB/s
 encrypt-cfb:   17.4         114 MB/s
 decrypt-cfb:   32.6         64 MB/s

after (decrypt+iobuf opt)
-------------------------
               gpg process
armor:         user time    pipe transfer rate
 decrypt-aead:  22.5         92 MB/s
 decrypt-cfb:   24.4         85 MB/s

Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
 0 files changed

diff --git a/common/iobuf.c b/common/iobuf.c
index 18a458e0a..5eeba8fe6 100644
--- a/common/iobuf.c
+++ b/common/iobuf.c
@@ -2610,12 +2610,50 @@ iobuf_read_line (iobuf_t a, byte ** addr_of_buffer,
     }
 
   p = buffer;
-  while ((c = iobuf_get (a)) != -1)
+  while (1)
     {
-      *p++ = c;
-      nbytes++;
-      if (c == '\n')
-	break;
+      if (!a->nofast && a->d.start < a->d.len && nbytes < length - 1)
+	/* Fast path for finding '\n' by using standard C library's optimized
+	   memchr.  */
+	{
+	  unsigned size = a->d.len - a->d.start;
+	  byte *newline_pos;
+
+	  if (size > length - 1 - nbytes)
+	    size = length - 1 - nbytes;
+
+	  newline_pos = memchr (a->d.buf + a->d.start, '\n', size);
+	  if (newline_pos)
+	    {
+	      /* Found newline, copy buffer and return. */
+	      size = (newline_pos - (a->d.buf + a->d.start)) + 1;
+	      memcpy (p, a->d.buf + a->d.start, size);
+	      p += size;
+	      nbytes += size;
+	      a->d.start += size;
+	      a->nbytes += size;
+	      break;
+	    }
+	  else
+	    {
+	      /* No newline, copy buffer and continue. */
+	      memcpy (p, a->d.buf + a->d.start, size);
+	      p += size;
+	      nbytes += size;
+	      a->d.start += size;
+	      a->nbytes += size;
+	    }
+	}
+      else
+	{
+	  c = iobuf_readbyte (a);
+	  if (c == -1)
+	    break;
+	  *p++ = c;
+	  nbytes++;
+	  if (c == '\n')
+	    break;
+	}
 
       if (nbytes == length - 1)
 	/* We don't have enough space to add a \n and a \0.  Increase




More information about the Gnupg-devel mailing list