guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] 07/07: Speed up scm_c_write / scm_lfwrite


From: Andy Wingo
Subject: [Guile-commits] 07/07: Speed up scm_c_write / scm_lfwrite
Date: Tue, 24 May 2016 20:44:59 +0000 (UTC)

wingo pushed a commit to branch master
in repository guile.

commit 47918f38d9da5fe8e7e3dd0e7cf133b14c5cf04f
Author: Andy Wingo <address@hidden>
Date:   Tue May 24 22:42:51 2016 +0200

    Speed up scm_c_write / scm_lfwrite
    
    * libguile/ports-internal.h (scm_t_port): Add write_buf_aux field.
    * libguile/ports.h (scm_port_auxiliary_write_buffer): New internal
      decl.
    * libguile/ports.c (AUXILIARY_WRITE_BUFFER_SIZE): New constant.
      (initialize_port_buffers): Init aux write buf.
      (scm_port_auxiliary_write_buffer): Lazily allocate an aux write
      buffer.
      (scm_c_write): Arrange to write through an aux buffer if the port is
      unbuffered.
---
 libguile/ports-internal.h |    1 +
 libguile/ports.c          |   50 ++++++++++++++++++++++++++++++++++++++++++---
 libguile/ports.h          |    1 +
 3 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/libguile/ports-internal.h b/libguile/ports-internal.h
index 7aabee7..d014415 100644
--- a/libguile/ports-internal.h
+++ b/libguile/ports-internal.h
@@ -312,6 +312,7 @@ struct scm_t_port
   /* Port buffers.  */
   SCM read_buf;
   SCM write_buf;
+  SCM write_buf_aux;
 
   /* All ports have read and write buffers; an unbuffered port simply
      has a one-byte buffer.  However unreading bytes can expand the read
diff --git a/libguile/ports.c b/libguile/ports.c
index f58da4b..3dd729d 100644
--- a/libguile/ports.c
+++ b/libguile/ports.c
@@ -56,7 +56,7 @@
 #include "libguile/strings.h"
 #include "libguile/mallocs.h"
 #include "libguile/validate.h"
-//#include "libguile/ports.h"
+#include "libguile/ports.h"
 #include "libguile/ports-internal.h"
 #include "libguile/vectors.h"
 #include "libguile/weak-set.h"
@@ -109,6 +109,9 @@ static SCM sym_error;
 static SCM sym_substitute;
 static SCM sym_escape;
 
+/* See scm_port_auxiliary_write_buffer and scm_c_write.  */
+static const size_t AUXILIARY_WRITE_BUFFER_SIZE = 256;
+
 
 
 
@@ -660,6 +663,7 @@ initialize_port_buffers (SCM port)
   pt->read_buffering = read_buf_size;
   pt->read_buf = make_port_buffer (port, read_buf_size);
   pt->write_buf = make_port_buffer (port, write_buf_size);
+  pt->write_buf_aux = SCM_BOOL_F;
 }
 
 SCM
@@ -2647,6 +2651,23 @@ SCM_DEFINE (scm_port_write_buffer, "port-write-buffer", 
1, 0, 0,
 }
 #undef FUNC_NAME
 
+SCM_DEFINE (scm_port_auxiliary_write_buffer, "port-auxiliary-write-buffer",
+            1, 0, 0, (SCM port),
+           "Return the auxiliary write buffer for a port.")
+#define FUNC_NAME s_scm_port_auxiliary_write_buffer
+{
+  scm_t_port *pt;
+
+  SCM_VALIDATE_OPPORT (1, port);
+
+  pt = SCM_PORT (port);
+  if (scm_is_false (pt->write_buf_aux))
+    pt->write_buf_aux = make_port_buffer (port, AUXILIARY_WRITE_BUFFER_SIZE);
+
+  return pt->write_buf_aux;
+}
+#undef FUNC_NAME
+
 
 
 
@@ -2774,22 +2795,45 @@ scm_c_write (SCM port, const void *ptr, size_t size)
   scm_t_port *pt;
   SCM write_buf;
   size_t written = 0;
+  int using_aux_buffer = 0;
   const scm_t_uint8 *src = ptr;
 
   SCM_VALIDATE_OPOUTPORT (1, port);
 
   pt = SCM_PORT (port);
-  write_buf = pt->write_buf;
 
   if (pt->rw_random)
     scm_end_input (port);
 
+  /* Imagine we are writing 40 bytes on an unbuffered port.  If we were
+     writing from a bytevector we could pass that write directly to the
+     port.  But since we aren't, we need to go through a bytevector, and
+     if we went through the port buffer we'd have to make 40 individual
+     calls to the write function.  That would be terrible.  Really we
+     need an intermediate bytevector.  But, we shouldn't use a trick
+     analogous to what we do with expand-port-read-buffer!, because the
+     way we use the cur and end cursors doesn't seem to facilitate that.
+     So instead we buffer through an auxiliary write buffer if needed.
+     To avoid re-allocating this buffer all the time, we store it on the
+     port.  It should never be left with buffered data.
+
+     Use of an auxiliary write buffer is triggered if the buffer is
+     smaller than the size we would make for an auxiliary write buffer,
+     and the write is bigger than the buffer.  */
+  write_buf = pt->write_buf;
+  if (scm_port_buffer_size (write_buf) < size &&
+      scm_port_buffer_size (write_buf) < AUXILIARY_WRITE_BUFFER_SIZE)
+    {
+      using_aux_buffer = 1;
+      write_buf = scm_port_auxiliary_write_buffer (port);
+    }
+
   while (written < size)
     {
       size_t did_put = scm_port_buffer_put (write_buf, src, size - written);
       written += did_put;
       src += did_put;
-      if (scm_port_buffer_can_put (write_buf) == 0)
+      if (using_aux_buffer || scm_port_buffer_can_put (write_buf) == 0)
         scm_i_write (port, write_buf);
     }
 }
diff --git a/libguile/ports.h b/libguile/ports.h
index 2ebcf06..13661e0 100644
--- a/libguile/ports.h
+++ b/libguile/ports.h
@@ -208,6 +208,7 @@ SCM_INTERNAL SCM scm_port_read (SCM port);
 SCM_INTERNAL SCM scm_port_write (SCM port);
 SCM_INTERNAL SCM scm_port_read_buffer (SCM port);
 SCM_INTERNAL SCM scm_port_write_buffer (SCM port);
+SCM_INTERNAL SCM scm_port_auxiliary_write_buffer (SCM port);
 
 /* Output.  */
 SCM_API void scm_putc (char c, SCM port);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]