This change modifies quinn-proto to allow callers to submit a list
of one or more owned `Bytes` chunks for transmission instead of
pure byte slices. This will provide a more efficient zero-copy
interface for applications which already make use of owned
`Bytes` buffers.
The internals of quinn-proto have been refactored in order to keep
the ability to pass `&[u8]` buffers and defer the conversion into
`Bytes` as long as possible, in order to avoid unnecessary allocations
if no data can be stored due to flow control.
Since the loop was not exited after a close frame was transmitted,
other data in the same space could have been transmitted after
the frame. This adds a `break` to fix this.
The TestEndpoint so far tried to send a single big datagram instead of using
proper GSO sending to emit multiple datagrams.
In order to avoid relying on platform GSO support, this change will simply
split up GSO transmissions into multiple Transmits in the endpoint.
This change implements an initial version of GSO support [1][2][3]
for Linux, which improves the effiency of sending data.
The approach taken in this change is to create a buffer which contains
multiple datagrams in `Connection::poll_transmit`. This was picked
over trying to merge packets in the endpoint task, since packets
seem to need to be padded to a common segment size in order to
make them sendable via GSO.
In order to to this in an efficient fashion, the `poll_transmit`
method was restructred. Instead of selecting spaces upfront, it
will now loop through all possible packet spaces, check if there is
pending data to send and create packets and datagrams out of this.
The last packet which was written to a datagram buffer is not
finalized until it is clear whether follow-up packets need to be
written, since we need to know whether this packet should get padded
to MTU length or not.
This change doesn't enable GSO yet, since it will only produce a
single datagram. I will create a separate change for this.
Performance measurements:
**No GSO:**
```
Sent 1073741824 bytes on 1 streams in 4.31s (237.66 MiB/s)
```
**With GSO (up to 8 packets):**
```
Sent 1073741824 bytes on 1 streams in 3.02s (339.18 MiB/s)
```
[1] http://vger.kernel.org/lpc_net2018_talks/willemdebruijn-lpc2018-udpgso-paper-DRAFT-1.pdf
[2] http://vger.kernel.org/lpc_net2018_talks/willemdebruijn-lpc2018-udpgso-presentation-20181104.pdf
[3] https://lwn.net/Articles/752956/
This change defers padding packets as a runtime decision
while the packet is populated.
For individual packets, we store in `SentFrames` whether a padding is
required. If padding is required a `min_datagram_size` variable is
increased, which will later on assure that only the last packet in a
datagram gets padded.
With GSO storing the buffer inside the builder does not work
due to lifetime issues - we need to hold the buffer across various packets.
This keeps the buffer outside of the builder and just references the
start of a packet via an offset.
This also removes the lifetime from `PacketBuilder`.
rustls defaults to CHACHA20, which is rather slow on desktop hardware.
This change allows to specify a single cipher suite for this test, and
sets the default to AES128.
CHACHA20 (default):
> Sent 4294967296 bytes on 1 streams in 14.86s (275.68 MiB/s)
AES128:
> Sent 4294967296 bytes on 1 streams in 12.21s (335.59 MiB/s)
Testing showed that there is a huge performance boost using AES ciphers
due to hardware acceleration. Therefore those should be preferred.
As an example, a benchmark run using CHACHA20 reached a throughput
of 350MB/s, whereas the same configuration using AES128 reached 520MB/s.
While CHACHA20 might have higher performance on devices without
hardware acceleration for AES, this set of devices might now be tiny.
This causes nom to be pulled in, which currently causes the CI error and build
conflict between `funty` and `bitvec`: https://github.com/myrrlyn/funty/issues/3
We don't need the feature in this scenario anyway.