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

fix(transport): only emit SendStreamWritable on ack if prev. blocked #1821

Closed
wants to merge 2 commits into from

Conversation

mxinden
Copy link
Collaborator

@mxinden mxinden commented Apr 13, 2024

neqo_transport::SendStream emits ConnectionEvent::SendStreamWritable to inform a user that they can write more data into a stream.

It emits this event in 3 cases:

  • on SendStream::new
  • on SendStream::set_max_data
  • on SendStream::mark_as_acked

Emitting a SendStreamWritable event, even though writing wasn't previously blocked, is useless. That is why SendStream::set_max_data only emits the event if sending was previously blocked on stream flow control.

pub fn set_max_stream_data(&mut self, limit: u64) {
if let SendStreamState::Ready { fc, .. } | SendStreamState::Send { fc, .. } =
&mut self.state
{
let stream_was_blocked = fc.available() == 0;
fc.update(limit);
if stream_was_blocked && self.avail() > 0 {
self.conn_events.send_stream_writable(self.stream_id);
}
}
}

This commit adds the corresponding check to SendStream::mark_as_acked as well. I.e. it checks whether sending was previously blocked on the tx buffer size, before emitting a SendStreamWritable event.

This is especially relevant for SendStream::mark_as_acked, as each received ack would otherwise result in a SendStreamWritable event. The event in itself isn't expensive. The logic it triggers is.


As an example, I was seeing > 200 SendStreamWritable events queued at once in the Download benchmark.

I suggest prioritizing the related #1819 (bug) before this pull request (optimization).

`neqo_transport::SendStream` emits `ConnectionEvent::SendStreamWritable` to
inform a user that they can write more data into a stream.

It emits this event in 3 cases:

- on `SendStream::new`
- on `SendStream::set_max_data`
- on `SendStream::mark_as_acked`

Emitting a `SendStreamWritable` event, even though writing wasn't previously
blocked, is useless. That is why `SendStream::set_max_data` only emits the event
if sending was previously blocked on stream flow control.

https://github.com/mozilla/neqo/blob/c004359a817ffdea33394e94944d2f882e7e78af/neqo-transport/src/send_stream.rs#L1206-L1216

This commit adds the corresponding check to `SendStream::mark_as_acked` as well.
I.e. it checks whether sending was previously blocked on the tx buffer size,
before emitting a `SendStreamWritable` event.

This is especially relevant for `SendStream::mark_as_acked`, as each received
ack would otherwise result in a `SendStreamWritable` event. The event in itself
isn't expensive. The logic it triggers is.
@mxinden mxinden changed the title fix(SendStream): only emit SendStreamWritable on ack if prev. blocked fix(transport): only emit SendStreamWritable on ack if prev. blocked Apr 13, 2024
Copy link

codecov bot commented Apr 15, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 93.13%. Comparing base (c004359) to head (55b2bc8).
Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1821   +/-   ##
=======================================
  Coverage   93.13%   93.13%           
=======================================
  Files         117      117           
  Lines       36353    36383   +30     
=======================================
+ Hits        33857    33887   +30     
  Misses       2496     2496           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@mxinden
Copy link
Collaborator Author

mxinden commented Apr 15, 2024

I expect the latest benchmark stall to be due to #1819.

mxinden added a commit to mxinden/neqo that referenced this pull request Apr 17, 2024
Previously `SendMessage::send_data` could stall, if less than the minimum
message size is available to be sent. See
mozilla#1819 for details.

This commit implements solution (3) proposed in
mozilla#1819.

This commit introduces `SendStream::set_writable_event_low_watermark` which is
then used in `SendMessage::send_data` to signal to `SendStream` the minimum
required send space (low watermark) for the next send. Once reached,
`SendStream` emits a `SendStreamWritable` eventually triggering another
`SendMessage::send_data`.

Alternative to mozilla#1835. Compared to
mozilla#1835, this fix does not utilize the
`SendMessage` buffer, thus does not introduce an indirection to the send path.
In addition, under the assumption that available send space is increased in
larger batches, this fix does not send tiny data frames (2 byte header, 1 byte
goodput). Downside, compared to mozilla#1835, is
that it requires both changes in `neqo-transport` and `neqo-http3`.

Secondarily, this fixes mozilla#1821 as well.
mxinden added a commit to mxinden/neqo that referenced this pull request Apr 17, 2024
Previously `SendMessage::send_data` could stall, if less than the minimum
message size is available to be sent. See
mozilla#1819 for details.

This commit implements solution (3) proposed in
mozilla#1819.

This commit introduces `SendStream::set_writable_event_low_watermark` which is
then used in `SendMessage::send_data` to signal to `SendStream` the minimum
required send space (low watermark) for the next send. Once reached,
`SendStream` emits a `SendStreamWritable` eventually triggering another
`SendMessage::send_data`.

Alternative to mozilla#1835. Compared to
mozilla#1835, this fix does not utilize the
`SendMessage` buffer, thus does not introduce an indirection to the send path.
In addition, under the assumption that available send space is increased in
larger batches, this fix does not send tiny data frames (2 byte header, 1 byte
goodput). Downside, compared to mozilla#1835, is
that it requires both changes in `neqo-transport` and `neqo-http3`.

Secondarily, this fixes mozilla#1821 as well.
@mxinden
Copy link
Collaborator Author

mxinden commented Apr 22, 2024

Note that this pull request would be made obsolete by #1838. I prefer #1838 over this pull request.

github-merge-queue bot pushed a commit that referenced this pull request May 7, 2024
…1838)

* fix(SendMessage): use SendStream::set_writable_event_low_watermark

Previously `SendMessage::send_data` could stall, if less than the minimum
message size is available to be sent. See
#1819 for details.

This commit implements solution (3) proposed in
#1819.

This commit introduces `SendStream::set_writable_event_low_watermark` which is
then used in `SendMessage::send_data` to signal to `SendStream` the minimum
required send space (low watermark) for the next send. Once reached,
`SendStream` emits a `SendStreamWritable` eventually triggering another
`SendMessage::send_data`.

Alternative to #1835. Compared to
#1835, this fix does not utilize the
`SendMessage` buffer, thus does not introduce an indirection to the send path.
In addition, under the assumption that available send space is increased in
larger batches, this fix does not send tiny data frames (2 byte header, 1 byte
goodput). Downside, compared to #1835, is
that it requires both changes in `neqo-transport` and `neqo-http3`.

Secondarily, this fixes #1821 as well.

* Move const

* Add documentation

* Add SendStream test

* Fix intra doc links

* Add neqo-http3 test

* Replace goodput with payload

* Re-trigger benchmarks

Let's see whether the "Download" benchmark is consistent.

* Rename emit_writable_event to maybe_emit_writable_event

* Replace expect with unwrap

* Use NonZeroUsize::get

* Replace expect with unwrap

* %s/Actually sending/Sending

* Typo

* Have update() return available amount

* Document setting once would suffice

* Reduce verbosity

* fix: drop RefCell mutable borrow early
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.

1 participant