k0001 / network-simple

Haskell library abstracting common network sockets usage patterns.
BSD 3-Clause "New" or "Revised" License
33 stars 9 forks source link

Vectored IO will reduce system calls and make sending faster #11

Closed kvanbere closed 10 years ago

kvanbere commented 10 years ago

Consider: https://github.com/k0001/network-simple/blob/master/src/Network/Simple/TCP.hs#L316

network now has vectored IO: https://hackage.haskell.org/package/network-2.5.0.0/docs/Network-Socket-ByteString.html#g:2

This will be faster on platforms supporting it.

kvanbere commented 10 years ago

Also, this is a good read: http://blog.libtorrent.org/2012/12/principles-of-high-performance-programs/

It's what got me curious to see if Haskell had vectored IO support.

k0001 commented 10 years ago

@kvanberendonck thanks for bringing this up.

So, if I understand you correctly, the intention here is to add, alongside Network.Simple.TCP.send, something like this which internally uses vectored IO:

sendMany :: MonadIO m => NS.Socket -> [BS.ByteString] -> m ()

Is that what you have on your mind?

kvanbere commented 10 years ago

Ah, my mistake. I did not see the braces in the type.

I got the impression since ByteStrings were chunked internally this would be a free performance upgrade to sending many chunks from a chunked BS. Maybe the performance win still exists, but it could be harder to attain.

kvanbere commented 10 years ago

Turns out lazy ByteStrings already have this support in network. http://hackage.haskell.org/package/network-2.3.0.11/docs/src/Network-Socket-ByteString-Lazy.html#send

(note the c_writev).

There is no way to make strict Bytestrings faster with vectored IO unless you have a streaming library like, for example, pipes-group. Sorry I closed this kind of too promptly. Reopen if you want to add support for vectored IO to network-simple for lists of ByteStrings.

k0001 commented 10 years ago

Still, I think it would be useful to export sendLazy :: MonadIO m => NS.Socket -> Lazy.ByteString -> m () from Network.Simple.TCP, which does just that. A Lazy ByteString is, after all, pretty much a list of strict ByteStrings. What do you think?

kvanbere commented 10 years ago

It would be a good idea. If anything, to open up room for experimentation later.


Related to pipes-network: I wonder if it's possible to rig up pipes-network to have a batching interface. Like, "run this pipe until it returns Nothing and then send all the ByteStrings you get at once using vectored IO". This would make it extremely easy to wrap around the main packet processing loop of i.e. a game server, so if it needs to send 2-3 packets to the same socket in reaction to some message, they go out vectored (and you yield Nothing once at the very end to "flush"..)

kvanbere commented 10 years ago

12

k0001 commented 10 years ago

I don't think we should add that behaviour to pipes-network as it seems quite specific to a particular use case and it can be confusing (and “not simple”, as in network-simple) to new users. Besides, you can already use send (or this newly introduced sendLazy) as a Pipes.Effect without any lifting whatsoever, so in a sense you can already accomplish what you want, right?