Skip to content
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

feat: DPLPMTUD #1903

Draft
wants to merge 57 commits into
base: main
Choose a base branch
from
Draft

feat: DPLPMTUD #1903

wants to merge 57 commits into from

Conversation

larseggert
Copy link
Collaborator

@larseggert larseggert commented May 14, 2024

This implements a simplified variant of PLDPMTUD (aka RFC8899), which by default probes for increasingly larger PMTUs using an MTU table.

There is currently no attempt to repeat the PMTUD at intervals. There is also no attempt to detect PMTUs that are in between values in the table. There is no attempt to handle the case where the PMTU shrinks.

A lot of the existing tests (~50%) break when PMTUD is enabled, so this PR disables it by default. New tests that cover PMTUD were added to this PR.

Fixes #243

@larseggert larseggert changed the title feat: Groudwork for DPLPMTUD feat: Groundwork for DPLPMTUD May 14, 2024
Copy link

github-actions bot commented May 14, 2024

Failed Interop Tests

QUIC Interop Runner, client vs. server

All results

Succeeded Interop Tests

QUIC Interop Runner, client vs. server

Unsupported Interop Tests

QUIC Interop Runner, client vs. server

@mxinden
Copy link
Collaborator

mxinden commented May 14, 2024

(There are also a bunch of warning about unused code that is actually used. I don't understand why that is, since those functions mirror existing ones such as cwnd_avail.)

As far as I can tell the trait function CongestionControl::cwnd_min and its implementation <ClassicCongestionControl<T> as CongestionControl>::cwnd_min are only called in PacketSender::cwnd_min. PacketSender::cwnd_min is only called in testing code. Thus, cargo complains about the 3 not being used.

Does that make sense @larseggert?

Copy link

github-actions bot commented May 14, 2024

Firefox builds for this PR

The following builds are available for testing. Crossed-out builds did not succeed.

neqo-transport/src/pmtud.rs Outdated Show resolved Hide resolved
neqo-transport/src/path.rs Outdated Show resolved Hide resolved
Copy link

github-actions bot commented May 14, 2024

Benchmark results

Performance differences relative to b900860.

coalesce_acked_from_zero 1+1 entries: No change in performance detected.
       time:   [196.26 ns 196.72 ns 197.21 ns]
       change: [-0.4267% -0.0721% +0.2810%] (p = 0.70 > 0.05)
Found 12 outliers among 100 measurements (12.00%)
  5 (5.00%) high mild
  7 (7.00%) high severe
coalesce_acked_from_zero 3+1 entries: Change within noise threshold.
       time:   [237.02 ns 237.73 ns 238.43 ns]
       change: [-1.6460% -1.2165% -0.8542%] (p = 0.00 < 0.05)
Found 19 outliers among 100 measurements (19.00%)
  15 (15.00%) high mild
  4 (4.00%) high severe
coalesce_acked_from_zero 10+1 entries: No change in performance detected.
       time:   [236.56 ns 236.90 ns 237.37 ns]
       change: [-1.1836% -0.4907% +0.3412%] (p = 0.26 > 0.05)
Found 3 outliers among 100 measurements (3.00%)
  3 (3.00%) high severe
coalesce_acked_from_zero 1000+1 entries: No change in performance detected.
       time:   [218.37 ns 218.57 ns 218.79 ns]
       change: [-6.2263% -2.4119% -0.1027%] (p = 0.18 > 0.05)
Found 14 outliers among 100 measurements (14.00%)
  3 (3.00%) low mild
  3 (3.00%) high mild
  8 (8.00%) high severe
RxStreamOrderer::inbound_frame(): Change within noise threshold.
       time:   [119.04 ms 119.16 ms 119.28 ms]
       change: [+0.1833% +0.3087% +0.4264%] (p = 0.00 < 0.05)

transfer/Run multiple transfers with varying seeds
time: [11.673 ms 11.972 ms 12.287 ms]
thrpt: [325.54 MiB/s 334.11 MiB/s 342.68 MiB/s]
change:
time: [-90.172% -89.920% -89.677%] (p = 0.00 < 0.05)
thrpt: [+868.74% +892.07% +917.51%]
:green_heart: Performance has improved.
Found 2 outliers among 100 measurements (2.00%)
2 (2.00%) high mild

transfer/Run multiple transfers with the same seed: 💚 Performance has improved.
       time:   [48.990 ms 49.276 ms 49.442 ms]
       thrpt:  [80.903 MiB/s 81.175 MiB/s 81.650 MiB/s]
change:
       time:   [-58.866% -58.606% -58.429%] (p = 0.00 < 0.05)
       thrpt:  [+140.55% +141.58% +143.11%]
Found 3 outliers among 100 measurements (3.00%)
  1 (1.00%) low severe
  1 (1.00%) low mild
  1 (1.00%) high mild
1-conn/1-100mb-resp (aka. Download)/client: 💚 Performance has improved.
       time:   [160.89 ms 169.02 ms 176.88 ms]
       thrpt:  [565.37 MiB/s 591.64 MiB/s 621.56 MiB/s]
change:
       time:   [-84.839% -83.199% -80.866%] (p = 0.00 < 0.05)
       thrpt:  [+422.62% +495.22% +559.59%]
Found 2 outliers among 10 measurements (20.00%)
  1 (10.00%) high mild
  1 (10.00%) high severe
1-conn/10_000-parallel-1b-resp (aka. RPS)/client: No change in performance detected.
       time:   [390.15 ms 393.63 ms 397.11 ms]
       thrpt:  [25.182 Kelem/s 25.405 Kelem/s 25.631 Kelem/s]
change:
       time:   [-2.3395% -1.1675% +0.0092%] (p = 0.06 > 0.05)
       thrpt:  [-0.0092% +1.1813% +2.3956%]
Found 1 outliers among 100 measurements (1.00%)
  1 (1.00%) low mild
1-conn/1-1b-resp (aka. HPS)/client: No change in performance detected.
       time:   [41.889 ms 42.076 ms 42.255 ms]
       thrpt:  [23.666  elem/s 23.766  elem/s 23.873  elem/s]
change:
       time:   [-0.1532% +0.3684% +0.8589%] (p = 0.16 > 0.05)
       thrpt:  [-0.8516% -0.3670% +0.1535%]
Found 28 outliers among 100 measurements (28.00%)
  11 (11.00%) low severe
  3 (3.00%) low mild
  14 (14.00%) high severe

Client/server transfer results

Transfer of 134217728 bytes over loopback.

Client Server CC Pacing Mean [ms] Min [ms] Max [ms] Relative
msquic msquic 395.7 ± 32.0 357.3 463.3 1.00
neqo msquic reno on 810.7 ± 30.7 771.8 871.2 1.00
neqo msquic reno 786.4 ± 17.5 767.5 815.9 1.00
neqo msquic cubic on 802.4 ± 27.9 766.8 843.2 1.00
neqo msquic cubic 805.6 ± 63.3 762.3 966.2 1.00
msquic neqo reno on 448.2 ± 32.2 414.6 530.4 1.00
msquic neqo reno 504.8 ± 214.6 393.1 1103.0 1.00
msquic neqo cubic on 494.5 ± 39.7 454.1 566.9 1.00
msquic neqo cubic 451.1 ± 43.6 378.7 500.1 1.00
neqo neqo reno on 708.0 ± 269.5 571.7 1434.5 1.00
neqo neqo reno 578.4 ± 25.3 532.0 624.3 1.00
neqo neqo cubic on 607.7 ± 43.0 525.5 667.6 1.00
neqo neqo cubic 597.6 ± 56.4 518.4 705.3 1.00

⬇️ Download logs

@larseggert larseggert marked this pull request as ready for review May 15, 2024 16:29
@larseggert larseggert changed the title feat: Groundwork for DPLPMTUD feat: DPLPMTUD May 21, 2024
Copy link
Member

@martinthomson martinthomson left a comment

Choose a reason for hiding this comment

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

I'm not seeing PMTUD tests, which would be necessary for this.

The big question I have is the one that Christian makes about PTMUD generally: how do you know that the bytes you use on PMTUD pay you back?

There is probably a case for sending probes when you have spare sending capacity and nothing better to send. Indeed, successfully probing will let us push congestion windows up more and could even improve performance.

What I'm seeing here displaces other data. I'd like to see something that doesn't do that. There's a fundamental problem that needs analysis though. You can't predict that a connection will be used for uploads, so you don't know when probes will really help. I see a few cases:

  1. The connection is short-lived or low volume. Probes are strictly wasteful.
  2. The connection is long-lived and high volume, with ample idle time for probing. Probes can use gaps. This might be a video stream, where probing can fit into a warmup period. Probes are therefore easy and super-helpful.
  3. The connection exists only to support a smaller upload. The upload is small enough that probes are wasteful.
  4. The connection exists only to support a larger upload. The upload is large enough that spending bytes on probing early on is a good investment.

Case 1 and 2 are easy to deal with. We could probe on an idle connection and tolerate a small amount of waste for case 1 if it makes case 2 appreciably better.

The split between 3 and 4 is rough. There is an uncertain zone between the two as well where some probing is justified, but successive rounds of probing might be wasteful as the throughput gain over the remaining time diminishes relative to the wasted effort of extra probes.

Right now, you don't send real data in probes. You are effectively betting on the probes being lost. But you could send data, which would reduce the harm in case 3. It might even make the code slightly simpler.

neqo-transport/src/pmtud.rs Outdated Show resolved Hide resolved
neqo-transport/src/pmtud.rs Outdated Show resolved Hide resolved
neqo-transport/src/pace.rs Outdated Show resolved Hide resolved
neqo-transport/src/path.rs Outdated Show resolved Hide resolved
neqo-transport/src/path.rs Outdated Show resolved Hide resolved
neqo-transport/src/pmtud.rs Outdated Show resolved Hide resolved
neqo-transport/src/pmtud.rs Outdated Show resolved Hide resolved
neqo-transport/src/pmtud.rs Outdated Show resolved Hide resolved
neqo-transport/src/pmtud.rs Outdated Show resolved Hide resolved
neqo-transport/src/path.rs Outdated Show resolved Hide resolved
Co-authored-by: Martin Thomson <mt@lowentropy.net>
Signed-off-by: Lars Eggert <lars@eggert.org>
neqo-transport/src/cc/classic_cc.rs Show resolved Hide resolved
neqo-transport/src/pmtud.rs Outdated Show resolved Hide resolved
neqo-transport/src/pmtud.rs Outdated Show resolved Hide resolved
neqo-transport/src/pmtud.rs Outdated Show resolved Hide resolved
neqo-transport/src/pmtud.rs Outdated Show resolved Hide resolved
now: Instant,
) {
// Track lost probes
let lost = self.count_pmtud_probes(lost_packets);
Copy link
Collaborator

@mxinden mxinden May 28, 2024

Choose a reason for hiding this comment

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

Is there a scenario where lost can be larger than 1? In other words, is there a scenario where more than one probe is in-flight at once?

If I understand correctly prepare_probe is only called in Probe::Needed. prepare_probe switches to Probe::Prepared. The state only switches back to Probe::Needed, when the in-flight probe has been lost or acked. Thus there is never more than one probe in-flight.

If the above is correct, why is there a count_pmtud_probes function? Am I missing something?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I tried to implement the algorithm @martinthomson outlined. There may well be optimizations.

larseggert and others added 11 commits May 28, 2024 16:34
Co-authored-by: Max Inden <mail@max-inden.de>
Signed-off-by: Lars Eggert <lars@eggert.org>
Co-authored-by: Max Inden <mail@max-inden.de>
Signed-off-by: Lars Eggert <lars@eggert.org>
Co-authored-by: Max Inden <mail@max-inden.de>
Signed-off-by: Lars Eggert <lars@eggert.org>
Co-authored-by: Max Inden <mail@max-inden.de>
Signed-off-by: Lars Eggert <lars@eggert.org>
@larseggert
Copy link
Collaborator Author

Making this a draft until the test failure is fixed.

@larseggert larseggert marked this pull request as draft May 31, 2024 12:50
@larseggert larseggert marked this pull request as draft May 31, 2024 12:50
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.

PMTU discovery
3 participants