crystal icon indicating copy to clipboard operation
crystal copied to clipboard

Socket#sendfile

Open carlhoerberg opened this issue 5 years ago • 7 comments

Request for comments

Benchmark result:

    copy 4.0kiB 209.50k (  4.77µs) (± 3.76%)  0.0B/op   1.23× slower
sendfile 4.0kiB 257.89k (  3.88µs) (± 3.72%)  0.0B/op        fastest
    copy 1.0MiB   1.09k (914.69µs) (± 5.40%)  0.0B/op   2.30× slower
sendfile 1.0MiB   2.51k (397.83µs) (± 2.92%)  0.0B/op        fastest
    copy 128MiB   7.94  (125.88ms) (± 5.99%)  0.0B/op   2.16× slower
sendfile 128MiB  17.17  ( 58.24ms) (± 3.59%)  0.0B/op        fastest

Benchmark code:

require "benchmark"
require "socket"

nc = Process.new "nc", ["-l", "-k", "localhost", "1234"]

{ 4096, 1024**2, 128 * 1024**2 }.each do |size|
  TCPSocket.open("localhost", 1234) do |s|
    File.open("/tmp/a", "w+") do |a|
      a.delete
      a.print "a" * size

      Benchmark.ips do |x|
        x.report("copy #{size.humanize_bytes}") do
          a.rewind
          IO.copy a, s, a.size
        end
        x.report("sendfile #{size.humanize_bytes}") do
          a.rewind
          s.sendfile a, a.size
        end
      end
    end
  end
end
nc.kill

carlhoerberg avatar Mar 22 '20 01:03 carlhoerberg

Obviously have to copy/write the read buffer of the source before the sendfile call, just as in #8919, but waiting to see if that's being accepted first

carlhoerberg avatar Mar 22 '20 01:03 carlhoerberg

Please allow this discussion to continue before making any changes to the code

RX14 avatar Mar 23 '20 10:03 RX14

libevent implements sendfile in its event buffer thingy. But I guess there must been some reason to why Crystal has it's own buffering layer instead of using libevent's?

http://www.wangafu.net/~nickm/libevent-2.1/doxygen/html/buffer_8h.html#a601996b1fc1f5c165dc62b89acbd069e

carlhoerberg avatar Apr 14 '20 22:04 carlhoerberg

I think those functions were unknown to the implementors.

asterite avatar Apr 14 '20 22:04 asterite

I think IO::Buffered was implemented before we started using libevent.

ysbaddaden avatar Apr 15 '20 09:04 ysbaddaden

I'd prefer not to bind crystal's IO design closer to libevent than it already is, personally.

RX14 avatar Apr 15 '20 14:04 RX14

How is the impact of using sendfile with a large file? Does the system gets into a long syscall? I guess when the fd is set as nonblocking it should return as soon as the output buffer is full, but is worth to try. Just because the test benchmark gives better numbers doesn't necessarily mean is good for a system running with many concurrent users. We need to check how it affects latency in those cases.

In any case, I think I'd prefer to have the Socket#sendfile but not make the automatic switch in IO#copy. If sendfile only works with sockets (and files?) then it makes sense to be a method in the Socket class. And let the one writing the code to decide if the syscall is preferred or not. At least as a non-breaking change starting point.

waj avatar Jun 06 '20 16:06 waj