-
Notifications
You must be signed in to change notification settings - Fork 124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(udp): pre-allocate receive buffer #1707
Conversation
Instead of allocating a new receive buffer on each call to `neqo_common::udp::Socket::recv`, preallocate a long-lived buffer in `Socket::bind` and reuse this buffer on each read.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1707 +/- ##
==========================================
- Coverage 92.98% 92.97% -0.01%
==========================================
Files 120 120
Lines 37340 37342 +2
==========================================
- Hits 34719 34718 -1
- Misses 2621 2624 +3 ☔ View full report in Codecov by Sentry. |
Ok(Some(Datagram::new( | ||
meta.addr, | ||
*local_address, | ||
meta.ecn.map(|n| IpTos::from(n as u8)).unwrap_or_default(), | ||
None, // TODO: get the real TTL https://github.com/quinn-rs/quinn/issues/1749 | ||
&buf[..meta.len], | ||
&self.recv_buf[..meta.len], | ||
))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that each call to Datagram::new
allocates the datagram's data in a new Vec
.
neqo/neqo-common/src/datagram.rs
Lines 20 to 35 in ad027cf
impl Datagram { | |
pub fn new<V: Into<Vec<u8>>>( | |
src: SocketAddr, | |
dst: SocketAddr, | |
tos: IpTos, | |
ttl: Option<u8>, | |
d: V, | |
) -> Self { | |
Self { | |
src, | |
dst, | |
tos, | |
ttl, | |
d: d.into(), | |
} | |
} |
Changing this is a larger undertaking I would like to tackle with #1693.
@@ -31,6 +32,7 @@ impl Socket { | |||
Ok(Self { | |||
state: quinn_udp::UdpSocketState::new((&socket).into())?, | |||
socket: tokio::net::UdpSocket::from_std(socket)?, | |||
recv_buf: vec![0; u16::MAX as usize], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is too large. I get that we don't want to overflow, but unless we are receiving multiple datagrams, we only need 2k or so (a constant might be a good idea for that limit).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this too large? This is about ~43 packets, which is smaller than realistic WAN congestion windows. Are you worried about Fx memory usage of this is per-socket?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ignore the comment. I was reading this patch on its own and missed the follow-up that includes multiple packets.
I do think that a constant is the right thing to use for this, rather than the (rather arbitrary) u16::MAX
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are two server implementations based on neqo: 1. https://github.com/mozilla/neqo/tree/main/neqo-bin/src/server - http3 and http09 implementation - used for manual testing and QUIC Interop 2. https://searchfox.org/mozilla-central/source/netwerk/test/http3server/src/main.rs - used to test Firefox I assume one was once an exact copy of the other. Both implement their own I/O, event loop, ... Since then, the two implementations diverged significantly. Especially (1) saw a lot of improvements in recent months: - mozilla#1564 - mozilla#1569 - mozilla#1578 - mozilla#1581 - mozilla#1604 - mozilla#1612 - mozilla#1676 - mozilla#1692 - mozilla#1707 - mozilla#1708 - mozilla#1727 - mozilla#1753 - mozilla#1756 - mozilla#1766 - mozilla#1772 - mozilla#1786 - mozilla#1787 - mozilla#1788 - mozilla#1794 - mozilla#1806 - mozilla#1808 - mozilla#1848 - mozilla#1866 At this point, bugs in (2) are hard to fix, see e.g. mozilla#1801. This commit merges (2) into (1), thus removing all duplicate logic and having (2) benefit from all the recent improvements to (1).
There are two server implementations based on neqo: 1. https://github.com/mozilla/neqo/tree/main/neqo-bin/src/server - http3 and http09 implementation - used for manual testing and QUIC Interop 2. https://searchfox.org/mozilla-central/source/netwerk/test/http3server/src/main.rs - used to test Firefox I assume one was once an exact copy of the other. Both implement their own I/O, event loop, ... Since then, the two implementations diverged significantly. Especially (1) saw a lot of improvements in recent months: - mozilla#1564 - mozilla#1569 - mozilla#1578 - mozilla#1581 - mozilla#1604 - mozilla#1612 - mozilla#1676 - mozilla#1692 - mozilla#1707 - mozilla#1708 - mozilla#1727 - mozilla#1753 - mozilla#1756 - mozilla#1766 - mozilla#1772 - mozilla#1786 - mozilla#1787 - mozilla#1788 - mozilla#1794 - mozilla#1806 - mozilla#1808 - mozilla#1848 - mozilla#1866 At this point, bugs in (2) are hard to fix, see e.g. mozilla#1801. This commit merges (2) into (1), thus removing all duplicate logic and having (2) benefit from all the recent improvements to (1).
* refactor(bin): introduce server/http3.rs and server/http09.rs The QUIC Interop Runner requires an http3 and http09 implementation for both client and server. The client code is already structured into an http3 and an http09 implementation since #1727. This commit does the same for the server side, i.e. splits the http3 and http09 implementation into separate Rust modules. * refactor: merge mozilla-central http3 server into neqo-bin There are two server implementations based on neqo: 1. https://github.com/mozilla/neqo/tree/main/neqo-bin/src/server - http3 and http09 implementation - used for manual testing and QUIC Interop 2. https://searchfox.org/mozilla-central/source/netwerk/test/http3server/src/main.rs - used to test Firefox I assume one was once an exact copy of the other. Both implement their own I/O, event loop, ... Since then, the two implementations diverged significantly. Especially (1) saw a lot of improvements in recent months: - #1564 - #1569 - #1578 - #1581 - #1604 - #1612 - #1676 - #1692 - #1707 - #1708 - #1727 - #1753 - #1756 - #1766 - #1772 - #1786 - #1787 - #1788 - #1794 - #1806 - #1808 - #1848 - #1866 At this point, bugs in (2) are hard to fix, see e.g. #1801. This commit merges (2) into (1), thus removing all duplicate logic and having (2) benefit from all the recent improvements to (1). * Move firefox.rs to mozilla-central * Reduce HttpServer trait functions * Extract constructor * Remove unused deps * Remove clap color feature Nice to have. Adds multiple dependencies. Hard to justify for mozilla-central.
Instead of allocating a new receive buffer on each call to
neqo_common::udp::Socket::recv
, preallocate a long-lived buffer inSocket::bind
and reuse this buffer on each read.See flamegraphs below. With the patch
neqo_common::udp::Socket::recv
simply delegates totokio::net::udp::UdpSocket::try_io
instead of spending significant time inmemset
.Quick-fix while working on #1693.
Addresses first performance issue in #1690.
Before:
After: