unofficial mirror of guix-devel@gnu.org 
 help / color / mirror / code / Atom feed
* RPC pipelining
@ 2017-07-10 15:50 Ludovic Courtès
  2017-07-11 11:18 ` Roel Janssen
  0 siblings, 1 reply; 6+ messages in thread
From: Ludovic Courtès @ 2017-07-10 15:50 UTC (permalink / raw)
  To: guix-devel

[-- Attachment #1: Type: text/plain, Size: 3099 bytes --]

Hello Guix!

One of the main sources of slowness when talking to a remote daemon, as
with GUIX_DAEMON_SOCKET=guix://…, is the many RPCs that translate in
lots of network round trips:

--8<---------------cut here---------------start------------->8---
$ GUIX_PROFILING=rpc ./pre-inst-env guix build inkscape -d --no-grafts
/gnu/store/iymxyy5sn0qrkivppl6fn0javnmr3nss-inkscape-0.92.1.drv
Remote procedure call summary: 1006 RPCs
  built-in-builders              ...     1
  add-to-store                   ...   136
  add-text-to-store              ...   869
--8<---------------cut here---------------end--------------->8---

In this example we’re making ~1,000 round trips; not good!

Before changing the protocol, an idea that came to mind is to do “RPC
pipelining”: send as many RPC requests at once, then read all the
corresponding responses.

It turns out to necessitate a small change in the daemon, though, but
the attached patch demonstrates it: the client buffers all
‘add-text-to-store’ RPCs, and writes them all at once when another RPC
is made (because other RPCs, which are not buffered, might depend on the
effect of those ‘add-text-to-store’ RPCs) or when the connection is
closed.  In practice, on the example above, it manages to buffer all 869
RPCs and send them all at once.

To estimate the effectiveness of this approach, I introduced delay on
the loopback device with tc-netem(8) and measured execution time (the
first run uses pipelining, the second doesn’t):

--8<---------------cut here---------------start------------->8---
$ sudo tc qdisc add dev lo root netem delay 150ms
$ time GUIX_DAEMON_SOCKET=guix://localhost ./pre-inst-env guix build inkscape -d --no-grafts
accepted connection from 127.0.0.1
/gnu/store/iymxyy5sn0qrkivppl6fn0javnmr3nss-inkscape-0.92.1.drv

;;; (flush-pending-rpcs 869)

real	0m47.796s
user	0m1.307s
sys	0m0.056s
$ time GUIX_DAEMON_SOCKET=guix://localhost guix build inkscape -d --no-grafts
accepted connection from 127.0.0.1
/gnu/store/iymxyy5sn0qrkivppl6fn0javnmr3nss-inkscape-0.92.1.drv

real	5m7.226s
user	0m1.392s
sys	0m0.056s
$ sudo tc qdisc del dev lo root
--8<---------------cut here---------------end--------------->8---

So the wall-clock time is divided by 6 thanks to ‘add-text-to-store’
pipelining, but it’s still pretty high due to the 136 ‘add-to-store’
RPCs which are still *not* pipelined.

It’s less clear what to do with these.  Buffering them would require
clients to compute the store file name of the files that are passed to
‘add-to-store’, which involves computing the hash of the files itself,
which can be quite costly and redundant with what the daemon will do
eventually anyway.  The CPU cost might be compensated for when latency
is high, but not when latency is low.

Anyway, food for thought!

For now, if those using Guix on clusters are willing to test the patch
below (notice that you need to run the patched guix-daemon as well), I’d
be interested in seeing how representative the above test is!

Ludo’.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-patch, Size: 8588 bytes --]

diff --git a/guix/store.scm b/guix/store.scm
index b15da5485..1ba22cf2d 100644
--- a/guix/store.scm
+++ b/guix/store.scm
@@ -40,6 +40,7 @@
   #:use-module (ice-9 regex)
   #:use-module (ice-9 vlist)
   #:use-module (ice-9 popen)
+  #:use-module (ice-9 format)
   #:use-module (web uri)
   #:export (%daemon-socket-uri
             %gc-roots-directory
@@ -322,7 +323,7 @@
 
 (define-record-type <nix-server>
   (%make-nix-server socket major minor
-                    buffer flush
+                    buffer flush pending-rpcs
                     ats-cache atts-cache)
   nix-server?
   (socket nix-server-socket)
@@ -332,6 +333,10 @@
   (buffer nix-server-output-port)                 ;output port
   (flush  nix-server-flush-output)                ;thunk
 
+  ;; List of pending 'add-text-to-store' RPC arguments.
+  (pending-rpcs nix-server-pending-rpcs
+                set-nix-server-pending-rpcs!)
+
   ;; Caches.  We keep them per-connection, because store paths build
   ;; during the session are temporary GC roots kept for the duration of
   ;; the session.
@@ -509,7 +514,7 @@ for this connection will be pinned.  Return a server object."
                       (let ((conn (%make-nix-server port
                                                     (protocol-major v)
                                                     (protocol-minor v)
-                                                    output flush
+                                                    output flush '()
                                                     (make-hash-table 100)
                                                     (make-hash-table 100))))
                         (let loop ((done? (process-stderr conn)))
@@ -521,8 +526,17 @@ for this connection will be pinned.  Return a server object."
   (force-output (nix-server-output-port server))
   ((nix-server-flush-output server)))
 
+(define (flush-pending-rpcs server)
+  (let ((len (length (nix-server-pending-rpcs server))))
+    (when (> len 0)
+      (pk 'flush-pending-rpcs len)
+      (add-data-to-store/multiple server
+                                  (reverse (nix-server-pending-rpcs server)))
+      (set-nix-server-pending-rpcs! server '()))))
+
 (define (close-connection server)
   "Close the connection to SERVER."
+  (flush-pending-rpcs server)
   (close (nix-server-socket server)))
 
 (define-syntax-rule (with-store store exp ...)
@@ -811,6 +825,8 @@ bytevector) as its internal buffer, and a thunk to flush this output port."
        docstring
        (let* ((s (nix-server-socket server))
               (buffered (nix-server-output-port server)))
+         (unless (eq? 'name 'add-text-to-store)
+           (flush-pending-rpcs server))
          (record-operation 'name)
          (write-int (operation-id name) buffered)
          (write-arg type arg buffered)
@@ -822,6 +838,32 @@ bytevector) as its internal buffer, and a thunk to flush this output port."
            (or done? (loop (process-stderr server))))
          (values (read-arg return s) ...))))))
 
+
+(define-syntax operation-pipeline
+  (syntax-rules ()
+    "Define a client-side RPC stub for the given operation."
+    ((_ (name (type arg) ...) docstring return ...)
+     (lambda (server arg-list)
+       docstring
+       (let* ((s (nix-server-socket server))
+              (buffered (nix-server-output-port server)))
+         (record-operation 'name)
+         (for-each (match-lambda
+                     ((arg ...)
+                      (write-int (operation-id name) buffered)
+                      (write-arg type arg buffered)
+                      ...))
+                   arg-list)
+         (write-buffered-output server)
+
+         (map (lambda (_)
+                ;; Loop until the server is done sending error output.
+                (let loop ((done? (process-stderr server)))
+                  (or done? (loop (process-stderr server))))
+
+                (list (read-arg return s) ...))
+              arg-list))))))
+
 (define-syntax-rule (define-operation (name args ...)
                       docstring return ...)
   (define name
@@ -856,6 +898,20 @@ string).  Raise an error if no such path exists."
   "Return the info (hash, references, etc.) for PATH."
   path-info)
 
+(define add-data-to-store/multiple
+  (operation-pipeline
+   (add-text-to-store (string name) (bytevector text)
+                      (string-list references))
+   #f
+   store-path))
+
+(define (add-data-to-store/buffer server name bytes references)
+  (let ((pending (nix-server-pending-rpcs server)))
+    (set-nix-server-pending-rpcs! server
+                                  (cons (list name bytes references)
+                                        pending))
+    (text-output-path name bytes references)))
+
 (define add-data-to-store
   ;; A memoizing version of `add-to-store', to avoid repeated RPCs with
   ;; the very same arguments during a given session.
@@ -871,7 +927,7 @@ path."
       (let* ((args  `(,bytes ,name ,references))
              (cache (nix-server-add-text-to-store-cache server)))
         (or (hash-ref cache args)
-            (let ((path (add-text-to-store server name bytes references)))
+            (let ((path (add-data-to-store/buffer server name bytes references)))
               (hash-set! cache args path)
               path))))))
 
@@ -1485,6 +1541,16 @@ the derivation called NAME with hash HASH."
                   name
                   (string-append name "-" output))))
 
+(define (text-output-path name bv references)
+  "Return an output path for NAME, with contents BV and the given REFERENCES.
+The result is the same as that produced by 'add-data-to-store' with the same
+arguments."
+  (store-path (string-append "text"
+                             (string-join (sort references string<?)
+                                          ":" 'prefix))
+              (sha256 bv)
+              name))
+
 (define* (fixed-output-path name hash
                             #:key
                             (output "out")
diff --git a/nix/nix-daemon/nix-daemon.cc b/nix/nix-daemon/nix-daemon.cc
index 7d26b6135..72851e1cb 100644
--- a/nix/nix-daemon/nix-daemon.cc
+++ b/nix/nix-daemon/nix-daemon.cc
@@ -9,6 +9,7 @@
 #include "builtins.hh"
 
 #include <algorithm>
+#include <iostream>
 
 #include <cstring>
 #include <unistd.h>
@@ -79,8 +80,7 @@ static void tunnelStderr(const unsigned char * buf, size_t count)
 
 
 /* Return true if the remote side has closed its end of the
-   connection, false otherwise.  Should not be called on any socket on
-   which we expect input! */
+   connection, false otherwise.  */
 static bool isFarSideClosed(int socket)
 {
     struct timeval timeout;
@@ -95,17 +95,24 @@ static bool isFarSideClosed(int socket)
 
     if (!FD_ISSET(socket, &fds)) return false;
 
-    /* Destructive read to determine whether the select() marked the
-       socket as readable because there is actual input or because
-       we've reached EOF (i.e., a read of size 0 is available). */
-    char c;
-    int rd;
-    if ((rd = read(socket, &c, 1)) > 0)
-        throw Error("EOF expected (protocol error?)");
-    else if (rd == -1 && errno != ECONNRESET)
-        throw SysError("expected connection reset or EOF");
+    /* Check whether whether 'select' marked the socket as readable because
+       there is actual input or because we've reached EOF (i.e., a read of
+       size 0 is available).  */
+    char c; int rd;
+    do {
+	rd = recv(socket, &c, sizeof c, MSG_PEEK);
+    }
+    while (rd == -1 && errno == EINTR);
 
-    return true;
+    if (rd == -1) {
+	if (errno == ECONNRESET)
+	    /* Remote side is definitely closed.  */
+	    return true;
+	else
+	    throw SysError("while peeking client input");
+    }
+
+    return rd == 0;
 }
 
 
@@ -136,9 +143,6 @@ static void sigPollHandler(int sigNo)
                 const char * s = "SIGPOLL\n";
                 write(STDERR_FILENO, s, strlen(s));
             }
-        } else {
-            const char * s = "spurious SIGPOLL\n";
-            write(STDERR_FILENO, s, strlen(s));
         }
     }
     catch (Error & e) {
@@ -847,8 +851,8 @@ static void acceptConnection(int fdSocket)
 
 	  /* If we're on a TCP connection, disable Nagle's algorithm so that
 	     data is sent as soon as possible.  */
-	  (void) setsockopt(remote, SOL_TCP, TCP_NODELAY,
-			    &enabled, sizeof enabled);
+	  // (void) setsockopt(remote, SOL_TCP, TCP_NODELAY,
+	  // 		    &enabled, sizeof enabled);
 
 #if defined(TCP_QUICKACK)
 	  /* Enable TCP quick-ack if applicable; this might help a little.  */

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: RPC pipelining
  2017-07-10 15:50 RPC pipelining Ludovic Courtès
@ 2017-07-11 11:18 ` Roel Janssen
  2017-07-11 14:40   ` Ludovic Courtès
  0 siblings, 1 reply; 6+ messages in thread
From: Roel Janssen @ 2017-07-11 11:18 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guix-devel

Hello Ludo’!

Thanks for working so hard on this.
I run into trouble with my test setup..

[roel@hpcguix ~]$ time ./guixr environment --ad-hoc coreutils -- true

;;; (flush-pending-rpcs 170)

;;; (flush-pending-rpcs 4)
substitute: guix substitute: warning: ACL for archive imports seems to be uninitialized, substitutes may be unavailable
substitute: ;;; Failed to autoload make-session in (gnutls):
substitute: ;;; ERROR: missing interface for module (gnutls)
substitute: Backtrace:
substitute:            1 (primitive-load "/gnu/repositories/guix/scripts/guix")
substitute: In guix/ui.scm:
substitute:   1352:12  0 (run-guix-command _ . _)
substitute: 
substitute: guix/ui.scm:1352:12: In procedure run-guix-command:
substitute: guix/ui.scm:1352:12: In procedure module-lookup: Unbound variable: make-session
guix environment: error: build failed: writing to file: Broken pipe

real    0m8.679s
user    0m1.199s
sys     0m0.202s


But FWIW, I think the time between no output and the "substitute: ..."
output is dramatically shorter.

I'll report back when I have a better testing environment ready.

Kind regards,
Roel Janssen


Ludovic Courtès writes:

> Hello Guix!
>
> One of the main sources of slowness when talking to a remote daemon, as
> with GUIX_DAEMON_SOCKET=guix://…, is the many RPCs that translate in
> lots of network round trips:
>
> --8<---------------cut here---------------start------------->8---
> $ GUIX_PROFILING=rpc ./pre-inst-env guix build inkscape -d --no-grafts
> /gnu/store/iymxyy5sn0qrkivppl6fn0javnmr3nss-inkscape-0.92.1.drv
> Remote procedure call summary: 1006 RPCs
>   built-in-builders              ...     1
>   add-to-store                   ...   136
>   add-text-to-store              ...   869
> --8<---------------cut here---------------end--------------->8---
>
> In this example we’re making ~1,000 round trips; not good!
>
> Before changing the protocol, an idea that came to mind is to do “RPC
> pipelining”: send as many RPC requests at once, then read all the
> corresponding responses.
>
> It turns out to necessitate a small change in the daemon, though, but
> the attached patch demonstrates it: the client buffers all
> ‘add-text-to-store’ RPCs, and writes them all at once when another RPC
> is made (because other RPCs, which are not buffered, might depend on the
> effect of those ‘add-text-to-store’ RPCs) or when the connection is
> closed.  In practice, on the example above, it manages to buffer all 869
> RPCs and send them all at once.
>
> To estimate the effectiveness of this approach, I introduced delay on
> the loopback device with tc-netem(8) and measured execution time (the
> first run uses pipelining, the second doesn’t):
>
> --8<---------------cut here---------------start------------->8---
> $ sudo tc qdisc add dev lo root netem delay 150ms
> $ time GUIX_DAEMON_SOCKET=guix://localhost ./pre-inst-env guix build inkscape -d --no-grafts
> accepted connection from 127.0.0.1
> /gnu/store/iymxyy5sn0qrkivppl6fn0javnmr3nss-inkscape-0.92.1.drv
>
> ;;; (flush-pending-rpcs 869)
>
> real	0m47.796s
> user	0m1.307s
> sys	0m0.056s
> $ time GUIX_DAEMON_SOCKET=guix://localhost guix build inkscape -d --no-grafts
> accepted connection from 127.0.0.1
> /gnu/store/iymxyy5sn0qrkivppl6fn0javnmr3nss-inkscape-0.92.1.drv
>
> real	5m7.226s
> user	0m1.392s
> sys	0m0.056s
> $ sudo tc qdisc del dev lo root
> --8<---------------cut here---------------end--------------->8---
>
> So the wall-clock time is divided by 6 thanks to ‘add-text-to-store’
> pipelining, but it’s still pretty high due to the 136 ‘add-to-store’
> RPCs which are still *not* pipelined.
>
> It’s less clear what to do with these.  Buffering them would require
> clients to compute the store file name of the files that are passed to
> ‘add-to-store’, which involves computing the hash of the files itself,
> which can be quite costly and redundant with what the daemon will do
> eventually anyway.  The CPU cost might be compensated for when latency
> is high, but not when latency is low.
>
> Anyway, food for thought!
>
> For now, if those using Guix on clusters are willing to test the patch
> below (notice that you need to run the patched guix-daemon as well), I’d
> be interested in seeing how representative the above test is!
>
> Ludo’.
>
> diff --git a/guix/store.scm b/guix/store.scm
> index b15da5485..1ba22cf2d 100644
> --- a/guix/store.scm
> +++ b/guix/store.scm
> @@ -40,6 +40,7 @@
>    #:use-module (ice-9 regex)
>    #:use-module (ice-9 vlist)
>    #:use-module (ice-9 popen)
> +  #:use-module (ice-9 format)
>    #:use-module (web uri)
>    #:export (%daemon-socket-uri
>              %gc-roots-directory
> @@ -322,7 +323,7 @@
>  
>  (define-record-type <nix-server>
>    (%make-nix-server socket major minor
> -                    buffer flush
> +                    buffer flush pending-rpcs
>                      ats-cache atts-cache)
>    nix-server?
>    (socket nix-server-socket)
> @@ -332,6 +333,10 @@
>    (buffer nix-server-output-port)                 ;output port
>    (flush  nix-server-flush-output)                ;thunk
>  
> +  ;; List of pending 'add-text-to-store' RPC arguments.
> +  (pending-rpcs nix-server-pending-rpcs
> +                set-nix-server-pending-rpcs!)
> +
>    ;; Caches.  We keep them per-connection, because store paths build
>    ;; during the session are temporary GC roots kept for the duration of
>    ;; the session.
> @@ -509,7 +514,7 @@ for this connection will be pinned.  Return a server object."
>                        (let ((conn (%make-nix-server port
>                                                      (protocol-major v)
>                                                      (protocol-minor v)
> -                                                    output flush
> +                                                    output flush '()
>                                                      (make-hash-table 100)
>                                                      (make-hash-table 100))))
>                          (let loop ((done? (process-stderr conn)))
> @@ -521,8 +526,17 @@ for this connection will be pinned.  Return a server object."
>    (force-output (nix-server-output-port server))
>    ((nix-server-flush-output server)))
>  
> +(define (flush-pending-rpcs server)
> +  (let ((len (length (nix-server-pending-rpcs server))))
> +    (when (> len 0)
> +      (pk 'flush-pending-rpcs len)
> +      (add-data-to-store/multiple server
> +                                  (reverse (nix-server-pending-rpcs server)))
> +      (set-nix-server-pending-rpcs! server '()))))
> +
>  (define (close-connection server)
>    "Close the connection to SERVER."
> +  (flush-pending-rpcs server)
>    (close (nix-server-socket server)))
>  
>  (define-syntax-rule (with-store store exp ...)
> @@ -811,6 +825,8 @@ bytevector) as its internal buffer, and a thunk to flush this output port."
>         docstring
>         (let* ((s (nix-server-socket server))
>                (buffered (nix-server-output-port server)))
> +         (unless (eq? 'name 'add-text-to-store)
> +           (flush-pending-rpcs server))
>           (record-operation 'name)
>           (write-int (operation-id name) buffered)
>           (write-arg type arg buffered)
> @@ -822,6 +838,32 @@ bytevector) as its internal buffer, and a thunk to flush this output port."
>             (or done? (loop (process-stderr server))))
>           (values (read-arg return s) ...))))))
>  
> +
> +(define-syntax operation-pipeline
> +  (syntax-rules ()
> +    "Define a client-side RPC stub for the given operation."
> +    ((_ (name (type arg) ...) docstring return ...)
> +     (lambda (server arg-list)
> +       docstring
> +       (let* ((s (nix-server-socket server))
> +              (buffered (nix-server-output-port server)))
> +         (record-operation 'name)
> +         (for-each (match-lambda
> +                     ((arg ...)
> +                      (write-int (operation-id name) buffered)
> +                      (write-arg type arg buffered)
> +                      ...))
> +                   arg-list)
> +         (write-buffered-output server)
> +
> +         (map (lambda (_)
> +                ;; Loop until the server is done sending error output.
> +                (let loop ((done? (process-stderr server)))
> +                  (or done? (loop (process-stderr server))))
> +
> +                (list (read-arg return s) ...))
> +              arg-list))))))
> +
>  (define-syntax-rule (define-operation (name args ...)
>                        docstring return ...)
>    (define name
> @@ -856,6 +898,20 @@ string).  Raise an error if no such path exists."
>    "Return the info (hash, references, etc.) for PATH."
>    path-info)
>  
> +(define add-data-to-store/multiple
> +  (operation-pipeline
> +   (add-text-to-store (string name) (bytevector text)
> +                      (string-list references))
> +   #f
> +   store-path))
> +
> +(define (add-data-to-store/buffer server name bytes references)
> +  (let ((pending (nix-server-pending-rpcs server)))
> +    (set-nix-server-pending-rpcs! server
> +                                  (cons (list name bytes references)
> +                                        pending))
> +    (text-output-path name bytes references)))
> +
>  (define add-data-to-store
>    ;; A memoizing version of `add-to-store', to avoid repeated RPCs with
>    ;; the very same arguments during a given session.
> @@ -871,7 +927,7 @@ path."
>        (let* ((args  `(,bytes ,name ,references))
>               (cache (nix-server-add-text-to-store-cache server)))
>          (or (hash-ref cache args)
> -            (let ((path (add-text-to-store server name bytes references)))
> +            (let ((path (add-data-to-store/buffer server name bytes references)))
>                (hash-set! cache args path)
>                path))))))
>  
> @@ -1485,6 +1541,16 @@ the derivation called NAME with hash HASH."
>                    name
>                    (string-append name "-" output))))
>  
> +(define (text-output-path name bv references)
> +  "Return an output path for NAME, with contents BV and the given REFERENCES.
> +The result is the same as that produced by 'add-data-to-store' with the same
> +arguments."
> +  (store-path (string-append "text"
> +                             (string-join (sort references string<?)
> +                                          ":" 'prefix))
> +              (sha256 bv)
> +              name))
> +
>  (define* (fixed-output-path name hash
>                              #:key
>                              (output "out")
> diff --git a/nix/nix-daemon/nix-daemon.cc b/nix/nix-daemon/nix-daemon.cc
> index 7d26b6135..72851e1cb 100644
> --- a/nix/nix-daemon/nix-daemon.cc
> +++ b/nix/nix-daemon/nix-daemon.cc
> @@ -9,6 +9,7 @@
>  #include "builtins.hh"
>  
>  #include <algorithm>
> +#include <iostream>
>  
>  #include <cstring>
>  #include <unistd.h>
> @@ -79,8 +80,7 @@ static void tunnelStderr(const unsigned char * buf, size_t count)
>  
>  
>  /* Return true if the remote side has closed its end of the
> -   connection, false otherwise.  Should not be called on any socket on
> -   which we expect input! */
> +   connection, false otherwise.  */
>  static bool isFarSideClosed(int socket)
>  {
>      struct timeval timeout;
> @@ -95,17 +95,24 @@ static bool isFarSideClosed(int socket)
>  
>      if (!FD_ISSET(socket, &fds)) return false;
>  
> -    /* Destructive read to determine whether the select() marked the
> -       socket as readable because there is actual input or because
> -       we've reached EOF (i.e., a read of size 0 is available). */
> -    char c;
> -    int rd;
> -    if ((rd = read(socket, &c, 1)) > 0)
> -        throw Error("EOF expected (protocol error?)");
> -    else if (rd == -1 && errno != ECONNRESET)
> -        throw SysError("expected connection reset or EOF");
> +    /* Check whether whether 'select' marked the socket as readable because
> +       there is actual input or because we've reached EOF (i.e., a read of
> +       size 0 is available).  */
> +    char c; int rd;
> +    do {
> +	rd = recv(socket, &c, sizeof c, MSG_PEEK);
> +    }
> +    while (rd == -1 && errno == EINTR);
>  
> -    return true;
> +    if (rd == -1) {
> +	if (errno == ECONNRESET)
> +	    /* Remote side is definitely closed.  */
> +	    return true;
> +	else
> +	    throw SysError("while peeking client input");
> +    }
> +
> +    return rd == 0;
>  }
>  
>  
> @@ -136,9 +143,6 @@ static void sigPollHandler(int sigNo)
>                  const char * s = "SIGPOLL\n";
>                  write(STDERR_FILENO, s, strlen(s));
>              }
> -        } else {
> -            const char * s = "spurious SIGPOLL\n";
> -            write(STDERR_FILENO, s, strlen(s));
>          }
>      }
>      catch (Error & e) {
> @@ -847,8 +851,8 @@ static void acceptConnection(int fdSocket)
>  
>  	  /* If we're on a TCP connection, disable Nagle's algorithm so that
>  	     data is sent as soon as possible.  */
> -	  (void) setsockopt(remote, SOL_TCP, TCP_NODELAY,
> -			    &enabled, sizeof enabled);
> +	  // (void) setsockopt(remote, SOL_TCP, TCP_NODELAY,
> +	  // 		    &enabled, sizeof enabled);
>  
>  #if defined(TCP_QUICKACK)
>  	  /* Enable TCP quick-ack if applicable; this might help a little.  */

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: RPC pipelining
  2017-07-11 11:18 ` Roel Janssen
@ 2017-07-11 14:40   ` Ludovic Courtès
  2017-07-12 10:32     ` Roel Janssen
  0 siblings, 1 reply; 6+ messages in thread
From: Ludovic Courtès @ 2017-07-11 14:40 UTC (permalink / raw)
  To: Roel Janssen; +Cc: guix-devel

Hi Roel,

Roel Janssen <roel@gnu.org> skribis:

> substitute: guix substitute: warning: ACL for archive imports seems to be uninitialized, substitutes may be unavailable
> substitute: ;;; Failed to autoload make-session in (gnutls):
> substitute: ;;; ERROR: missing interface for module (gnutls)
> substitute: Backtrace:
> substitute:            1 (primitive-load "/gnu/repositories/guix/scripts/guix")
> substitute: In guix/ui.scm:
> substitute:   1352:12  0 (run-guix-command _ . _)
> substitute: 
> substitute: guix/ui.scm:1352:12: In procedure run-guix-command:
> substitute: guix/ui.scm:1352:12: In procedure module-lookup: Unbound variable: make-session
> guix environment: error: build failed: writing to file: Broken pipe

This is because ‘guix substitute’, called by ‘guix-daemon’, doesn’t find
(gnutls) in its GUILE_LOAD_PATH.

Use either “sudo -E ./pre-inst-env guix-daemon …” so that guix-daemon
inherits GUILE_LOAD_PATH and GUILE_LOAD_COMPILED_PATH, or
--no-substitutes.

Thanks for testing!

Ludo’.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: RPC pipelining
  2017-07-11 14:40   ` Ludovic Courtès
@ 2017-07-12 10:32     ` Roel Janssen
  2017-07-12 13:23       ` Ricardo Wurmus
  0 siblings, 1 reply; 6+ messages in thread
From: Roel Janssen @ 2017-07-12 10:32 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guix-devel


Ludovic Courtès writes:

> Hi Roel,
>
> Roel Janssen <roel@gnu.org> skribis:
>
>> substitute: guix substitute: warning: ACL for archive imports seems to be uninitialized, substitutes may be unavailable
>> substitute: ;;; Failed to autoload make-session in (gnutls):
>> substitute: ;;; ERROR: missing interface for module (gnutls)
>> substitute: Backtrace:
>> substitute:            1 (primitive-load "/gnu/repositories/guix/scripts/guix")
>> substitute: In guix/ui.scm:
>> substitute:   1352:12  0 (run-guix-command _ . _)
>> substitute: 
>> substitute: guix/ui.scm:1352:12: In procedure run-guix-command:
>> substitute: guix/ui.scm:1352:12: In procedure module-lookup: Unbound variable: make-session
>> guix environment: error: build failed: writing to file: Broken pipe
>
> This is because ‘guix substitute’, called by ‘guix-daemon’, doesn’t find
> (gnutls) in its GUILE_LOAD_PATH.
>
> Use either “sudo -E ./pre-inst-env guix-daemon …” so that guix-daemon
> inherits GUILE_LOAD_PATH and GUILE_LOAD_COMPILED_PATH, or
> --no-substitutes.
>
> Thanks for testing!
>
> Ludo’.

Thanks for the pointer.  I think it was a bad idea to try it with the
pre-inst-env, because before it even got to this point I had to modify
the location of guile in the header of scripts/guix.

So, maybe I shouldn't be using the pre-inst-env at all and just
properly install the patched version.  I can always --roll-back anyway.

So I applied the patch, and ran:
make dist

Which produced a tarball.
I then modified the guix recipe to use the tarball instead of a git
checkout.  But unfortunately, building it is again troublesome:

...
  GUILEC   guix/scripts/import/gem.go
  GUILEC   guix/scripts/import/pypi.go
  GUILEC   guix/scripts/import/stackage.go
  GUILEC   guix/ssh.go
  GUILEC   guix/scripts/copy.go
  GUILEC   guix/store/ssh.go
  GUILEC   guix/scripts/offload.go
  GUILEC   guix/config.go
  GUILEC   guix/tests.go
  GUILEC   guix/tests/http.go
;;; Failed to autoload make-page-map in (charting):
;;; ERROR: missing interface for module (charting)
;;; Failed to autoload make-page-map in (charting):
;;; ERROR: missing interface for module (charting)
;;; Failed to autoload read-pid-file in (shepherd service):
;;; ERROR: missing interface for module (shepherd service)
;;; Failed to autoload read-pid-file in (shepherd service):
;;; ERROR: missing interface for module (shepherd service)
;;; Failed to autoload exec-command in (shepherd service):
;;; ERROR: missing interface for module (shepherd service)
;;; Failed to autoload read-pid-file in (shepherd service):
;;; ERROR: missing interface for module (shepherd service)
random seed for tests: 1499856249
;;; Failed to autoload make-page-map in (charting):
;;; ERROR: missing interface for module (charting)
;;; Failed to autoload make-page-map in (charting):
;;; ERROR: missing interface for module (charting)
;;; Failed to autoload make-page-map in (charting):
;;; ERROR: missing interface for module (charting)
guix/scripts/size.scm:211:2: warning: possibly unbound variable `make-page-map'
;;; Failed to autoload make-page-map in (charting):
;;; ERROR: missing interface for module (charting)
;;; Failed to autoload make-page-map in (charting):
;;; ERROR: missing interface for module (charting)
;;; Failed to autoload read-pid-file in (shepherd service):
;;; ERROR: missing interface for module (shepherd service)
;;; Failed to autoload read-pid-file in (shepherd service):
;;; ERROR: missing interface for module (shepherd service)
;;; Failed to autoload exec-command in (shepherd service):
;;; ERROR: missing interface for module (shepherd service)
;;; Failed to autoload read-pid-file in (shepherd service):
;;; ERROR: missing interface for module (shepherd service)
;;; Failed to autoload read-pid-file in (shepherd service):
;;; ERROR: missing interface for module (shepherd service)
;;; Failed to autoload exec-command in (shepherd service):
;;; ERROR: missing interface for module (shepherd service)
;;; Failed to autoload read-pid-file in (shepherd service):
;;; ERROR: missing interface for module (shepherd service)
gnu/build/shepherd.scm:98:13: warning: possibly unbound variable `read-pid-file'
gnu/build/shepherd.scm:159:32: warning: possibly unbound variable `exec-command'
gnu/build/shepherd.scm:170:14: warning: possibly unbound variable `read-pid-file'
;;; Failed to autoload read-pid-file in (shepherd service):
;;; ERROR: missing interface for module (shepherd service)
;;; Failed to autoload exec-command in (shepherd service):
;;; ERROR: missing interface for module (shepherd service)
;;; Failed to autoload read-pid-file in (shepherd service):
;;; ERROR: missing interface for module (shepherd service)
;;; Failed to autoload read-pid-file in (shepherd service):
;;; ERROR: missing interface for module (shepherd service)
;;; Failed to autoload exec-command in (shepherd service):
;;; ERROR: missing interface for module (shepherd service)
;;; Failed to autoload read-pid-file in (shepherd service):
;;; ERROR: missing interface for module (shepherd service)

Some deprecated features have been used.  Set the environment
variable GUILE_WARN_DEPRECATED to "detailed" and rerun the
program to get more information.  Set it to "no" to suppress
this message.
...


Why does Guix need Shepherd?  And if it needs the (charting)
module, why isn't guile-charting already an input?

If I could get this to work, then I could use this mechanism in the
future too, to test patches on our cluster before they end up in
upstream.

Kind regards,
Roel Janssen

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: RPC pipelining
  2017-07-12 10:32     ` Roel Janssen
@ 2017-07-12 13:23       ` Ricardo Wurmus
  2017-07-17  7:55         ` Ludovic Courtès
  0 siblings, 1 reply; 6+ messages in thread
From: Ricardo Wurmus @ 2017-07-12 13:23 UTC (permalink / raw)
  To: Roel Janssen; +Cc: guix-devel, Ludovic Courtès


> Why does Guix need Shepherd?  And if it needs the (charting)
> module, why isn't guile-charting already an input?

Guile Charting is optional.  The error is misleadingly alarming.

-- 
Ricardo

GPG: BCA6 89B6 3655 3801 C3C6  2150 197A 5888 235F ACAC
https://elephly.net

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: RPC pipelining
  2017-07-12 13:23       ` Ricardo Wurmus
@ 2017-07-17  7:55         ` Ludovic Courtès
  0 siblings, 0 replies; 6+ messages in thread
From: Ludovic Courtès @ 2017-07-17  7:55 UTC (permalink / raw)
  To: Ricardo Wurmus; +Cc: guix-devel

Ricardo Wurmus <rekado@elephly.net> skribis:

>> Why does Guix need Shepherd?  And if it needs the (charting)
>> module, why isn't guile-charting already an input?
>
> Guile Charting is optional.  The error is misleadingly alarming.

Yes, same for Shepherd (both are mere warnings, but I agree they can be
misleading.)

Does “make dist” eventually fail?

Thanks,
Ludo’.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2017-07-17  7:55 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-07-10 15:50 RPC pipelining Ludovic Courtès
2017-07-11 11:18 ` Roel Janssen
2017-07-11 14:40   ` Ludovic Courtès
2017-07-12 10:32     ` Roel Janssen
2017-07-12 13:23       ` Ricardo Wurmus
2017-07-17  7:55         ` Ludovic Courtès

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).