This is an automated email from the ASF dual-hosted git repository.

masayuki pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new b96035885a stdio: Implement simple buffered out stream for vdprintf
b96035885a is described below

commit b96035885a294bbfbfdccac45b1b8bdd7e58e834
Author: Huang Qi <[email protected]>
AuthorDate: Mon Feb 27 18:32:38 2023 +0800

    stdio: Implement simple buffered out stream for vdprintf
    
    Improve performance for raw fd based printf like operation.
    
    Signed-off-by: Huang Qi <[email protected]>
---
 include/nuttx/streams.h                  |  28 ++++++++
 libs/libc/stdio/lib_vdprintf.c           |   7 +-
 libs/libc/stream/Kconfig                 |   4 ++
 libs/libc/stream/Make.defs               |   2 +-
 libs/libc/stream/lib_bufferedoutstream.c | 120 +++++++++++++++++++++++++++++++
 5 files changed, 159 insertions(+), 2 deletions(-)

diff --git a/include/nuttx/streams.h b/include/nuttx/streams.h
index c49f6f0718..6ba76492b9 100644
--- a/include/nuttx/streams.h
+++ b/include/nuttx/streams.h
@@ -217,6 +217,14 @@ struct lib_rawsostream_s
   int                    fd;
 };
 
+struct lib_bufferedoutstream_s
+{
+  struct lib_outstream_s      public;
+  FAR struct lib_outstream_s *backend;
+  int                         pending;
+  char                        buffer[CONFIG_STREAM_OUT_BUFFER_SIZE];
+};
+
 /* This is a special stream that does buffered character I/O.  NOTE that is
  * CONFIG_SYSLOG_BUFFER is not defined, it is the same as struct
  * lib_outstream_s
@@ -372,6 +380,26 @@ void lib_rawoutstream(FAR struct lib_rawoutstream_s 
*outstream, int fd);
 void lib_rawsistream(FAR struct lib_rawsistream_s *instream, int fd);
 void lib_rawsostream(FAR struct lib_rawsostream_s *outstream, int fd);
 
+/****************************************************************************
+ * Name: lib_bufferedoutstream
+ *
+ * Description:
+ *   Wrap a raw output stream to a buffered output stream.
+ *
+ * Input Parameters:
+ *   outstream - User allocated, uninitialized instance of struct
+ *               lib_bufferedoutstream_s to be initialized.
+ *   backend   - User allocated, initialized instance of struct
+ *               lib_outstream_s to be buffered.
+ *
+ * Returned Value:
+ *   None (User allocated instance initialized).
+ *
+ ****************************************************************************/
+
+void lib_bufferedoutstream(FAR struct lib_bufferedoutstream_s *outstream,
+                           FAR struct lib_outstream_s *backend);
+
 /****************************************************************************
  * Name: lib_lowoutstream
  *
diff --git a/libs/libc/stdio/lib_vdprintf.c b/libs/libc/stdio/lib_vdprintf.c
index 90a4b2367c..27d94df583 100644
--- a/libs/libc/stdio/lib_vdprintf.c
+++ b/libs/libc/stdio/lib_vdprintf.c
@@ -50,10 +50,15 @@
 
 int vdprintf(int fd, FAR const IPTR char *fmt, va_list ap)
 {
+  int ret;
   struct lib_rawoutstream_s rawoutstream;
+  struct lib_bufferedoutstream_s outstream;
 
   /* Wrap the fd in a stream object and let lib_vsprintf do the work. */
 
   lib_rawoutstream(&rawoutstream, fd);
-  return lib_vsprintf(&rawoutstream.public, fmt, ap);
+  lib_bufferedoutstream(&outstream, &rawoutstream.public);
+  ret = lib_vsprintf(&outstream.public, fmt, ap);
+  lib_stream_flush(&outstream.public);
+  return ret;
 }
diff --git a/libs/libc/stream/Kconfig b/libs/libc/stream/Kconfig
index 90554aa661..77cb42e3da 100644
--- a/libs/libc/stream/Kconfig
+++ b/libs/libc/stream/Kconfig
@@ -21,4 +21,8 @@ config STREAM_LZF_BLOG
 
 endif
 
+config STREAM_OUT_BUFFER_SIZE
+       int "Output stream buffer size"
+       default 64
+
 endmenu # Locale Support
diff --git a/libs/libc/stream/Make.defs b/libs/libc/stream/Make.defs
index 868ff05576..0b6757c9bd 100644
--- a/libs/libc/stream/Make.defs
+++ b/libs/libc/stream/Make.defs
@@ -26,7 +26,7 @@ CSRCS += lib_memsostream.c lib_lowoutstream.c 
lib_rawinstream.c
 CSRCS += lib_rawoutstream.c lib_rawsistream.c lib_rawsostream.c
 CSRCS += lib_zeroinstream.c lib_nullinstream.c lib_nulloutstream.c
 CSRCS += lib_mtdoutstream.c lib_libnoflush.c lib_libsnoflush.c
-CSRCS += lib_syslogstream.c
+CSRCS += lib_syslogstream.c lib_bufferedoutstream.c
 
 # The remaining sources files depend upon C streams
 
diff --git a/libs/libc/stream/lib_bufferedoutstream.c 
b/libs/libc/stream/lib_bufferedoutstream.c
new file mode 100644
index 0000000000..4018b0cebb
--- /dev/null
+++ b/libs/libc/stream/lib_bufferedoutstream.c
@@ -0,0 +1,120 @@
+/****************************************************************************
+ * libs/libc/stream/lib_bufferedoutstream.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <nuttx/fs/fs.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: bufferedoutstream_flush
+ ****************************************************************************/
+
+static int bufferedoutstream_flush(FAR struct lib_outstream_s *this)
+{
+  FAR struct lib_bufferedoutstream_s *rthis =
+    (FAR struct lib_bufferedoutstream_s *)this;
+  int ret = OK;
+
+  ret = lib_stream_puts(rthis->backend, rthis->buffer,
+                        rthis->pending);
+
+  if (ret >= 0)
+    {
+      rthis->pending = 0;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: bufferedoutstream_puts
+ ****************************************************************************/
+
+static int bufferedoutstream_puts(FAR struct lib_outstream_s *this,
+                                 FAR const void *buf, int len)
+{
+  FAR struct lib_bufferedoutstream_s *rthis =
+    (FAR struct lib_bufferedoutstream_s *)this;
+  int ret = len;
+
+  if (rthis->pending + len <= CONFIG_STREAM_OUT_BUFFER_SIZE)
+    {
+      /* If buffer is enough to save incoming data, cache it */
+
+      memcpy(rthis->buffer + rthis->pending, buf, len);
+      rthis->pending += len;
+    }
+  else
+    {
+      /* Or, for long data flush buffer and write it directly */
+
+      ret = lib_stream_flush(this);
+      if (ret >= 0)
+        {
+          ret = lib_stream_puts(rthis->backend, buf, len);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: bufferedoutstream_putc
+ ****************************************************************************/
+
+static void bufferedoutstream_putc(FAR struct lib_outstream_s *this, int ch)
+{
+  char c = ch;
+
+  bufferedoutstream_puts(this, &c, 1);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lib_bufferedoutstream
+ ****************************************************************************/
+
+void lib_bufferedoutstream(FAR struct lib_bufferedoutstream_s *outstream,
+                           FAR struct lib_outstream_s *backend)
+{
+  outstream->public.putc  = bufferedoutstream_putc;
+  outstream->public.puts  = bufferedoutstream_puts;
+  outstream->public.flush = bufferedoutstream_flush;
+  outstream->public.nput  = 0;
+  outstream->backend      = backend;
+  outstream->pending      = 0;
+}

Reply via email to