Skip to content

fix(transport): honor peer UDP payload limits for ordinary datagrams - #4081

Open
zerox80 wants to merge 4 commits into
mozilla:mainfrom
zerox80:codex/peer-udp-payload-limit
Open

zerox80 wants to merge 4 commits into
mozilla:mainfrom
zerox80:codex/peer-udp-payload-limit

Conversation

@zerox80

@zerox80 zerox80 commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

When a peer advertises max_udp_payload_size = 1200, neqo only used it to bound PMTUD probes. Ordinary datagrams still used the default PLPMTU of 1252 (IPv4) or 1232 (IPv6) bytes, which such a peer may drop.

Cap plpmtu() by the peer limit and apply it in set_initial_limits(), so it is in effect as soon as the peer's transport parameters are known, including the remembered ones for 0-RTT, and on all paths.

Pacer::next() now takes the current PLPMTU as an argument, like it already takes cwnd, instead of keeping a copy that had to be synced on ACK and loss.

When the peer limit lowers the PLPMTU, cwnd is reduced to the initial window for the new size (RFC 9002, Section 7.2).

See RFC 9000, Section 18.2.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Applying the peer limit leaves the pacer using its previous MTU until later ACK or loss processing.

1 open finding
What changed in this PR

Caps ordinary QUIC datagrams by the peer-advertised UDP payload limit while preserving PMTU discovery state.

Changes:

  • Applies the peer limit to effective PLPMTU.
  • Adds IPv4/IPv6, directional, PMTUD, congestion-control, and pacing tests.
File Description
neqo-transport/​src/​pmtud.rs Caps effective PLPMTU and adds unit coverage.
neqo-transport/​src/​sender.rs Tests congestion-control and pacer behavior.
neqo-transport/​src/​connection/​tests/​pmtud.rs Adds end-to-end payload-limit tests.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread neqo-transport/src/pmtud.rs Outdated
Comment on lines 118 to 119
pub const fn set_peer_max_udp_payload(&mut self, peer_max_udp_payload: usize) {
self.peer_max_udp_payload = Some(peer_max_udp_payload);
@codecov

codecov Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.03%. Comparing base (e0f8bbf) to head (18837d6).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4081      +/-   ##
==========================================
- Coverage   97.19%   97.03%   -0.16%     
==========================================
  Files         113      118       +5     
  Lines       41742    42189     +447     
  Branches    41742    42189     +447     
==========================================
+ Hits        40570    40940     +370     
- Misses       1156     1223      +67     
- Partials       16       26      +10     
Flag Coverage Δ
freebsd 94.67% <100.00%> (-0.12%) ⬇️
linux 97.23% <100.00%> (+<0.01%) ⬆️
macos 95.42% <100.00%> (+0.01%) ⬆️
windows 95.51% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
neqo-common 99.31% <ø> (ø)
neqo-http3 95.44% <ø> (+0.03%) ⬆️
neqo-qpack 97.10% <ø> (ø)
neqo-transport 98.03% <100.00%> (-0.02%) ⬇️
neqo-udp 95.37% <ø> (ø)
mtu 89.13% <ø> (ø)

@codspeed

codspeed Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will regress 2 benchmarks

⚠️ 1 benchmark spent significant time in system calls

System calls cannot be consistently instrumented, so they are not included in the measure, which understates the real cost. Please switch to the Walltime instrument to accurately measure system calls.

Measurement and system calls

⚡ 4 improved benchmarks
❌ 2 regressed benchmarks
✅ 95 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
❌ CPU Simulation spend disabled 12 µs 12.5 µs -4.15%
❌ Walltime neqo-neqo-cubic 25.1 ms 26 ms -3.49%
⚡ CPU Simulation next fast-path 14.5 µs 12.8 µs +13.34%
⚡ Walltime walltime/pacing-true/same-seed 4.4 ms 4.3 ms +3.36%
⚡ Walltime walltime/pacing-false/same-seed 3.9 ms 3.8 ms +3.17%
⚡ CPU Simulation simulated/pacing-false/varying-seeds 70.5 ms 68.6 ms +2.7%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing zerox80:codex/peer-udp-payload-limit (18837d6) with main (a04c990)

Open in CodSpeed

@zerox80 zerox80 closed this Oct 16, 2026
@zerox80
zerox80 deleted the codex/peer-udp-payload-limit branch October 16, 2026 17:37
@zerox80
zerox80 restored the codex/peer-udp-payload-limit branch October 16, 2026 17:40
@zerox80 zerox80 reopened this Oct 16, 2026
@larseggert
larseggert requested a balanced review from Copilot October 19, 2026 14:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The focused sizing and pacing changes have relevant regression coverage and no identified blocking issues.

1 open issue

Review effort: Balanced

@larseggert larseggert left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be much more concise. There are also some correctness concerns.

Comment thread neqo-transport/src/connection/mod.rs Outdated
path.borrow_mut()
.pmtud_mut()
.set_peer_max_udp_payload(max_udp_payload);
path.borrow_mut().set_peer_max_udp_payload(max_udp_payload);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes the limit only apply at handshake completion, which is too late.

Comment thread neqo-transport/src/sender.rs Outdated
}

/// Apply the peer's UDP payload limit and synchronize the pacer's packet size.
pub fn set_peer_max_udp_payload(&mut self, peer_max_udp_payload: usize) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more place that has to remember to sync the pacer. Can we route through PacketSender?

Comment thread neqo-transport/src/pmtud.rs Outdated
/// Set the peer's `max_udp_payload_size` transport parameter as an upper bound for probing.
/// Set the peer's `max_udp_payload_size` transport parameter as an upper bound for datagrams
/// and probing.
pub const fn set_peer_max_udp_payload(&mut self, peer_max_udp_payload: usize) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The capped plpmtu gets no mtu_updated qlog event.

Comment thread neqo-transport/src/path.rs Outdated
p.prime_rtt(primary.borrow().rtt());
if let Some(peer_max) = primary.borrow().pmtud().peer_max_udp_payload() {
p.pmtud_mut().set_peer_max_udp_payload(peer_max);
p.set_peer_max_udp_payload(peer_max);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Paths that exist before the parameters are processed never get the limit

/// sent in an ordinary datagram, capped by the peer's receive limit when known. PMTU probes
/// use [`Self::probe_size`] and are separately bounded by the peer's receive limit.
#[must_use]
pub const fn plpmtu(&self) -> usize {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you consolidate the capping with what next does?

tparams::{TransportParameter, TransportParameterId},
};

fn connect_with_udp_payload_limits(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reuse/extend the existing helpers please.

}

#[test]
fn peer_max_udp_payload_limits_datagrams() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of duplication between the two tests, be more DRY.
Also, why the loops here? The behavior does not depend on them at all?

@zerox80

zerox80 commented Oct 19, 2026

Copy link
Copy Markdown
Contributor Author

@larseggert Thanks, I’ll simplify this and address the correctness gaps: apply the limit when peer transport parameters become available, propagate it to existing and future paths, and consolidate the sizing logic with pacing and qlog updates. I’ll also reuse the existing test helpers and replace the duplicated cases with focused regression coverage.

@zerox80
zerox80 force-pushed the codex/peer-udp-payload-limit branch from 681076f to badbe6c Compare October 19, 2026 20:27

@larseggert larseggert left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is getting more complex and not less. @zerox80, please check your LLM output.

Comment on lines +55 to +114
#[test]
fn peer_max_udp_payload_limits_datagrams() {
let params = ConnectionParameters::default()
.pmtud(true)
.pmtud_iface_mtu(false);
let mut client = new_client(params.clone());
let mut server = new_server(params);
client
.set_local_tparam(
TransportParameterId::MaxUdpPayloadSize,
TransportParameter::Integer(1200),
)
.unwrap();
connect(&mut client, &mut server);

check_datagram_sizes(&mut server, &mut client, 1200);
assert_eq!(server.stats().pmtud_tx, 0);
let client_mtu = client.plpmtu();
assert!(client_mtu > 1200);
check_datagram_sizes(&mut client, &mut server, client_mtu);
}

#[test]
fn peer_max_udp_payload_applies_during_handshake() {
let mut client = new_client(ConnectionParameters::default());
let mut server = default_server();
client
.set_local_tparam(
TransportParameterId::MaxUdpPayloadSize,
TransportParameter::Integer(1200),
)
.unwrap();
server.process_input(client.process_output(now()).dgram().unwrap(), now());
let response = server
.process(client.process_output(now()).dgram(), now())
.dgram()
.unwrap();
assert_eq!(*server.state(), crate::State::Handshaking);
assert_eq!(server.plpmtu(), 1200);
assert_eq!(response.len(), 1200);
}

#[test]
fn peer_max_udp_payload_applies_to_resumption() {
let mut client = new_client(ConnectionParameters::default());
let mut server = default_server();
server
.set_local_tparam(
TransportParameterId::MaxUdpPayloadSize,
TransportParameter::Integer(1200),
)
.unwrap();
connect(&mut client, &mut server);
let token = super::exchange_ticket(&mut client, &mut server, now());
let mut client = new_client(ConnectionParameters::default());
client.enable_resumption(now(), token).unwrap();
assert_eq!(client.plpmtu(), 1200);
assert_eq!(client.process_output(now()).dgram().unwrap().len(), 1200);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests still have a lot of duplication. Don't repeat yourself.

Comment thread neqo-transport/src/path.rs Outdated

/// Whether PMTUD is enabled for this connection.
pmtud: bool,
peer_max_udp_payload: Option<usize>,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this per path? TPs apply to a connection.

.dgram()
.unwrap();
assert_eq!(datagrams.num_datagrams(), 2);
// GSO permits a larger probe first, followed by a smaller last datagram.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh? GSO does not matter here.

The peer's max_udp_payload_size only bounded PMTUD probes, so ordinary
datagrams could still use the default 1252/1232-byte PLPMTU when the
peer advertised 1200.

Cap plpmtu() by the peer limit, sharing the bound with next(). Apply it
in set_initial_limits(), so it takes effect as soon as the peer's
transport parameters are known (including remembered ones for 0-RTT),
on all paths, and log the resulting MTU change. The pacer now picks up
PLPMTU changes before each send.
@zerox80
zerox80 force-pushed the codex/peer-udp-payload-limit branch from badbe6c to 07c7dee Compare October 20, 2026 16:06
@zerox80

zerox80 commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

This PR is getting more complex and not less. @zerox80, please check your LLM output.

Sorry about the last round. I used an LLM for parts of it and missed some of the things it added when I went over it. I started over from main and kept only what's needed:

  • plpmtu() is capped by the peer limit, using the same bound as next(), and a change logs mtu_updated.
  • The limit is applied in set_initial_limits(), so it is in effect as soon as the peer's transport parameters are known (including the remembered ones for 0-RTT), on all paths. No extra state in Paths anymore.
  • Two connection tests (server's first flight, resumed client's first flight) replace the old ones.

Why per path: Pmtud sits in each path's sender, and CC and the pacer read plpmtu() from there, so each path's Pmtud needs the value, as on main already. New paths copy it from the primary.

Pacer: on_packet_sent() now refreshes the pacer MTU before each send, so no other place has to remember to sync it. Happy to change that if you had something else in mind.

@zerox80
zerox80 requested a review from larseggert October 20, 2026 16:22
The pacer kept its own copy of the packet size, which every PLPMTU
change had to sync. Pass the PLPMTU to `Pacer::next()` instead, so the
pacer always uses the current value.
RFC 9002 Section 7.2: if the maximum datagram size decreases, the
congestion window SHOULD be set to the new initial congestion window.
Route the peer limit through the congestion controller so it can do
that, without raising a window that is already smaller.

Share an assertion helper across the connection tests, check that a new
path inherits the limit, and assert the logged MTU values.
@zerox80

zerox80 commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Follow-up to my comment above: I pushed two more commits. One passes the current PLPMTU directly to the pacer instead of keeping a separate copy, removing the synchronization logic. The other caps cwnd at the new initial window when the peer limit lowers the PLPMTU, following RFC 9002 Section 7.2.

I realize this increased the diff again. I'm having trouble finding a smaller approach that still addresses the correctness concerns.

Would you prefer keeping these changes together, splitting the pacer refactor and the cwnd adjustment into separate PRs, or taking a different approach? I'd appreciate any pointers on what you'd simplify.

@github-actions

Copy link
Copy Markdown
Contributor

Failed Interop Tests

QUIC Interop Runner, client vs. server, differences relative to main at e0f8bbf.

neqo-pr as clientneqo-pr as server
neqo-pr vs. go-x-net: BP BA
neqo-pr vs. haproxy: BP BA
neqo-pr vs. kwik: 🚀S ⚠️H C20 M Z ⚠️3 L1 C1 🚀BA
neqo-pr vs. linuxquic: baseline result missing
neqo-pr vs. lsquic: L1 C1
neqo-pr vs. msquic: Z A L1 🚀L2 C1 🚀BP
neqo-pr vs. mvfst: A 🚀BA
neqo-pr vs. neqo: Z A
neqo-pr vs. nginx: BP BA
neqo-pr vs. ngtcp2: Z ⚠️L1 CM
neqo-pr vs. picoquic: ⚠️Z A
neqo-pr vs. quic-go: A
neqo-pr vs. quiche: BP BA
neqo-pr vs. s2n-quic: CM
neqo-pr vs. tquic: S BP BA
neqo-pr vs. xquic: S R Z A L1 C1
go-x-net vs. neqo-pr: CM
kwik vs. neqo-pr: BP BA CM
linuxquic vs. neqo-pr: baseline result missing
msquic vs. neqo-pr: CM
mvfst vs. neqo-pr: Z L1 C1 CM
neqo vs. neqo-pr: baseline result missing
openssl vs. neqo-pr: LR M A CM
quic-go vs. neqo-pr: CM
quic-zig vs. neqo-pr: CM
quiche vs. neqo-pr: run cancelled after 20 min
quinn vs. neqo-pr: 🚀C1 V2 CM
s2n-quic vs. neqo-pr: CM
tquic vs. neqo-pr: CM
xquic vs. neqo-pr: M CM
All results

Succeeded Interop Tests

QUIC Interop Runner, client vs. server

neqo-pr as client

neqo-pr as server

Unsupported Interop Tests

QUIC Interop Runner, client vs. server

neqo-pr as client

neqo-pr as server

@github-actions

Copy link
Copy Markdown
Contributor

Benchmark results

No significant performance differences relative to a8809b4.

All results
transfer/1-conn/1-100mb-req (aka. Upload)/mtu-1500
       time:   [60.158 ms 60.192 ms 60.229 ms]
       thrpt:  [1.6214 GiB/s 1.6224 GiB/s 1.6233 GiB/s]
Found 2 outliers among 100 measurements (2.00%)
2 (2.00%) high mild
transfer/1-conn/1-100mb-resp (aka. Download)/mtu-1500
       time:   [60.325 ms 60.371 ms 60.416 ms]
       thrpt:  [1.6164 GiB/s 1.6176 GiB/s 1.6188 GiB/s]
Found 2 outliers among 100 measurements (2.00%)
1 (1.00%) low mild
1 (1.00%) high mild
transfer/1-conn/1-1b-resp (aka. HPS)/mtu-1500
       time:   [3.5402 ms 3.5409 ms 3.5417 ms]
       thrpt:  [282.35   B/s 282.41   B/s 282.47   B/s]
Found 9 outliers among 100 measurements (9.00%)
7 (7.00%) high mild
2 (2.00%) high severe
transfer/1-conn/10_000-parallel-1b-resp (aka. RPS)/mtu-1500
       time:   [81.000 ms 81.247 ms 81.455 ms]
       thrpt:  [122.77 Kelem/s 123.08 Kelem/s 123.46 Kelem/s]
Found 4 outliers among 100 measurements (4.00%)
2 (2.00%) low severe
2 (2.00%) low mild
streams-flow-controlled/walltime/1-streams/each-4194304-bytes
       time:   [12.605 ms 12.608 ms 12.612 ms]
       thrpt:  [317.16 MiB/s 317.25 MiB/s 317.34 MiB/s]
streams-flow-controlled/walltime/10-streams/each-1048576-bytes
       time:   [33.694 ms 33.708 ms 33.721 ms]
       thrpt:  [296.55 MiB/s 296.67 MiB/s 296.79 MiB/s]
Found 3 outliers among 100 measurements (3.00%)
1 (1.00%) low mild
2 (2.00%) high mild
streams/walltime/1-streams/each-1000-bytes
       time:   [155.95 µs 156.57 µs 157.36 µs]
       thrpt:  [6.0605 MiB/s 6.0911 MiB/s 6.1152 MiB/s]
Found 2 outliers among 100 measurements (2.00%)
2 (2.00%) high mild
streams/walltime/1000-streams/each-1-bytes
       time:   [4.4804 ms 4.4846 ms 4.4888 ms]
       thrpt:  [217.56 KiB/s 217.76 KiB/s 217.96 KiB/s]
Found 3 outliers among 100 measurements (3.00%)
3 (3.00%) low mild
streams/walltime/1000-streams/each-1000-bytes
       time:   [14.806 ms 14.816 ms 14.827 ms]
       thrpt:  [64.320 MiB/s 64.366 MiB/s 64.413 MiB/s]
transfer/walltime/pacing-false/same-seed
       time:   [3.8808 ms 3.8834 ms 3.8866 ms]
       thrpt:  [1.0051 GiB/s 1.0059 GiB/s 1.0066 GiB/s]
Found 1 outliers among 100 measurements (1.00%)
1 (1.00%) high mild
transfer/walltime/pacing-false/varying-seeds
       time:   [3.8905 ms 3.8922 ms 3.8944 ms]
       thrpt:  [1.0031 GiB/s 1.0036 GiB/s 1.0040 GiB/s]
transfer/walltime/pacing-true/same-seed
       time:   [4.1099 ms 4.1130 ms 4.1166 ms]
       thrpt:  [971.67 MiB/s 972.53 MiB/s 973.26 MiB/s]
transfer/walltime/pacing-true/varying-seeds
       time:   [4.1809 ms 4.1830 ms 4.1854 ms]
       thrpt:  [955.70 MiB/s 956.26 MiB/s 956.73 MiB/s]
Found 1 outliers among 100 measurements (1.00%)
1 (1.00%) low mild

Instructions per cycle

Criterion reported no significant timing changes.

All benchmarks
Benchmark IPC before IPC after ΔIPC
transfer/walltime/pacing-false/same-seed 2.88 2.82 -2.0%
transfer/walltime/pacing-false/varying-seeds 2.87 2.83 -1.5%
streams-flow-controlled/walltime/1-streams/each-4194304-bytes 2.98 3.01 +1.2%
streams/walltime/1000-streams/each-1-bytes 3.26 3.28 +0.6%
transfer/walltime/pacing-true/same-seed 2.88 2.86 -0.5%
streams-flow-controlled/walltime/10-streams/each-1048576-bytes 3.19 3.17 -0.4%
transfer/1-conn/1-100mb-resp (aka. Download)/mtu-1500 3.19 3.18 -0.4%
transfer/1-conn/10_000-parallel-1b-resp (aka. RPS)/mtu-1500 3.19 3.18 -0.4%
streams/walltime/1000-streams/each-1000-bytes 2.95 2.96 +0.4%
transfer/1-conn/1-100mb-req (aka. Upload)/mtu-1500 3.12 3.12 +0.3%
transfer/walltime/pacing-true/varying-seeds 2.87 2.87 -0.2%
transfer/1-conn/1-1b-resp (aka. HPS)/mtu-1500 2.22 2.22 -0.1%
streams/walltime/1-streams/each-1000-bytes 2.57 2.57 -0.0%
Profiles for profiler.firefox.com (64)

Download data for profiler.firefox.com or download performance comparison data.

@github-actions

Copy link
Copy Markdown
Contributor

Client/server transfer results

Performance differences relative to a8809b4.

Transfer of 33554432 bytes over loopback, min. 100 runs. All unit-less numbers are in milliseconds.

Client vs. server Mean±σ Min–Max Median±MAD MiB/s±σ ΔMedian
google-neqo-cubic 80.7 ± 0.4 79.8 – 81.7 80.7 ± 0.4 396.7 ± 2.1 💔 +1.1 (+1.4%)
neqo-google-cubic 268.6 ± 39.7 201.0 – 328.6 283.2 ± 37.2 119.1 ± 17.6 💔 +74.9 (+35.9%)
neqo-neqo-newreno-nopacing 23.1 ± 0.2 22.8 – 23.6 23.0 ± 0.1 1386.0 ± 9.7 💚 -0.3 (-1.5%)

Table above only shows statistically significant changes. See all results below.

All results

Transfer of 33554432 bytes over loopback, min. 100 runs. All unit-less numbers are in milliseconds.

Client vs. server Mean±σ Min–Max Median±MAD MiB/s±σ ΔMedian
google-google 155.9 ± 0.7 154.1 – 157.5 156.0 ± 0.7 205.2 ± 0.9
google-neqo-cubic 80.7 ± 0.4 79.8 – 81.7 80.7 ± 0.4 396.7 ± 2.1 💔 +1.1 (+1.4%)
neqo-google-cubic 268.6 ± 39.7 201.0 – 328.6 283.2 ± 37.2 119.1 ± 17.6 💔 +74.9 (+35.9%)
neqo-neqo-cubic 23.3 ± 0.2 22.9 – 23.7 23.2 ± 0.1 1375.4 ± 9.6 -0.1 (-0.6%)
neqo-neqo-cubic-nopacing 23.1 ± 0.2 22.8 – 23.7 23.1 ± 0.2 1383.5 ± 10.8 -0.0 (-0.1%)
neqo-neqo-newreno 23.4 ± 0.2 23.0 – 23.9 23.3 ± 0.1 1369.9 ± 9.3 -0.1 (-0.3%)
neqo-neqo-newreno-nopacing 23.1 ± 0.2 22.8 – 23.6 23.0 ± 0.1 1386.0 ± 9.7 💚 -0.3 (-1.5%)
neqo-quiche-cubic 34.5 ± 0.3 33.9 – 35.6 34.4 ± 0.4 928.7 ± 9.0 +0.2 (+0.4%)
neqo-s2n-cubic 44.9 ± 0.2 44.5 – 45.3 44.9 ± 0.2 712.4 ± 3.4 -0.0 (-0.1%)
quiche-neqo-cubic 35.7 ± 0.4 34.9 – 37.2 35.7 ± 0.4 895.4 ± 10.8 -0.1 (-0.2%)
quiche-quiche 41.3 ± 0.3 40.4 – 42.0 41.3 ± 0.3 774.6 ± 5.9
s2n-neqo-cubic 126.6 ± 0.6 125.8 – 129.5 126.5 ± 0.5 252.7 ± 1.2 +0.3 (+0.2%)
s2n-s2n ⚠️ 177.1 ± 26.0 145.6 – 296.2 170.7 ± 1.3 180.7 ± 26.6

Download data for profiler.firefox.com or download performance comparison data.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants