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: auto-tune stream receive window #1868

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

Conversation

mxinden
Copy link
Collaborator

@mxinden mxinden commented May 2, 2024

Previously the stream send and receive window had a hard limit at 1MB. On high latency and/or high bandwidth connections (i.e. large bandwidth-delay product), 1 MB is not enough to exhaust the available bandwidth.

Sample scenario:

delay_s = 0.05
window_bits = 1 * 1024 * 1024 * 8
bandwidth_bits_s = window_bits / delay_s
bandwidth_mbits_s = bandwidth_bits_s / 1024 / 1024 # 160.0

In other words, on a 50 ms connection a 1 MB window can at most achieve 160 Mbit/s.

This commit introduces an auto-tuning algorithm for the stream receive window, increasing the window towards the bandwidth-delay product of the connection.


Work in progress for now. Able to transfer >160Mbit/s on a 50ms link already.

Currently implementing the algorithm proposed in #733 (comment). I still have to familiarize myself with the algorithm proposed in #733 (comment). Which ever is chosen, both need the same scaffolding.

Fixes #733.

TODO

  • Reasonable upper limit (e.g. 500ms and 1gbit/s)
  • Shrink buffers
  • Investigate only linear CC increase on simulator (no loss)

mxinden added 2 commits April 25, 2024 16:43
This commit adds a basic smoke test using the `test-ficture` simulator,
asserting that on a connection with unlimited bandwidth and 50ms round-trip-time
Neqo can eventually achieve > 1 Gbit/s throughput.

Showcases the potential a future stream flow-control auto-tuning algorithm can have.

See mozilla#733.
Previously the stream send and receive window had a hard limit at 1MB. On high
latency and/or high bandwidth connections, 1 MB is not enough to exhaust the
available bandwidth.

Sample scenario:

```
delay_s = 0.05
window_bits = 1 * 1024 * 1024 * 8
bandwidth_bits_s = window_bits / delay_s
bandwidth_mbits_s = bandwidth_bits_s / 1024 / 1024 # 160.0
```

In other words, on a 50 ms connection a 1 MB window can at most achieve 160
Mbit/s.

This commit introduces an auto-tuning algorithm for the stream receive window,
increasing the window towards the bandwidth-delay product of the connection.
Copy link

github-actions bot commented May 7, 2024

Failed Interop Tests

QUIC Interop Runner, client vs. server, differences relative to bb45c74.

neqo-latest as client

neqo-latest as server

All results

Succeeded Interop Tests

QUIC Interop Runner, client vs. server

neqo-latest as client

neqo-latest as server

Unsupported Interop Tests

QUIC Interop Runner, client vs. server

neqo-latest as client

neqo-latest as server

Copy link

github-actions bot commented May 7, 2024

Firefox builds for this PR

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

mxinden added 17 commits May 14, 2024 15:49
This commit adds a basic smoke test using the `test-fixture` simulator,
asserting the expected bandwidth on a 1 gbit link.

Given mozilla#733, the current expected bandwidth
is limited by the fixed sized stream receive buffer (1MiB).
A `Node` (e.g. a `Client`, `Server` or `TailDrop` router) can be in 3 states:

``` rust
enum NodeState {
    /// The node just produced a datagram.  It should be activated again as soon as possible.
    Active,
    /// The node is waiting.
    Waiting(Instant),
    /// The node became idle.
    Idle,
}
```

`NodeHolder::ready()` determines whether a `Node` is ready to be processed
again. When `NodeState::Waiting`, it should only be ready when `t <= now`, i.e.
the waiting time has passed, not `t >= now`.

``` rust
impl NodeHolder {
    fn ready(&self, now: Instant) -> bool {
        match self.state {
            Active => true,
            Waiting(t) => t <= now, // not >=
            Idle => false,
        }
    }
}
```

The previous behavior lead to wastefull non-ready `Node`s being processed and
thus a large test runtime when e.g. simulating a gbit
connection (mozilla#2203).
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.

Better algorithm for stream flow control
1 participant