[racket] Performance of open-output-nowhere

From: Antonio Menezes Leitao (antonio.menezes.leitao at ist.utl.pt)
Date: Thu Jul 24 19:21:10 EDT 2014

On Thu, Jul 24, 2014 at 10:04 AM, Matthew Flatt <mflatt at cs.utah.edu> wrote:

> At Thu, 24 Jul 2014 09:27:42 +0100, Antonio Menezes Leitao wrote:
> > Hi,
> >
> > While trying to benchmark some of my code, I tried to minimize the time
> > spend on predefined IO functions, such as write-byte & friends, by using
> > the port returned by open-output-nowhere, expecting that it would be
> faster
> > than using, e.g., open-output-bytes, which has to accumulate the output.
> >
> > However, contrary to my expectations, it turns out that using
> > open-output-nowhere is 10 times slower that using open-output-bytes.
> >
> > Here is one example:
> >
> > #lang racket
> > (define (test i n p)
> >   (time (for ([l (in-range n)])
> >           (write-byte i p))))
> >
> > (test 123 100000000 (open-output-bytes))
> > (test 123 100000000 (open-output-nowhere))
> >
> > I'm getting:
> >
> > cpu time: 2860 real time: 2854 gc time: 32
> > cpu time: 28906 real time: 28904 gc time: 125
> >
> > What's causing this difference?
>
> Byte-string output ports are built into the run-time system, while
> `open-output-nowhere` is implemented with `make-output-port`. The
> run-time system does a lot of work to protect itself from output ports
> constructed by `make-output-port` that might be misbehaved, so that's
> why it's is slower. Meanwhile, the path to write a single byte to a
> byte-string port is streamlined within the run-time system.
>
> I've considered building `open-output-nowhere` into the run-time
> system, but I think we're more likely to go the other direction:
> re-implement the port layer in Racket with a simpler and smaller
> interface from the run-time system.
>

Is it possible to do the second approach without degrading the current
performance of byte-string output ports? If that's possible, I would
definitely prefer that.

Out of curiosity, does this difference in performance show up in your
> application? Writing a single byte at a time in blocking mode is the
> worst-case scenario for comparing byte-string ports versus ports
> constructed with `make-output-port`. Still, given the speed for writing
> 100 million individual bytes even for `open-output-nowhere`, I would
> expect a typical application driving that work to take a lot more time.
>

This is just a matter of expectations. I expected that an output port that
does not write anything has a smaller impact on the performance than an
output port that has to keep the output in a buffer.

In fact, my application does not need to use ports created by
open-output-nowhere but for purposes of comparing the performance of two
different approaches to a particular encoding scheme, I was trying to
minimize the time spend in the output functions and I imagined that a
simple way of doing that without messing with the code of the functions
would be to use an output port that does not write anything. Moreover, this
has the advantage that it does not run out of memory even if the benchmark
runs for a very long time. This is what I expect, for example, from Common
Lisp and, indeed, that's the case in the Common Lisp implementations that I
use (allegro and sbcl).

Thanks for the explanation.

Best,
António.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20140725/a39de3d3/attachment.html>

Posted on the users mailing list.