unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
From: Mark H Weaver <mhw@netris.org>
To: Rob Browning <rlb@defaultvalue.org>
Cc: guile-devel@gnu.org
Subject: Re: Unexpectedly low read/write performance of open-pipe
Date: Tue, 09 Apr 2019 04:35:38 -0400	[thread overview]
Message-ID: <87k1g3y3re.fsf@netris.org> (raw)
In-Reply-To: <87k1g3ll96.fsf@trouble.defaultvalue.org> (Rob Browning's message of "Tue, 09 Apr 2019 01:56:37 -0500")

Hi Rob,

Rob Browning <rlb@defaultvalue.org> writes:

> Mark H Weaver <mhw@netris.org> writes:
>
>> See below for a draft reimplementation of the OPEN_BOTH mode of
>> open-pipe* based on R6RS custom binary input/output.  On my machine it
>> increases the speed of your test by a factor of ~1k.
>
> Hah, I was about to report that I'd tested something along similar lines
> (though much more a quick hack to just replace make-rw-port and see what
> happened), and that I had seen substantial improvements:
>
>   (define (make-rw-bin-port read-port write-port)
>     (define (read! dest offset count)
>       (let ((result (get-bytevector-n! read-port dest offset count)))
>         (if (eof-object? result) 0 result)))
>     (define (write! src offset count)
>       (put-bytevector write-port src offset count)
>       count)
>     (define (close x)
>       (close-port read-port)
>       (close-port write-port))
>     (make-custom-binary-input/output-port "open-bin-pipe-port"
>                                           read! write! #f #f
>                                           close))

Hah, we had the same idea! :-)

FYI, the reason I didn't use 'get-bytevector-n!', although it leads to
the much simpler code above, is that it has the wrong semantics
w.r.t. blocking behavior.  'get-bytevector-n!' blocks until the entire
requested count is read, returning less than the requested amount only
if EOF is reached.

In this case, 'read!' is free to return less than 'count' bytes, and
should block _only_ as needed to ensure that at least one byte is
returned (or EOF).  Of course, an effort should be made to return
additional bytes, and preferably a sizeable buffer, but only if it can
be done without blocking unnecessarily.

Guile has only one I/O primitive capable of doing this job efficiently:
'get-bytevector-some'.  Internally, it works by simply returning the
entire existing port read buffer if it's non-empty.  If the read buffer
is empty, then read(2) is used to refill the read buffer, which is then
returned to the user.

The reason for the extra complexity in my reimplementation is that
there's no way to specify an upper bound on the size of the bytevector
returned by 'get-bytevector-some', so in general we may need to preserve
the remaining bytes more future 'read!' calls.

>> Let me know how it works for you.
>
> For a first quick test of your patch using the original program I was
> working on, I see about ~1.4MiB/s without the patch, and about 150MiB/s
> with it, measured by pv.

It's interesting that I saw a much larger improvement than you're
seeing.  In my case, the numbers reported by your test program went from
~0.35 mb/s to ~333 mb/s, on a Thinkpad X200.

> (If the patch holds up, it'd be nice to have in 2.2, but I suppose that
>  might not be appropriate.)

I think it's probably fine for 2.2, although a more careful check should
be made for differences in behavior between the old and new
implementations, and tests should be added.  I'll try to get to it soon.

      Regards,
        Mark



  reply	other threads:[~2019-04-09  8:35 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-04-07 18:28 Unexpectedly low read/write performance of open-pipe Rob Browning
2019-04-07 18:45 ` Rob Browning
2019-04-07 19:47   ` Rob Browning
2019-04-07 21:28     ` Rob Browning
2019-04-08 10:52       ` Mark H Weaver
2019-04-09  6:56         ` Rob Browning
2019-04-09  8:35           ` Mark H Weaver [this message]
2019-04-09  9:21             ` Chris Vine
2019-04-09 18:24               ` Mark H Weaver
2019-04-09 21:36                 ` Chris Vine
2019-04-10  0:07                 ` Mark H Weaver
2019-04-16 21:42                   ` Mark H Weaver
2019-04-09 18:33               ` Mark H Weaver
2019-04-17  4:02           ` Mark H Weaver
2019-04-21 16:22             ` Rob Browning
2019-04-22 18:39               ` Arne Babenhauserheide
2019-04-23  7:32 ` tomas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87k1g3y3re.fsf@netris.org \
    --to=mhw@netris.org \
    --cc=guile-devel@gnu.org \
    --cc=rlb@defaultvalue.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).