[racket] Performance of open-output-nowhere
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.
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.