• Andrei Tudor Călin's avatar
    net: add support for splice(2) in (*TCPConn).ReadFrom on Linux · f2316c27
    Andrei Tudor Călin authored
    This change adds support for the splice system call on Linux,
    for the purpose of optimizing (*TCPConn).ReadFrom by reducing
    copies of data from and to userspace. It does so by creating a
    temporary pipe and splicing data from the source connection to the
    pipe, then from the pipe to the destination connection. The pipe
    serves as an in-kernel buffer for the data transfer.
    
    No new API is added to package net, but a new Splice function is
    added to package internal/poll, because using splice requires help
    from the network poller. Users of the net package should benefit
    from the change transparently.
    
    This change only enables the optimization if the Reader in ReadFrom
    is a TCP connection. Since splice is a more general interface, it
    could, in theory, also be enabled if the Reader were a unix socket,
    or the read half of a pipe.
    
    However, benchmarks show that enabling it for unix sockets is most
    likely not a net performance gain. The tcp <- unix case is also
    fairly unlikely to be used very much by users of package net.
    
    Enabling the optimization for pipes is also problematic from an
    implementation perspective, since package net cannot easily get at
    the *poll.FD of an *os.File. A possible solution to this would be
    to dup the pipe file descriptor, register the duped descriptor with
    the network poller, and work on that *poll.FD instead of the original.
    However, this seems too intrusive, so it has not been done. If there
    was a clean way to do it, it would probably be worth doing, since
    splicing from a pipe to a socket can be done directly.
    
    Therefore, this patch only enables the optimization for what is likely
    the most common use case: tcp <- tcp.
    
    The following benchmark compares the performance of the previous
    userspace genericReadFrom code path to the new optimized code path.
    The sub-benchmarks represent chunk sizes used by the writer on the
    other end of the Reader passed to ReadFrom.
    
    benchmark                          old ns/op     new ns/op     delta
    BenchmarkTCPReadFrom/1024-4        4727          4954          +4.80%
    BenchmarkTCPReadFrom/2048-4        4389          4301          -2.01%
    BenchmarkTCPReadFrom/4096-4        4606          4534          -1.56%
    BenchmarkTCPReadFrom/8192-4        5219          4779          -8.43%
    BenchmarkTCPReadFrom/16384-4       8708          8008          -8.04%
    BenchmarkTCPReadFrom/32768-4       16349         14973         -8.42%
    BenchmarkTCPReadFrom/65536-4       35246         27406         -22.24%
    BenchmarkTCPReadFrom/131072-4      72920         52382         -28.17%
    BenchmarkTCPReadFrom/262144-4      149311        95094         -36.31%
    BenchmarkTCPReadFrom/524288-4      306704        181856        -40.71%
    BenchmarkTCPReadFrom/1048576-4     674174        357406        -46.99%
    
    benchmark                          old MB/s     new MB/s     speedup
    BenchmarkTCPReadFrom/1024-4        216.62       206.69       0.95x
    BenchmarkTCPReadFrom/2048-4        466.61       476.08       1.02x
    BenchmarkTCPReadFrom/4096-4        889.09       903.31       1.02x
    BenchmarkTCPReadFrom/8192-4        1569.40      1714.06      1.09x
    BenchmarkTCPReadFrom/16384-4       1881.42      2045.84      1.09x
    BenchmarkTCPReadFrom/32768-4       2004.18      2188.41      1.09x
    BenchmarkTCPReadFrom/65536-4       1859.38      2391.25      1.29x
    BenchmarkTCPReadFrom/131072-4      1797.46      2502.21      1.39x
    BenchmarkTCPReadFrom/262144-4      1755.69      2756.68      1.57x
    BenchmarkTCPReadFrom/524288-4      1709.42      2882.98      1.69x
    BenchmarkTCPReadFrom/1048576-4     1555.35      2933.84      1.89x
    
    Fixes #10948
    
    Change-Id: I3ce27f21f7adda8b696afdc48a91149998ae16a5
    Reviewed-on: https://go-review.googlesource.com/107715
    Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
    Run-TryBot: Ian Lance Taylor <iant@golang.org>
    TryBot-Result: Gobot Gobot <gobot@golang.org>
    Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
    f2316c27