From mboxrd@z Thu Jan 1 00:00:00 1970 From: ludovic.courtes@inria.fr (Ludovic =?utf-8?Q?Court=C3=A8s?=) Subject: Re: RPC performance Date: Mon, 19 Jun 2017 10:15:51 +0200 Message-ID: <87poe01jgo.fsf@gnu.org> References: <20170527105641.9426-1-mail@cbaines.net> <20170527123113.1ca668e7@cbaines.net> <87tw424cap.fsf@gnu.org> <87fufhkw85.fsf@gnu.org> <871sr0ok2h.fsf@gnu.org> <8760gbh2th.fsf@gnu.org> <87efuym57c.fsf@gnu.org> <87a85kt7ad.fsf_-_@gnu.org> <87a85hnvqm.fsf@gnu.org> <87tw3lyz7t.fsf@inria.fr> <87poe4c5y9.fsf_-_@gnu.org> <87fuezkquf.fsf@gnu.org> <87lgoq8ch8.fsf@gnu.org> <87k2497kk7.fsf@elephly.net> <87vans1k5e.fsf_-_@inria.fr> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Return-path: Received: from eggs.gnu.org ([2001:4830:134:3::10]:35416) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dMrqo-0007hp-Cy for guix-devel@gnu.org; Mon, 19 Jun 2017 04:15:59 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dMrql-00088e-5r for guix-devel@gnu.org; Mon, 19 Jun 2017 04:15:58 -0400 Received: from mail2-relais-roc.national.inria.fr ([192.134.164.83]:37832) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dMrqk-00086a-Ol for guix-devel@gnu.org; Mon, 19 Jun 2017 04:15:55 -0400 In-Reply-To: <87vans1k5e.fsf_-_@inria.fr> ("Ludovic \=\?utf-8\?Q\?Court\=C3\=A8s\?\= \=\?utf-8\?Q\?\=22's\?\= message of "Mon, 19 Jun 2017 10:01:01 +0200") List-Id: "Development of GNU Guix and the GNU System distribution." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-devel-bounces+gcggd-guix-devel=m.gmane.org@gnu.org Sender: "Guix-devel" To: Ricardo Wurmus Cc: guix-devel@gnu.org --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable ludovic.courtes@inria.fr (Ludovic Court=C3=A8s) skribis: > There are several ways we can improve it, and over time we should try to > implement all of them: > > 1. Buffer writes to the server socket (currently it=E2=80=99s terrible = if you > look at the =E2=80=98write=E2=80=99 calls in =E2=80=98strace=E2=80= =99). Could you test the effect of the patch below? It reduces the number of =E2=80=98write=E2=80=99 calls from 9.5K to 2.0K on =E2=80=9Cguix build pyth= on2-numpy=E2=80=9D. (It=E2=80=99s not acceptable as-is because it allocates a new port and associated buffer at each RPC, meaning that on my laptop the cost in user time slightly outweighs the cost in system time.) Ludo=E2=80=99. --=-=-= Content-Type: text/x-patch Content-Disposition: inline diff --git a/guix/store.scm b/guix/store.scm index 2acab6b1a..47fa3447f 100644 --- a/guix/store.scm +++ b/guix/store.scm @@ -321,13 +321,15 @@ ;; remote-store.cc (define-record-type - (%make-nix-server socket major minor + (%make-nix-server socket major minor buffer ats-cache atts-cache) nix-server? (socket nix-server-socket) (major nix-server-major-version) (minor nix-server-minor-version) + (buffer nix-server-output-buffer) + ;; Caches. We keep them per-connection, because store paths build ;; during the session are temporary GC roots kept for the duration of ;; the session. @@ -499,6 +501,7 @@ for this connection will be pinned. Return a server object." (let ((conn (%make-nix-server port (protocol-major v) (protocol-minor v) + (make-bytevector 8192) (make-hash-table 100) (make-hash-table 100)))) (let loop ((done? (process-stderr conn))) @@ -718,6 +721,41 @@ encoding conversion errors." (let loop ((done? (process-stderr server))) (or done? (process-stderr server))))) +(define (buffering-output-port port buffer) + ;; Note: In Guile 2.2.2, custom binary output ports already have their own + ;; 4K internal buffer. + (define size + (bytevector-length buffer)) + + (define total 0) + + (define (flush) + (put-bytevector port buffer 0 total) + (set! total 0)) + + (define (write bv offset count) + (if (zero? count) ;end of file + (flush) + (let loop ((offset offset) + (count count) + (written 0)) + (cond ((= total size) + (flush) + (loop offset count written)) + ((zero? count) + written) + (else + (let ((to-copy (min count (- size total)))) + (bytevector-copy! bv offset buffer total to-copy) + (set! total (+ total to-copy)) + (loop (+ offset to-copy) (- count to-copy) + (+ written to-copy)))))))) + + (let ((port (make-custom-binary-output-port "buffering-output-port" + write #f #f flush))) + (setvbuf port _IONBF) + port)) + (define %rpc-calls ;; Mapping from RPC names (symbols) to invocation counts. (make-hash-table)) @@ -755,11 +793,15 @@ encoding conversion errors." ((_ (name (type arg) ...) docstring return ...) (lambda (server arg ...) docstring - (let ((s (nix-server-socket server))) + (let* ((s (nix-server-socket server)) + (buffered (buffering-output-port + s (nix-server-output-buffer server)))) (record-operation 'name) - (write-int (operation-id name) s) - (write-arg type arg s) + (write-int (operation-id name) buffered) + (write-arg type arg buffered) ... + (close-port buffered) + ;; Loop until the server is done sending error output. (let loop ((done? (process-stderr server))) (or done? (loop (process-stderr server)))) --=-=-=--