guix-commits
[Top][All Lists]
Advanced

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

[shepherd] 02/02: service: Logging fibers read lines into a pre-allocate


From: Ludovic Courtès
Subject: [shepherd] 02/02: service: Logging fibers read lines into a pre-allocated buffer.
Date: Wed, 2 Nov 2022 09:25:28 -0400 (EDT)

civodul pushed a commit to branch master
in repository shepherd.

commit 0ad9f39f14fb65f4d632d46f74d35ff46c5b8f02
Author: Ludovic Courtès <ludo@gnu.org>
AuthorDate: Sat Oct 22 15:59:34 2022 +0200

    service: Logging fibers read lines into a pre-allocated buffer.
    
    This reduces heap allocation on each line that is logged.
    
    * modules/shepherd/service.scm (%logging-buffer-size): New variable.
    (read-line!): New procedure.
    (%service-file-logger): Use it instead of 'read-line'.  Use 'put-string'
    instead of 'display'.
    (service-builtin-logger): Likewise.
---
 modules/shepherd/service.scm | 54 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 43 insertions(+), 11 deletions(-)

diff --git a/modules/shepherd/service.scm b/modules/shepherd/service.scm
index 9d0ade6..e851406 100644
--- a/modules/shepherd/service.scm
+++ b/modules/shepherd/service.scm
@@ -38,7 +38,6 @@
   #:use-module (ice-9 match)
   #:use-module (ice-9 format)
   #:autoload   (ice-9 ports internal) (port-read-wait-fd)
-  #:autoload   (ice-9 rdelim) (read-line)
   #:autoload   (ice-9 pretty-print) (truncated-print)
   #:use-module (shepherd support)
   #:use-module (shepherd comm)
@@ -876,6 +875,29 @@ daemon writing FILE is running in a separate PID 
namespace."
               (try-again)
               (apply throw args)))))))
 
+(define %logging-buffer-size
+  ;; Size of the buffer for each line read by logging fibers.
+  512)
+
+(define (read-line! str port)
+  "This is an interruptible version of the 'read-line!' procedure from (ice-9
+rdelim)."
+  ;; As of Guile 3.0.8, (@ (ice-9 rdelim) read-line!) calls
+  ;; '%read-delimited!', which is in C and thus non-interruptible.
+  (define len
+    (string-length str))
+
+  (let loop ((i 0))
+    (and (< i len)
+         (match (read-char port)
+           ((? eof-object? eof)
+            eof)
+           ((or #\newline #\return)
+            i)
+           (chr
+            (string-set! str i chr)
+            (loop (+ i 1)))))))
+
 (define (%service-file-logger file input)
   "Like 'service-file-logger', but doesn't handle the case in which FILE does
 not exist."
@@ -887,17 +909,21 @@ not exist."
     (lambda ()
       (call-with-port output
         (lambda (output)
+          (define line
+            (make-string %logging-buffer-size))
+
           (let loop ()
-            (match (read-line input)
+            (match (read-line! line input)
               ((? eof-object?)
                (close-port input)
                (close-port output))
-              (line
+              (count
                (let ((prefix (strftime default-logfile-date-format
-                                       (localtime (current-time)))))
+                                       (localtime (current-time))))
+                     (count  (or count (string-length line))))
                  ;; Avoid (ice-9 format) to reduce heap allocations.
-                 (display prefix output)
-                 (display line output)
+                 (put-string output prefix)
+                 (put-string output line 0 count)
                  (newline output)
                  (loop))))))))))
 
@@ -918,18 +944,24 @@ FILE."
   "Return a thunk meant to run as a fiber that reads from INPUT and logs to
 'log-output-port'."
   (lambda ()
+    (define line
+      (make-string %logging-buffer-size))
+
     (let loop ()
-      (match (read-line input)
+      (match (read-line! line input)
         ((? eof-object?)
          (close-port input))
-        (line
+        (count
          (let ((prefix (strftime (%current-logfile-date-format)
-                                 (localtime (current-time)))))
+                                 (localtime (current-time))))
+               (count  (or count (string-length line))))
            ;; TODO: Print the PID of COMMAND.  The actual PID is potentially
            ;; not known until after 'read-pid-file' has completed, so it would
            ;; need to be communicated.
-           (simple-format (log-output-port) "~a[~a] ~a~%"
-                          prefix command line))
+           (simple-format (log-output-port) "~a[~a] "
+                          prefix command)
+           (put-string (log-output-port) line 0 count)
+           (newline (log-output-port)))
          (loop))))))
 
 (define (format-supplementary-groups supplementary-groups)



reply via email to

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