Skip to content

Commit

Permalink
Use WorkLimiter also for sending data
Browse files Browse the repository at this point in the history
This adds time-based yielding to the send loop in the same fashion it
had been previously added ot the receive loop.
In my performance testing this didn't show a noticeable difference - likely
because in the current benchmark the client is the bottleneck. But it should
make things more deterministic.
  • Loading branch information
Matthias247 committed Sep 19, 2021
1 parent 5d3a103 commit 437a60c
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 6 deletions.
20 changes: 14 additions & 6 deletions quinn/src/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::{
connection::Connecting,
platform::{RecvMeta, UdpSocket, BATCH_SIZE},
work_limiter::WorkLimiter,
ConnectionEvent, EndpointEvent, VarInt, IO_LOOP_BOUND, RECV_TIME_BOUND,
ConnectionEvent, EndpointEvent, VarInt, IO_LOOP_BOUND, RECV_TIME_BOUND, SEND_TIME_BOUND,
};

/// A QUIC endpoint.
Expand Down Expand Up @@ -269,6 +269,7 @@ where
driver_lost: bool,
recv_limiter: WorkLimiter,
recv_buf: Box<[u8]>,
send_limiter: WorkLimiter,
idle: Broadcast,
}

Expand Down Expand Up @@ -340,7 +341,7 @@ where
}

fn drive_send(&mut self, cx: &mut Context) -> Result<bool, io::Error> {
let mut transmits = 0;
self.send_limiter.start_cycle();
loop {
while self.outgoing.len() < BATCH_SIZE {
match self.inner.poll_transmit() {
Expand All @@ -349,22 +350,28 @@ where
}
}
if self.outgoing.is_empty() {
self.send_limiter.finish_cycle();
return Ok(false);
}

if !self.send_limiter.allow_work() {
self.send_limiter.finish_cycle();
return Ok(true);
}

match self.socket.poll_send(cx, self.outgoing.as_slices().0) {
Poll::Ready(Ok(n)) => {
self.outgoing.drain(..n);
// We count transmits instead of `poll_send` calls since the cost
// of a `sendmmsg` still linearily increases with number of packets.
transmits += n;
if transmits >= IO_LOOP_BOUND {
return Ok(true);
}
self.send_limiter.record_work(n);
}
Poll::Pending => {
self.send_limiter.finish_cycle();
return Ok(false);
}
Poll::Ready(Err(e)) => {
self.send_limiter.finish_cycle();
return Err(e);
}
}
Expand Down Expand Up @@ -522,6 +529,7 @@ where
driver_lost: false,
recv_buf: recv_buf.into(),
recv_limiter: WorkLimiter::new(RECV_TIME_BOUND),
send_limiter: WorkLimiter::new(SEND_TIME_BOUND),
idle: Broadcast::new(),
})))
}
Expand Down
3 changes: 3 additions & 0 deletions quinn/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,6 @@ const IO_LOOP_BOUND: usize = 160;
/// Going much lower does not yield any noticeable difference, since a single `recvmmsg`
/// batch of size 32 was observed to take 30us on some systems.
const RECV_TIME_BOUND: Duration = Duration::from_micros(50);

/// The maximum amount of time that should be spent in `sendmsg()` calls per endpoint iteration
const SEND_TIME_BOUND: Duration = Duration::from_micros(50);

0 comments on commit 437a60c

Please sign in to comment.